X-Git-Url: https://git.distorted.org.uk/u/mdw/putty/blobdiff_plain/8faa456cf83ade45a6a2f33784d46b9963a0f77e..2184a5d91ffbcf2de2f730c83dda2d9443035f50:/telnet.c diff --git a/telnet.c b/telnet.c index 3cef9c76..5c5d2ce3 100644 --- a/telnet.c +++ b/telnet.c @@ -174,9 +174,11 @@ static struct Opt *opts[] = { &o_we_sga, &o_they_sga, NULL }; +#define TELNET_MAX_BACKLOG 4096 + static int echoing = TRUE, editing = TRUE; static int activated = FALSE; - +static int telnet_bufsize; static int in_synch; static int sb_opt, sb_len; static char *sb_buf = NULL; @@ -185,8 +187,10 @@ static int sb_size = 0; static void c_write1(int c) { + int backlog; char cc = (char) c; - from_backend(0, &cc, 1); + backlog = from_backend(0, &cc, 1); + sk_set_frozen(s, backlog > TELNET_MAX_BACKLOG); } static void log_option(char *sender, int cmd, int option) @@ -206,7 +210,7 @@ static void send_opt(int cmd, int option) b[0] = IAC; b[1] = cmd; b[2] = option; - sk_write(s, b, 3); + telnet_bufsize = sk_write(s, b, 3); log_option("client", cmd, option); } @@ -226,7 +230,7 @@ static void option_side_effects(struct Opt *o, int enabled) echoing = !enabled; else if (o->option == TELOPT_SGA && o->send == DO) editing = !enabled; - ldisc_send(NULL, 0); /* cause ldisc to notice the change */ + ldisc_send(NULL, 0, 0); /* cause ldisc to notice the change */ /* Ensure we get the minimum options */ if (!activated) { @@ -340,7 +344,7 @@ static void process_subneg(void) n = 4 + strlen(cfg.termspeed); b[n] = IAC; b[n + 1] = SE; - sk_write(s, b, n + 2); + telnet_bufsize = sk_write(s, b, n + 2); logevent("server:\tSB TSPEED SEND"); sprintf(logbuf, "client:\tSB TSPEED IS %s", cfg.termspeed); logevent(logbuf); @@ -361,7 +365,7 @@ static void process_subneg(void) 'a' : cfg.termtype[n]); b[n + 4] = IAC; b[n + 5] = SE; - sk_write(s, b, n + 6); + telnet_bufsize = sk_write(s, b, n + 6); b[n + 4] = 0; logevent("server:\tSB TTYPE SEND"); sprintf(logbuf, "client:\tSB TTYPE IS %s", b + 4); @@ -437,7 +441,7 @@ static void process_subneg(void) } b[n++] = IAC; b[n++] = SE; - sk_write(s, b, n); + telnet_bufsize = sk_write(s, b, n); sprintf(logbuf, "client:\tSB %s IS %s", telopt(sb_opt), n == 6 ? "" : ""); logevent(logbuf); @@ -565,8 +569,10 @@ static void do_telnet_read(char *buf, int len) static int telnet_closing(Plug plug, char *error_msg, int error_code, int calling_back) { - sk_close(s); - s = NULL; + if (s) { + sk_close(s); + s = NULL; + } if (error_msg) { /* A socket error has occurred. */ connection_fatal(error_msg); @@ -582,18 +588,25 @@ static int telnet_receive(Plug plug, int urgent, char *data, int len) return 1; } +static void telnet_sent(Plug plug, int bufsize) +{ + 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'. + * Also places the canonical host name into `realhost'. It must be + * freed by the caller. */ -static char *telnet_init(char *host, int port, char **realhost) +static char *telnet_init(char *host, int port, char **realhost, int nodelay) { static struct plug_function_table fn_table = { telnet_closing, - telnet_receive + telnet_receive, + telnet_sent }, *fn_table_ptr = &fn_table; SockAddr addr; @@ -602,6 +615,11 @@ static char *telnet_init(char *host, int port, char **realhost) /* * Try to find host. */ + { + char buf[200]; + sprintf(buf, "Looking up host \"%.170s\"", host); + logevent(buf); + } addr = sk_namelookup(host, realhost); if ((err = sk_addr_error(addr))) return err; @@ -612,7 +630,13 @@ static char *telnet_init(char *host, int port, char **realhost) /* * Open socket. */ - s = sk_new(addr, port, 0, 1, &fn_table_ptr); + { + char buf[200], addrbuf[100]; + sk_getaddr(addr, addrbuf, 100); + sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); + logevent(buf); + } + s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; @@ -647,15 +671,17 @@ static char *telnet_init(char *host, int port, char **realhost) /* * Called to send data down the Telnet connection. */ -static void telnet_send(char *buf, int len) +static int telnet_send(char *buf, int len) { char *p; static unsigned char iac[2] = { IAC, IAC }; static unsigned char cr[2] = { CR, NUL }; +#if 0 static unsigned char nl[2] = { CR, LF }; +#endif if (s == NULL) - return; + return 0; p = buf; while (p < buf + len) { @@ -663,13 +689,24 @@ static void telnet_send(char *buf, int len) while (iswritable((unsigned char) *p) && p < buf + len) p++; - sk_write(s, q, p - q); + telnet_bufsize = sk_write(s, q, p - q); while (p < buf + len && !iswritable((unsigned char) *p)) { - sk_write(s, (unsigned char) *p == IAC ? iac : nl, 2); + telnet_bufsize = + sk_write(s, (unsigned char) *p == IAC ? iac : cr, 2); p++; } } + + return telnet_bufsize; +} + +/* + * Called to query the current socket sendability status. + */ +static int telnet_sendbuffer(void) +{ + return telnet_bufsize; } /* @@ -691,7 +728,7 @@ static void telnet_size(void) b[6] = rows & 0xFF; b[7] = IAC; b[8] = SE; - sk_write(s, b, 9); + telnet_bufsize = sk_write(s, b, 9); sprintf(logbuf, "client:\tSB NAWS %d,%d", ((unsigned char) b[3] << 8) + (unsigned char) b[4], ((unsigned char) b[5] << 8) + (unsigned char) b[6]); @@ -712,56 +749,59 @@ static void telnet_special(Telnet_Special code) switch (code) { case TS_AYT: b[1] = AYT; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_BRK: b[1] = BREAK; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_EC: b[1] = EC; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_EL: b[1] = EL; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_GA: b[1] = GA; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_NOP: b[1] = NOP; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_ABORT: b[1] = ABORT; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_AO: b[1] = AO; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_IP: b[1] = IP; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_SUSP: b[1] = SUSP; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_EOR: b[1] = EOR; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); break; case TS_EOF: b[1] = xEOF; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); + break; + case TS_EOL: + telnet_bufsize = sk_write(s, "\r\n", 2); break; case TS_SYNCH: b[1] = DM; - sk_write(s, b, 1); - sk_write_oob(s, b + 1, 1); + telnet_bufsize = sk_write(s, b, 1); + telnet_bufsize = sk_write_oob(s, b + 1, 1); break; case TS_RECHO: if (o_echo.state == INACTIVE || o_echo.state == REALLY_INACTIVE) { @@ -778,7 +818,7 @@ static void telnet_special(Telnet_Special code) case TS_PING: if (o_they_sga.state == ACTIVE) { b[1] = NOP; - sk_write(s, b, 2); + telnet_bufsize = sk_write(s, b, 2); } break; } @@ -794,6 +834,11 @@ static int telnet_sendok(void) return 1; } +static void telnet_unthrottle(int backlog) +{ + sk_set_frozen(s, backlog > TELNET_MAX_BACKLOG); +} + static int telnet_ldisc(int option) { if (option == LD_ECHO) @@ -806,10 +851,12 @@ static int telnet_ldisc(int option) Backend telnet_backend = { telnet_init, telnet_send, + telnet_sendbuffer, telnet_size, telnet_special, telnet_socket, telnet_sendok, telnet_ldisc, + telnet_unthrottle, 23 };