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