From 727a4b977ec6549d94da3f694bf3fe8b0121db58 Mon Sep 17 00:00:00 2001 From: Marc Fournier Date: Sat, 13 Feb 2016 11:51:23 +0100 Subject: [PATCH 1/1] daemon/common.[ch]: add set_sock_opts() function Enables the TCP keepalive mechanism on a given socket. This would typically be used on sockets opened by write plugins which submit data to a remote server. Up to now, collectd fails to notice when a remote server dies without properly closing the network connection, leading to more and more memory getting allocated as the values pile up in the write queue. The keepalive values are proportional to the configured `Interval`. The first probe is emitted `10 x Interval` seconds after the last TCP packet was seen, and then once per `Interval` until the threshold defined by the OS is reached. See: http://www.tldp.org/HOWTO/html_single/TCP-Keepalive-HOWTO/#checkdeadpeers --- src/daemon/common.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ src/daemon/common.h | 3 +++ 2 files changed, 47 insertions(+) diff --git a/src/daemon/common.c b/src/daemon/common.c index b60530a1..c4dbecbe 100644 --- a/src/daemon/common.c +++ b/src/daemon/common.c @@ -51,6 +51,10 @@ # include #endif +#if HAVE_NETINET_TCP_H +# include +#endif + /* for ntohl and htonl */ #if HAVE_ARPA_INET_H # include @@ -1557,6 +1561,46 @@ int service_name_to_port_number (const char *service_name) return (-1); } /* int service_name_to_port_number */ +void set_sock_opts (int sockfd) /* {{{ */ +{ + int status; + int socktype; + + socklen_t socklen = sizeof (socklen_t); + int so_keepalive = 1; + int tcp_keepidle = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 100 + 1); + int tcp_keepintvl = ((CDTIME_T_TO_MS(plugin_get_interval()) - 1) / 1000 + 1); + + status = getsockopt (sockfd, SOL_SOCKET, SO_TYPE, &socktype, &socklen); + if (status != 0) + { + WARNING ("set_sock_opts: failed to determine socket type"); + return; + } + + if (socktype == SOCK_STREAM) + { + status = setsockopt(sockfd, SOL_SOCKET, SO_KEEPALIVE, + &so_keepalive, sizeof (so_keepalive)); + if (status != 0) + WARNING ("set_sock_opts: failed to set socket keepalive flag"); + +#ifdef TCP_KEEPIDLE + status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPIDLE, + &tcp_keepidle, sizeof (tcp_keepidle)); + if (status != 0) + WARNING ("set_sock_opts: failed to set socket tcp keepalive time"); +#endif + +#ifdef TCP_KEEPINTVL + status = setsockopt(sockfd, IPPROTO_TCP, TCP_KEEPINTVL, + &tcp_keepintvl, sizeof (tcp_keepintvl)); + if (status != 0) + WARNING ("set_sock_opts: failed to set socket tcp keepalive interval"); +#endif + } +} /* }}} void set_sock_opts */ + int strtoderive (const char *string, derive_t *ret_value) /* {{{ */ { derive_t tmp; diff --git a/src/daemon/common.h b/src/daemon/common.h index 8079661a..5ad2b50d 100644 --- a/src/daemon/common.h +++ b/src/daemon/common.h @@ -361,6 +361,9 @@ int value_to_rate (gauge_t *ret_rate, value_t value, int ds_type, cdtime_t t, * (in the range [1-65535]). Returns less than zero on error. */ int service_name_to_port_number (const char *service_name); +/* Sets various, non-default, socket options */ +void set_sock_opts (int sockfd); + /** Parse a string to a derive_t value. Returns zero on success or non-zero on * failure. If failure is returned, ret_value is not touched. */ int strtoderive (const char *string, derive_t *ret_value); -- 2.11.0