From: Marc Fournier Date: Sat, 13 Feb 2016 10:51:23 +0000 (+0100) Subject: daemon/common.[ch]: add set_sock_opts() function X-Git-Tag: collectd-5.6.0~67^2~4 X-Git-Url: https://git.octo.it/?p=collectd.git;a=commitdiff_plain;h=727a4b977ec6549d94da3f694bf3fe8b0121db58;hp=7a65aadcc432d3341f5cca816c6a157b1b9d6116 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 --- 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);