telnet.c

来自「大名鼎鼎的远程登录软件putty的Symbian版源码」· C语言 代码 · 共 1,061 行 · 第 1/2 页

C
1,061
字号
    }}static void do_telnet_read(Telnet telnet, char *buf, int len){    while (len--) {	int c = (unsigned char) *buf++;	switch (telnet->state) {	  case TOP_LEVEL:	  case SEENCR:	    if (c == NUL && telnet->state == SEENCR)		telnet->state = TOP_LEVEL;	    else if (c == IAC)		telnet->state = SEENIAC;	    else {		if (!telnet->in_synch)		    c_write1(telnet, c);#if 1		/* I can't get the F***ing winsock to insert the urgent IAC		 * into the right position! Even with SO_OOBINLINE it gives		 * it to recv too soon. And of course the DM byte (that		 * arrives in the same packet!) appears several K later!!		 *		 * Oh well, we do get the DM in the right place so I'll		 * just stop hiding on the next 0xf2 and hope for the best.		 */		else if (c == DM)		    telnet->in_synch = 0;#endif		if (c == CR && telnet->opt_states[o_they_bin.index] != ACTIVE)		    telnet->state = SEENCR;		else		    telnet->state = TOP_LEVEL;	    }	    break;	  case SEENIAC:	    if (c == DO)		telnet->state = SEENDO;	    else if (c == DONT)		telnet->state = SEENDONT;	    else if (c == WILL)		telnet->state = SEENWILL;	    else if (c == WONT)		telnet->state = SEENWONT;	    else if (c == SB)		telnet->state = SEENSB;	    else if (c == DM) {		telnet->in_synch = 0;		telnet->state = TOP_LEVEL;	    } else {		/* ignore everything else; print it if it's IAC */		if (c == IAC) {		    c_write1(telnet, c);		}		telnet->state = TOP_LEVEL;	    }	    break;	  case SEENWILL:	    proc_rec_opt(telnet, WILL, c);	    telnet->state = TOP_LEVEL;	    break;	  case SEENWONT:	    proc_rec_opt(telnet, WONT, c);	    telnet->state = TOP_LEVEL;	    break;	  case SEENDO:	    proc_rec_opt(telnet, DO, c);	    telnet->state = TOP_LEVEL;	    break;	  case SEENDONT:	    proc_rec_opt(telnet, DONT, c);	    telnet->state = TOP_LEVEL;	    break;	  case SEENSB:	    telnet->sb_opt = c;	    telnet->sb_len = 0;	    telnet->state = SUBNEGOT;	    break;	  case SUBNEGOT:	    if (c == IAC)		telnet->state = SUBNEG_IAC;	    else {	      subneg_addchar:		if (telnet->sb_len >= telnet->sb_size) {		    telnet->sb_size += SB_DELTA;		    telnet->sb_buf = sresize(telnet->sb_buf, telnet->sb_size,					     unsigned char);		}		telnet->sb_buf[telnet->sb_len++] = c;		telnet->state = SUBNEGOT;	/* in case we came here by goto */	    }	    break;	  case SUBNEG_IAC:	    if (c != SE)		goto subneg_addchar;   /* yes, it's a hack, I know, but... */	    else {		process_subneg(telnet);		telnet->state = TOP_LEVEL;	    }	    break;	}    }}static int telnet_closing(Plug plug, const char *error_msg, int error_code,			  int calling_back){    Telnet telnet = (Telnet) plug;    if (telnet->s) {        sk_close(telnet->s);        telnet->s = NULL;    }    if (error_msg) {	/* A socket error has occurred. */	logevent(telnet->frontend, error_msg);	connection_fatal(telnet->frontend, "%s", error_msg);    }				       /* Otherwise, the remote side closed the connection normally. */    return 0;}static int telnet_receive(Plug plug, int urgent, char *data, int len){    Telnet telnet = (Telnet) plug;    if (urgent)	telnet->in_synch = TRUE;    do_telnet_read(telnet, data, len);    return 1;}static void telnet_sent(Plug plug, int bufsize){    Telnet telnet = (Telnet) plug;    telnet->bufsize = bufsize;}/* * Called to set up the Telnet connection. * * Returns an error message, or NULL on success. * * Also places the canonical host name into `realhost'. It must be * freed by the caller. */static const char *telnet_init(void *frontend_handle, void **backend_handle,			       Config *cfg,			       char *host, int port, char **realhost,			       int nodelay, int keepalive){    static const struct plug_function_table fn_table = {	telnet_closing,	telnet_receive,	telnet_sent    };    SockAddr addr;    const char *err;    Telnet telnet;    telnet = snew(struct telnet_tag);    telnet->fn = &fn_table;    telnet->cfg = *cfg;		       /* STRUCTURE COPY */    telnet->s = NULL;    telnet->echoing = TRUE;    telnet->editing = TRUE;    telnet->activated = FALSE;    telnet->sb_buf = NULL;    telnet->sb_size = 0;    telnet->frontend = frontend_handle;    telnet->term_width = telnet->cfg.width;    telnet->term_height = telnet->cfg.height;    telnet->state = TOP_LEVEL;    *backend_handle = telnet;    /*     * Try to find host.     */    {	char *buf;	buf = dupprintf("Looking up host \"%s\"", host);	logevent(telnet->frontend, buf);	sfree(buf);    }    addr = name_lookup(host, port, realhost, &telnet->cfg);    if ((err = sk_addr_error(addr)) != NULL) {	sk_addr_free(addr);	return err;    }    if (port < 0)	port = 23;		       /* default telnet port */    /*     * Open socket.     */    {	char *buf, addrbuf[100];	sk_getaddr(addr, addrbuf, 100);	buf = dupprintf("Connecting to %s port %d", addrbuf, port);	logevent(telnet->frontend, buf);	sfree(buf);    }    telnet->s = new_connection(addr, *realhost, port, 0, 1,			       nodelay, keepalive, (Plug) telnet, &telnet->cfg);    if ((err = sk_socket_error(telnet->s)) != NULL)	return err;    /*     * Initialise option states.     */    if (telnet->cfg.passive_telnet) {	const struct Opt *const *o;	for (o = opts; *o; o++)	    telnet->opt_states[(*o)->index] = INACTIVE;    } else {	const struct Opt *const *o;	for (o = opts; *o; o++) {	    telnet->opt_states[(*o)->index] = (*o)->initial_state;	    if (telnet->opt_states[(*o)->index] == REQUESTED)		send_opt(telnet, (*o)->send, (*o)->option);	}	telnet->activated = TRUE;    }    /*     * Set up SYNCH state.     */    telnet->in_synch = FALSE;    /*     * We can send special commands from the start.     */    update_specials_menu(telnet->frontend);    return NULL;}static void telnet_free(void *handle){    Telnet telnet = (Telnet) handle;    sfree(telnet->sb_buf);    if (telnet->s)	sk_close(telnet->s);    sfree(telnet);}/* * Reconfigure the Telnet backend. There's no immediate action * necessary, in this backend: we just save the fresh config for * any subsequent negotiations. */static void telnet_reconfig(void *handle, Config *cfg){    Telnet telnet = (Telnet) handle;    telnet->cfg = *cfg;		       /* STRUCTURE COPY */}/* * Called to send data down the Telnet connection. */static int telnet_send(void *handle, char *buf, int len){    Telnet telnet = (Telnet) handle;    unsigned char *p, *end;    static const unsigned char iac[2] = { IAC, IAC };    static const unsigned char cr[2] = { CR, NUL };#if 0    static const unsigned char nl[2] = { CR, LF };#endif    if (telnet->s == NULL)	return 0;    p = (unsigned char *)buf;    end = (unsigned char *)(buf + len);    while (p < end) {	unsigned char *q = p;	while (p < end && iswritable(*p))	    p++;	telnet->bufsize = sk_write(telnet->s, (char *)q, p - q);	while (p < end && !iswritable(*p)) {	    telnet->bufsize = 		sk_write(telnet->s, (char *)(*p == IAC ? iac : cr), 2);	    p++;	}    }    return telnet->bufsize;}/* * Called to query the current socket sendability status. */static int telnet_sendbuffer(void *handle){    Telnet telnet = (Telnet) handle;    return telnet->bufsize;}/* * Called to set the size of the window from Telnet's POV. */static void telnet_size(void *handle, int width, int height){    Telnet telnet = (Telnet) handle;    unsigned char b[24];    int n;    char *logbuf;    telnet->term_width = width;    telnet->term_height = height;    if (telnet->s == NULL || telnet->opt_states[o_naws.index] != ACTIVE)	return;    n = 0;    b[n++] = IAC;    b[n++] = SB;    b[n++] = TELOPT_NAWS;    b[n++] = telnet->term_width >> 8;    if (b[n-1] == IAC) b[n++] = IAC;   /* duplicate any IAC byte occurs */    b[n++] = telnet->term_width & 0xFF;    if (b[n-1] == IAC) b[n++] = IAC;   /* duplicate any IAC byte occurs */    b[n++] = telnet->term_height >> 8;    if (b[n-1] == IAC) b[n++] = IAC;   /* duplicate any IAC byte occurs */    b[n++] = telnet->term_height & 0xFF;    if (b[n-1] == IAC) b[n++] = IAC;   /* duplicate any IAC byte occurs */    b[n++] = IAC;    b[n++] = SE;    telnet->bufsize = sk_write(telnet->s, (char *)b, n);    logbuf = dupprintf("client:\tSB NAWS %d,%d",		       telnet->term_width, telnet->term_height);    logevent(telnet->frontend, logbuf);    sfree(logbuf);}/* * Send Telnet special codes. */static void telnet_special(void *handle, Telnet_Special code){    Telnet telnet = (Telnet) handle;    unsigned char b[2];    if (telnet->s == NULL)	return;    b[0] = IAC;    switch (code) {      case TS_AYT:	b[1] = AYT;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_BRK:	b[1] = BREAK;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_EC:	b[1] = EC;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_EL:	b[1] = EL;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_GA:	b[1] = GA;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_NOP:	b[1] = NOP;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_ABORT:	b[1] = ABORT;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_AO:	b[1] = AO;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_IP:	b[1] = IP;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_SUSP:	b[1] = SUSP;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_EOR:	b[1] = EOR;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_EOF:	b[1] = xEOF;	telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	break;      case TS_EOL:	/* In BINARY mode, CR-LF becomes just CR -	 * and without the NUL suffix too. */	if (telnet->opt_states[o_we_bin.index] == ACTIVE)	    telnet->bufsize = sk_write(telnet->s, "\r", 1);	else	    telnet->bufsize = sk_write(telnet->s, "\r\n", 2);	break;      case TS_SYNCH:	b[1] = DM;	telnet->bufsize = sk_write(telnet->s, (char *)b, 1);	telnet->bufsize = sk_write_oob(telnet->s, (char *)(b + 1), 1);	break;      case TS_RECHO:	if (telnet->opt_states[o_echo.index] == INACTIVE ||	    telnet->opt_states[o_echo.index] == REALLY_INACTIVE) {	    telnet->opt_states[o_echo.index] = REQUESTED;	    send_opt(telnet, o_echo.send, o_echo.option);	}	break;      case TS_LECHO:	if (telnet->opt_states[o_echo.index] == ACTIVE) {	    telnet->opt_states[o_echo.index] = REQUESTED;	    send_opt(telnet, o_echo.nsend, o_echo.option);	}	break;      case TS_PING:	if (telnet->opt_states[o_they_sga.index] == ACTIVE) {	    b[1] = NOP;	    telnet->bufsize = sk_write(telnet->s, (char *)b, 2);	}	break;      default:	break;	/* never heard of it */    }}static const struct telnet_special *telnet_get_specials(void *handle){    static const struct telnet_special specials[] = {	{"Are You There", TS_AYT},	{"Break", TS_BRK},	{"Synch", TS_SYNCH},	{"Erase Character", TS_EC},	{"Erase Line", TS_EL},	{"Go Ahead", TS_GA},	{"No Operation", TS_NOP},	{NULL, TS_SEP},	{"Abort Process", TS_ABORT},	{"Abort Output", TS_AO},	{"Interrupt Process", TS_IP},	{"Suspend Process", TS_SUSP},	{NULL, TS_SEP},	{"End Of Record", TS_EOR},	{"End Of File", TS_EOF},	{NULL, TS_EXITMENU}    };    return specials;}static Socket telnet_socket(void *handle){    Telnet telnet = (Telnet) handle;    return telnet->s;}static int telnet_sendok(void *handle){    /* Telnet telnet = (Telnet) handle; */    return 1;}static void telnet_unthrottle(void *handle, int backlog){    Telnet telnet = (Telnet) handle;    sk_set_frozen(telnet->s, backlog > TELNET_MAX_BACKLOG);}static int telnet_ldisc(void *handle, int option){    Telnet telnet = (Telnet) handle;    if (option == LD_ECHO)	return telnet->echoing;    if (option == LD_EDIT)	return telnet->editing;    return FALSE;}static void telnet_provide_ldisc(void *handle, void *ldisc){    Telnet telnet = (Telnet) handle;    telnet->ldisc = ldisc;}static void telnet_provide_logctx(void *handle, void *logctx){    /* This is a stub. */}static int telnet_exitcode(void *handle){    Telnet telnet = (Telnet) handle;    if (telnet->s != NULL)        return -1;                     /* still connected */    else        /* Telnet doesn't transmit exit codes back to the client */        return 0;}Backend telnet_backend = {    telnet_init,    telnet_free,    telnet_reconfig,    telnet_send,    telnet_sendbuffer,    telnet_size,    telnet_special,    telnet_get_specials,    telnet_socket,    telnet_exitcode,    telnet_sendok,    telnet_ldisc,    telnet_provide_ldisc,    telnet_provide_logctx,    telnet_unthrottle,    23};

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?