Merge branch 'master' of git://cadel.mutabah.net/acess2
[tpg/acess2.git] / Usermode / Applications / telnetd_src / main.c
1 /*
2  * Acess2 Telnet Server (TCP server test case)
3  * - By John Hodge (thePowersGang)
4  *
5  * main.c
6  * - All
7  */
8 #include <stddef.h>
9 #include <net.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <acess/sys.h>
13 #include <assert.h>
14
15 // === TYPES ===
16 enum eTelnetMode
17 {
18         MODE_DATA,
19         MODE_IAC,
20         MODE_WILL,
21         MODE_WONT,
22         MODE_DO,
23         MODE_DONT
24 };
25
26 typedef struct sClient
27 {
28         enum eTelnetMode        Mode;
29          int    Socket;
30          int    pty;
31          int    stdin;
32          int    stdout;
33 } tClient;
34
35 // === PROTOTYPES ===
36 void    EventLoop(void);
37 void    Server_NewClient(int FD);
38 void    HandleServerBoundData(tClient *Client);
39 void    HandleClientBoundData(tClient *Client);
40
41 // === GLOBALS ===
42 // --- Configuration ---
43  int    giConfig_MaxClients = 5;
44 // --- State ---
45  int    giServerFD;
46 tClient *gaClients;
47  int    giNumClients;
48
49 // === CODE ===
50 int main(int argc, char *argv[])
51 {
52         // TODO: Configure
53
54         // Initialise
55         gaClients = calloc(giConfig_MaxClients, sizeof(tClient));
56
57         // Open server
58         {
59                 uint8_t data[16];
60                  int    addrtype = Net_ParseAddress("10.0.2.10", data);
61                  int    port = 23;
62                 giServerFD = Net_OpenSocket(addrtype, data, "tcps");
63                 _SysIOCtl(giServerFD, 4, &port);        // Set port and start listening
64         }
65
66         // Event loop
67         EventLoop();
68         
69         return 0;
70 }
71
72 static void FD_SET_MAX(fd_set *set, int fd, int *maxfd)
73 {
74         FD_SET(fd, set);
75         if(*maxfd < fd) *maxfd = fd;
76 }
77
78 void EventLoop(void)
79 {
80         fd_set  fds;
81          int    maxfd;
82
83         for( ;; )
84         {
85                 FD_ZERO(&fds);
86                 maxfd = 0;
87                 // Fill select
88                 FD_SET_MAX(&fds, giServerFD, &maxfd);
89                 for( int i = 0; i < giConfig_MaxClients; i ++ )
90                 {
91                         if( gaClients[i].Socket == 0 )  continue ;
92                         _SysDebug("Socket = %i, pty = %i",
93                                 gaClients[i].Socket, gaClients[i].pty);
94                         FD_SET_MAX(&fds, gaClients[i].Socket, &maxfd);
95                         FD_SET_MAX(&fds, gaClients[i].pty,  &maxfd);
96                 }
97                 
98                 // Select!
99                 _SysSelect( maxfd+1, &fds, NULL, NULL, NULL, 0 );
100                 
101                 // Check events
102                 if( FD_ISSET(giServerFD, &fds) )
103                 {
104                         Server_NewClient(giServerFD);
105                 }
106                 for( int i = 0; i < giConfig_MaxClients; i ++ )
107                 {
108                         if( FD_ISSET(gaClients[i].Socket, &fds) )
109                         {
110                                 // Handle client data
111                                 HandleServerBoundData(&gaClients[i]);
112                         }
113                         if( FD_ISSET(gaClients[i].pty, &fds) )
114                         {
115                                 // Handle output from terminal
116                                 HandleClientBoundData(&gaClients[i]);
117                         }
118                 }
119         }
120 }
121
122 void Server_NewClient(int FD)
123 {
124         tClient *clt = NULL;
125         
126         // TODO: Is this done in the IPStack?
127         if( giNumClients == giConfig_MaxClients )
128         {
129                 // Open, reject
130                 _SysClose( _SysOpenChild(FD, "", OPENFLAG_READ) );
131                 return ;
132         }
133         
134         // Allocate client structure and open socket
135         for( int i = 0; i < giConfig_MaxClients; i ++ )
136         {
137                 if( gaClients[i].Socket == 0 ) {
138                         clt = &gaClients[i];
139                         break;
140                 }
141         }
142         assert(clt);
143         // Accept the connection
144         clt->Socket = _SysOpenChild(FD, "", OPENFLAG_READ|OPENFLAG_WRITE);
145         giNumClients ++;
146         
147         // Create stdin/stdout
148         // TODO: Use PTYs
149         clt->stdin = _SysOpen("/Devices/fifo/anon", OPENFLAG_READ|OPENFLAG_WRITE);
150         clt->stdout = _SysOpen("/Devices/fifo/anon", OPENFLAG_READ|OPENFLAG_WRITE);
151         
152         // TODO: Arguments and envp
153         {
154                  int    clientfd = _SysOpen("/Devices/pts/telnetd0c", OPENFLAG_READ|OPENFLAG_WRITE);
155                 if(clientfd < 0) {
156                         perror("Unable to open login PTY");
157                         _SysClose(clt->Socket);
158                         _SysClose(clt->pty);
159                         clt->Socket = 0;
160                         return ;
161                 }
162                 int fds[3] = {clientfd, clientfd, clientfd};
163                 const char      *argv[] = {"login", NULL};
164                 _SysSpawn("/Acess/SBin/login", argv, argv, 3, fds, NULL);
165         }
166 }
167
168 void HandleServerBoundData(tClient *Client)
169 {
170         uint8_t buf[BUFSIZ];
171         size_t  len;
172         
173         len = _SysRead(Client->Socket, buf, BUFSIZ);
174         if( len == 0 )  return ;
175         if( len == -1 ) {
176                 return ;
177         }
178         // handle options
179          int    last_flush = 0;
180         for( int i = 0; i < len; i ++ )
181         {
182                 switch(Client->Mode)
183                 {
184                 case MODE_IAC:
185                         Client->Mode = MODE_DATA;
186                         switch(buf[i])
187                         {
188                         case 240:       // End of subnegotiation parameters
189                         case 241:       // Nop
190                                 break;
191                         case 242:       // SYNCH
192                         case 243:       // NVT Break
193                         case 244:       // Function 'IP' (Ctrl-C)
194                                 
195                                 break;
196                         case 245:       // Function 'AO'
197                         case 246:       // Function 'AYT'
198                         case 247:       // Function 'EC'
199                         case 248:       // Function 'EL'
200                         case 249:       // GA Signal
201                         case 250:       // Subnegotation
202                                 break;
203                         case 251:       // WILL
204                                 Client->Mode = MODE_WILL;
205                                 break;
206                         case 252:       // WONT
207                                 Client->Mode = MODE_WILL;
208                                 break;
209                         case 253:       // DO
210                                 Client->Mode = MODE_WILL;
211                                 break;
212                         case 254:       // DONT
213                                 Client->Mode = MODE_WILL;
214                                 break;
215                         case 255:       // Literal 255
216                                 Client->Mode = MODE_DATA;
217                                 i --;   // hacky!
218                                 break;
219                         }
220                         break;
221                 case MODE_WILL:
222                         _SysDebug("Option %i WILL", buf[i]);
223                         Client->Mode = MODE_DATA;
224                         break;
225                 case MODE_WONT:
226                         _SysDebug("Option %i WONT", buf[i]);
227                         Client->Mode = MODE_DATA;
228                         break;
229                 case MODE_DO:
230                         _SysDebug("Option %i DO", buf[i]);
231                         Client->Mode = MODE_DATA;
232                         break;
233                 case MODE_DONT:
234                         _SysDebug("Option %i DONT", buf[i]);
235                         Client->Mode = MODE_DATA;
236                         break;
237                 case MODE_DATA:
238                         if( buf[i] == 255 )
239                                 Client->Mode = MODE_IAC;
240                         else
241                                 _SysWrite(Client->pty, buf+i, 1);
242                         break;
243                 }
244         }
245 }
246
247 void HandleClientBoundData(tClient *Client)
248 {
249         char    buf[BUFSIZ];
250          int    len;
251         
252         len = _SysRead(Client->pty, buf, BUFSIZ);
253         if( len <= 0 )  return ;
254         _SysWrite(Client->Socket, buf, len);
255 }
256

UCC git Repository :: git.ucc.asn.au