master-service.c revision 8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1
7cb128dc4cae2a03a742f63ba7afee23c78e3af0Phil Carmody/* Copyright (c) 2005-2015 Dovecot authors, see the included COPYING file */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define DEFAULT_CONFIG_FILE_PATH SYSCONFDIR"/dovecot.conf"
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_CONFIG_FILE_ENV) provides path to configuration file/socket */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen/* getenv(MASTER_DOVECOT_VERSION_ENV) provides master's version number */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen#define MASTER_DOVECOT_VERSION_ENV "DOVECOT_VERSION"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen/* when we're full of connections, how often to check if login state has
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen changed. we normally notice it immediately because of a signal, so this is
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen just a fallback against race conditions. */
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen/* If die callback hasn't managed to stop the service for this many seconds,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen#define MASTER_SERVICE_DIE_TIMEOUT_MSECS (30*1000)
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenstatic void master_service_io_listeners_close(struct master_service *service);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service);
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainenmaster_status_send(struct master_service *service, bool important_update);
104318260228780a5c6b3181b3401e8e504e2776Timo Sirainen return "c:i:ko:OL";
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenstatic void sig_die(const siginfo_t *si, void *context)
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen /* SIGINT comes either from master process or from keyboard. we don't
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen want to log it in either case.*/
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_warning("Killed with signal %d (by pid=%s uid=%s code=%s)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen lib_signal_code_to_str(si->si_signo, si->si_code));
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_NO_IDLE_DIE) != 0) {
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen /* never die when idling */
f46363f428d8f2784146d36692b21936a48a7006Timo Sirainen } else if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen /* SIGINT came from master. die only if we're not handling
b437874782ad048daa155e0ac863c2326c3f5e43Timo Sirainen any clients currently. */
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen /* we don't want to die - send a notification to master
2f94ca6b0f70641fe31c8e1f93404ca0df8bb289Timo Sirainen so it doesn't think we're ignoring it completely. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainensig_state_changed(const siginfo_t *si ATTR_UNUSED, void *context)
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenstatic void master_service_verify_version_string(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen strcmp(service->version_string, PACKAGE_VERSION) != 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen "(if you don't care, set version_ignore=yes)",
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenmaster_service_init(const char *name, enum master_service_flags flags,
a3fe8c0c54d87822f4b4f8f0d10caac611861b2bTimo Sirainen int *argc, char **argv[], const char *getopt_str)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen unsigned int count;
0c22bef8f5b35c645de8affd8746307fc53bd222Timo Sirainen (flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
78fa3c578c14ee8a612f86cf73b6181c7f16463fTimo Sirainen fd_debug_verify_leaks(MASTER_LISTEN_FD_FIRST + count, 1024);
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen /* make sure we can dump core, at least until
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen privileges are dropped. (i'm not really sure why this
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen is needed, because doing the same just before exec
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen doesn't help, and exec shouldn't affect this with
8451c4b5afc1ff5366438b2766f75b592c33e1ecTimo Sirainen non-setuid/gid binaries..) */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* NOTE: we start rooted, so keep the code minimal until
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen restrict_access_by_env() is called */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* Set a logging prefix temporarily. This will be ignored once the log
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen is properly initialized */
40a8e6948d662339c0c5e2c7abfb84ae7c1803fdTimo Sirainen /* ignore these signals as early as possible */
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen /* keep getopt_str first in case it contains "+" */
e6b4168ba670d9e51ea7877661def039ae6b53c3Timo Sirainen i_strconcat(getopt_str, master_service_getopt_string(), NULL);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen service->config_path = i_strdup(getenv(MASTER_CONFIG_FILE_ENV));
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen service->config_path = i_strdup(DEFAULT_CONFIG_FILE_PATH);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen service->version_string = getenv(MASTER_DOVECOT_VERSION_ENV);
f7423cbbd9dea363a5df18ebb96da055a977ae79Timo Sirainen str_array_length((void *)service->listener_names);
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen service->want_ssl_settings = service->ssl_socket_count > 0 ||
32b78da5dfbbf6a06b3dbdc9278c60b55714f9bcTimo Sirainen (flags & MASTER_SERVICE_FLAG_USE_SSL_SETTINGS) != 0;
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen /* set up some kind of logging until we know exactly how and where
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen we want to log */
ca4526e3b5fbf5ea3dd477a2098522a44c9ac52cTimo Sirainen i_set_failure_prefix("%s(%s): ", name, getenv("USER"));
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if ((flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* initialize master_status structure */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen str_to_uint(value, &service->master_status.uid) < 0)
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* set the default limit */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (value == NULL || str_to_uint(value, &count) < 0 ||
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen master_service_set_client_limit(service, count);
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* seve the process limit */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen /* set the default service count */
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0 &&
c444eeaa2866152cf62652698aa11b125e8454bcTimo Sirainen master_service_set_service_count(service, count);
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen /* set the idle kill timeout */
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainen if (value != NULL && str_to_uint(value, &count) == 0)
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen if ((flags & MASTER_SERVICE_FLAG_KEEP_CONFIG_OPEN) != 0) {
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen /* since we're going to keep the config socket open anyway,
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen open it now so we can read settings even after privileges
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen are dropped. */
b7b9d4be2a1ff399026a5d6feeffd3a048f22be0Timo Sirainen master_service_config_socket_try_open(service);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen master_service_verify_version_string(service);
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainenint master_getopt(struct master_service *service)
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen i_assert(master_getopt_str_is_valid(service->getopt_str));
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen while ((c = getopt(service->argc, service->argv,
578ef2538ccf42e2a48234c24a8b709397101d88Timo Sirainen if (!master_service_parse_option(service, c, optarg))
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainenbool master_getopt_str_is_valid(const char *str)
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen unsigned int i, j;
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen /* make sure there are no duplicates. there are few enough characters
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen that this should be fast enough. */
9b0f6b90ff8d1d6efd718b0d7cbe01b2454e9fd6Timo Sirainen if (str[i] == ':' || str[i] == '+' || str[i] == '-')
e0740628f6ca05f4bc79a9d8a90b650f4d38d4d0Timo Sirainenvoid master_service_init_log(struct master_service *service,
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0 &&
c6335901c67a4c9365319190a111a2168f3b06f5Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_DONT_LOG_TO_STDERR) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (getenv("LOG_SERVICE") != NULL && !service->log_directly) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* logging via log service */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* error logging goes to file or stderr */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(service->set->log_path, "syslog") == 0 ||
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->info_log_path, "syslog") == 0 ||
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->debug_log_path, "syslog") == 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* something gets logged to syslog */
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen if (!syslog_facility_find(service->set->syslog_facility,
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_syslog("dovecot", LOG_NDELAY, facility);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (strcmp(service->set->log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* set error handlers back to file */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->info_log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen path = home_expand(service->set->info_log_path);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen strcmp(service->set->debug_log_path, "syslog") != 0) {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen path = home_expand(service->set->debug_log_path);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainen i_set_failure_timestamp_format(service->set->log_timestamp);
3f603ef00e35fca21605afa0ad8d76e94fee2b96Timo Sirainenvoid master_service_set_die_with_master(struct master_service *service,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainenvoid master_service_set_die_callback(struct master_service *service,
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen void (*callback)(void))
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainenvoid master_service_set_idle_die_callback(struct master_service *service,
ccf50662cc02b5e703039a4ff7f91a4470e25b71Timo Sirainen bool (*callback)(void))
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainenstatic bool get_instance_config(const char *name, const char **config_path_r)
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen /* note that we don't have any settings yet. we're just finding out
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen which dovecot.conf we even want to read! so we must use the
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen hardcoded state_dir path. */
d9515a2eaa94c8287188c38fc28028727671e729Timo Sirainen instance_path = t_strconcat(PKG_STATEDIR"/"MASTER_INSTANCE_FNAME, NULL);
2e533fb1283b5f06a4063b519e47f1861c910386Timo Sirainen list = master_instance_list_init(instance_path);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen inst = master_instance_list_find_by_name(list, name);
96d19229e5f322411eb84446e5477d8170cfa5afTimo Sirainen path = t_strdup_printf("%s/dovecot.conf", inst->base_dir);
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenbool master_service_parse_option(struct master_service *service,
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen service->config_path_changed_with_param = TRUE;
6efdbeab167483597bef087f70ea852d1256a082Timo Sirainen service->config_path_changed_with_param = TRUE;
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (!array_is_created(&service->config_overrides))
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen array_append(&service->config_overrides, &arg, 1);
047c00cd3f7f403672f81569413669238df8c15aTimo Sirainen service->flags |= MASTER_SERVICE_FLAG_NO_CONFIG_SETTINGS;
8d7eb4104707c60ca7e9d0228b37c5133476907bTimo Sirainenstatic void master_service_error(struct master_service *service)
86791365b10f45982c88e70f2eb94fd6c3fea151Timo Sirainen service->total_available_count || service->die_with_master) {
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainenstatic void master_status_error(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* status fd is a write-only pipe, so if we're here it means the
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master wants us to die (or died itself). don't die until all
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service connections are finished. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* the log fd may also be closed already, don't die when trying to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_init_finish(struct master_service *service)
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen enum libsig_flags sigint_flags = LIBSIG_FLAG_DELAYED;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* set default signal handlers */
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0)
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGINT, sigint_flags, sig_die, service);
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGTERM, LIBSIG_FLAG_DELAYED, sig_die, service);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_TRACK_LOGIN_STATE) != 0) {
5512d420d826a2f9d4e7cb4e4919e1864fe688b0Timo Sirainen lib_signals_set_handler(SIGUSR1, LIBSIG_FLAGS_SAFE,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (fstat(MASTER_STATUS_FD, &st) < 0 || !S_ISFIFO(st.st_mode))
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_fatal("Must be started by dovecot master process");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* start listening errors for status fd, it means master died */
cbcba924a745c938260fd39cb284175b75f8eaf2Timo Sirainen service->io_status_error = io_add(MASTER_DEAD_FD, IO_ERROR,
8b5c520883aa37bb55646286d375fdbae294d710Timo Sirainen (service->flags & MASTER_SERVICE_FLAG_NO_SSL_INIT) == 0)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STD_CLIENT) != 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we already have a connection to be served */
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen const char *value = getenv(DOVECOT_PRESERVE_ENVS_ENV);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen value = t_strconcat(value, " "DOVECOT_PRESERVE_ENVS_ENV, NULL);
d5eb47a791ec56149fd711cd8e44efc8babeaae5Timo Sirainen env_clean_except(t_strsplit_spaces(value, " "));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_client_limit(struct master_service *service,
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen unsigned int used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->master_status.available_count ==
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->total_available_count = client_limit;
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen service->master_status.available_count = client_limit - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_client_limit(struct master_service *service)
1ffb2afe6d7e8860a2231a4827078cf2ef9c22cdTimo Sirainenunsigned int master_service_get_process_limit(struct master_service *service)
d4845c4245638fd6f02dc0cb92c3465fae763cbbTimo Sirainenunsigned int master_service_get_process_min_avail(struct master_service *service)
0161376aac025266d8654577c4b9ce371ffc87eaTimo Sirainenunsigned int master_service_get_idle_kill_secs(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_set_service_count(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int count)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->master_status.available_count = count - used;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_service_count(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenunsigned int master_service_get_socket_count(struct master_service *service)
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainenconst char *master_service_get_socket_name(struct master_service *service,
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen unsigned int i;
7f1b897201d80c83c96b0d663f2a14c517d48f14Timo Sirainen i_assert(listen_fd >= MASTER_LISTEN_FD_FIRST);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenvoid master_service_set_avail_overflow_callback(struct master_service *service,
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen void (*callback)(void))
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_config_path(struct master_service *service)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenconst char *master_service_get_version_string(struct master_service *service)
b2d562f9c7fd13f9a16e9b3bcee904630b80b1feTimo Sirainenconst char *master_service_get_name(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_run(struct master_service *service,
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen master_service_connection_callback_t *callback)
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_stop(struct master_service *service)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainenvoid master_service_stop_new_connections(struct master_service *service)
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen /* make sure we stop after servicing current connections */
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen current_count = service->total_available_count -
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen service->total_available_count = current_count;
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen /* notify master that we're not accepting any more
275385a2ecc58e41dc7df3ce3cd943caaa58c4d1Timo Sirainen connections */
71df09024cea5f2faa93da3bb9513ee96ba6bf22Timo Sirainenbool master_service_is_killed(struct master_service *service)
57397188558fcd1a9e24dbbbd2952eac9c45c20dTimo Sirainenbool master_service_is_master_stopped(struct master_service *service)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenvoid master_service_anvil_send(struct master_service *service, const char *cmd)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_STANDALONE) != 0)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen ret = write(MASTER_ANVIL_FD, cmd, strlen(cmd));
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen /* anvil process was probably recreated, don't bother
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen logging an error about losing connection to it */
1bea4b9c24fbe2b457950c09cf072292a6701cffTimo Sirainen } else if (ret == 0)
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainenvoid master_service_client_connection_created(struct master_service *service)
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen i_assert(service->master_status.available_count > 0);
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenvoid master_service_client_connection_handled(struct master_service *service,
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen i_error("close(service connection) failed: %m");
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen master_service_client_connection_destroyed(service);
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen /* reading FIFOs stays open forever, don't count them
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen as real clients */
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen master_service_client_connection_destroyed(service);
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen if (service->master_status.available_count == 0 &&
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen /* we're not going to accept any more connections after this.
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen go ahead and close the connection early. don't do this
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen before calling callback, because it may want to access
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen the listen_fd (e.g. to check socket permissions). */
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainenvoid master_service_client_connection_callback(struct master_service *service,
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen master_service_client_connection_handled(service, conn);
db693bf6fcae96d834567f1782257517b7207655Timo Sirainenvoid master_service_client_connection_accept(struct master_service_connection *conn)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid master_service_client_connection_destroyed(struct master_service *service)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen /* we can listen again */
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen if (service->service_count_left == service->total_available_count) {
885e1b36da370a674c0fd3b85db53740d7dcbd9bTimo Sirainen i_assert(service->master_status.available_count <
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen i_assert(service->master_status.available_count ==
de70a6f77fc3b350eeee4e2a0d29dd07ddde431bTimo Sirainen } else if ((service->io_status_error == NULL ||
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen /* we've finished handling all clients, and
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen a) master has closed the connection
c668292359474a4aa8c608b30a858337fa3fc813Timo Sirainen b) there are no listeners (std-client?) */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void master_service_set_login_state(struct master_service *service,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->master_status.available_count > 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* some processes should now be able to handle new connections,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen although we can't. but there may be race conditions, so
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen make sure that we'll check again soon if the state has
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen changed to "full" without our knowledge. */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen /* make sure we're listening for more connections */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen i_error("Invalid master login state: %d", state);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic void master_service_refresh_login_state(struct master_service *service)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen ret = lseek(MASTER_LOGIN_NOTIFY_FD, 0, SEEK_CUR);
3ba9a079592f46e94ce846e5aa80e4d479cd5e41Timo Sirainenvoid master_service_close_config_fd(struct master_service *service)
6a6e3c2538a08cc4880a8db7e0a9a3392122ea04Timo Sirainen i_error("close(master config fd) failed: %m");
8d3278a82b964217d95c340ec6f82037cdc59d19Timo Sirainenvoid master_service_deinit(struct master_service **_service)
d39a04db2f4d0599cb9b5f03a9aa10a3c234453cTimo Sirainen if (array_is_created(&service->config_overrides))
41789540204ce091b2c06629d9a31788082e5da8Timo Sirainen /* run atexit callbacks before destroying ioloop */
0c96e2994ab4e25c9042ce21e9d39ca5054df3b6Timo Sirainen p_strsplit_free(default_pool, service->listener_names);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void master_service_listen(struct master_service_listener *l)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->master_status.available_count == 0) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* we are full. stop listening for now, unless overflow
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen callback destroys one of the existing connections */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->master_status.available_count == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen conn.fd = net_accept(l->fd, &conn.remote_ip, &conn.remote_port);
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* it's not a socket. should be a fifo. */
56ba5a9b62e3ce527e898a8fe3b1a015ab30ed54Timo Sirainen (fstat(l->fd, &st) == 0 && S_ISFIFO(st.st_mode))) {
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* BSDI fails accept(fifo) with EINVAL. */
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen /* try again later after one of the existing
5ff22d69989a3ccc2d947164e47996f720d493d8Timo Sirainen connections has died */
835ba470fb6a73b74e258e12678236106d0df09eTimo Sirainen /* use the "listener" as the connection fd and stop the
21e6b4fd844fd074583b17f09e1f27b9835ee238Timo Sirainen master_service_client_connection_created(service);
8ab32a83ca0ead65c5670f337ca3a4d7a0fd0ed1Timo Sirainen master_service_client_connection_callback(service, &conn);
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainenstatic void io_listeners_init(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_new(struct master_service_listener, service->socket_count);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct master_service_listener *l = &service->listeners[i];
7487ff578435377bbeefffdbfb78ca09ed1292dfTimo Sirainen if (i >= service->socket_count - service->ssl_socket_count)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenvoid master_service_io_listeners_add(struct master_service *service)
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen unsigned int i;
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen struct master_service_listener *l = &service->listeners[i];
2ac0a22865272cb4311a1bd09eb69b475625b3ebTimo Sirainen l->io = io_add(MASTER_LISTEN_FD_FIRST + i, IO_READ,
442232f2d1cfdf28f3a18aa00a5c19246d321036Timo Sirainenvoid master_service_io_listeners_remove(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen unsigned int i;
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainenvoid master_service_ssl_io_listeners_remove(struct master_service *service)
f29756821a4c6b12b73e4a2a3e1c230117a43773Timo Sirainen unsigned int i;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainenstatic void master_service_io_listeners_close(struct master_service *service)
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen unsigned int i;
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen /* close via listeners. some fds might be pipes that are
bd20ef9d5c639faf470912ab94e6e6627d3eaebaTimo Sirainen currently handled as clients. we don't want to close them. */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic bool master_status_update_is_important(struct master_service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->master_status.available_count == 0)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainenmaster_status_send(struct master_service *service, bool important_update)
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen ret = write(MASTER_STATUS_FD, &service->master_status,
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* success */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* delayed important update sent successfully */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen } else if (ret >= 0) {
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* shouldn't happen? */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen i_error("write(master_status_fd) returned %d", (int)ret);
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* failure */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen i_error("write(master_status_fd) failed: %m");
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen /* reader is busy, but it's important to get this notification
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen through. send it when possible. */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainenvoid master_status_update(struct master_service *service)
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen if ((service->flags & MASTER_SERVICE_FLAG_UPDATE_PROCTITLE) != 0 &&
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen service->set != NULL && service->set->verbose_proctitle) T_BEGIN {
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen unsigned int used_count = service->total_available_count -
e2bdca8201e4aa1cd31332ffbdd4c6eef9151d5eTimo Sirainen process_title_set(t_strdup_printf("[%u connections]",
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen important_update = master_status_update_is_important(service);
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* a) closed, b) updating to same state */
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen if (ioloop_time == service->last_sent_status_time &&
2037c54ef0239bf7814badab08fc15f945f560fbTimo Sirainen /* don't spam master */
b17d7bbd284df42e6aeb74f8de0f73ee07cfccb6Timo Sirainen master_status_send(service, important_update);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainenbool version_string_verify(const char *line, const char *service_name,
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainen return version_string_verify_full(line, service_name,
6303f32ad4af9cb08794561e6324df1c6c5fb637Timo Sirainenbool version_string_verify_full(const char *line, const char *service_name,
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen unsigned int service_name_len = strlen(service_name);
f158d9a303bb15a6848ca276c9391c7ca52e452bTimo Sirainen if (strncmp(line, service_name, service_name_len) != 0 ||