On Fri, Feb 12, 2010 at 09:45:02AM -0600, Gary Mills wrote:
> I'm willing to add a `keepalive' option to Cyrus master along with the
> setsockopt() system call to enable that setting. This option could be
> added to the cyrus.conf file for any services that could benefit from
> it. Would this be a reasonable addition to Cyrus?
How does this look?
+{ "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) */
A switch to enable keepalive, plus options to edit each of the
tunables. The full patch is attached - not tested except for
a compile yet.
Bron.
diff --git a/imap/sync_client.c b/imap/sync_client.c
index b26768d..41ac6c1 100644
--- a/imap/sync_client.c
+++ b/imap/sync_client.c
@@ -3418,6 +3418,36 @@ 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");
+ }
+ 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");
+ }
+ }
+ 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");
+ }
+ }
+ 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");
+ }
+ }
+ }
} 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..395e3ff 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,41 @@ 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");
+ }
+ 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");
+ }
+ }
+ 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");
+ }
+ }
+ 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");
+ }
+ }
+ }
}
-
+
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