Add a configuration option for TCP keepalives (SO_KEEPALIVE), default off.
authorjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Sun, 20 Jun 2004 17:07:38 +0000 (17:07 +0000)
committerjacob <jacob@cda61777-01e9-0310-a592-d414129be87e>
Sun, 20 Jun 2004 17:07:38 +0000 (17:07 +0000)
No very good reason, but I've occasionally wanted to frob it to see if it
makes any difference to problems I'm having, and it was easy.

Tested that it does actually cause keepalives on Windows (with tcpdump);
should also work on Unix. Not implemented on Mac (does nothing), but then
neither is TCP_NODELAY.

Quite a big checkin, much of which is adding `keepalive' alongside `nodelay'
in network function calls.

git-svn-id: svn://svn.tartarus.org/sgt/putty@4309 cda61777-01e9-0310-a592-d414129be87e

29 files changed:
config.c
doc/config.but
mac/macnet.c
mac/macterm.c
mac/mtcpnet.c
mac/otnet.c
network.h
plink.c
portfwd.c
pproxy.c
proxy.c
psftp.c
putty.h
raw.c
rlogin.c
scp.c
settings.c
ssh.c
telnet.c
testback.c
unix/pterm.c
unix/pty.c
unix/uxnet.c
unix/uxplink.c
unix/uxproxy.c
window.c
winhelp.h
winnet.c
x11fwd.c

index 50548ee..d3d76f5 100644 (file)
--- a/config.c
+++ b/config.c
@@ -1292,6 +1292,10 @@ void setup_config_box(struct controlbox *b, struct sesslist *sesslist,
                          'n', HELPCTX(connection_nodelay),
                          dlg_stdcheckbox_handler,
                          I(offsetof(Config,tcp_nodelay)));
+           ctrl_checkbox(s, "Enable TCP keepalives (SO_KEEPALIVE option)",
+                         'p', HELPCTX(connection_tcpkeepalive),
+                         dlg_stdcheckbox_handler,
+                         I(offsetof(Config,tcp_keepalives)));
        }
 
     }
index 7572a77..2279db5 100644 (file)
@@ -1,4 +1,4 @@
-\versionid $Id: config.but,v 1.83 2004/06/15 11:31:30 jacob Exp $
+\versionid $Id: config.but,v 1.84 2004/06/20 17:07:36 jacob Exp $
 
 \C{config} Configuring PuTTY
 
@@ -1506,7 +1506,8 @@ what \e{kind} of network problems you have between you and the
 server.
 
 Keepalives are only supported in Telnet and SSH; the Rlogin and Raw
-protocols offer no way of implementing them.
+protocols offer no way of implementing them. (For an alternative, see
+\k{config-tcp-keepalives}.)
 
 Note that if you are using SSH1 and the server has a bug that makes
 it unable to deal with SSH1 ignore messages (see
@@ -1525,6 +1526,34 @@ types of server.
 
 The Nagle algorithm is disabled by default.
 
+\S{config-tcp-keepalives} \q{Enable TCP keepalives}
+
+\cfg{winhelp-topic}{connection.tcpkeepalive}
+
+\e{NOTE:} TCP keepalives should not be confused with the
+application-level keepalives described in \k{config-keepalive}. If in
+doubt, you probably want application-level keepalives; TCP keepalives
+are provided for completeness.
+
+The idea of TCP keepalives is similar to application-level keepalives,
+and the same caveats apply. The main differences are:
+
+\b TCP keepalives are available on \e{all} connection types, including
+Raw and Rlogin.
+
+\b The interval between TCP keepalives is usually much longer,
+typically two hours; this is set by the operating system, and cannot
+be configured within PuTTY.
+
+\b If the operating system does not receive a response to a keepalive,
+it may send out more in quick succession and if terminate the connection
+if no response is received.
+
+TCP keepalives may be useful for ensuring that half-open connections
+are terminated than for keeping a connection alive.
+
+TCP keepalives are disabled by default.
+
 \H{config-proxy} The Proxy panel
 
 \cfg{winhelp-topic}{proxy.main}
index 106a631..9fab15b 100644 (file)
@@ -12,7 +12,7 @@ struct macnet_stack {
     void (*addrcopy)(SockAddr, char *);
     void (*addr_free)(SockAddr);
     Socket (*skregister)(void *, Plug); /* "register" is a reserved word */
-    Socket (*new)(SockAddr, int, int, int, int, Plug);
+    Socket (*new)(SockAddr, int, int, int, int, int, Plug);
     Socket (*newlistener)(char *, int, Plug, int);
     char *(*addr_error)(SockAddr);
     void (*poll)(void);
@@ -128,11 +128,12 @@ Socket sk_register(void *sock, Plug plug)
 }
 
 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
-             int nodelay, Plug plug)
+             int nodelay, int keepalive, Plug plug)
 {
 
     if (stack != NULL)
-       return stack->new(addr, port, privport, oobinline, nodelay, plug);
+       return stack->new(addr, port, privport, oobinline, nodelay, keepalive,
+                         plug);
     return NULL;
 }
 
index 88eb266..7766c7b 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: macterm.c,v 1.75 2003/05/04 14:18:18 simon Exp $ */
+/* $Id: macterm.c,v 1.76 2004/06/20 17:07:37 jacob Exp $ */
 /*
  * Copyright (c) 1999 Simon Tatham
  * Copyright (c) 1999, 2002 Ben Harris
@@ -158,7 +158,8 @@ void mac_startsession(Session *s)
     term_provide_logctx(s->term, s->logctx);
 
     errmsg = s->back->init(s, &s->backhandle, &s->cfg, s->cfg.host,
-                          s->cfg.port, &s->realhost, s->cfg.tcp_nodelay);
+                          s->cfg.port, &s->realhost, s->cfg.tcp_nodelay,
+                          s->cfg.tcp_keepalives);
     if (errmsg != NULL)
        fatalbox("%s", errmsg);
     s->back->provide_logctx(s->backhandle, s->logctx);
index a8404b7..791557d 100644 (file)
@@ -410,7 +410,7 @@ Socket mactcp_register(void *sock, Plug plug)
 static TCPNotifyUPP mactcp_asr_upp;
 
 Socket mactcp_new(SockAddr addr, int port, int privport, int oobinline,
-             int nodelay, Plug plug)
+             int nodelay, int keepalive, Plug plug)
 {
     static struct socket_function_table fn_table = {
        mactcp_plug,
index 7881e02..35d3b16 100644 (file)
@@ -234,7 +234,7 @@ Socket ot_register(void *sock, Plug plug)
 }
 
 Socket ot_new(SockAddr addr, int port, int privport, int oobinline,
-             int nodelay, Plug plug)
+             int nodelay, int keepalive, Plug plug)
 {
     static struct socket_function_table fn_table = {
        ot_tcp_plug,
@@ -281,7 +281,7 @@ Socket ot_new(SockAddr addr, int port, int privport, int oobinline,
        return (Socket) ret;
     }
 
-    /* TODO: oobinline, nodelay */
+    /* TODO: oobinline, nodelay, keepalive */
 
     /*
      * Bind to local address.
index cb077fd..4574207 100644 (file)
--- a/network.h
+++ b/network.h
@@ -79,8 +79,8 @@ struct plug_function_table {
  * responsibility for freeing it */
 Socket new_connection(SockAddr addr, char *hostname,
                      int port, int privport,
-                     int oobinline, int nodelay, Plug plug,
-                     const Config *cfg);
+                     int oobinline, int nodelay, int keepalive,
+                     Plug plug, const Config *cfg);
 Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only,
                    const Config *cfg);
 SockAddr name_lookup(char *host, int port, char **canonicalname,
@@ -90,8 +90,8 @@ SockAddr name_lookup(char *host, int port, char **canonicalname,
 /* (same caveat about addr as new_connection()) */
 Socket platform_new_connection(SockAddr addr, char *hostname,
                               int port, int privport,
-                              int oobinline, int nodelay, Plug plug,
-                              const Config *cfg);
+                              int oobinline, int nodelay, int keepalive,
+                              Plug plug, const Config *cfg);
 
 /* socket functions */
 
@@ -111,7 +111,7 @@ void sk_addr_free(SockAddr addr);
 /* NB, control of 'addr' is passed via sk_new, which takes responsibility
  * for freeing it, as for new_connection() */
 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
-             int nodelay, Plug p);
+             int nodelay, int keepalive, Plug p);
 
 Socket sk_newlistener(char *srcaddr, int port, Plug plug, int local_host_only);
 
diff --git a/plink.c b/plink.c
index a0a9541..92769e8 100644 (file)
--- a/plink.c
+++ b/plink.c
@@ -564,7 +564,7 @@ int main(int argc, char **argv)
            (GetFileType(GetStdHandle(STD_INPUT_HANDLE)) == FILE_TYPE_CHAR);
 
        error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port,
-                          &realhost, nodelay);
+                          &realhost, nodelay, cfg.tcp_keepalives);
        if (error) {
            fprintf(stderr, "Unable to open connection:\n%s", error);
            return 1;
index d994171..b95e5ac 100644 (file)
--- a/portfwd.c
+++ b/portfwd.c
@@ -390,7 +390,7 @@ const char *pfd_newconnect(Socket *s, char *hostname, int port,
     pr->dynamic = 0;
 
     pr->s = *s = new_connection(addr, dummy_realhost, port,
-                               0, 1, 0, (Plug) pr, cfg);
+                               0, 1, 0, 0, (Plug) pr, cfg);
     if ((err = sk_socket_error(*s)) != NULL) {
        sfree(pr);
        return err;
index 5cb9016..9c4c2d8 100644 (file)
--- a/pproxy.c
+++ b/pproxy.c
@@ -10,8 +10,8 @@
 
 Socket platform_new_connection(SockAddr addr, char *hostname,
                               int port, int privport,
-                              int oobinline, int nodelay, Plug plug,
-                              const Config *cfg)
+                              int oobinline, int nodelay, int keepalive,
+                              Plug plug, const Config *cfg)
 {
     return NULL;
 }
diff --git a/proxy.c b/proxy.c
index dd5c428..d3bcca6 100644 (file)
--- a/proxy.c
+++ b/proxy.c
@@ -356,8 +356,8 @@ SockAddr name_lookup(char *host, int port, char **canonicalname,
 
 Socket new_connection(SockAddr addr, char *hostname,
                      int port, int privport,
-                     int oobinline, int nodelay, Plug plug,
-                     const Config *cfg)
+                     int oobinline, int nodelay, int keepalive,
+                     Plug plug, const Config *cfg)
 {
     static const struct socket_function_table socket_fn_table = {
        sk_proxy_plug,
@@ -388,7 +388,8 @@ Socket new_connection(SockAddr addr, char *hostname,
        Socket sret;
 
        if ((sret = platform_new_connection(addr, hostname, port, privport,
-                                           oobinline, nodelay, plug, cfg)) !=
+                                           oobinline, nodelay, keepalive,
+                                           plug, cfg)) !=
            NULL)
            return sret;
 
@@ -444,7 +445,7 @@ Socket new_connection(SockAddr addr, char *hostname,
         */
        ret->sub_socket = sk_new(proxy_addr, cfg->proxy_port,
                                 privport, oobinline,
-                                nodelay, (Plug) pplug);
+                                nodelay, keepalive, (Plug) pplug);
        if (sk_socket_error(ret->sub_socket) != NULL)
            return (Socket) ret;
 
@@ -456,7 +457,7 @@ Socket new_connection(SockAddr addr, char *hostname,
     }
 
     /* no proxy, so just return the direct socket */
-    return sk_new(addr, port, privport, oobinline, nodelay, plug);
+    return sk_new(addr, port, privport, oobinline, nodelay, keepalive, plug);
 }
 
 Socket new_listener(char *srcaddr, int port, Plug plug, int local_host_only,
diff --git a/psftp.c b/psftp.c
index b134c50..10056bd 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -1939,7 +1939,8 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
 
     back = &ssh_backend;
 
-    err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost,0);
+    err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost,
+                    0, cfg.tcp_keepalives);
     if (err != NULL) {
        fprintf(stderr, "ssh_init: %s\n", err);
        return 1;
diff --git a/putty.h b/putty.h
index 723f1e6..fed589b 100644 (file)
--- a/putty.h
+++ b/putty.h
@@ -269,7 +269,8 @@ enum {
 struct backend_tag {
     const char *(*init) (void *frontend_handle, void **backend_handle,
                         Config *cfg,
-                        char *host, int port, char **realhost, int nodelay);
+                        char *host, int port, char **realhost, int nodelay,
+                        int keepalive);
     void (*free) (void *handle);
     /* back->reconfig() passes in a replacement configuration. */
     void (*reconfig) (void *handle, Config *cfg);
@@ -329,6 +330,7 @@ struct config_tag {
     int warn_on_close;
     int ping_interval;                /* in seconds */
     int tcp_nodelay;
+    int tcp_keepalives;
     /* Proxy options */
     char proxy_exclude_list[512];
     int proxy_dns;
diff --git a/raw.c b/raw.c
index 4c9e5be..8c1f97f 100644 (file)
--- a/raw.c
+++ b/raw.c
@@ -69,7 +69,8 @@ static void raw_sent(Plug plug, int bufsize)
  */
 static const char *raw_init(void *frontend_handle, void **backend_handle,
                            Config *cfg,
-                           char *host, int port, char **realhost, int nodelay)
+                           char *host, int port, char **realhost, int nodelay,
+                           int keepalive)
 {
     static const struct plug_function_table fn_table = {
        raw_closing,
@@ -115,7 +116,7 @@ static const char *raw_init(void *frontend_handle, void **backend_handle,
        logevent(raw->frontend, buf);
        sfree(buf);
     }
-    raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay,
+    raw->s = new_connection(addr, *realhost, port, 0, 1, nodelay, keepalive,
                            (Plug) raw, cfg);
     if ((err = sk_socket_error(raw->s)) != NULL)
        return err;
index af3bd87..f2b61d2 100644 (file)
--- a/rlogin.c
+++ b/rlogin.c
@@ -100,7 +100,7 @@ static void rlogin_sent(Plug plug, int bufsize)
 static const char *rlogin_init(void *frontend_handle, void **backend_handle,
                               Config *cfg,
                               char *host, int port, char **realhost,
-                              int nodelay)
+                              int nodelay, int keepalive)
 {
     static const struct plug_function_table fn_table = {
        rlogin_closing,
@@ -149,7 +149,7 @@ static const char *rlogin_init(void *frontend_handle, void **backend_handle,
        sfree(buf);
     }
     rlogin->s = new_connection(addr, *realhost, port, 1, 0,
-                              nodelay, (Plug) rlogin, cfg);
+                              nodelay, keepalive, (Plug) rlogin, cfg);
     if ((err = sk_socket_error(rlogin->s)) != NULL)
        return err;
 
diff --git a/scp.c b/scp.c
index 06bf089..f7fa255 100644 (file)
--- a/scp.c
+++ b/scp.c
@@ -450,7 +450,8 @@ static void do_cmd(char *host, char *user, char *cmd)
 
     back = &ssh_backend;
 
-    err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost,0);
+    err = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port, &realhost, 
+                    0, cfg.tcp_keepalives);
     if (err != NULL)
        bump("ssh_init: %s", err);
     logctx = log_init(NULL, &cfg);
index 99ec7ee..a5f2e44 100644 (file)
@@ -182,6 +182,7 @@ void save_open_settings(void *sesskey, int do_host, Config *cfg)
     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_i(sesskey, "TCPKeepalives", cfg->tcp_keepalives);
     write_setting_s(sesskey, "TerminalType", cfg->termtype);
     write_setting_s(sesskey, "TerminalSpeed", cfg->termspeed);
 
@@ -411,6 +412,7 @@ void load_open_settings(void *sesskey, int do_host, Config *cfg)
        cfg->ping_interval = pingmin * 60 + pingsec;
     }
     gppi(sesskey, "TCPNoDelay", 1, &cfg->tcp_nodelay);
+    gppi(sesskey, "TCPKeepalives", 0, &cfg->tcp_keepalives);
     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 dec48ce..6c94ba4 100644 (file)
--- a/ssh.c
+++ b/ssh.c
@@ -2128,7 +2128,7 @@ static void ssh_sent(Plug plug, int bufsize)
  * freed by the caller.
  */
 static const char *connect_to_host(Ssh ssh, char *host, int port,
-                                  char **realhost, int nodelay)
+                                  char **realhost, int nodelay, int keepalive)
 {
     static const struct plug_function_table fn_table = {
        ssh_closing,
@@ -2169,7 +2169,7 @@ static const char *connect_to_host(Ssh ssh, char *host, int port,
     }
     ssh->fn = &fn_table;
     ssh->s = new_connection(addr, *realhost, port,
-                           0, 1, nodelay, (Plug) ssh, &ssh->cfg);
+                           0, 1, nodelay, keepalive, (Plug) ssh, &ssh->cfg);
     if ((err = sk_socket_error(ssh->s)) != NULL) {
        ssh->s = NULL;
        return err;
@@ -6183,7 +6183,8 @@ static void ssh2_protocol(Ssh ssh, unsigned char *in, int inlen, int ispkt)
  */
 static const char *ssh_init(void *frontend_handle, void **backend_handle,
                            Config *cfg,
-                           char *host, int port, char **realhost, int nodelay)
+                           char *host, int port, char **realhost, int nodelay,
+                           int keepalive)
 {
     const char *p;
     Ssh ssh;
@@ -6267,7 +6268,7 @@ static const char *ssh_init(void *frontend_handle, void **backend_handle,
 
     ssh->protocol = NULL;
 
-    p = connect_to_host(ssh, host, port, realhost, nodelay);
+    p = connect_to_host(ssh, host, port, realhost, nodelay, keepalive);
     if (p != NULL)
        return p;
 
index 2edae21..6f4f54c 100644 (file)
--- a/telnet.c
+++ b/telnet.c
@@ -674,7 +674,7 @@ static void telnet_sent(Plug plug, int bufsize)
 static const char *telnet_init(void *frontend_handle, void **backend_handle,
                               Config *cfg,
                               char *host, int port, char **realhost,
-                              int nodelay)
+                              int nodelay, int keepalive)
 {
     static const struct plug_function_table fn_table = {
        telnet_closing,
@@ -729,7 +729,7 @@ static const char *telnet_init(void *frontend_handle, void **backend_handle,
        sfree(buf);
     }
     telnet->s = new_connection(addr, *realhost, port, 0, 1,
-                              nodelay, (Plug) telnet, &telnet->cfg);
+                              nodelay, keepalive, (Plug) telnet, &telnet->cfg);
     if ((err = sk_socket_error(telnet->s)) != NULL)
        return err;
 
index 22860f3..bc2eb31 100644 (file)
@@ -1,4 +1,4 @@
-/* $Id: testback.c,v 1.9 2003/05/10 11:57:55 ben Exp $ */
+/* $Id: testback.c,v 1.10 2004/06/20 17:07:32 jacob Exp $ */
 /*
  * Copyright (c) 1999 Simon Tatham
  * Copyright (c) 1999 Ben Harris
@@ -34,9 +34,9 @@
 #include "putty.h"
 
 static const char *null_init(void *, void **, Config *, char *, int, char **,
-                            int);
+                            int, int);
 static const char *loop_init(void *, void **, Config *, char *, int, char **,
-                            int);
+                            int, int);
 static void null_free(void *);
 static void loop_free(void *);
 static void null_reconfig(void *, Config *);
@@ -72,14 +72,14 @@ struct loop_state {
 
 static const char *null_init(void *frontend_handle, void **backend_handle,
                             Config *cfg, char *host, int port,
-                            char **realhost, int nodelay) {
+                            char **realhost, int nodelay, int keepalive) {
 
     return NULL;
 }
 
 static const char *loop_init(void *frontend_handle, void **backend_handle,
                             Config *cfg, char *host, int port,
-                            char **realhost, int nodelay) {
+                            char **realhost, int nodelay, int keepalive) {
     struct loop_state *st = snew(struct loop_state);
 
     st->term = frontend_handle;
index 87339fb..8e2554d 100644 (file)
@@ -3367,7 +3367,8 @@ int pt_main(int argc, char **argv)
 
        error = inst->back->init((void *)inst, &inst->backhandle,
                                  &inst->cfg, inst->cfg.host, inst->cfg.port,
-                                 &realhost, inst->cfg.tcp_nodelay);
+                                 &realhost, inst->cfg.tcp_nodelay,
+                                inst->cfg.tcp_keepalives);
 
        if (error) {
            char *msg = dupprintf("Unable to open connection to %s:\n%s",
index 7f46f1a..20ddc80 100644 (file)
@@ -486,7 +486,8 @@ static void pty_uxsel_setup(void)
  * freed by the caller.
  */
 static const char *pty_init(void *frontend, void **backend_handle, Config *cfg,
-                           char *host, int port, char **realhost, int nodelay)
+                           char *host, int port, char **realhost, int nodelay,
+                           int keepalive)
 {
     int slavefd;
     pid_t pid, pgrp;
index 1e7d51b..08fb4e1 100644 (file)
@@ -378,7 +378,7 @@ Socket sk_register(OSSocket sockfd, Plug plug)
 }
 
 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
-             int nodelay, Plug plug)
+             int nodelay, int keepalive, Plug plug)
 {
     int s;
 #ifdef IPV6
@@ -433,6 +433,11 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
        setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
     }
 
+    if (keepalive) {
+       int b = TRUE;
+       setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
+    }
+
     /*
      * Bind to local address.
      */
index e59a701..6bf2c85 100644 (file)
@@ -557,7 +557,7 @@ int main(int argc, char **argv)
        int nodelay = cfg.tcp_nodelay && isatty(0);
 
        error = back->init(NULL, &backhandle, &cfg, cfg.host, cfg.port,
-                          &realhost, nodelay);
+                          &realhost, nodelay, cfg.tcp_keepalives);
        if (error) {
            fprintf(stderr, "Unable to open connection:\n%s\n", error);
            return 1;
index b3f75e8..1191a61 100644 (file)
@@ -221,8 +221,8 @@ static int localproxy_select_result(int fd, int event)
 
 Socket platform_new_connection(SockAddr addr, char *hostname,
                               int port, int privport,
-                              int oobinline, int nodelay, Plug plug,
-                              const Config *cfg)
+                              int oobinline, int nodelay, int keepalive,
+                              Plug plug, const Config *cfg)
 {
     char *cmd;
 
index 71f30b4..e720ed3 100644 (file)
--- a/window.c
+++ b/window.c
@@ -611,7 +611,8 @@ int WINAPI WinMain(HINSTANCE inst, HINSTANCE prev, LPSTR cmdline, int show)
        char *realhost;
 
        error = back->init(NULL, &backhandle, &cfg,
-                          cfg.host, cfg.port, &realhost, cfg.tcp_nodelay);
+                          cfg.host, cfg.port, &realhost, cfg.tcp_nodelay,
+                          cfg.tcp_keepalives);
        back->provide_logctx(backhandle, logctx);
        if (error) {
            char *str = dupprintf("%s Error", appname);
index bbde922..5271f92 100644 (file)
--- a/winhelp.h
+++ b/winhelp.h
@@ -63,6 +63,7 @@
 #define WINHELP_CTX_connection_username "connection.username"
 #define WINHELP_CTX_connection_keepalive "connection.keepalive"
 #define WINHELP_CTX_connection_nodelay "connection.nodelay"
+#define WINHELP_CTX_connection_tcpkeepalive "connection.tcpkeepalive"
 #define WINHELP_CTX_proxy_type "proxy.type"
 #define WINHELP_CTX_proxy_main "proxy.main"
 #define WINHELP_CTX_proxy_exclude "proxy.exclude"
index 21a2f29..bcb22bf 100644 (file)
--- a/winnet.c
+++ b/winnet.c
@@ -658,7 +658,7 @@ Socket sk_register(void *sock, Plug plug)
 }
 
 Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
-             int nodelay, Plug plug)
+             int nodelay, int keepalive, Plug plug)
 {
     static const struct socket_function_table fn_table = {
        sk_tcp_plug,
@@ -722,6 +722,11 @@ Socket sk_new(SockAddr addr, int port, int privport, int oobinline,
        p_setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (void *) &b, sizeof(b));
     }
 
+    if (keepalive) {
+       BOOL b = TRUE;
+       p_setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (void *) &b, sizeof(b));
+    }
+
     /*
      * Bind to local address.
      */
index 049381b..b0b8269 100644 (file)
--- a/x11fwd.c
+++ b/x11fwd.c
@@ -310,7 +310,7 @@ const char *x11_init(Socket * s, char *display, void *c, void *auth,
     pr->c = c;
 
     pr->s = *s = new_connection(addr, dummy_realhost, port,
-                               0, 1, 0, (Plug) pr, cfg);
+                               0, 1, 0, 0, (Plug) pr, cfg);
     if ((err = sk_socket_error(*s)) != NULL) {
        sfree(pr);
        return err;