Hello, I previously sent this patch for mpd 0.16.7. This is the same but on master branch from git://git.musicpd.org/master/mpd.git. Since I don't have windows, the
winsock code in set_tcp_keep_alive() is not tested at all.
Sorry. The patch adds options to configure TCP keep alive on client connections. I found it especially useful
for clients connecting through wifi that leave dangling
connections when wifi is turned off or the device goes out of
range. Combined with low max connections it soon causes clients
to not be able to connect. Yoav
Sample configuration: # Client TCP keep alive ####################################################### # # For clients connected by TCP on supported platforms. # Allows detection of dangling connections due to clients disappearing from # the network without closing their connections. # tcp_keep_alive "yes" tcp_keep_alive_idle "10" tcp_keep_alive_interval "10" tcp_keep_alive_count "2" # ############################################################################### |
TCP keepalive configuration option From: geneticdrift <geneticdr...@iotide.com> Helps detecting dangling client connections. --- src/client_new.c | 9 +++++++ src/conf.c | 4 +++ src/conf.h | 14 +++++++++++ src/socket_util.c | 67 +++++++++++++++++++++++++++++++++++++++++++++++++++++ src/socket_util.h | 16 +++++++++++++ 5 files changed, 110 insertions(+) diff --git a/src/client_new.c b/src/client_new.c index cf28c43..875a7dc 100644 --- a/src/client_new.c +++ b/src/client_new.c @@ -24,6 +24,7 @@ #include "resolver.h" #include "permission.h" #include "glib_socket.h" +#include "conf.h" #include <assert.h> #include <sys/types.h> @@ -123,6 +124,14 @@ client_new(struct player_control *player_control, client->messages = NULL; client->num_messages = 0; + if ((sa->sa_family == AF_INET || sa->sa_family == AF_INET6) && + config_get_bool(CONF_TCP_KEEP_ALIVE, DEFAULT_TCP_KEEP_ALIVE)) { + set_tcp_keep_alive(fd, + config_get_positive(CONF_TCP_KEEP_ALIVE_IDLE, DEFAULT_TCP_KEEP_ALIVE_IDLE), + config_get_positive(CONF_TCP_KEEP_ALIVE_INTERVAL, DEFAULT_TCP_KEEP_ALIVE_INTERVAL), + config_get_positive(CONF_TCP_KEEP_ALIVE_COUNT, DEFAULT_TCP_KEEP_ALIVE_COUNT)); + } + (void)send(fd, GREETING, sizeof(GREETING) - 1, 0); client_list_add(client); diff --git a/src/conf.c b/src/conf.c index 549ff51..4ca4cdc 100644 --- a/src/conf.c +++ b/src/conf.c @@ -102,6 +102,10 @@ static struct config_entry config_entries[] = { { .name = CONF_DESPOTIFY_USER, false, false }, { .name = CONF_DESPOTIFY_PASSWORD, false, false}, { .name = CONF_DESPOTIFY_HIGH_BITRATE, false, false }, + { .name = CONF_TCP_KEEP_ALIVE, false, false }, + { .name = CONF_TCP_KEEP_ALIVE_IDLE, false, false }, + { .name = CONF_TCP_KEEP_ALIVE_INTERVAL, false, false }, + { .name = CONF_TCP_KEEP_ALIVE_COUNT, false, false }, { .name = "filter", true, true }, }; diff --git a/src/conf.h b/src/conf.h index 815c739..f986f18 100644 --- a/src/conf.h +++ b/src/conf.h @@ -75,9 +75,23 @@ #define CONF_DESPOTIFY_USER "despotify_user" #define CONF_DESPOTIFY_PASSWORD "despotify_password" #define CONF_DESPOTIFY_HIGH_BITRATE "despotify_high_bitrate" +/** + * tcp keep alive + */ +#define CONF_TCP_KEEP_ALIVE "tcp_keep_alive" +#define CONF_TCP_KEEP_ALIVE_IDLE "tcp_keep_alive_idle" +#define CONF_TCP_KEEP_ALIVE_INTERVAL "tcp_keep_alive_interval" +#define CONF_TCP_KEEP_ALIVE_COUNT "tcp_keep_alive_count" #define DEFAULT_PLAYLIST_MAX_LENGTH (1024*16) #define DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS false +/** + * defaults for tcp keep alive + */ +#define DEFAULT_TCP_KEEP_ALIVE false +#define DEFAULT_TCP_KEEP_ALIVE_IDLE 7200 +#define DEFAULT_TCP_KEEP_ALIVE_INTERVAL 75 +#define DEFAULT_TCP_KEEP_ALIVE_COUNT 9 #define MAX_FILTER_CHAIN_LENGTH 255 diff --git a/src/socket_util.c b/src/socket_util.c index a06a0cb..265b0c8 100644 --- a/src/socket_util.c +++ b/src/socket_util.c @@ -26,6 +26,7 @@ #ifndef G_OS_WIN32 #include <sys/socket.h> +#include <netinet/tcp.h> #else /* G_OS_WIN32 */ #include <ws2tcpip.h> #include <winsock.h> @@ -98,3 +99,69 @@ socket_keepalive(int fd) return setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, (const char *)&reuse, sizeof(reuse)); } + +int set_tcp_keep_alive(int fd, int keep_idle, int keep_interval, + int keep_count, + GError **error) { +#ifndef G_OS_WIN32 + int ret; + int optval; + const int optlen = sizeof(optval); + + optval = 1; + + ret = setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, + (const void*)&optval, optlen); + + if (ret < 0) { + g_set_error(error, listen_quark(), errno, + "setsockopt() SO_KEEPALIVE failed: %s", g_strerror(errno)); + return -1; + } + + optval = keep_idle; + ret = setsockopt(fd, SOL_TCP, TCP_KEEPIDLE, + (const void*)&optval, optlen); + if (ret < 0) { + g_set_error(error, listen_quark(), errno, + "setsockopt() TCP_KEEPIDLE failed: %s", g_strerror(errno)); + return -1; + } + + optval = keep_interval; + ret = setsockopt(fd, SOL_TCP, TCP_KEEPINTVL, + (const void*)&optval, optlen); + if (ret < 0) { + g_set_error(error, listen_quark(), errno, + "setsockopt() TCP_KEEPINTVL failed: %s", g_strerror(errno)); + return -1; + } + + optval = keep_count; + ret = setsockopt(fd, SOL_TCP, TCP_KEEPCNT, + (const void*)&optval, optlen); + if (ret < 0) { + g_set_error(error, listen_quark(), errno, + "setsockopt() TCP_KEEPCNT failed: %s", g_strerror(errno)); + return -1; + } +#else + // WinSock structure for KeepAlive timing settings + struct tcp_keepalive settings; + settings.onoff = 1; + settings.keepalivetime = keep_idle * 1000; + settings.keepaliveinterval = keep_interval * 1000; + + DWORD bytesReturned; + WSAOVERLAPPED overlapped; + overlapped.hEvent = NULL; + + WSAIoctl(sockFD, SIO_KEEPALIVE_VALS, &settings, sizeof(struct tcp_keepalive), + NULL, + 0, + &bytesReturned, + &overlapped, + NULL); +#endif + return 0; +} diff --git a/src/socket_util.h b/src/socket_util.h index 93bd273..19a2026 100644 --- a/src/socket_util.h +++ b/src/socket_util.h @@ -53,4 +53,20 @@ socket_bind_listen(int domain, int type, int protocol, int socket_keepalive(int fd); +/** + * Set tcp keepalive socket options. (since Linux 2.4) + * + * Sets the socket options: SO_KEEPALIVE, TCP_KEEPIDLE, TCP_KEEPINTVL, TCP_KEEPCNT + * + * @param fd The socket file descriptor. + * @param keep_idle The number of seconds a connection needs to be idle before TCP begins sending out keep-alive probes. + * @param keep_interval The number of seconds between TCP keep-alive probes. + * @param keep_count The maximum number of keepalive probes TCP should send before dropping the connection. + * @return 0 - success, -1 failure + */ +int +set_tcp_keep_alive(int fd, int keep_idle, int keep_interval, + int keep_count, + GError **error); + #endif
------------------------------------------------------------------------------ Live Security Virtual Conference Exclusive live event will cover all the ways today's security and threat landscape has changed and how IT managers can respond. Discussions will include endpoint security, mobile security and the latest in malware threats. http://www.accelacomm.com/jaw/sfrnl04242012/114/50122263/
_______________________________________________ Musicpd-dev-team mailing list Musicpd-dev-team@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/musicpd-dev-team