diff --git a/configure b/configure index 1cbeabc..b932fc3 100755 --- a/configure +++ b/configure @@ -1673,6 +1673,37 @@ if test "$fdt" = "yes" ; then echo "FDT_LIBS=-lfdt" >> $config_mak fi +cat > $TMPC << EOF +#include +int main(void) { + int val = 1; + if (setsockopt(0, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) + return 1; + return 0; +} +EOF +if $cc $ARCH_CFLAGS -o $TMPE $TMPC >/dev/null 2> /dev/null ; then + echo "#define HAVE_SO_KEEPALIVE 1" >> $config_h +fi +cat > $TMPC << EOF +#include +#include +#include +int main(void) { + int val = 1; + if (setsockopt(0, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0) + return 1; + if (setsockopt(0, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0) + return 1; + if (setsockopt(0, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0) + return 1; + return 0; +} +EOF +if $cc $ARCH_CFLAGS -o $TMPE $TMPC >/dev/null 2> /dev/null ; then + echo "#define HAVE_TCP_KEEPXXXX 1" >> $config_h +fi + # XXX: suppress that if [ "$bsd" = "yes" ] ; then echo "#define O_LARGEFILE 0" >> $config_h diff --git a/net.c b/net.c index 7ae1e6d..bb85889 100644 --- a/net.c +++ b/net.c @@ -2209,3 +2209,36 @@ void net_client_check(void) vlan->id); } } + +int enable_tcp_keepalive(int sd, int keepidle, int keepintvl, int keepcnt) +{ +#ifdef HAVE_SO_KEEPALIVE + int val = 1; + + if (setsockopt(sd, SOL_SOCKET, SO_KEEPALIVE, &val, sizeof(val)) < 0) { + return -1; + } + +#ifdef HAVE_TCP_KEEPXXXX + val = keepidle; + if ((val > 0) && + (setsockopt(sd, IPPROTO_TCP, TCP_KEEPIDLE, &val, sizeof(val)) < 0)) { + fprintf(stderr, "failed to set tcp idle interval on fd %d\n", sd); + } + + val = keepintvl; + if ((val > 0) && + (setsockopt(sd, IPPROTO_TCP, TCP_KEEPINTVL, &val, sizeof(val)) < 0)) { + fprintf(stderr, "failed to set tcp probe interval on fd %d\n", sd); + } + + val = keepcnt; + if ((val > 0) && + (setsockopt(sd, IPPROTO_TCP, TCP_KEEPCNT, &val, sizeof(val)) < 0)) { + fprintf(stderr, "failed to set tcp missed probe count on fd %d\n", sd); + } +#endif +#endif + + return 0; +} diff --git a/net.h b/net.h index cdf63a4..c7dbadf 100644 --- a/net.h +++ b/net.h @@ -119,6 +119,8 @@ void net_client_check(void); void net_host_device_add(Monitor *mon, const char *device, const char *opts); void net_host_device_remove(Monitor *mon, int vlan_id, const char *device); +int enable_tcp_keepalive(int sd, int keepidle, int keepintvl, int keepcnt); + #define DEFAULT_NETWORK_SCRIPT "/etc/qemu-ifup" #define DEFAULT_NETWORK_DOWN_SCRIPT "/etc/qemu-ifdown" #ifdef __sun__ diff --git a/qemu-char.c b/qemu-char.c index 664cbfd..d52ca78 100644 --- a/qemu-char.c +++ b/qemu-char.c @@ -103,6 +103,15 @@ #include "qemu_socket.h" +/* timers for TCP keepalives: start probes after VNC_TCP_KEEPIDLE + * seconds of no activity, send probes every VNC_TCP_KEEPINTVL seconds, + * close connection after VNC_TCP_KEEPCNT failed probes + */ +#define CHAR_TCP_KEEPIDLE 60 +#define CHAR_TCP_KEEPIDLE 60 +#define CHAR_TCP_KEEPINTVL 12 +#define CHAR_TCP_KEEPCNT 5 + /***********************************************************/ /* character device */ @@ -1990,6 +1999,10 @@ static void tcp_chr_accept(void *opaque) if (fd < 0 && errno != EINTR) { return; } else if (fd >= 0) { + if (enable_tcp_keepalive(fd, CHAR_TCP_KEEPIDLE, + CHAR_TCP_KEEPINTVL, CHAR_TCP_KEEPCNT) != 0) { + fprintf(stderr, "VNC: failed to enable TCP keep alives\n"); + } if (s->do_telnetopt) tcp_chr_telnet_init(fd); break; diff --git a/vnc.c b/vnc.c index ab1f044..c42cba9 100644 --- a/vnc.c +++ b/vnc.c @@ -32,6 +32,14 @@ #define VNC_REFRESH_INTERVAL (1000 / 30) +/* timers for TCP keepalives: start probes after VNC_TCP_KEEPIDLE + * seconds of no activity, send probes every VNC_TCP_KEEPINTVL seconds, + * close connection after VNC_TCP_KEEPCNT failed probes + */ +#define VNC_TCP_KEEPIDLE 60 +#define VNC_TCP_KEEPINTVL 12 +#define VNC_TCP_KEEPCNT 5 + #include "vnc_keysym.h" #include "d3des.h" @@ -2021,6 +2029,11 @@ static void vnc_listen_read(void *opaque) int csock = accept(vs->lsock, (struct sockaddr *)&addr, &addrlen); if (csock != -1) { + if (enable_tcp_keepalive(csock, VNC_TCP_KEEPIDLE, + VNC_TCP_KEEPINTVL, VNC_TCP_KEEPCNT) != 0) { + fprintf(stderr, "VNC: failed to enable TCP keep alives\n"); + } + vnc_connect(vs, csock); } }