From 2184a5d91ffbcf2de2f730c83dda2d9443035f50 Mon Sep 17 00:00:00 2001 From: simon Date: Thu, 29 Nov 2001 21:47:11 +0000 Subject: [PATCH] Configurable TCP_NODELAY option on network connections git-svn-id: svn://svn.tartarus.org/sgt/putty@1428 cda61777-01e9-0310-a592-d414129be87e --- network.h | 2 +- plink.c | 5 ++++- portfwd.c | 2 +- psftp.c | 2 +- putty.h | 3 ++- raw.c | 4 ++-- rlogin.c | 4 ++-- scp.c | 2 +- settings.c | 2 ++ ssh.c | 8 ++++---- telnet.c | 4 ++-- windlg.c | 18 +++++++++++++++++- window.c | 2 +- winnet.c | 7 ++++++- x11fwd.c | 2 +- 15 files changed, 47 insertions(+), 20 deletions(-) diff --git a/network.h b/network.h index 28744a6f..3ec9eb78 100644 --- a/network.h +++ b/network.h @@ -68,7 +68,7 @@ void sk_getaddr(SockAddr addr, char *buf, int buflen); void sk_addr_free(SockAddr addr); Socket sk_new(SockAddr addr, int port, int privport, int oobinline, - Plug p); + int nodelay, Plug p); Socket sk_newlistener(int port, Plug plug, int local_host_only); diff --git a/plink.c b/plink.c index 8d4701a9..5ef9da2e 100644 --- a/plink.c +++ b/plink.c @@ -735,8 +735,11 @@ int main(int argc, char **argv) { char *error; char *realhost; + /* nodelay is only useful if stdin is a character device (console) */ + int nodelay = cfg.tcp_nodelay && + (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR); - error = back->init(cfg.host, cfg.port, &realhost); + error = back->init(cfg.host, cfg.port, &realhost, nodelay); if (error) { fprintf(stderr, "Unable to open connection:\n%s", error); return 1; diff --git a/portfwd.c b/portfwd.c index 00fc098f..732bfc5b 100644 --- a/portfwd.c +++ b/portfwd.c @@ -138,7 +138,7 @@ char *pfd_newconnect(Socket *s, char *hostname, int port, void *c) pr->ready = 1; pr->c = c; - pr->s = *s = sk_new(addr, port, 0, 1, (Plug) pr); + pr->s = *s = sk_new(addr, port, 0, 1, 0, (Plug) pr); if ((err = sk_socket_error(*s))) { sfree(pr); return err; diff --git a/psftp.c b/psftp.c index 6b7ff1d1..250a5fcc 100644 --- a/psftp.c +++ b/psftp.c @@ -1820,7 +1820,7 @@ int main(int argc, char *argv[]) back = &ssh_backend; - err = back->init(cfg.host, cfg.port, &realhost); + err = back->init(cfg.host, cfg.port, &realhost, 0); if (err != NULL) { fprintf(stderr, "ssh_init: %s", err); return 1; diff --git a/putty.h b/putty.h index ada08584..352a4ef3 100644 --- a/putty.h +++ b/putty.h @@ -202,7 +202,7 @@ enum { }; typedef struct { - char *(*init) (char *host, int port, char **realhost); + char *(*init) (char *host, int port, char **realhost, int nodelay); /* back->send() returns the current amount of buffered data. */ int (*send) (char *buf, int len); /* back->sendbuffer() does the same thing but without attempting a send */ @@ -236,6 +236,7 @@ typedef struct { int close_on_exit; int warn_on_close; int ping_interval; /* in seconds */ + int tcp_nodelay; /* SSH options */ char remote_cmd[512]; char remote_cmd2[512]; /* fallback if the first fails diff --git a/raw.c b/raw.c index 4b170511..e3fcbc00 100644 --- a/raw.c +++ b/raw.c @@ -57,7 +57,7 @@ static void raw_sent(Plug plug, int bufsize) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static char *raw_init(char *host, int port, char **realhost) +static char *raw_init(char *host, int port, char **realhost, int nodelay) { static struct plug_function_table fn_table = { raw_closing, @@ -92,7 +92,7 @@ static char *raw_init(char *host, int port, char **realhost) sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); logevent(buf); } - s = sk_new(addr, port, 0, 1, &fn_table_ptr); + s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; diff --git a/rlogin.c b/rlogin.c index cee653ac..97699aea 100644 --- a/rlogin.c +++ b/rlogin.c @@ -86,7 +86,7 @@ static void rlogin_sent(Plug plug, int bufsize) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static char *rlogin_init(char *host, int port, char **realhost) +static char *rlogin_init(char *host, int port, char **realhost, int nodelay) { static struct plug_function_table fn_table = { rlogin_closing, @@ -121,7 +121,7 @@ static char *rlogin_init(char *host, int port, char **realhost) sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); logevent(buf); } - s = sk_new(addr, port, 1, 0, &fn_table_ptr); + s = sk_new(addr, port, 1, 0, nodelay, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; diff --git a/scp.c b/scp.c index db9952ef..c40d7cce 100644 --- a/scp.c +++ b/scp.c @@ -689,7 +689,7 @@ static void do_cmd(char *host, char *user, char *cmd) back = &ssh_backend; - err = back->init(cfg.host, cfg.port, &realhost); + err = back->init(cfg.host, cfg.port, &realhost, 0); if (err != NULL) bump("ssh_init: %s", err); ssh_scp_init(); diff --git a/settings.c b/settings.c index 27c21dda..24d6aeb5 100644 --- a/settings.c +++ b/settings.c @@ -145,6 +145,7 @@ void save_settings(char *section, int do_host, Config * cfg) write_setting_i(sesskey, "WarnOnClose", !!cfg->warn_on_close); write_setting_i(sesskey, "PingInterval", cfg->ping_interval / 60); /* minutes */ write_setting_i(sesskey, "PingIntervalSecs", cfg->ping_interval % 60); /* seconds */ + write_setting_i(sesskey, "TCPNoDelay", cfg->tcp_nodelay); write_setting_s(sesskey, "TerminalType", cfg->termtype); write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed); { @@ -326,6 +327,7 @@ void load_settings(char *section, int do_host, Config * cfg) gppi(sesskey, "PingIntervalSecs", 0, &pingsec); cfg->ping_interval = pingmin * 60 + pingsec; } + gppi(sesskey, "TCPNoDelay", 1, &cfg->tcp_nodelay); gpps(sesskey, "TerminalType", "xterm", cfg->termtype, sizeof(cfg->termtype)); gpps(sesskey, "TerminalSpeed", "38400,38400", cfg->termspeed, diff --git a/ssh.c b/ssh.c index 0d299eaf..2163e211 100644 --- a/ssh.c +++ b/ssh.c @@ -1657,7 +1657,7 @@ static void ssh_sent(Plug plug, int bufsize) * Also places the canonical host name into `realhost'. It must be * freed by the caller. */ -static char *connect_to_host(char *host, int port, char **realhost) +static char *connect_to_host(char *host, int port, char **realhost, int nodelay) { static struct plug_function_table fn_table = { ssh_closing, @@ -1714,7 +1714,7 @@ static char *connect_to_host(char *host, int port, char **realhost) sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); logevent(buf); } - s = sk_new(addr, port, 0, 1, &fn_table_ptr); + s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; @@ -5109,7 +5109,7 @@ static void ssh2_protocol(unsigned char *in, int inlen, int ispkt) * * Returns an error message, or NULL on success. */ -static char *ssh_init(char *host, int port, char **realhost) +static char *ssh_init(char *host, int port, char **realhost, int nodelay) { char *p; @@ -5125,7 +5125,7 @@ static char *ssh_init(char *host, int port, char **realhost) ssh_overall_bufsize = 0; ssh_fallback_cmd = 0; - p = connect_to_host(host, port, realhost); + p = connect_to_host(host, port, realhost, nodelay); if (p != NULL) return p; diff --git a/telnet.c b/telnet.c index 06717f1e..5c5d2ce3 100644 --- a/telnet.c +++ b/telnet.c @@ -601,7 +601,7 @@ static void telnet_sent(Plug plug, int bufsize) * 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, @@ -636,7 +636,7 @@ static char *telnet_init(char *host, int port, char **realhost) sprintf(buf, "Connecting to %.100s port %d", addrbuf, port); logevent(buf); } - s = sk_new(addr, port, 0, 1, &fn_table_ptr); + s = sk_new(addr, port, 0, 1, nodelay, &fn_table_ptr); if ((err = sk_socket_error(s))) return err; diff --git a/windlg.c b/windlg.c index 7113360d..f3084ce2 100644 --- a/windlg.c +++ b/windlg.c @@ -405,12 +405,14 @@ enum { IDCX_ABOUT = IDC_TITLE_CONNECTION, IDC_BOX_CONNECTION1, IDC_BOX_CONNECTION2, + IDC_BOX_CONNECTION3, IDC_TTSTATIC, IDC_TTEDIT, IDC_LOGSTATIC, IDC_LOGEDIT, IDC_PINGSTATIC, IDC_PINGEDIT, + IDC_NODELAY, connectionpanelend, telnetpanelstart, @@ -612,6 +614,7 @@ static void init_dlg_ctrls(HWND hwnd, int keepsess) cfg.protocol == PROT_RLOGIN ? IDC_PROTRLOGIN : IDC_PROTRAW); SetDlgItemInt(hwnd, IDC_PINGEDIT, cfg.ping_interval, FALSE); + CheckDlgButton(hwnd, IDC_NODELAY, cfg.tcp_nodelay); CheckRadioButton(hwnd, IDC_DEL008, IDC_DEL127, cfg.bksp_is_delete ? IDC_DEL127 : IDC_DEL008); @@ -1224,7 +1227,7 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) } if (panel == connectionpanelstart) { - /* The Connection panel. Accelerators used: [acgo] tuk */ + /* The Connection panel. Accelerators used: [acgo] tukn */ struct ctlpos cp; ctlposinit(&cp, hwnd, 80, 3, 13); bartitle(&cp, "Options controlling the connection", @@ -1248,6 +1251,13 @@ static void create_controls(HWND hwnd, int dlgtype, int panel) staticedit(&cp, "Seconds between &keepalives (0 to turn off)", IDC_PINGSTATIC, IDC_PINGEDIT, 20); endbox(&cp); + if (dlgtype == 0) { + beginbox(&cp, "Low-level TCP connection options", + IDC_BOX_CONNECTION3); + checkbox(&cp, "Disable &Nagle's algorithm (TCP_NODELAY option)", + IDC_NODELAY); + endbox(&cp); + } } if (panel == telnetpanelstart) { @@ -1777,6 +1787,12 @@ static int GenericMainDlgProc(HWND hwnd, UINT msg, MyGetDlgItemInt(hwnd, IDC_PINGEDIT, &cfg.ping_interval); break; + case IDC_NODELAY: + if (HIWORD(wParam) == BN_CLICKED || + HIWORD(wParam) == BN_DOUBLECLICKED) + cfg.tcp_nodelay = + IsDlgButtonChecked(hwnd, IDC_NODELAY); + break; case IDC_DEL008: case IDC_DEL127: if (HIWORD(wParam) == BN_CLICKED || diff --git a/window.c b/window.c index 11533e29..8b404ab1 100644 --- a/window.c +++ b/window.c @@ -508,7 +508,7 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show) char msg[1024], *title; char *realhost; - error = back->init(cfg.host, cfg.port, &realhost); + error = back->init(cfg.host, cfg.port, &realhost, cfg.tcp_nodelay); if (error) { sprintf(msg, "Unable to open connection to\n" "%.800s\n" "%s", cfg.host, error); diff --git a/winnet.c b/winnet.c index 8e1c2a1d..991443ad 100644 --- a/winnet.c +++ b/winnet.c @@ -439,7 +439,7 @@ Socket sk_register(void *sock, Plug plug) } Socket sk_new(SockAddr addr, int port, int privport, int oobinline, - Plug plug) + int nodelay, Plug plug) { static struct socket_function_table fn_table = { sk_tcp_plug, @@ -494,6 +494,11 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline, setsockopt(s, SOL_SOCKET, SO_OOBINLINE, (void *) &b, sizeof(b)); } + if (nodelay) { + BOOL b = TRUE; + setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b)); + } + /* * Bind to local address. */ diff --git a/x11fwd.c b/x11fwd.c index ac0ff04a..6fde0d8f 100644 --- a/x11fwd.c +++ b/x11fwd.c @@ -195,7 +195,7 @@ char *x11_init(Socket * s, char *display, void *c) pr->throttled = pr->throttle_override = 0; pr->c = c; - pr->s = *s = sk_new(addr, port, 0, 1, (Plug) pr); + pr->s = *s = sk_new(addr, port, 0, 1, 0, (Plug) pr); if ((err = sk_socket_error(*s))) { sfree(pr); return err; -- 2.11.0