static void telnet_process_request (char_tcp_t *drv, unsigned option) { unsigned st; st = drv->telnet_state; switch (option) { case TELNET_OPT_BINARY: if ((st == CHAR_TCP_DO) || (st == CHAR_TCP_DONT)) { /* We insist on being binary. */ telnet_will (drv, TELNET_OPT_BINARY); } else if ((st == CHAR_TCP_WILL) || (st == CHAR_TCP_WONT)) { /* We insist on being binary. */ telnet_do (drv, TELNET_OPT_BINARY); } return; case TELNET_OPT_ECHO: if (st == CHAR_TCP_WILL) { /* We refuse that the client performs echoing itself. */ telnet_dont (drv, TELNET_OPT_ECHO); } else if (st == CHAR_TCP_DONT) { /* We insist on echoing. */ telnet_will (drv, TELNET_OPT_ECHO); } return; case TELNET_OPT_SUPPRESS_GO_AHEAD: if (st == CHAR_TCP_DONT) { /* We will never send go-aheads. */ telnet_will (drv, TELNET_OPT_SUPPRESS_GO_AHEAD); } else if ((st == CHAR_TCP_WILL) || (st == CHAR_TCP_WONT)) { /* The client may or may not suppress go-aheads at its own * volition. */ telnet_send_request (drv, TELNET_OPT_SUPPRESS_GO_AHEAD, (st == CHAR_TCP_WILL) ? CHAR_TCP_DO : CHAR_TCP_DONT ); } return; default: /* unknown option, refuse it. */ telnet_send_request (drv, option, (st == CHAR_TCP_WILL) ? TELNET_DONT : TELNET_WONT ); } }
static void chr_tcp_init_connection (char_tcp_t *drv) { tcp_set_nodelay (drv->fd, 1); drv->telnet_state = CHAR_TCP_DATA; if (drv->telnet && drv->telnetinit) { /* Instruct telnet client to switch to character mode. */ telnet_do (drv, TELNET_OPT_BINARY); telnet_will (drv, TELNET_OPT_ECHO); telnet_will (drv, TELNET_OPT_SUPPRESS_GO_AHEAD); } }
/* * Perform Telnet protocol processing, copying the contents of the raw input * queue to the canonical queue. */ static void telnet_input(telnet_t *tp) { u_char c; while (!nq_empty(tp->t_rawq)) { c = nq_getc(tp->t_rawq); switch (tp->t_state) { case TS_DATA: switch (c) { case NUL: break; case BS: telnet_ec(tp); break; case LF: telnet_eol(tp); return; case CR: tp->t_state = TS_CR; break; case DEL: telnet_ec(tp); break; case IAC: tp->t_state = TS_IAC; break; default: telnet_canq_putc(tp, c); break; } break; case TS_CR: telnet_eol(tp); tp->t_state = TS_DATA; return; case TS_IAC: tp->t_state = TS_DATA; switch (c) { case DM: telnet_dm(tp); break; case AYT: telnet_ayt(tp); break; case EC: telnet_ec(tp); break; case EL: telnet_el(tp); break; case SB: tp->t_state = TS_IAC_SB; break; case WILL: tp->t_state = TS_IAC_WILL; break; case WONT: tp->t_state = TS_IAC_WONT; break; case DO: tp->t_state = TS_IAC_DO; break; case DONT: tp->t_state = TS_IAC_DONT; break; case IAC: telnet_canq_putc(tp, c); break; } break; case TS_IAC_SB: telnet_sb(tp, c); tp->t_state = TS_IAC_SB_DATA; break; case TS_IAC_SB_DATA: switch (c) { case IAC: tp->t_state = TS_IAC_SB_IAC; break; default: telnet_optq_putc(tp, c); break; } break; case TS_IAC_SB_IAC: tp->t_state = TS_IAC_SB_DATA; switch (c) { case SE: telnet_se(tp); tp->t_state = TS_DATA; break; case IAC: telnet_optq_putc(tp, c); break; } break; case TS_IAC_WILL: telnet_will(tp, c); tp->t_state = TS_DATA; break; case TS_IAC_WONT: telnet_wont(tp, c); tp->t_state = TS_DATA; break; case TS_IAC_DO: telnet_do(tp, c); tp->t_state = TS_DATA; break; case TS_IAC_DONT: telnet_dont(tp, c); tp->t_state = TS_DATA; break; } } if ((tp->t_flags & (TF_SGA | TF_GA)) == 0) { if (nq_avail(tp->t_outq) >= 2) { tp->t_flags |= TF_GA; telnet_send_ga(tp); } } nq_init(tp->t_rawq); }