1 /*---------------------------------------------------------------------
2 RETRO is a personal, minimalistic forth with a pragmatic focus
3
4 This implements Nga, the virtual machine at the heart of RETRO. It
5 includes a number of I/O interfaces, extensive commentary, and has
6 been refined by over a decade of use and development.
7
8 Copyright (c) 2008 - 2020, Charles Childers
9
10 Portions are based on Ngaro, which was additionally copyrighted by
11 the following:
12
13 Copyright (c) 2009 - 2010, Luke Parrish
14 Copyright (c) 2010, Marc Simpson
15 Copyright (c) 2010, Jay Skeer
16 Copyright (c) 2011, Kenneth Keating
17 ---------------------------------------------------------------------*/
18
19
20 /*---------------------------------------------------------------------
21 C Headers
22 ---------------------------------------------------------------------*/
23
24 #include <ctype.h>
25 #include <errno.h>
26 #include <math.h>
27 #include <signal.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <sys/stat.h>
32 #include <sys/types.h>
33 #include <sys/wait.h>
34 #include <unistd.h>
35 #include <limits.h>
36 #include <fcntl.h>
37
38 #include "config.h"
39
40 /*---------------------------------------------------------------------
41 BSD Sockets
42 ---------------------------------------------------------------------*/
43
44 #include <arpa/inet.h>
45 #include <netinet/in.h>
46 #include <sys/socket.h>
47 #include <netdb.h>
48
49 int SocketID[16];
50 struct sockaddr_in Sockets[16];
51
52 struct addrinfo hints, *res;
53
socket_getaddrinfo()54 void socket_getaddrinfo() {
55 char host[1025], port[6];
56 bsd_strlcpy(port, string_extract(stack_pop()), 5);
57 bsd_strlcpy(host, string_extract(stack_pop()), 1024);
58 getaddrinfo(host, port, &hints, &res);
59 }
60
socket_get_host()61 void socket_get_host() {
62 struct hostent *hp;
63 struct in_addr **addr_list;
64
65 hp = gethostbyname(string_extract(stack_pop()));
66 if (hp == NULL) {
67 memory[stack_pop()] = 0;
68 return;
69 }
70
71 addr_list = (struct in_addr **)hp->h_addr_list;
72 string_inject(inet_ntoa(*addr_list[0]), stack_pop());
73 }
74
socket_create()75 void socket_create() {
76 int i;
77 int sock = socket(PF_INET, SOCK_STREAM, 0);
78 for (i = 0; i < 16; i++) {
79 if (SocketID[i] == 0 && sock != 0) {
80 SocketID[i] = sock;
81 stack_push((CELL)i);
82 sock = 0;
83 }
84 }
85 }
86
socket_bind()87 void socket_bind() {
88 int sock, port;
89 memset(&hints, 0, sizeof hints);
90 hints.ai_family = AF_UNSPEC;
91 hints.ai_socktype = SOCK_STREAM;
92 hints.ai_flags = AI_PASSIVE;
93
94 sock = stack_pop();
95 port = stack_pop();
96
97 getaddrinfo(NULL, string_extract(port), &hints, &res);
98 stack_push((CELL) bind(SocketID[sock], res->ai_addr, res->ai_addrlen));
99 stack_push(errno);
100 }
101
socket_listen()102 void socket_listen() {
103 int sock = stack_pop();
104 int backlog = stack_pop();
105 stack_push(listen(SocketID[sock], backlog));
106 stack_push(errno);
107 }
108
socket_accept()109 void socket_accept() {
110 int i;
111 int sock = stack_pop();
112 struct sockaddr_storage their_addr;
113 socklen_t addr_size = sizeof their_addr;
114 int new_fd = accept(SocketID[sock], (struct sockaddr *)&their_addr, &addr_size);
115
116 for (i = 0; i < 16; i++) {
117 if (SocketID[i] == 0 && new_fd != 0) {
118 SocketID[i] = new_fd;
119 stack_push((CELL)i);
120 new_fd = 0;
121 }
122 }
123 stack_push(errno);
124 }
125
socket_connect()126 void socket_connect() {
127 stack_push((CELL)connect(SocketID[stack_pop()], res->ai_addr, res->ai_addrlen));
128 stack_push(errno);
129 }
130
socket_send()131 void socket_send() {
132 int sock = stack_pop();
133 char *buf = string_extract(stack_pop());
134 stack_push(send(SocketID[sock], buf, strlen(buf), 0));
135 stack_push(errno);
136 }
137
socket_sendto()138 void socket_sendto() {
139 }
140
socket_recv()141 void socket_recv() {
142 char buf[8193];
143 int sock = stack_pop();
144 int limit = stack_pop();
145 int dest = stack_pop();
146 int len = recv(SocketID[sock], buf, limit, 0);
147 if (len > 0) buf[len] = '\0';
148 if (len > 0) string_inject(buf, dest);
149 stack_push(len);
150 stack_push(errno);
151 }
152
socket_recvfrom()153 void socket_recvfrom() {
154 }
155
socket_close()156 void socket_close() {
157 int sock = stack_pop();
158 close(SocketID[sock]);
159 SocketID[sock] = 0;
160 }
161
162 Handler SocketActions[] = {
163 socket_get_host,
164 socket_create, socket_bind, socket_listen,
165 socket_accept, socket_connect, socket_send,
166 socket_sendto, socket_recv, socket_recvfrom,
167 socket_close, socket_getaddrinfo
168 };
169
io_socket()170 void io_socket() {
171 SocketActions[stack_pop()]();
172 }
173
query_socket()174 void query_socket() {
175 stack_push(0);
176 stack_push(7);
177 }
178