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