Configurable TCP_NODELAY option on network connections
authorsimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 29 Nov 2001 21:47:11 +0000 (21:47 +0000)
committersimon <simon@cda61777-01e9-0310-a592-d414129be87e>
Thu, 29 Nov 2001 21:47:11 +0000 (21:47 +0000)
git-svn-id: svn://svn.tartarus.org/sgt/putty@1428 cda61777-01e9-0310-a592-d414129be87e

15 files changed:
network.h
plink.c
portfwd.c
psftp.c
putty.h
raw.c
rlogin.c
scp.c
settings.c
ssh.c
telnet.c
windlg.c
window.c
winnet.c
x11fwd.c

index 28744a6..3ec9eb7 100644 (file)
--- 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 8d4701a..5ef9da2 100644 (file)
--- 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;
index 00fc098..732bfc5 100644 (file)
--- 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 6b7ff1d..250a5fc 100644 (file)
--- 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 ada0858..352a4ef 100644 (file)
--- 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 4b17051..e3fcbc0 100644 (file)
--- 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;
 
index cee653a..97699ae 100644 (file)
--- 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 db9952e..c40d7cc 100644 (file)
--- 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();
index 27c21dd..24d6aeb 100644 (file)
@@ -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 0d299ea..2163e21 100644 (file)
--- 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;
 
index 06717f1..5c5d2ce 100644 (file)
--- 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;
 
index 7113360..f3084ce 100644 (file)
--- 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 ||
index 11533e2..8b404ab 100644 (file)
--- 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);
index 8e1c2a1..991443a 100644 (file)
--- 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.
      */
index ac0ff04..6fde0d8 100644 (file)
--- 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;