On Sun, Feb 14, 2010 at 08:38:34AM +1100, Bron Gondwana wrote: > > One thing to watch is that only SO_KEEPALIVE is standard. The other > > three symbols: TCP_KEEPCNT, TCP_KEEPIDLE, and TCP_KEEPINTVL only exist > > in some operating systems. They have global settings but don't have > > per-socket options. For these, the setsockopt() function calls need > > to be conditional on the symbols. > > Hmm - yeah, OK. I'll protect them with #ifdefs. Here's the patch redone with those...
diff --git a/imap/sync_client.c b/imap/sync_client.c index b26768d..e12e27a 100644 --- a/imap/sync_client.c +++ b/imap/sync_client.c @@ -3418,6 +3418,42 @@ struct backend *replica_connect(struct backend *be, const char *servername, (void *) &on, sizeof(on)) != 0) { syslog(LOG_ERR, "unable to setsocketopt(TCP_NODELAY): %m"); } + + /* turn on TCP keepalive if set */ + if (config_getswitch(IMAPOPT_TCP_KEEPALIVE)) { + int r; + int optval = 1; + socklen_t optlen = sizeof(optval); + + r = setsockopt(be->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(SO_KEEPALIVE): %m"); + } +#ifdef TCP_KEEPCNT + if (config_getint(IMAPOPT_TCP_KEEPALIVE_CNT)) { + r = setsockopt(be->sock, SOL_TCP, TCP_KEEPCNT, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPCNT): %m"); + } + } +#endif +#ifdef TCP_KEEPIDLE + if (config_getint(IMAPOPT_TCP_KEEPALIVE_IDLE)) { + r = setsockopt(be->sock, SOL_TCP, TCP_KEEPIDLE, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPIDLE): %m"); + } + } +#endif +#ifdef TCP_KEEPINTVL + if (config_getint(IMAPOPT_TCP_KEEPALIVE_INTVL)) { + r = setsockopt(be->sock, SOL_TCP, TCP_KEEPINTVL, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPINTVL): %m"); + } + } +#endif + } } else { syslog(LOG_ERR, "unable to getprotobyname(\"tcp\"): %m"); } diff --git a/lib/imapoptions b/lib/imapoptions index 1ae2da0..52224e5 100644 --- a/lib/imapoptions +++ b/lib/imapoptions @@ -1139,6 +1139,20 @@ product version in the capabilities */ { "syslog_prefix", NULL, STRING } /* String to be prepended to the process name in syslog entries. */ +{ "tcp_keepalive", 0, SWITCH } +/* Enable keepalive on TCP connections */ + +{ "tcp_keepalive_cnt", 0, INT } +/* Number of TCP keepalive probes to send before declaring the + connection dead (0 == system default) */ + +{ "tcp_keepalive_idle", 0, INT } +/* Number of seconds a connection must be idle before keepalive + probes are sent (0 == system default) */ + +{ "tcp_keepalive_intvl", 0, INT } +/* Number of seconds between keepalive probes (0 == system default) */ + { "temp_path", "/tmp", STRING } /* The pathname to store temporary files in */ diff --git a/master/service.c b/master/service.c index ab1409b..925a792 100644 --- a/master/service.c +++ b/master/service.c @@ -61,6 +61,7 @@ #include <netdb.h> #include <sys/socket.h> #include <netinet/in.h> +#include <netinet/tcp.h> #include <arpa/inet.h> #include <errno.h> #include <stdlib.h> @@ -512,8 +513,47 @@ int main(int argc, char **argv, char **envp) close(fd); continue; } + + /* turn on TCP keepalive if set */ + if (config_getswitch(IMAPOPT_TCP_KEEPALIVE)) { + int r; + int optval = 1; + socklen_t optlen = sizeof(optval); + + r = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(SO_KEEPALIVE): %m"); + } +#ifdef TCP_KEEPCNT + optval = config_getint(IMAPOPT_TCP_KEEPALIVE_CNT); + if (optval) { + r = setsockopt(fd, SOL_TCP, TCP_KEEPCNT, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPCNT): %m"); + } + } +#endif +#ifdef TCP_KEEPIDLE + optval = config_getint(IMAPOPT_TCP_KEEPALIVE_IDLE); + if (optval) { + r = setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPIDLE): %m"); + } + } +#endif +#ifdef TCP_KEEPINTVL + optval = config_getint(IMAPOPT_TCP_KEEPALIVE_INTVL); + if (optval) { + r = setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, &optval, optlen); + if (r < 0) { + syslog(LOG_ERR, "unable to setsocketopt(TCP_KEEPINTVL): %m"); + } + } +#endif + } } - + notify_master(STATUS_FD, MASTER_SERVICE_UNAVAILABLE); syslog(LOG_DEBUG, "accepted connection");
---- Cyrus Home Page: http://cyrusimap.web.cmu.edu/ Cyrus Wiki/FAQ: http://cyrusimap.web.cmu.edu/twiki List Archives/Info: http://asg.web.cmu.edu/cyrus/mailing-list.html