dovecot-2.1: systemd: If a socket is enabled in systemd but not ...

dovecot at dovecot.org dovecot at dovecot.org
Fri May 4 21:52:39 EEST 2012


details:   http://hg.dovecot.org/dovecot-2.1/rev/4a3bf567da54
changeset: 14503:4a3bf567da54
user:      Timo Sirainen <tss at iki.fi>
date:      Fri May 04 21:52:05 2012 +0300
description:
systemd: If a socket is enabled in systemd but not in Dovecot config, close it.
Based on patch by Michal Hlavinka.

diffstat:

 src/master/service-listen.c |  90 +++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 90 insertions(+), 0 deletions(-)

diffs (114 lines):

diff -r 40a544fc4778 -r 4a3bf567da54 src/master/service-listen.c
--- a/src/master/service-listen.c	Fri May 04 21:40:57 2012 +0300
+++ b/src/master/service-listen.c	Fri May 04 21:52:05 2012 +0300
@@ -14,6 +14,7 @@
 #include <unistd.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <sys/socket.h>
 
 #define MIN_BACKLOG 4
 #define MAX_BACKLOG 511
@@ -242,6 +243,90 @@
 	return ret;
 }
 
+#ifdef HAVE_SYSTEMD
+static int get_socket_info(int fd, unsigned int *family, unsigned int *port)
+{
+	union sockaddr_union {
+		struct sockaddr sa;
+		struct sockaddr_in in4;
+		struct sockaddr_in6 in6;
+	} sockaddr;
+	socklen_t l;
+
+	if (port) *port = -1;
+	if (family) *family = -1;
+
+	memset(&sockaddr, 0, sizeof(sockaddr));
+	l = sizeof(sockaddr);
+
+	if (getsockname(fd, &sockaddr.sa, &l) < 0)
+	      return -errno;
+
+	if (family) *family = sockaddr.sa.sa_family;
+	if (port) {
+		if (sockaddr.sa.sa_family == AF_INET) {
+			if (l < sizeof(struct sockaddr_in))
+				return -EINVAL;
+
+			*port = ntohs(sockaddr.in4.sin_port);
+		} else {
+			if (l < sizeof(struct sockaddr_in6))
+				return -EINVAL;
+
+			*port = ntohs(sockaddr.in6.sin6_port);
+		}
+	}
+	return 0;
+}
+
+static int services_verify_systemd(struct service_list *service_list)
+{
+	struct service *const *services;
+	static int sd_fds = -1;
+	int fd, fd_max;
+
+	if (sd_fds < 0) {
+		sd_fds = sd_listen_fds(0);
+		if (sd_fds == -1) {
+			i_error("sd_listen_fds() failed: %m");
+			return -1;
+		}
+	}
+
+	fd_max = SD_LISTEN_FDS_START + sd_fds - 1;
+	for (fd = SD_LISTEN_FDS_START; fd <= fd_max; fd++) {
+		if (sd_is_socket_inet(fd, 0, SOCK_STREAM, 1, 0) > 0) {
+			int found = FALSE;
+			unsigned int port, family;
+			get_socket_info(fd, &family, &port);
+			
+			array_foreach(&service_list->services, services) {
+				struct service_listener *const *listeners;
+
+				array_foreach(&(*services)->listeners, listeners) {
+					struct service_listener *l = *listeners;
+					if (l->type != SERVICE_LISTENER_INET)
+						continue;
+					if (l->set.inetset.set->port == port &&
+					    l->set.inetset.ip.family == family) {
+						found = TRUE;
+						break;
+					}
+				}
+				if (found) break;
+			}
+			if (!found) {
+				i_error("systemd listens on port %d, but it's not configured in Dovecot. Closing.",port);
+				if (shutdown(fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
+					i_error("shutdown() failed: %m");
+				if (dup2(null_fd, fd) < 0)
+					i_error("dup2() failed: %m");
+			}
+		}
+	}
+}
+#endif
+
 int services_listen(struct service_list *service_list)
 {
 	struct service *const *services;
@@ -252,6 +337,11 @@
 		if (ret2 < ret)
 			ret = ret2;
 	}
+
+#ifdef HAVE_SYSTEMD
+	if (ret == 0)
+		services_verify_systemd(service_list);
+#endif
 	return ret;
 }
 


More information about the dovecot-cvs mailing list