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.

Thanks,

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

Reply via email to