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