master-service.c revision 01230de017cd273de41143d88e9c18df1243ae8a
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (C) 2005-2009 Timo Sirainen */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "lib.h"
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen#include "lib-signals.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "ioloop.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "array.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "env-util.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include "home-expand.h"
abf015c9682f0f723db87a7c97bc284ef814818fTimo Sirainen#include "restrict-access.h"
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen#include "fd-close-on-exec.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "syslog-util.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "master-service-private.h"
fa2a11210f20fb8998ed656f75e163191c8047e6Timo Sirainen#include "master-service-settings.h"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <stdlib.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <unistd.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#include <sys/stat.h>
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen#include <syslog.h>
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MASTER_CONFIG_FILE_ENV "CONFIG_FILE"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void io_listeners_add(struct master_service *service);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void io_listeners_remove(struct master_service *service);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenstatic void master_status_update(struct master_service *service);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenconst char *master_service_getopt_string(void)
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen{
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen return "c:ko:s:L";
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen}
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainen
c3a636e4c9ae776e0eed06b6d7ad1ccfb6003afdTimo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen{
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen struct master_service *service = context;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* warn about being killed because of some signal, except SIGINT (^C)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen which is too common at least while testing :) */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (si->si_signo != SIGINT) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen si->si_signo, dec2str(si->si_pid),
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen dec2str(si->si_uid),
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_loop_stop(service->ioloop);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void master_service_verify_version(struct master_service *service)
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen{
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen if (service->version_string != NULL &&
49621bf0ef1d55aaaa2dc7d76011cbfeabdcfbe1Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
fa2433aebcf3fccfa30ca9eed9b1a9166cf92ee2Timo Sirainen i_fatal("Dovecot version mismatch: "
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen "Master is v%s, %s is v"PACKAGE_VERSION" "
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(if you don't care, set version_ignore=yes)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->name, service->version_string);
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen }
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen}
5d03d9f439e41c90215a3c938ffebe4c2a8ae257Timo Sirainen
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainenstruct master_service *
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
3482fee0e3733456512ba110780824e6daa7ff9fTimo Sirainen int argc, char *argv[])
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
12797080b552a3c1727b73b61cc7427bec0c7472Timo Sirainen struct master_service *service;
49fd8c950e3da2ed32506e617a4b1480a07f874fTimo Sirainen const char *str;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(name != NULL);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen#ifdef DEBUG
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen if (getenv("GDB") == NULL) {
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen int count;
b9b841558c5f91db7f5fc71c0ac62aad1bbf6418Timo Sirainen
d1fff80640050631b06bfab904a34b2ad24601e8Timo Sirainen str = getenv("SOCKET_COUNT");
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen count = str == NULL ? 0 : atoi(str);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
1388b590dbd85245b591346f860bc1319953318aTimo Sirainen }
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen#endif
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
2fb9ae42f9e36388ec6db24188b9108434043fd0Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen restrict_access_by_env() is called */
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch lib_init();
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch /* Set a logging prefix temporarily. This will be ignored once the log
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen is properly initialized */
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(init): ", name));
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen
38f227941bcf673e0e523c1ac7267bca9cbcd2c4Timo Sirainen if (getenv(MASTER_UID_ENV) == NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen flags |= MASTER_SERVICE_FLAG_STANDALONE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service = i_new(struct master_service, 1);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->argc = argc;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->argv = argv;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->name = i_strdup(name);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->flags = flags;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->ioloop = io_loop_create();
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->service_count_left = (unsigned int)-1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->config_fd = -1;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->config_path = getenv(MASTER_CONFIG_FILE_ENV);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (service->config_path == NULL)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->config_path = DEFAULT_CONFIG_FILE_PATH;
2eb2cf8eeb763bd5ca9b6848dce32f0303e88ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->socket_count = 1;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->version_string = PACKAGE_VERSION;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str = getenv("SOCKET_COUNT");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (str != NULL)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->socket_count = atoi(str);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen str = getenv("SSL_SOCKET_COUNT");
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (str != NULL)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen service->ssl_socket_count = atoi(str);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* set up some kind of logging until we know exactly how and where
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen we want to log */
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (getenv("LOG_SERVICE") != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_internal();
367e28a16854ee9f7247b2518f36f5e9163fcc10Timo Sirainen if (getenv("USER") != NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s(%s): ",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen name, getenv("USER")));
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_set_failure_prefix(t_strdup_printf("%s: ", name));
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen master_service_verify_version(service);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return service;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen}
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainenvoid master_service_init_log(struct master_service *service, const char *prefix,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen unsigned int max_lines_per_sec)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen{
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen const char *path;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_LOG_TO_STDERR) != 0) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_set_failure_file("/dev/stderr", "");
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen return;
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen }
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen /* logging via log service */
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen i_set_failure_internal();
7af5f78e9fee296e42430d94ef252ff0333d8024Timo Sirainen i_set_failure_prefix(prefix);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen return;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (service->set == NULL) {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_set_failure_file("/dev/stderr", prefix);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen return;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen }
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (*service->set->log_path == '\0') {
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* log to syslog */
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen int facility;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen &facility))
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen facility = LOG_MAIL;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_set_failure_prefix(prefix);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen } else {
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen /* log to file or stderr */
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen path = home_expand(service->set->log_path);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen i_set_failure_file(path, prefix);
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen }
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen path = home_expand(service->set->info_log_path);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen if (*path != '\0')
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen i_set_info_file(path);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
1f5597beba229acd914e30a6da3c0e62d83b6e8fTimo Sirainen}
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainenbool master_service_parse_option(struct master_service *service,
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen int opt, const char *arg)
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen{
47569a4b2b4d3cc55e786177798c922c3c44233dTimo Sirainen int i;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen switch (opt) {
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen case 'c':
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen service->config_path = arg;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen break;
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen case 'k':
417642ddac19708bea6dd2c2bbeaf6a9578d521bTimo Sirainen service->keep_environment = TRUE;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen break;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen case 'o':
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen if (!array_is_created(&service->config_overrides))
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen i_array_init(&service->config_overrides, 16);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen array_append(&service->config_overrides, &arg, 1);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen break;
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen case 's':
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if ((i = atoi(arg)) < 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal("Invalid socket count: %s", arg);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->socket_count = i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen case 'L':
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->log_directly = TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen break;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen default:
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return FALSE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return TRUE;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void master_status_error(void *context)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct master_service *service = context;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master wants us to die (or died itself). don't die until all
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service connections are finished. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_remove(&service->io_status_error);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* the log fd may also be closed already, don't die when trying to
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen log later */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_ignore_errors(TRUE);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (service->master_status.available_count ==
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen service->total_available_count)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen master_service_stop(service);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_init_finish(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen struct stat st;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen const char *value;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_assert(service->total_available_count == 0);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* set default signal handlers */
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen lib_signals_init();
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen lib_signals_ignore(SIGPIPE, TRUE);
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen lib_signals_ignore(SIGALRM, FALSE);
f3e17726502b6cf1912f30aae7e283b5d31ea69cTimo Sirainen lib_signals_set_handler(SIGINT, TRUE, sig_die, service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signals_set_handler(SIGTERM, TRUE, sig_die, service);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen i_fatal("Must be started by dovecot master process");
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* initialize master_status structure */
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen value = getenv(MASTER_UID_ENV);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen if (value == NULL)
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen i_fatal(MASTER_UID_ENV" not set");
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen service->master_status.pid = getpid();
e30b9e07f9657c35ca09ac36d57d60cbe2ebbc66Timo Sirainen service->master_status.uid =
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen /* set the default limit */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen value = getenv(MASTER_CLIENT_LIMIT_ENV);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen count = value == NULL ? 0 :
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen (unsigned int)strtoul(value, NULL, 10);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (count == 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_fatal(MASTER_CLIENT_LIMIT_ENV" not set");
002179a890bf4f1942cad6463787719eaa9fd6c0Timo Sirainen master_service_set_client_limit(service, count);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* start listening errors for status fd, it means master died */
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch service->io_status_error = io_add(MASTER_STATUS_FD, IO_ERROR,
e438c85a6b0f77889e25913bbbba808d6078282dStephan Bosch master_status_error, service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen } else {
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen master_service_set_client_limit(service, 1);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master_service_set_service_count(service, 1);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen }
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen io_listeners_add(service);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen /* we already have a connection to be served */
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen service->master_status.available_count--;
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen }
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen master_status_update(service);
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen}
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainen
542e28b384a6b26695f3e8de38fd5727d06f3333Timo Sirainenvoid master_service_env_clean(bool preserve_home)
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch{
ab90f702ceedb7ba445a9a592be0b213b27cbafaStephan Bosch const char *user, *tz, *home;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen#ifdef DEBUG
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen bool gdb = getenv("GDB") != NULL;
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen#endif
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen
5a9912dcadfd467c5ea54bdc3331eef359f0b1c5Timo Sirainen user = getenv("USER");
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (user != NULL)
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen user = t_strconcat("USER=", user, NULL);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen tz = getenv("TZ");
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen if (tz != NULL)
4c261fb48e6e36570a0841aa51ca483024d6a0a6Timo Sirainen tz = t_strconcat("TZ=", tz, NULL);
18c209a06941ef583b08b173dadfbe4571995bf9Timo Sirainen home = preserve_home ? getenv("HOME") : NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (home != NULL)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen home = t_strconcat("HOME=", home, NULL);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
c07d7eb3ca9754367697c98f5e66a3982a45d142Timo Sirainen /* Note that if the original environment was set with env_put(), the
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen environment strings will be invalid after env_clean(). That's why
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen we t_strconcat() them above. */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen env_clean();
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (user != NULL) env_put(user);
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen if (tz != NULL) env_put(tz);
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen if (home != NULL) env_put(home);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#ifdef DEBUG
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (gdb) env_put("GDB=1");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#endif
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen unsigned int client_limit)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen i_assert(service->master_status.available_count ==
b9dc21a94401638c00e40b695998875e1563ce77Timo Sirainen service->total_available_count);
b9dc21a94401638c00e40b695998875e1563ce77Timo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen service->total_available_count = client_limit;
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainen service->master_status.available_count = client_limit;
27ca6cb0548c6478005c77d04be641356ec7d83cTimo Sirainen}
27ca6cb0548c6478005c77d04be641356ec7d83cTimo Sirainen
fc464e5b2b2ab4d415a5d5b90ce4475d34620a75Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return service->total_available_count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
4da8c6cdefabd31262318c32da3c13de1d9ea953Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned int count)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen unsigned int used;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen used = service->total_available_count -
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen service->master_status.available_count;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen i_assert(count >= used);
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen if (service->total_available_count > count) {
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen service->total_available_count = count;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen service->master_status.available_count = count - used;
3b22894b8805b186c73d8b754001e8d7e944be85Timo Sirainen }
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->service_count_left = count;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return service->service_count_left;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return service->socket_count;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return service->config_path;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen return service->version_string;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenvoid master_service_run(struct master_service *service,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen master_service_connection_callback_t *callback)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->callback = callback;
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen io_loop_run(service->ioloop);
9261dbf0675204898c6557591c7aa376e23a52b2Timo Sirainen service->callback = NULL;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenvoid master_service_stop(struct master_service *service)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_loop_stop(service->ioloop);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen{
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen ssize_t ret;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen return;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (ret < 0)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen i_error("write(anvil) failed: %m");
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen else if (ret == 0)
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen i_error("write(anvil) failed: EOF");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen else {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert((size_t)ret == strlen(cmd));
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (service->listeners == NULL) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* we can listen again */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_listeners_add(service);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen i_assert(service->total_available_count > 0);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (service->service_count_left != service->total_available_count) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(service->service_count_left == (unsigned int)-1);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->master_status.available_count++;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen } else {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* we have only limited amount of service requests left */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(service->service_count_left > 0);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->service_count_left--;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->total_available_count--;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (service->service_count_left == 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_assert(service->master_status.available_count ==
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->total_available_count);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen master_service_stop(service);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen master_status_update(service);
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen if (service->io_status_error == NULL &&
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen service->master_status.available_count ==
39f5c2b2143842ff6f827b7198cae8853b8c5bbaTimo Sirainen service->total_available_count) {
b55f914c0ade77252cfd798ea8eb9a84bda56315Timo Sirainen /* master has closed the connection and we have nothing else
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen to do anymore. */
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen master_service_stop(service);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen }
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen}
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainenvoid master_service_deinit(struct master_service **_service)
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen{
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen struct master_service *service = *_service;
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen *_service = NULL;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_listeners_remove(service);
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (service->io_status_error != NULL)
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen io_remove(&service->io_status_error);
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (service->io_status_write != NULL)
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen io_remove(&service->io_status_write);
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen if (array_is_created(&service->config_overrides))
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen array_free(&service->config_overrides);
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen lib_signals_deinit();
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen io_loop_destroy(&service->ioloop);
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen
19cadcc25c26af7afea1355d78e20ad64eaad263Timo Sirainen i_free(service->name);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_free(service);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen lib_deinit();
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void master_service_listen(struct master_service_listener *l)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen struct master_service_connection conn;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (l->service->master_status.available_count == 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* we are full. stop listening for now. */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_listeners_remove(l->service);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen memset(&conn, 0, sizeof(conn));
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen conn.listen_fd = l->fd;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (conn.fd < 0) {
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen if (conn.fd == -1)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (errno != ENOTSOCK) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_error("net_accept() failed: %m");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_listeners_remove(l->service);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* it's not a socket. probably a fifo. use the "listener"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen as the connection fd */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_remove(&l->io);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen conn.fd = l->fd;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen conn.ssl = l->ssl;
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen net_set_nonblock(conn.fd, TRUE);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen l->service->master_status.available_count--;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen master_status_update(l->service);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen l->service->callback(&conn);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen}
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainenstatic void io_listeners_add(struct master_service *service)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen unsigned int i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (service->socket_count == 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->listeners =
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_new(struct master_service_listener, service->socket_count);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen for (i = 0; i < service->socket_count; i++) {
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen struct master_service_listener *l = &service->listeners[i];
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen l->service = service;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen l->fd = MASTER_LISTEN_FD_FIRST + i;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen master_service_listen, l);
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
216cd45a5f47c9bd46fe67c1b3bd6b1a42f6e39cTimo Sirainen l->ssl = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen}
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void io_listeners_remove(struct master_service *service)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen unsigned int i;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (service->listeners != NULL) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen for (i = 0; i < service->socket_count; i++) {
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen if (service->listeners[i].io != NULL)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_remove(&service->listeners[i].io);
2f90189c6ee66a17f7bf838a8eb8a69868630fb8Timo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_free_and_null(service->listeners);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen}
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen{
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen if (service->master_status.available_count == 0)
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen return TRUE;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen if (!service->initial_status_sent)
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen return TRUE;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen return FALSE;
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen}
20dca965f48c1d7600a268d380c0b5fb5f1011d5Timo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainenstatic void master_status_update(struct master_service *service)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen{
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ssize_t ret;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (service->master_status.pid == 0)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen return; /* closed */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen sizeof(service->master_status));
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (ret > 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* success */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (service->io_status_write != NULL) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* delayed important update sent successfully */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen io_remove(&service->io_status_write);
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen }
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->initial_status_sent = TRUE;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen } else if (ret == 0) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* shouldn't happen? */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_error("write(master_status_fd) returned 0");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->master_status.pid = 0;
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen } else if (errno != EAGAIN) {
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen /* failure */
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen if (errno != EPIPE)
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen i_error("write(master_status_fd) failed: %m");
13b063ba3ea51256fd97d7fa883f14cb08842b0dTimo Sirainen service->master_status.pid = 0;
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen } else if (master_status_update_is_important(service)) {
7f472e15b5f19a3536634863950c80a88079da23Timo Sirainen /* reader is busy, but it's important to get this notification
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen through. send it when possible. */
0139fcb57a88f6ed27a1bb4a1bd537b04fd2b5d6Timo Sirainen if (service->io_status_write == NULL) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->io_status_write =
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen io_add(MASTER_STATUS_FD, IO_WRITE,
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen master_status_update, service);
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen }
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen }
70afae43cc78ea6ecca83f6c587072c442a15ec1Timo Sirainen}
c06d6ea0766d0520af1a93e6000c0e73f350e0a2Timo Sirainen