src/telnet.c

Go to the documentation of this file.
00001 #include <stdio.h>
00002 #include <stdlib.h>
00003 #include <gc/gc.h>
00004 #include <stdarg.h>
00005 #include <unistd.h>
00006 #include <string.h>
00007 #include <sys/types.h>
00008 #include <sys/time.h>
00009 #include <sys/socket.h>
00010 #include <netinet/in.h>
00011 #include <netinet/ip.h>
00012 #include <netinet/tcp.h>
00013 #include <fcntl.h>
00014 #include <time.h>
00015 #include <event.h>
00016 #include <netdb.h>
00017 #include <signal.h>
00018 #define DEBUG
00019 #include <debug.h>
00020 #include <rbtree.h>
00021 #include "network.h"
00022 #include "telnet.h"
00023 #include "client.h"
00024 
00025 static void telnet_send_req(DESC * client, int how, int request);
00026 static void telnet_send_subop(DESC * client, int how, int option);
00027 static void telnet_handle_will(DESC * client, int option);
00028 static void telnet_handle_wont(DESC * client, int option);
00029 static int telnet_handle_subop(DESC * client, unsigned char *buffer,
00030                                                            int length);
00031 
00032 int telnet_init(DESC * client)
00033 {
00034         dprintk("telnet initializing.");
00035         strncpy(client->termtype, "vt100", 16);
00036         client->telnet_win_width = 80;
00037         client->telnet_win_height = 25;
00038 
00039         telnet_send_req(client, TELNET_DO, TELNET_OPT_TERMTYPE);
00040         telnet_send_req(client, TELNET_DO, TELNET_OPT_WINSIZE);
00041         return 1;
00042 }
00043 
00044 /* Client Ring Buffer Handling */
00045 static void telnet_send_req(DESC * client, int how, int request)
00046 {
00047         unsigned char buffer[16] = { TELNET_IAC, how, request };
00048         network_write(client, (void *) buffer, 3);
00049 }
00050 static void telnet_send_subop(DESC * client, int option, int how)
00051 {
00052         unsigned char buffer[16] =
00053                 { TELNET_IAC, TELNET_SB, option, how, TELNET_IAC, TELNET_SE };
00054         network_write(client, (void *) buffer, 6);
00055 }
00056 
00057 static void telnet_handle_will(DESC * client, int option)
00058 {
00059         switch (option) {
00060         case TELNET_OPT_TERMTYPE:
00061                 client->telnet_has_termtype = TSTATE_SUP;
00062                 dprintk("client acknowledged TERMTYPE");
00063                 break;
00064         case TELNET_OPT_WINSIZE:
00065                 client->telnet_has_winsize = TSTATE_SUP;
00066                 dprintk("client acknowledged WINSIZE");
00067                 break;
00068         }
00069 }
00070 
00071 static void telnet_handle_wont(DESC * client, int option)
00072 {
00073         switch (option) {
00074         case TELNET_OPT_TERMTYPE:
00075                 client->telnet_has_termtype = TSTATE_UNSUP;
00076                 strncpy(client->termtype, "vt100", 16);
00077                 break;
00078         case TELNET_OPT_WINSIZE:
00079                 client->telnet_has_winsize = TSTATE_UNSUP;
00080                 client->telnet_win_width = 80;
00081                 client->telnet_win_height = 25;
00082                 break;
00083         }
00084 }
00085 
00086 static void telnet_check_options(DESC * client)
00087 {
00088         if(client->telnet_has_termtype == TSTATE_SUP) {
00089                 client->telnet_has_termtype = TSTATE_REQUEST;
00090                 telnet_send_subop(client, TELNET_OPT_TERMTYPE, TELNET_SUB_REQUIRED);
00091         } else if(client->telnet_has_termtype == TSTATE_REQUEST) {
00092                 client->telnet_has_termtype = TSTATE_UNSUP;
00093         }
00094 
00095         if(client->telnet_has_winsize == TSTATE_SUP) {
00096                 client->telnet_has_winsize = TSTATE_REQUEST;
00097                 telnet_send_subop(client, TELNET_OPT_WINSIZE, TELNET_SUB_REQUIRED);
00098         } else if(client->telnet_has_winsize == TSTATE_REQUEST) {
00099                 client->telnet_has_termtype = TSTATE_UNSUP;
00100         }
00101 }
00102 
00103 static int telnet_handle_subop(DESC * client, unsigned char *buffer,
00104                                                            int length)
00105 {
00106         int iter;
00107         if(buffer[1] != TELNET_SUB_SUPPLIED)
00108                 dfail("unexpected reply in telnet suboption negotiation.");
00109         iter = 2;
00110         switch (buffer[0]) {
00111         case TELNET_OPT_TERMTYPE:
00112                 memset(client->termtype, 0, 16);
00113                 for(iter = 2; iter < length && iter < 18 && buffer[iter] != 0xFF;
00114                         iter++) {
00115                         client->termtype[iter - 2] = buffer[iter];
00116                 }
00117                 iter++;
00118                 dprintk("Received Terminal Type '%s'", client->termtype);
00119                 client->telnet_has_termtype = TSTATE_REPLIED;
00120                 break;
00121         case TELNET_OPT_WINSIZE:
00122                 client->telnet_win_width = buffer[2];
00123                 client->telnet_win_height = buffer[4];
00124                 iter = 6;
00125                 dprintk("Received Window Size %dx%d", client->telnet_win_width,
00126                                 client->telnet_win_height);
00127                 client->telnet_has_winsize = TSTATE_REPLIED;
00128                 break;
00129         default:
00130                 dfail("unexpected reply in telnet usboption negotiation.");
00131         }
00132         return iter;
00133 }
00134 
00135 #define ring_avail(client) (client->ringtail > client->ringhead ? RING_LENGTH - client->ringtail + client->ringhead : \
00136         client->ringhead - client->ringtail)
00137 #define ring_char(client, x) (client->ringbuffer[(client->ringhead+x)%RING_LENGTH])
00138 #define ring_length(client) (client->ringtail >= client->ringhead ? client->ringtail - client->ringhead : \
00139         RING_LENGTH - client->ringhead + client->ringtail)
00140 #define ring_eat(client, x) (client->ringhead = (client->ringhead+x) % RING_LENGTH)
00141 
00142 void telnet_read_ring(DESC * client)
00143 {
00144         int iter, complete;
00145         unsigned char subopt_buffer[32];
00146 
00147         dprintk
00148                 ("Ring Read started, input length = %d, ringhead = %d, ringtail = %d. ",
00149                  ring_length(client), client->ringhead, client->ringtail);
00150 
00151         while (ring_length(client) > 0) {
00152                 dprintk
00153                         ("Parsing data 0x%02x,  %d bytes in ring, ringhead = %d, ringtail = %d",
00154                          ring_char(client, 0), ring_length(client), client->ringhead,
00155                          client->ringtail);
00156                 switch (ring_char(client, 0)) {
00157                 case TELNET_IAC:
00158                         if(ring_length(client) < 2)
00159                                 return;
00160                         dprintk("TELNET COMMADN %d", ring_char(client, 1));
00161                         switch ((unsigned char) ring_char(client, 1)) {
00162                         case TELNET_WILL:
00163                                 telnet_handle_will(client, ring_char(client, 2));
00164                                 ring_eat(client, 3);
00165                                 break;
00166                         case TELNET_WONT:
00167                                 telnet_handle_wont(client, ring_char(client, 2));
00168                                 ring_eat(client, 3);
00169                                 break;
00170                         case TELNET_SB:
00171                                 complete = 0;
00172                                 for(iter = 2; !complete && iter < ring_avail(client); iter++) {
00173                                         subopt_buffer[iter - 2] = ring_char(client, iter);
00174                                         if(ring_char(client, iter) == TELNET_SE) {
00175                                                 telnet_handle_subop(client, subopt_buffer, iter - 2);
00176                                                 complete = 1;
00177                                                 ring_eat(client, iter + 1);
00178                                         }
00179                                 }
00180                                 if(!complete)
00181                                         return;
00182                                 break;
00183                         case TELNET_IAC:
00184                                 client->inputbuffer[client->inputtail++] = TELNET_IAC;
00185                         default:
00186                                 ring_eat(client, 2);
00187                                 break;
00188                         }
00189                         break;
00190                 case 0:
00191                         ring_eat(client, 1);
00192                         break;
00193                 case '\r':
00194                 case '\n':
00195                         if(ring_length(client) > 1 && (ring_char(client, 1) == '\r' ||
00196                                                                                    ring_char(client, 1) == '\n')) {
00197                                 ring_eat(client, 1);
00198                         }
00199                         if(client->inputtail == 0) {
00200                                 ring_eat(client, 1);
00201                                 continue;
00202                         }
00203                         client->inputbuffer[client->inputtail] = 0;
00204                         client_accept_input(client);
00205                         dprintk("Would Parse: %s", client->inputbuffer);
00206                         client->inputtail = 0;
00207                         ring_eat(client, 1);
00208                         break;
00209                 default:
00210                         client->inputbuffer[client->inputtail++] = ring_char(client, 0);
00211                         ring_eat(client, 1);
00212                         break;
00213                 }
00214         }
00215         if(client->ringhead == client->ringtail) {
00216                 client->ringhead = client->ringtail = 0;
00217         }
00218 
00219         telnet_check_options(client);
00220         dprintk
00221                 ("Ring Read finished. RingState = { head = %d, tail = %d }, InputState = { tail = %d }",
00222                  client->ringhead, client->ringtail, client->inputtail);
00223 }
00224 
00225 void telnet_disconnect(DESC * client)
00226 {
00227         network_disconnect(client);
00228 }
00229 
00230 void telnet_write(DESC * client, char *buffer, int length)
00231 {
00232         dprintk("telnet_write");
00233         // Color translation should occur here.
00234         network_write(client, buffer, length);
00235 }

Generated on Mon May 28 04:25:25 2007 for BattletechMUX by  doxygen 1.4.7