static void handle_net_output(int len) { byte outbuf[2 * DATABUFSIZE]; byte *dst = outbuf; byte *src = (byte*)G.buf; byte *end = src + len; while (src < end) { byte c = *src++; if (c == 0x1d) { con_escape(); return; } *dst = c; if (c == IAC) *++dst = c; /* IAC -> IAC IAC */ else if (c == '\r' || c == '\n') { /* Enter key sends '\r' in raw mode and '\n' in cooked one. * * See RFC 1123 3.3.1 Telnet End-of-Line Convention. * Using CR LF instead of other allowed possibilities * like CR NUL - easier to talk to HTTP/SMTP servers. */ *dst = '\r'; /* Enter -> CR LF */ *++dst = '\n'; } dst++; } if (dst - outbuf != 0) full_write(netfd, outbuf, dst - outbuf); }
static void handle_net_output(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 * * 2002-mar-21, Przemyslaw Czerpak ([email protected]) * 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 - why do you have to make 'many write()s'? * I don't understand. * So I implemented it. It's really useful for me. I hope that * other 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) { con_escape(); return; } outbuf[j++] = *p; if (*p == 0xff) outbuf[j++] = 0xff; else if (*p == 0x0d) outbuf[j++] = 0x00; } if (j > 0) write(netfd, outbuf, j); }
int telnet_main(int argc UNUSED_PARAM, char **argv) { char *host; int port; int len; #ifdef USE_POLL struct pollfd ufds[2]; #else fd_set readfds; int maxfd; #endif INIT_G(); #if ENABLE_FEATURE_AUTOWIDTH get_terminal_width_height(0, &G.win_width, &G.win_height); #endif #if ENABLE_FEATURE_TELNET_TTYPE G.ttype = getenv("TERM"); #endif if (tcgetattr(0, &G.termios_def) >= 0) { G.do_termios = 1; G.termios_raw = G.termios_def; cfmakeraw(&G.termios_raw); } #if ENABLE_FEATURE_TELNET_AUTOLOGIN if (1 & getopt32(argv, "al:", &G.autologin)) G.autologin = getenv("USER"); argv += optind; #else argv++; #endif if (!*argv) bb_show_usage(); host = *argv++; port = bb_lookup_port(*argv ? *argv++ : "telnet", "tcp", 23); if (*argv) /* extra params?? */ bb_show_usage(); xmove_fd(create_and_connect_stream_or_die(host, port), netfd); setsockopt(netfd, SOL_SOCKET, SO_KEEPALIVE, &const_int_1, sizeof(const_int_1)); signal(SIGINT, record_signo); #ifdef USE_POLL ufds[0].fd = 0; ufds[1].fd = netfd; ufds[0].events = ufds[1].events = POLLIN; #else FD_ZERO(&readfds); FD_SET(STDIN_FILENO, &readfds); FD_SET(netfd, &readfds); maxfd = netfd + 1; #endif while (1) { #ifndef USE_POLL fd_set rfds = readfds; switch (select(maxfd, &rfds, NULL, NULL, NULL)) #else switch (poll(ufds, 2, -1)) #endif { case 0: /* timeout */ case -1: /* error, ignore and/or log something, bay go to loop */ if (bb_got_signal) con_escape(); else sleep(1); break; default: #ifdef USE_POLL if (ufds[0].revents & POLLIN) #else if (FD_ISSET(STDIN_FILENO, &rfds)) #endif { len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE); if (len <= 0) doexit(EXIT_SUCCESS); TRACE(0, ("Read con: %d\n", len)); handle_net_output(len); } #ifdef USE_POLL if (ufds[1].revents & POLLIN) #else if (FD_ISSET(netfd, &rfds)) #endif { len = safe_read(netfd, G.buf, DATABUFSIZE); if (len <= 0) { write_str(1, "Connection closed by foreign host\r\n"); doexit(EXIT_FAILURE); } TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); handle_net_input(len); } } } /* while (1) */ }
int telnet_main(int argc UNUSED_PARAM, char **argv) { char *host; int port; int len; struct pollfd ufds[2]; INIT_G(); #if ENABLE_FEATURE_AUTOWIDTH get_terminal_width_height(0, &G.win_width, &G.win_height); #endif #if ENABLE_FEATURE_TELNET_TTYPE G.ttype = getenv("TERM"); #endif if (tcgetattr(0, &G.termios_def) >= 0) { G.do_termios = 1; G.termios_raw = G.termios_def; cfmakeraw(&G.termios_raw); } #if ENABLE_FEATURE_TELNET_AUTOLOGIN if (1 & getopt32(argv, "al:", &G.autologin)) G.autologin = getenv("USER"); argv += optind; #else argv++; #endif if (!*argv) bb_show_usage(); host = *argv++; port = bb_lookup_port(*argv ? *argv++ : "telnet", "tcp", 23); if (*argv) /* extra params?? */ bb_show_usage(); xmove_fd(create_and_connect_stream_or_die(host, port), netfd); setsockopt_keepalive(netfd); signal(SIGINT, record_signo); ufds[0].fd = STDIN_FILENO; ufds[0].events = POLLIN; ufds[1].fd = netfd; ufds[1].events = POLLIN; while (1) { if (poll(ufds, 2, -1) < 0) { /* error, ignore and/or log something, bay go to loop */ if (bb_got_signal) con_escape(); else sleep(1); continue; } // FIXME: reads can block. Need full bidirectional buffering. if (ufds[0].revents) { len = safe_read(STDIN_FILENO, G.buf, DATABUFSIZE); if (len <= 0) doexit(EXIT_SUCCESS); TRACE(0, ("Read con: %d\n", len)); handle_net_output(len); } if (ufds[1].revents) { len = safe_read(netfd, G.buf, DATABUFSIZE); if (len <= 0) { full_write1_str("Connection closed by foreign host\r\n"); doexit(EXIT_FAILURE); } TRACE(0, ("Read netfd (%d): %d\n", netfd, len)); handle_net_input(len); } } /* while (1) */ }