bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2005-2018 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "common.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "array.h"
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen#include "ioloop.h"
bdd36cfdba3ff66d25570a9ff568d69e1eb543cfTimo Sirainen#include "net.h"
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen#ifdef HAVE_SYSTEMD
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen#include "sd-daemon.h"
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-listen.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <fcntl.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <sys/stat.h>
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen#include <sys/socket.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen#define MIN_BACKLOG 4
31105f2fa51d648c07f85585452352aa83b6244cTimo Sirainen
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainenstatic unsigned int service_get_backlog(struct service *service)
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen{
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen unsigned int backlog;
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen
ada28ebc9a289d00672da2a1ff9e67a6895241f0Timo Sirainen i_assert(service->process_limit > 0);
ada28ebc9a289d00672da2a1ff9e67a6895241f0Timo Sirainen i_assert(service->client_limit > 0);
ada28ebc9a289d00672da2a1ff9e67a6895241f0Timo Sirainen
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen /* as unlikely as it is, avoid overflows */
f6f50f528f6dce764065780bf88ee1acb2422b0aTimo Sirainen if (service->client_limit > INT_MAX / service->process_limit)
f6f50f528f6dce764065780bf88ee1acb2422b0aTimo Sirainen backlog = INT_MAX;
f6f50f528f6dce764065780bf88ee1acb2422b0aTimo Sirainen else
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen backlog = service->process_limit * service->client_limit;
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen return I_MAX(backlog, MIN_BACKLOG);
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen}
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainenstatic int
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainenservice_file_chown(const struct service_listener *l)
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen{
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen uid_t uid = l->set.fileset.uid;
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen uid_t gid = l->set.fileset.gid;
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen if ((uid == (uid_t)-1 || uid == master_uid) &&
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen (gid == (gid_t)-1 || gid == master_gid))
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen return 0;
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen if (chown(l->set.fileset.set->path, uid, gid) < 0) {
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen service_error(l->service, "chown(%s, %lld, %lld) failed: %m",
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen l->set.fileset.set->path,
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen (long long)uid, (long long)gid);
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen return -1;
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen }
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen return 0;
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen}
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_unix_listener_listen(struct service_listener *l)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = l->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct file_listener_settings *set = l->set.fileset.set;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mode_t old_umask;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int fd, i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_umask = umask((set->mode ^ 0777) & 0777);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0;; i++) {
fd1f9cd9b139c2004d896108c440793949043562Timo Sirainen fd = net_listen_unix(set->path, service_get_backlog(service));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd != -1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno == EISDIR || errno == ENOENT) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* looks like the path doesn't exist. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (errno != EADDRINUSE) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "net_listen_unix(%s) failed: %m",
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen set->path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* already in use - see if it really exists.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen after 3 times just fail here. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd = net_connect_unix(set->path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd != -1 || errno != ECONNREFUSED || i >= 3) {
7b032348d7bbb93ff96188289d3dfc1899b9abb3Josef 'Jeff' Sipek i_close_fd(&fd);
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "Socket already exists: %s",
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen set->path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* delete and try again */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (unlink(set->path) < 0 && errno != ENOENT) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "unlink(%s) failed: %m",
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen set->path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen umask(old_umask);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(fd != -1);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen if (service_file_chown(l) < 0) {
4307c886579381dbb1897ea1388ae6978c96f560Timo Sirainen i_close_fd(&fd);
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen net_set_nonblock(fd, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd_close_on_exec(fd, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen l->fd = fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_fifo_listener_listen(struct service_listener *l)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = l->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct file_listener_settings *set = l->set.fileset.set;
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen unsigned int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen mode_t old_umask;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int fd, ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen for (i = 0;; i++) {
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen old_umask = umask((set->mode ^ 0777) & 0777);
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen ret = mkfifo(set->path, set->mode);
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen umask(old_umask);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen if (ret == 0)
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen break;
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen if (ret < 0 && (errno != EEXIST || i == 1)) {
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen service_error(service, "mkfifo(%s) failed: %m",
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen set->path);
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen return -1;
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen }
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen if (unlink(set->path) < 0) {
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen service_error(service, "unlink(%s) failed: %m",
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen set->path);
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen return -1;
6cdc919454b0f1503c6e42be1a7163260c9c3ea6Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen if (service_file_chown(l) < 0)
31ddc69105cb9540f0e1f219157dc0c684831ac4Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7cbdafb1d58561aff031faf3b10b6f64c2ead49fTimo Sirainen /* open as RDWR, so that even if the last writer closes,
7cbdafb1d58561aff031faf3b10b6f64c2ead49fTimo Sirainen we won't get EOF errors */
7cbdafb1d58561aff031faf3b10b6f64c2ead49fTimo Sirainen fd = open(set->path, O_RDWR | O_NONBLOCK);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fd == -1) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "open(%s) failed: %m", set->path);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd_close_on_exec(fd, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen l->fd = fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen#ifdef HAVE_SYSTEMD
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainenstatic int
009217abb57a24a4076092e8e4e165545747839eStephan Boschsystemd_listen_fd(const struct ip_addr *ip, in_port_t port, int *fd_r)
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen{
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen static int sd_fds = -1;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen int fd, fd_max;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen if (sd_fds < 0) {
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen sd_fds = sd_listen_fds(0);
27f5066c781a8a5ca4eaa5e928c43171f2d986d9Timo Sirainen if (sd_fds < 0) {
27f5066c781a8a5ca4eaa5e928c43171f2d986d9Timo Sirainen i_error("sd_listen_fds() failed: %s", strerror(-sd_fds));
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen return -1;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen }
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen }
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen fd_max = SD_LISTEN_FDS_START + sd_fds - 1;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen for (fd = SD_LISTEN_FDS_START; fd <= fd_max; fd++) {
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen if (sd_is_socket_inet(fd, ip->family, SOCK_STREAM, 1, port)) {
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen *fd_r = fd;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen return 0;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen }
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen }
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen /* when systemd didn't provide a usable socket,
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen fall back to the regular socket creation code */
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen *fd_r = -1;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen return 0;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen}
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen#endif
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_inet_listener_listen(struct service_listener *l)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service = l->service;
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen enum net_listen_flags flags = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen const struct inet_listener_settings *set = l->set.inetset.set;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port = set->port;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int fd;
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen#ifdef HAVE_SYSTEMD
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen if (systemd_listen_fd(&l->set.inetset.ip, port, &fd) < 0)
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen return -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen if (fd == -1)
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen#endif
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen {
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen if (set->reuse_port)
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen flags |= NET_LISTEN_FLAG_REUSEPORT;
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen fd = net_listen_full(&l->set.inetset.ip, &port, &flags,
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen service_get_backlog(service));
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen if (fd < 0) {
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen service_error(service, "listen(%s, %u) failed: %m",
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen l->inet_address, set->port);
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen return errno == EADDRINUSE ? 0 : -1;
f6ba2de94f207839983e1b5b4bac930df465f572Timo Sirainen }
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen l->reuse_port = (flags & NET_LISTEN_FLAG_REUSEPORT) != 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen net_set_nonblock(fd, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen fd_close_on_exec(fd, TRUE);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen l->fd = fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return 1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainenint service_listener_listen(struct service_listener *l)
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen{
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen switch (l->type) {
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen case SERVICE_LISTENER_UNIX:
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen return service_unix_listener_listen(l);
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen case SERVICE_LISTENER_FIFO:
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen return service_fifo_listener_listen(l);
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen case SERVICE_LISTENER_INET:
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen return service_inet_listener_listen(l);
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen }
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen i_unreached();
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen}
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic int service_listen(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret = 1, ret2 = 0;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service->listeners, listeners) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct service_listener *l = *listeners;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (l->fd != -1)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
5d4c793b4e3dbc07f08daa4465594b1857f80725Timo Sirainen ret2 = service_listener_listen(l);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret2 < ret)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = ret2;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen#ifdef HAVE_SYSTEMD
009217abb57a24a4076092e8e4e165545747839eStephan Boschstatic int get_socket_info(int fd, unsigned int *family, in_port_t *port)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen{
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen union sockaddr_union {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen struct sockaddr sa;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen struct sockaddr_in in4;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen struct sockaddr_in6 in6;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen } sockaddr;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen socklen_t l;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
009217abb57a24a4076092e8e4e165545747839eStephan Bosch // FIXME(Stephan): why -1?
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (port) *port = -1;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (family) *family = -1;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(&sockaddr);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen l = sizeof(sockaddr);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (getsockname(fd, &sockaddr.sa, &l) < 0)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen return -errno;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (family) *family = sockaddr.sa.sa_family;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (port) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (sockaddr.sa.sa_family == AF_INET) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (l < sizeof(struct sockaddr_in))
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen return -EINVAL;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen *port = ntohs(sockaddr.in4.sin_port);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen } else {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (l < sizeof(struct sockaddr_in6))
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen return -EINVAL;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen *port = ntohs(sockaddr.in6.sin6_port);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen return 0;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen}
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainenstatic int services_verify_systemd(struct service_list *service_list)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen{
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen struct service *const *services;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen static int sd_fds = -1;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen int fd, fd_max;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (sd_fds < 0) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen sd_fds = sd_listen_fds(0);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (sd_fds == -1) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen i_error("sd_listen_fds() failed: %m");
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen return -1;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen fd_max = SD_LISTEN_FDS_START + sd_fds - 1;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen for (fd = SD_LISTEN_FDS_START; fd <= fd_max; fd++) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (sd_is_socket_inet(fd, 0, SOCK_STREAM, 1, 0) > 0) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen int found = FALSE;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch in_port_t port;
009217abb57a24a4076092e8e4e165545747839eStephan Bosch unsigned int family;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen get_socket_info(fd, &family, &port);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen array_foreach(&service_list->services, services) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen struct service_listener *const *listeners;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen array_foreach(&(*services)->listeners, listeners) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen struct service_listener *l = *listeners;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (l->type != SERVICE_LISTENER_INET)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen continue;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (l->set.inetset.set->port == port &&
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen l->set.inetset.ip.family == family) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen found = TRUE;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen break;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (found) break;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (!found) {
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen i_error("systemd listens on port %d, but it's not configured in Dovecot. Closing.",port);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen if (shutdown(fd, SHUT_RDWR) < 0 && errno != ENOTCONN)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen i_error("shutdown() failed: %m");
aeef47104f7f40bd7db8a7a3fb2cea4ba78c0360Timo Sirainen if (dup2(dev_null_fd, fd) < 0)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen i_error("dup2() failed: %m");
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen }
5f99c6a6eed020491e5d803624299f3bce01d6a5Timo Sirainen return 0;
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen}
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen#endif
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainenstatic int services_listen_master(struct service_list *service_list)
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen{
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen const char *path;
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen mode_t old_umask;
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen path = t_strdup_printf("%s/master", service_list->set->base_dir);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen old_umask = umask(0600 ^ 0777);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen service_list->master_fd = net_listen_unix(path, 16);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen if (service_list->master_fd == -1 && errno == EADDRINUSE) {
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen /* already in use. all the other sockets were fine, so just
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen delete this and retry. */
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen i_unlink_if_exists(path);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen service_list->master_fd = net_listen_unix(path, 16);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen }
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen umask(old_umask);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen
9b7a4aa38539a9723586e150b13b14722f965f5eTimo Sirainen if (service_list->master_fd == -1) {
9b7a4aa38539a9723586e150b13b14722f965f5eTimo Sirainen i_error("net_listen_unix(%s) failed: %m", path);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen return 0;
9b7a4aa38539a9723586e150b13b14722f965f5eTimo Sirainen }
cf6118fe7f4fdd4b7153e320ace71c48d29c3fc9Timo Sirainen fd_close_on_exec(service_list->master_fd, TRUE);
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen return 1;
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen}
164f8e81a078c7b8f679fdd04892ffc9ba14bfa0Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint services_listen(struct service_list *service_list)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *const *services;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int ret = 1, ret2;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service_list->services, services) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen ret2 = service_listen(*services);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (ret2 < ret)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen ret = ret2;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
b39dd48436b5894d15ec0c632c8a65f936c2c487Timo Sirainen /* reloading config wants to continue even when we're returning 0. */
b39dd48436b5894d15ec0c632c8a65f936c2c487Timo Sirainen if (ret >= 0) {
b39dd48436b5894d15ec0c632c8a65f936c2c487Timo Sirainen ret2 = services_listen_master(service_list);
b39dd48436b5894d15ec0c632c8a65f936c2c487Timo Sirainen if (ret2 < ret)
b39dd48436b5894d15ec0c632c8a65f936c2c487Timo Sirainen ret = ret2;
b39dd48436b5894d15ec0c632c8a65f936c2c487Timo Sirainen }
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen#ifdef HAVE_SYSTEMD
33b0d86072e64c8ee1ccfb9d6c49cd437ca558d0Timo Sirainen if (ret > 0)
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen services_verify_systemd(service_list);
b5cbeb103ba21f96d71afc4a53412ad81ed898c6Timo Sirainen#endif
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return ret;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainenstatic bool listener_equals(const struct service_listener *l1,
d9a7e950a9cd21f2b4a90ec7759fca9e8fcc7995Timo Sirainen const struct service_listener *l2)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (l1->type != l2->type)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen switch (l1->type) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_LISTENER_UNIX:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_LISTENER_FIFO:
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen /* We could just keep using the same listener, but it's more
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen likely to cause problems if old process accepts a connection
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen before it knows that it should die. So just always unlink
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen and recreate unix/fifo listeners. */
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen case SERVICE_LISTENER_INET:
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (memcmp(&l1->set.inetset.ip, &l2->set.inetset.ip,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen sizeof(l1->set.inetset.ip)) != 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (l1->set.inetset.set->port != l2->set.inetset.set->port)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenint services_listen_using(struct service_list *new_service_list,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_list *old_service_list)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen struct service *const *services, *old_service, *new_service;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct service_listener *) new_listeners_arr;
4ee00532a265bdfb38539d811fcd12d51210ac35Timo Sirainen ARRAY(struct service_listener *) old_listeners_arr;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *new_listeners, *const *old_listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i, j, count, new_count, old_count;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen /* rescue anvil's UNIX socket listener */
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen new_service = service_lookup_type(new_service_list, SERVICE_TYPE_ANVIL);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen old_service = service_lookup_type(old_service_list, SERVICE_TYPE_ANVIL);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (old_service != NULL && new_service != NULL) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen new_listeners = array_get(&new_service->listeners, &new_count);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen old_listeners = array_get(&old_service->listeners, &old_count);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen for (i = 0; i < old_count && i < new_count; i++) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (new_listeners[i]->type != old_listeners[i]->type)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen break;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (i != new_count && i != old_count) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen i_error("Can't change anvil's listeners on the fly");
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen return -1;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen for (i = 0; i < new_count; i++) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen new_listeners[i]->fd = old_listeners[i]->fd;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen old_listeners[i]->fd = -1;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* first create an arrays of all listeners to make things easier */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen t_array_init(&new_listeners_arr, 64);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services = array_get(&new_service_list->services, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_append_array(&new_listeners_arr, &services[i]->listeners);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen t_array_init(&old_listeners_arr, 64);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services = array_get(&old_service_list->services, &count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < count; i++)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen array_append_array(&old_listeners_arr, &services[i]->listeners);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* then start moving fds */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new_listeners = array_get(&new_listeners_arr, &new_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_listeners = array_get(&old_listeners_arr, &old_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < new_count; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (j = 0; j < old_count; j++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (old_listeners[j]->fd != -1 &&
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen listener_equals(new_listeners[i],
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_listeners[j])) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen new_listeners[i]->fd = old_listeners[j]->fd;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen old_listeners[j]->fd = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen break;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* close what's left */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (j = 0; j < old_count; j++) {
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (old_listeners[j]->fd == -1)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen continue;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (close(old_listeners[j]->fd) < 0)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen i_error("close(listener) failed: %m");
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen switch (old_listeners[j]->type) {
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen case SERVICE_LISTENER_UNIX:
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen case SERVICE_LISTENER_FIFO: {
46b823ac3bce2c0f9f0fc73911e48d3a77b04fbeTimo Sirainen i_unlink(old_listeners[j]->set.fileset.set->path);
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen break;
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen }
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen case SERVICE_LISTENER_INET:
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen break;
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* and let services_listen() deal with the remaining fds */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return services_listen(new_service_list);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}