Magellan Linux

Diff of /trunk/mkinitrd-magellan/busybox/networking/telnet.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 983 by niro, Fri Apr 24 18:33:46 2009 UTC revision 984 by niro, Sun May 30 11:32:42 2010 UTC
# Line 21  Line 21 
21   *   *
22   */   */
23    
 #include <termios.h>  
24  #include <arpa/telnet.h>  #include <arpa/telnet.h>
25  #include <netinet/in.h>  #include <netinet/in.h>
26  #include "libbb.h"  #include "libbb.h"
# Line 78  struct globals { Line 77  struct globals {
77   struct termios termios_raw;   struct termios termios_raw;
78  };  };
79  #define G (*(struct globals*)&bb_common_bufsiz1)  #define G (*(struct globals*)&bb_common_bufsiz1)
 void BUG_telnet_globals_too_big(void);  
80  #define INIT_G() do { \  #define INIT_G() do { \
81   if (sizeof(G) > COMMON_BUFSIZE) \   struct G_sizecheck { \
82   BUG_telnet_globals_too_big(); \   char G_sizecheck[sizeof(G) > COMMON_BUFSIZE ? -1 : 1]; \
83   /* memset(&G, 0, sizeof G); - already is */ \   }; \
84  } while (0)  } while (0)
85    
86  /* Function prototypes */  /* Function prototypes */
# Line 93  static void will_charmode(void); Line 91  static void will_charmode(void);
91  static void telopt(byte c);  static void telopt(byte c);
92  static int subneg(byte c);  static int subneg(byte c);
93    
94  static void iacflush(void)  static void iac_flush(void)
95  {  {
96   write(netfd, G.iacbuf, G.iaclen);   write(netfd, G.iacbuf, G.iaclen);
97   G.iaclen = 0;   G.iaclen = 0;
# Line 108  static void doexit(int ev) Line 106  static void doexit(int ev)
106   exit(ev);   exit(ev);
107  }  }
108    
109  static void conescape(void)  static void con_escape(void)
110  {  {
111   char b;   char b;
112    
113   if (bb_got_signal) /* came from line  mode... go raw */   if (bb_got_signal) /* came from line mode... go raw */
114   rawmode();   rawmode();
115    
116   write_str(1, "\r\nConsole escape. Commands are:\r\n\n"   write_str(1, "\r\nConsole escape. Commands are:\r\n\n"
# Line 128  static void conescape(void) Line 126  static void conescape(void)
126   case 'l':   case 'l':
127   if (!bb_got_signal) {   if (!bb_got_signal) {
128   do_linemode();   do_linemode();
129   goto rrturn;   goto ret;
130   }   }
131   break;   break;
132   case 'c':   case 'c':
133   if (bb_got_signal) {   if (bb_got_signal) {
134   will_charmode();   will_charmode();
135   goto rrturn;   goto ret;
136   }   }
137   break;   break;
138   case 'z':   case 'z':
# Line 150  static void conescape(void) Line 148  static void conescape(void)
148    
149   if (bb_got_signal)   if (bb_got_signal)
150   cookmode();   cookmode();
151     ret:
  rrturn:  
152   bb_got_signal = 0;   bb_got_signal = 0;
153    
154  }  }
155    
156  static void handlenetoutput(int len)  static void handle_net_output(int len)
157  {  {
158   /* here we could do smart tricks how to handle 0xFF:s in output   /* here we could do smart tricks how to handle 0xFF:s in output
159   * stream like writing twice every sequence of FF:s (thus doing   * stream like writing twice every sequence of FF:s (thus doing
# Line 169  static void handlenetoutput(int len) Line 166  static void handlenetoutput(int len)
166   * first - I cannot use programs like sz/rz   * first - I cannot use programs like sz/rz
167   * second - the 0x0D is sent as one character and if the next   * second - the 0x0D is sent as one character and if the next
168   * char is 0x0A then it's eaten by a server side.   * char is 0x0A then it's eaten by a server side.
169   * third - whay doy you have to make 'many write()s'?   * third - why do you have to make 'many write()s'?
170   * I don't understand.   * I don't understand.
171   * So I implemented it. It's realy useful for me. I hope that   * So I implemented it. It's really useful for me. I hope that
172   * others people will find it interesting too.   * other people will find it interesting too.
173   */   */
174    
175   int i, j;   int i, j;
176   byte * p = (byte*)G.buf;   byte *p = (byte*)G.buf;
177   byte outbuf[4*DATABUFSIZE];   byte outbuf[4*DATABUFSIZE];
178    
179   for (i = len, j = 0; i > 0; i--, p++) {   for (i = len, j = 0; i > 0; i--, p++) {
180   if (*p == 0x1d) {   if (*p == 0x1d) {
181   conescape();   con_escape();
182   return;   return;
183   }   }
184   outbuf[j++] = *p;   outbuf[j++] = *p;
# Line 194  static void handlenetoutput(int len) Line 191  static void handlenetoutput(int len)
191   write(netfd, outbuf, j);   write(netfd, outbuf, j);
192  }  }
193    
194  static void handlenetinput(int len)  static void handle_net_input(int len)
195  {  {
196   int i;   int i;
197   int cstart = 0;   int cstart = 0;
# Line 207  static void handlenetinput(int len) Line 204  static void handlenetinput(int len)
204   cstart = i;   cstart = i;
205   G.telstate = TS_IAC;   G.telstate = TS_IAC;
206   }   }
207   } else   continue;
208   switch (G.telstate) {   }
209   case TS_0:   switch (G.telstate) {
210   if (c == IAC)   case TS_0:
211   G.telstate = TS_IAC;   if (c == IAC)
212   else   G.telstate = TS_IAC;
213   G.buf[cstart++] = c;   else
214   break;   G.buf[cstart++] = c;
215     break;
216    
217   case TS_IAC:   case TS_IAC:
218   if (c == IAC) { /* IAC IAC -> 0xFF */   if (c == IAC) { /* IAC IAC -> 0xFF */
219   G.buf[cstart++] = c;   G.buf[cstart++] = c;
  G.telstate = TS_0;  
  break;  
  }  
  /* else */  
  switch (c) {  
  case SB:  
  G.telstate = TS_SUB1;  
  break;  
  case DO:  
  case DONT:  
  case WILL:  
  case WONT:  
  G.telwish =  c;  
  G.telstate = TS_OPT;  
  break;  
  default:  
  G.telstate = TS_0; /* DATA MARK must be added later */  
  }  
  break;  
  case TS_OPT: /* WILL, WONT, DO, DONT */  
  telopt(c);  
220   G.telstate = TS_0;   G.telstate = TS_0;
221   break;   break;
222   case TS_SUB1: /* Subnegotiation */   }
223   case TS_SUB2: /* Subnegotiation */   /* else */
224   if (subneg(c))   switch (c) {
225   G.telstate = TS_0;   case SB:
226     G.telstate = TS_SUB1;
227     break;
228     case DO:
229     case DONT:
230     case WILL:
231     case WONT:
232     G.telwish =  c;
233     G.telstate = TS_OPT;
234   break;   break;
235     default:
236     G.telstate = TS_0; /* DATA MARK must be added later */
237   }   }
238     break;
239     case TS_OPT: /* WILL, WONT, DO, DONT */
240     telopt(c);
241     G.telstate = TS_0;
242     break;
243     case TS_SUB1: /* Subnegotiation */
244     case TS_SUB2: /* Subnegotiation */
245     if (subneg(c))
246     G.telstate = TS_0;
247     break;
248     }
249   }   }
250   if (G.telstate) {   if (G.telstate) {
251   if (G.iaclen) iacflush();   if (G.iaclen)
252   if (G.telstate == TS_0) G.telstate = 0;   iac_flush();
253     if (G.telstate == TS_0)
254     G.telstate = 0;
255   len = cstart;   len = cstart;
256   }   }
257    
# Line 259  static void handlenetinput(int len) Line 259  static void handlenetinput(int len)
259   write(STDOUT_FILENO, G.buf, len);   write(STDOUT_FILENO, G.buf, len);
260  }  }
261    
262  static void putiac(int c)  static void put_iac(int c)
263  {  {
264   G.iacbuf[G.iaclen++] = c;   G.iacbuf[G.iaclen++] = c;
265  }  }
266    
267  static void putiac2(byte wwdd, byte c)  static void put_iac2(byte wwdd, byte c)
268  {  {
269   if (G.iaclen + 3 > IACBUFSIZE)   if (G.iaclen + 3 > IACBUFSIZE)
270   iacflush();   iac_flush();
271    
272   putiac(IAC);   put_iac(IAC);
273   putiac(wwdd);   put_iac(wwdd);
274   putiac(c);   put_iac(c);
275  }  }
276    
277  #if ENABLE_FEATURE_TELNET_TTYPE  #if ENABLE_FEATURE_TELNET_TTYPE
278  static void putiac_subopt(byte c, char *str)  static void put_iac_subopt(byte c, char *str)
279  {  {
280   int len = strlen(str) + 6;   // ( 2 + 1 + 1 + strlen + 2 )   int len = strlen(str) + 6;   // ( 2 + 1 + 1 + strlen + 2 )
281    
282   if (G.iaclen + len > IACBUFSIZE)   if (G.iaclen + len > IACBUFSIZE)
283   iacflush();   iac_flush();
284    
285   putiac(IAC);   put_iac(IAC);
286   putiac(SB);   put_iac(SB);
287   putiac(c);   put_iac(c);
288   putiac(0);   put_iac(0);
289    
290   while (*str)   while (*str)
291   putiac(*str++);   put_iac(*str++);
292    
293   putiac(IAC);   put_iac(IAC);
294   putiac(SE);   put_iac(SE);
295  }  }
296  #endif  #endif
297    
298  #if ENABLE_FEATURE_TELNET_AUTOLOGIN  #if ENABLE_FEATURE_TELNET_AUTOLOGIN
299  static void putiac_subopt_autologin(void)  static void put_iac_subopt_autologin(void)
300  {  {
301   int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2)   int len = strlen(G.autologin) + 6; // (2 + 1 + 1 + strlen + 2)
302   const char *user = "USER";   const char *user = "USER";
303    
304   if (G.iaclen + len > IACBUFSIZE)   if (G.iaclen + len > IACBUFSIZE)
305   iacflush();   iac_flush();
306    
307   putiac(IAC);   put_iac(IAC);
308   putiac(SB);   put_iac(SB);
309   putiac(TELOPT_NEW_ENVIRON);   put_iac(TELOPT_NEW_ENVIRON);
310   putiac(TELQUAL_IS);   put_iac(TELQUAL_IS);
311   putiac(NEW_ENV_VAR);   put_iac(NEW_ENV_VAR);
312    
313   while (*user)   while (*user)
314   putiac(*user++);   put_iac(*user++);
315    
316   putiac(NEW_ENV_VALUE);   put_iac(NEW_ENV_VALUE);
317    
318   while (*G.autologin)   while (*G.autologin)
319   putiac(*G.autologin++);   put_iac(*G.autologin++);
320    
321   putiac(IAC);   put_iac(IAC);
322   putiac(SE);   put_iac(SE);
323  }  }
324  #endif  #endif
325    
326  #if ENABLE_FEATURE_AUTOWIDTH  #if ENABLE_FEATURE_AUTOWIDTH
327  static void putiac_naws(byte c, int x, int y)  static void put_iac_naws(byte c, int x, int y)
328  {  {
329   if (G.iaclen + 9 > IACBUFSIZE)   if (G.iaclen + 9 > IACBUFSIZE)
330   iacflush();   iac_flush();
331    
332   putiac(IAC);   put_iac(IAC);
333   putiac(SB);   put_iac(SB);
334   putiac(c);   put_iac(c);
335    
336   putiac((x >> 8) & 0xff);   put_iac((x >> 8) & 0xff);
337   putiac(x & 0xff);   put_iac(x & 0xff);
338   putiac((y >> 8) & 0xff);   put_iac((y >> 8) & 0xff);
339   putiac(y & 0xff);   put_iac(y & 0xff);
340    
341   putiac(IAC);   put_iac(IAC);
342   putiac(SE);   put_iac(SE);
343  }  }
344  #endif  #endif
345    
# Line 368  static void will_charmode(void) Line 368  static void will_charmode(void)
368   G.telflags |= (UF_ECHO | UF_SGA);   G.telflags |= (UF_ECHO | UF_SGA);
369   setConMode();   setConMode();
370    
371   putiac2(DO, TELOPT_ECHO);   put_iac2(DO, TELOPT_ECHO);
372   putiac2(DO, TELOPT_SGA);   put_iac2(DO, TELOPT_SGA);
373   iacflush();   iac_flush();
374  }  }
375    
376  static void do_linemode(void)  static void do_linemode(void)
# Line 379  static void do_linemode(void) Line 379  static void do_linemode(void)
379   G.telflags &= ~(UF_ECHO | UF_SGA);   G.telflags &= ~(UF_ECHO | UF_SGA);
380   setConMode();   setConMode();
381    
382   putiac2(DONT, TELOPT_ECHO);   put_iac2(DONT, TELOPT_ECHO);
383   putiac2(DONT, TELOPT_SGA);   put_iac2(DONT, TELOPT_SGA);
384   iacflush();   iac_flush();
385  }  }
386    
387  static void to_notsup(char c)  static void to_notsup(char c)
388  {  {
389   if (G.telwish == WILL)   if (G.telwish == WILL)
390   putiac2(DONT, c);   put_iac2(DONT, c);
391   else if (G.telwish == DO)   else if (G.telwish == DO)
392   putiac2(WONT, c);   put_iac2(WONT, c);
393  }  }
394    
395  static void to_echo(void)  static void to_echo(void)
396  {  {
397   /* if server requests ECHO, don't agree */   /* if server requests ECHO, don't agree */
398   if (G.telwish == DO) {   if (G.telwish == DO) {
399   putiac2(WONT, TELOPT_ECHO);   put_iac2(WONT, TELOPT_ECHO);
400   return;   return;
401   }   }
402   if (G.telwish == DONT)   if (G.telwish == DONT)
# Line 412  static void to_echo(void) Line 412  static void to_echo(void)
412   G.telflags ^= UF_ECHO;   G.telflags ^= UF_ECHO;
413    
414   if (G.telflags & UF_ECHO)   if (G.telflags & UF_ECHO)
415   putiac2(DO, TELOPT_ECHO);   put_iac2(DO, TELOPT_ECHO);
416   else   else
417   putiac2(DONT, TELOPT_ECHO);   put_iac2(DONT, TELOPT_ECHO);
418    
419   setConMode();   setConMode();
420   write_str(1, "\r\n");  /* sudden modec */   write_str(1, "\r\n");  /* sudden modec */
# Line 432  static void to_sga(void) Line 432  static void to_sga(void)
432    
433   G.telflags ^= UF_SGA; /* toggle */   G.telflags ^= UF_SGA; /* toggle */
434   if (G.telflags & UF_SGA)   if (G.telflags & UF_SGA)
435   putiac2(DO, TELOPT_SGA);   put_iac2(DO, TELOPT_SGA);
436   else   else
437   putiac2(DONT, TELOPT_SGA);   put_iac2(DONT, TELOPT_SGA);
438  }  }
439    
440  #if ENABLE_FEATURE_TELNET_TTYPE  #if ENABLE_FEATURE_TELNET_TTYPE
# Line 443  static void to_ttype(void) Line 443  static void to_ttype(void)
443   /* Tell server we will (or won't) do TTYPE */   /* Tell server we will (or won't) do TTYPE */
444    
445   if (G.ttype)   if (G.ttype)
446   putiac2(WILL, TELOPT_TTYPE);   put_iac2(WILL, TELOPT_TTYPE);
447   else   else
448   putiac2(WONT, TELOPT_TTYPE);   put_iac2(WONT, TELOPT_TTYPE);
449  }  }
450  #endif  #endif
451    
# Line 455  static void to_new_environ(void) Line 455  static void to_new_environ(void)
455   /* Tell server we will (or will not) do AUTOLOGIN */   /* Tell server we will (or will not) do AUTOLOGIN */
456    
457   if (G.autologin)   if (G.autologin)
458   putiac2(WILL, TELOPT_NEW_ENVIRON);   put_iac2(WILL, TELOPT_NEW_ENVIRON);
459   else   else
460   putiac2(WONT, TELOPT_NEW_ENVIRON);   put_iac2(WONT, TELOPT_NEW_ENVIRON);
461  }  }
462  #endif  #endif
463    
# Line 465  static void to_new_environ(void) Line 465  static void to_new_environ(void)
465  static void to_naws(void)  static void to_naws(void)
466  {  {
467   /* Tell server we will do NAWS */   /* Tell server we will do NAWS */
468   putiac2(WILL, TELOPT_NAWS);   put_iac2(WILL, TELOPT_NAWS);
469  }  }
470  #endif  #endif
471    
# Line 487  static void telopt(byte c) Line 487  static void telopt(byte c)
487  #if ENABLE_FEATURE_AUTOWIDTH  #if ENABLE_FEATURE_AUTOWIDTH
488   case TELOPT_NAWS:   case TELOPT_NAWS:
489   to_naws();   to_naws();
490   putiac_naws(c, G.win_width, G.win_height);   put_iac_naws(c, G.win_width, G.win_height);
491   break;   break;
492  #endif  #endif
493   default:   default:
# Line 506  static int subneg(byte c) Line 506  static int subneg(byte c)
506  #if ENABLE_FEATURE_TELNET_TTYPE  #if ENABLE_FEATURE_TELNET_TTYPE
507   else   else
508   if (c == TELOPT_TTYPE)   if (c == TELOPT_TTYPE)
509   putiac_subopt(TELOPT_TTYPE, G.ttype);   put_iac_subopt(TELOPT_TTYPE, G.ttype);
510  #endif  #endif
511  #if ENABLE_FEATURE_TELNET_AUTOLOGIN  #if ENABLE_FEATURE_TELNET_AUTOLOGIN
512   else   else
513   if (c == TELOPT_NEW_ENVIRON)   if (c == TELOPT_NEW_ENVIRON)
514   putiac_subopt_autologin();   put_iac_subopt_autologin();
515  #endif  #endif
516   break;   break;
517   case TS_SUB2:   case TS_SUB2:
# Line 611  int telnet_main(int argc UNUSED_PARAM, c Line 611  int telnet_main(int argc UNUSED_PARAM, c
611   case -1:   case -1:
612   /* error, ignore and/or log something, bay go to loop */   /* error, ignore and/or log something, bay go to loop */
613   if (bb_got_signal)   if (bb_got_signal)
614   conescape();   con_escape();
615   else   else
616   sleep(1);   sleep(1);
617   break;   break;
618   default:   default:
619    
620  #ifdef USE_POLL  #ifdef USE_POLL
621   if (ufds[0].revents) /* well, should check POLLIN, but ... */   if (ufds[0].revents)
622  #else  #else
623   if (FD_ISSET(STDIN_FILENO, &rfds))   if (FD_ISSET(STDIN_FILENO, &rfds))
624  #endif  #endif
625   {   {
626   len = read(STDIN_FILENO, G.buf, DATABUFSIZE);   len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE);
627   if (len <= 0)   if (len <= 0)
628   doexit(EXIT_SUCCESS);   doexit(EXIT_SUCCESS);
629   TRACE(0, ("Read con: %d\n", len));   TRACE(0, ("Read con: %d\n", len));
630   handlenetoutput(len);   handle_net_output(len);
631   }   }
632    
633  #ifdef USE_POLL  #ifdef USE_POLL
634   if (ufds[1].revents) /* well, should check POLLIN, but ... */   if (ufds[1].revents)
635  #else  #else
636   if (FD_ISSET(netfd, &rfds))   if (FD_ISSET(netfd, &rfds))
637  #endif  #endif
638   {   {
639   len = read(netfd, G.buf, DATABUFSIZE);   len = safe_read(netfd, G.buf, DATABUFSIZE);
640   if (len <= 0) {   if (len <= 0) {
641   write_str(1, "Connection closed by foreign host\r\n");   write_str(1, "Connection closed by foreign host\r\n");
642   doexit(EXIT_FAILURE);   doexit(EXIT_FAILURE);
643   }   }
644   TRACE(0, ("Read netfd (%d): %d\n", netfd, len));   TRACE(0, ("Read netfd (%d): %d\n", netfd, len));
645   handlenetinput(len);   handle_net_input(len);
646   }   }
647   }   }
648   } /* while (1) */   } /* while (1) */

Legend:
Removed from v.983  
changed lines
  Added in v.984