2 * Acess2 Telnet Server (TCP server test case)
3 * - By John Hodge (thePowersGang)
12 #include <acess/sys.h>
15 #include <acess/devices/pty.h>
32 typedef struct sClient
34 enum eTelnetMode Mode;
41 void Server_NewClient(int FD);
42 void HandleServerBoundData(tClient *Client);
43 void HandleClientBoundData(tClient *Client);
44 void HandleOptionRequest(tClient *Client, int Option, bool Value, bool IsRequest);
47 // --- Configuration ---
48 int giConfig_MaxClients = 5;
55 int main(int argc, char *argv[])
60 gaClients = calloc(giConfig_MaxClients, sizeof(tClient));
65 int addrtype = Net_ParseAddress("10.0.2.10", data);
67 giServerFD = Net_OpenSocket(addrtype, data, "tcps");
68 _SysIOCtl(giServerFD, 4, &port); // Set port and start listening
77 static void FD_SET_MAX(fd_set *set, int fd, int *maxfd)
80 if(*maxfd < fd) *maxfd = fd;
93 FD_SET_MAX(&fds, giServerFD, &maxfd);
94 for( int i = 0; i < giConfig_MaxClients; i ++ )
96 if( gaClients[i].Socket == 0 ) continue ;
97 FD_SET_MAX(&fds, gaClients[i].Socket, &maxfd);
98 FD_SET_MAX(&fds, gaClients[i].pty, &maxfd);
102 int rv = _SysSelect( maxfd+1, &fds, NULL, NULL, NULL, 0 );
103 _SysDebug("Select return %i", rv);
106 if( FD_ISSET(giServerFD, &fds) )
108 Server_NewClient(giServerFD);
110 for( int i = 0; i < giConfig_MaxClients; i ++ )
112 if( FD_ISSET(gaClients[i].Socket, &fds) )
114 // Handle client data
115 HandleServerBoundData(&gaClients[i]);
117 if( FD_ISSET(gaClients[i].pty, &fds) )
119 // Handle output from terminal
120 HandleClientBoundData(&gaClients[i]);
126 void Server_NewClient(int FD)
130 // TODO: Is this done in the IPStack?
131 if( giNumClients == giConfig_MaxClients )
134 _SysClose( _SysOpenChild(FD, "", OPENFLAG_READ) );
138 // Allocate client structure and open socket
139 for( int i = 0; i < giConfig_MaxClients; i ++ )
141 if( gaClients[i].Socket == 0 ) {
147 // Accept the connection
148 clt->Socket = _SysOpenChild(FD, "", OPENFLAG_READ|OPENFLAG_WRITE);
153 clt->pty = _SysOpen("/Devices/pts/ptmx", OPENFLAG_READ|OPENFLAG_WRITE);
155 perror("Unable to create/open PTY");
156 _SysDebug("Unable to create/open PTY: %s", strerror(errno));
157 _SysClose(clt->Socket);
163 _SysIOCtl(clt->pty, PTY_IOCTL_SETID, "telnetd#");
164 struct ptymode mode = {.InputMode = 0, .OutputMode=0};
165 struct ptydims dims = {.W = 80, .H = 25};
166 _SysIOCtl(clt->pty, PTY_IOCTL_SETMODE, &mode);
167 _SysIOCtl(clt->pty, PTY_IOCTL_SETDIMS, &dims);
170 // TODO: Arguments and envp
172 char pty_path[] = "/Devices/pts/telnetd000";
173 _SysIOCtl(clt->pty, PTY_IOCTL_GETID, pty_path+13);
174 int clientfd = _SysOpen(pty_path, OPENFLAG_READ|OPENFLAG_WRITE);
176 perror("Unable to open login PTY");
177 _SysClose(clt->Socket);
182 _SysDebug("Using client PTY %s", pty_path);
183 int fds[3] = {clientfd, clientfd, clientfd};
184 const char *argv[] = {"login", NULL};
185 _SysSpawn("/Acess/SBin/login", argv, argv, 3, fds, NULL);
190 void HandleServerBoundData(tClient *Client)
195 _SysDebug("Client %p", Client);
196 len = _SysRead(Client->Socket, buf, BUFSIZ);
197 _SysDebug("%i bytes for %p", len, Client);
198 if( len == 0 ) return ;
203 // int last_flush = 0;
204 for( int i = 0; i < len; i ++ )
209 Client->Mode = MODE_DATA;
212 case 240: // End of subnegotiation parameters
213 _SysDebug("End Subnegotiation");
218 case 243: // NVT Break
219 case 244: // Function 'IP' (Ctrl-C)
222 case 245: // Function 'AO'
223 case 246: // Function 'AYT'
224 case 247: // Function 'EC'
225 case 248: // Function 'EL'
226 case 249: // GA Signal
228 case 250: // Subnegotation
229 _SysDebug("Subnegotiation");
230 // TODO: Get option ID, and then cache until 'END SB' (240)
231 Client->Mode = MODE_SUBNEG_OPTION;
234 Client->Mode = MODE_WILL;
237 Client->Mode = MODE_WONT;
240 Client->Mode = MODE_DO;
243 Client->Mode = MODE_DONT;
245 case 255: // Literal 255
246 _SysWrite(Client->pty, buf+i, 1);
251 _SysDebug("Option %i WILL", buf[i]);
252 HandleOptionRequest(Client, buf[i], true, false);
253 Client->Mode = MODE_DATA;
256 _SysDebug("Option %i WONT", buf[i]);
257 HandleOptionRequest(Client, buf[i], false, false);
258 Client->Mode = MODE_DATA;
261 _SysDebug("Option %i DO", buf[i]);
262 HandleOptionRequest(Client, buf[i], true, true);
263 Client->Mode = MODE_DATA;
266 _SysDebug("Option %i DONT", buf[i]);
267 HandleOptionRequest(Client, buf[i], false, true);
268 Client->Mode = MODE_DATA;
270 case MODE_SUBNEG_OPTION:
271 _SysDebug("Option %i subnegotation", buf[i]);
272 Client->Mode = MODE_SUBNEG_DATA;
274 case MODE_SUBNEG_IAC:
277 case 240: // End subnegotation
278 // TODO: Handle subnegotation data
279 Client->Mode = MODE_DATA;
283 Client->Mode = MODE_SUBNEG_DATA;
286 _SysDebug("Unexpected %i in SUBNEG IAC", buf[i]);
287 Client->Mode = MODE_SUBNEG_DATA;
290 case MODE_SUBNEG_DATA:
292 Client->Mode = MODE_SUBNEG_IAC;
294 ;//_SysWrite(Client->pty, buf+i, 1);
299 Client->Mode = MODE_IAC;
301 _SysWrite(Client->pty, buf+i, 1);
307 void HandleClientBoundData(tClient *Client)
312 len = _SysRead(Client->pty, buf, BUFSIZ);
313 if( len <= 0 ) return ;
314 _SysWrite(Client->Socket, buf, len);
317 void HandleOptionRequest(tClient *Client, int Option, bool Value, bool IsRequest)
322 _SysDebug("Unknown option %i", Option);