X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=networking%2Ftelnet.c;h=5d7ecef3bf40f3b563caccf32bc2367d64e16ba9;hb=08ea11ab0749a7977e6d47cd0fa7b3c9cc10af32;hp=caca89d2d00ce271d7ff33835b4b0b2240d8fdad;hpb=4e5f82c76f08614d0b69f9ec4a8baac303af15f6;p=oweals%2Fbusybox.git diff --git a/networking/telnet.c b/networking/telnet.c index caca89d2d..5d7ecef3b 100644 --- a/networking/telnet.c +++ b/networking/telnet.c @@ -52,15 +52,14 @@ enum { typedef unsigned char byte; +enum { netfd = 3 }; struct globals { - int netfd; /* console fd:s are 0 and 1 (and 2) */ - short iaclen; /* could even use byte */ + int iaclen; /* could even use byte, but it's a loss on x86 */ byte telstate; /* telnet negotiation state from network input */ byte telwish; /* DO, DONT, WILL, WONT */ byte charmode; byte telflags; - byte gotsig; byte do_termios; #if ENABLE_FEATURE_TELNET_TTYPE char *ttype; @@ -69,7 +68,7 @@ struct globals { const char *autologin; #endif #if ENABLE_FEATURE_AUTOWIDTH - int win_width, win_height; + unsigned win_width, win_height; #endif /* same buffer used both for network and console read/write */ char buf[DATABUFSIZE]; @@ -78,9 +77,13 @@ struct globals { struct termios termios_def; struct termios termios_raw; }; - #define G (*(struct globals*)&bb_common_bufsiz1) - +void BUG_telnet_globals_too_big(void); +#define INIT_G() do { \ + if (sizeof(G) > COMMON_BUFSIZE) \ + BUG_telnet_globals_too_big(); \ + /* memset(&G, 0, sizeof G); - already is */ \ +} while (0) /* Function prototypes */ static void rawmode(void); @@ -92,12 +95,13 @@ static int subneg(byte c); static void iacflush(void) { - write(G.netfd, G.iacbuf, G.iaclen); + write(netfd, G.iacbuf, G.iaclen); G.iaclen = 0; } #define write_str(fd, str) write(fd, str, sizeof(str) - 1) +static void doexit(int ev) NORETURN; static void doexit(int ev) { cookmode(); @@ -108,7 +112,7 @@ static void conescape(void) { char b; - if (G.gotsig) /* came from line mode... go raw */ + if (bb_got_signal) /* came from line mode... go raw */ rawmode(); write_str(1, "\r\nConsole escape. Commands are:\r\n\n" @@ -117,18 +121,18 @@ static void conescape(void) " z suspend telnet\r\n" " e exit telnet\r\n"); - if (read(0, &b, 1) <= 0) - doexit(1); + if (read(STDIN_FILENO, &b, 1) <= 0) + doexit(EXIT_FAILURE); switch (b) { case 'l': - if (!G.gotsig) { + if (!bb_got_signal) { do_linemode(); goto rrturn; } break; case 'c': - if (G.gotsig) { + if (bb_got_signal) { will_charmode(); goto rrturn; } @@ -139,46 +143,44 @@ static void conescape(void) rawmode(); break; case 'e': - doexit(0); + doexit(EXIT_SUCCESS); } write_str(1, "continuing...\r\n"); - if (G.gotsig) + if (bb_got_signal) cookmode(); rrturn: - G.gotsig = 0; + bb_got_signal = 0; } static void handlenetoutput(int len) { - /* here we could do smart tricks how to handle 0xFF:s in output - * stream like writing twice every sequence of FF:s (thus doing - * many write()s. But I think interactive telnet application does - * not need to be 100% 8-bit clean, so changing every 0xff:s to - * 0x7f:s + /* here we could do smart tricks how to handle 0xFF:s in output + * stream like writing twice every sequence of FF:s (thus doing + * many write()s. But I think interactive telnet application does + * not need to be 100% 8-bit clean, so changing every 0xff:s to + * 0x7f:s * - * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com) - * I don't agree. - * first - I cannot use programs like sz/rz - * second - the 0x0D is sent as one character and if the next - * char is 0x0A then it's eaten by a server side. - * third - whay doy you have to make 'many write()s'? - * I don't understand. - * So I implemented it. It's realy useful for me. I hope that - * others people will find it interesting to. + * 2002-mar-21, Przemyslaw Czerpak (druzus@polbox.com) + * I don't agree. + * first - I cannot use programs like sz/rz + * second - the 0x0D is sent as one character and if the next + * char is 0x0A then it's eaten by a server side. + * third - whay doy you have to make 'many write()s'? + * I don't understand. + * So I implemented it. It's realy useful for me. I hope that + * others people will find it interesting too. */ int i, j; byte * p = (byte*)G.buf; byte outbuf[4*DATABUFSIZE]; - for (i = len, j = 0; i > 0; i--, p++) - { - if (*p == 0x1d) - { + for (i = len, j = 0; i > 0; i--, p++) { + if (*p == 0x1d) { conescape(); return; } @@ -189,7 +191,7 @@ static void handlenetoutput(int len) outbuf[j++] = 0x00; } if (j > 0) - write(G.netfd, outbuf, j); + write(netfd, outbuf, j); } static void handlenetinput(int len) @@ -197,73 +199,64 @@ static void handlenetinput(int len) int i; int cstart = 0; - for (i = 0; i < len; i++) - { + for (i = 0; i < len; i++) { byte c = G.buf[i]; - if (G.telstate == 0) /* most of the time state == 0 */ - { - if (c == IAC) - { + if (G.telstate == 0) { /* most of the time state == 0 */ + if (c == IAC) { cstart = i; G.telstate = TS_IAC; } - } - else - switch (G.telstate) - { - case TS_0: - if (c == IAC) - G.telstate = TS_IAC; - else - G.buf[cstart++] = c; - break; - - case TS_IAC: - if (c == IAC) /* IAC IAC -> 0xFF */ - { - 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); - G.telstate = TS_0; - break; - case TS_SUB1: /* Subnegotiation */ - case TS_SUB2: /* Subnegotiation */ - if (subneg(c)) - G.telstate = TS_0; - break; - } + } else + switch (G.telstate) { + case TS_0: + if (c == IAC) + G.telstate = TS_IAC; + else + G.buf[cstart++] = c; + break; + + case TS_IAC: + if (c == IAC) { /* IAC IAC -> 0xFF */ + 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); + G.telstate = TS_0; + break; + case TS_SUB1: /* Subnegotiation */ + case TS_SUB2: /* Subnegotiation */ + if (subneg(c)) + G.telstate = TS_0; + break; + } } - if (G.telstate) - { - if (G.iaclen) iacflush(); + if (G.telstate) { + if (G.iaclen) iacflush(); if (G.telstate == TS_0) G.telstate = 0; - len = cstart; } if (len) - write(1, G.buf, len); + write(STDOUT_FILENO, G.buf, len); } static void putiac(int c) @@ -350,7 +343,7 @@ static void putiac_naws(byte c, int x, int y) } #endif -static char const escapecharis[] = "\r\nEscape character is "; +static char const escapecharis[] ALIGN1 = "\r\nEscape character is "; static void setConMode(void) { @@ -437,7 +430,8 @@ static void to_sga(void) } else if (G.telwish == WONT) return; - if ((G.telflags ^= UF_SGA) & UF_SGA) /* toggle */ + G.telflags ^= UF_SGA; /* toggle */ + if (G.telflags & UF_SGA) putiac2(DO, TELOPT_SGA); else putiac2(DONT, TELOPT_SGA); @@ -529,12 +523,6 @@ static int subneg(byte c) return FALSE; } -static void fgotsig(int sig) -{ - G.gotsig = sig; -} - - static void rawmode(void) { if (G.do_termios) @@ -547,10 +535,11 @@ static void cookmode(void) tcsetattr(0, TCSADRAIN, &G.termios_def); } -void BUG_telnet_globals_too_big(void); +/* poll gives smaller (-70 bytes) code */ +#define USE_POLL 1 -int telnet_main(int argc, char** argv); -int telnet_main(int argc, char** argv) +int telnet_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int telnet_main(int argc UNUSED_PARAM, char **argv) { char *host; int port; @@ -562,9 +551,7 @@ int telnet_main(int argc, char** argv) int maxfd; #endif - if (sizeof(G) > sizeof(bb_common_bufsiz1)) - BUG_telnet_globals_too_big(); - /* memset(&G, 0, sizeof G); - already is */ + INIT_G(); #if ENABLE_FEATURE_AUTOWIDTH get_terminal_width_height(0, &G.win_width, &G.win_height); @@ -580,11 +567,8 @@ int telnet_main(int argc, char** argv) cfmakeraw(&G.termios_raw); } - if (argc < 2) - bb_show_usage(); - #if ENABLE_FEATURE_TELNET_AUTOLOGIN - if (1 & getopt32(argc, argv, "al:", &G.autologin)) + if (1 & getopt32(argv, "al:", &G.autologin)) G.autologin = getenv("USER"); argv += optind; #else @@ -597,20 +581,20 @@ int telnet_main(int argc, char** argv) if (*argv) /* extra params?? */ bb_show_usage(); - G.netfd = create_and_connect_stream_or_die(host, port); + xmove_fd(create_and_connect_stream_or_die(host, port), netfd); - setsockopt(G.netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); + setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); - signal(SIGINT, fgotsig); + signal(SIGINT, record_signo); #ifdef USE_POLL - ufds[0].fd = 0; ufds[1].fd = G.netfd; + ufds[0].fd = 0; ufds[1].fd = netfd; ufds[0].events = ufds[1].events = POLLIN; #else FD_ZERO(&readfds); - FD_SET(0, &readfds); - FD_SET(G.netfd, &readfds); - maxfd = G.netfd + 1; + FD_SET(STDIN_FILENO, &readfds); + FD_SET(netfd, &readfds); + maxfd = netfd + 1; #endif while (1) { @@ -626,7 +610,7 @@ int telnet_main(int argc, char** argv) /* timeout */ case -1: /* error, ignore and/or log something, bay go to loop */ - if (G.gotsig) + if (bb_got_signal) conescape(); else sleep(1); @@ -636,12 +620,12 @@ int telnet_main(int argc, char** argv) #ifdef USE_POLL if (ufds[0].revents) /* well, should check POLLIN, but ... */ #else - if (FD_ISSET(0, &rfds)) + if (FD_ISSET(STDIN_FILENO, &rfds)) #endif { - len = read(0, G.buf, DATABUFSIZE); + len = read(STDIN_FILENO, G.buf, DATABUFSIZE); if (len <= 0) - doexit(0); + doexit(EXIT_SUCCESS); TRACE(0, ("Read con: %d\n", len)); handlenetoutput(len); } @@ -649,17 +633,17 @@ int telnet_main(int argc, char** argv) #ifdef USE_POLL if (ufds[1].revents) /* well, should check POLLIN, but ... */ #else - if (FD_ISSET(G.netfd, &rfds)) + if (FD_ISSET(netfd, &rfds)) #endif { - len = read(G.netfd, G.buf, DATABUFSIZE); + len = read(netfd, G.buf, DATABUFSIZE); if (len <= 0) { write_str(1, "Connection closed by foreign host\r\n"); - doexit(1); + doexit(EXIT_FAILURE); } - TRACE(0, ("Read netfd (%d): %d\n", G.netfd, len)); + TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); handlenetinput(len); } } - } + } /* while (1) */ }