service-monitor.c revision 9cd232cda7563ad81c01776e5ebc5ed2b3cef898
e59faf65ce864fe95dc00f5d52b8323cdbd0608aTimo Sirainen/* Copyright (c) 2005-2010 Dovecot authors, see the included COPYING file */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "common.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "array.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "ioloop.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "fd-close-on-exec.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "hash.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "str.h"
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen#include "safe-mkstemp.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-process.h"
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen#include "service-process-notify.h"
fb08a91e3f2949ecefb647fa38206ca9aad5307fTimo Sirainen#include "service-anvil.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-log.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include "service-monitor.h"
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen#include <stdlib.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <unistd.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <sys/wait.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen#include <syslog.h>
d0720f3037064af4b92eccfc20a8814adcacf827Timo Sirainen#include <signal.h>
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen#define SERVICE_PROCESS_KILL_IDLE_MSECS (1000*60)
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen#define SERVICE_STARTUP_FAILURE_THROTTLE_SECS 60
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen#define SERVICE_DROP_WARN_INTERVAL_SECS 60
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainenstatic void service_monitor_start_extra_avail(struct service *service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainenstatic void service_process_kill_idle(struct service_process *process)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen{
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen struct service *service = process->service;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
c0e5c6a86e1de5d4f5591d39b4aa921a23c807d7Timo Sirainen if (service->process_avail <= service->set->process_min_avail) {
c0e5c6a86e1de5d4f5591d39b4aa921a23c807d7Timo Sirainen /* we don't have any extra idling processes anymore. */
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen timeout_remove(&process->to_idle);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen } else {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (kill(process->pid, SIGINT) < 0 && errno != ESRCH) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen service_error(service, "kill(%s, SIGINT) failed: %m",
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen dec2str(process->pid));
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen}
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainenstatic void service_status_more(struct service_process *process,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen const struct master_status *status)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen{
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen struct service *service = process->service;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen process->total_count +=
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen process->available_count - status->available_count;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen process->idle_start = 0;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (process->to_idle != NULL)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen timeout_remove(&process->to_idle);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (status->available_count != 0)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen return;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen /* process used up all of its clients */
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen i_assert(service->process_avail > 0);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen service->process_avail--;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->type == SERVICE_TYPE_LOGIN &&
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service->process_avail == 0 &&
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service->process_count == service->process_limit)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service_login_notify(service, TRUE);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen /* we may need to start more */
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen service_monitor_start_extra_avail(service);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen service_monitor_listen_start(service);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen}
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainenstatic void service_status_less(struct service_process *process,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen const struct master_status *status)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen{
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen struct service *service = process->service;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (process->available_count == 0) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen /* process can accept more clients again */
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (service->process_avail++ == 0)
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen service_monitor_listen_stop(service);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen i_assert(service->process_avail <= service->process_count);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (status->available_count == service->client_limit) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen process->idle_start = ioloop_time;
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen if (service->process_avail > service->set->process_min_avail &&
c0e5c6a86e1de5d4f5591d39b4aa921a23c807d7Timo Sirainen process->to_idle == NULL &&
c0e5c6a86e1de5d4f5591d39b4aa921a23c807d7Timo Sirainen service->type != SERVICE_TYPE_ANVIL) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen /* we have more processes than we really need.
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen add a bit of randomness so that we don't send the
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen signal to all of them at once */
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen process->to_idle =
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen timeout_add(SERVICE_PROCESS_KILL_IDLE_MSECS +
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen (rand() % 100)*10,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen service_process_kill_idle,
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen process);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->type == SERVICE_TYPE_LOGIN)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service_login_notify(service, FALSE);
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen}
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainenstatic void
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainenservice_status_input_one(struct service *service,
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen const struct master_status *status)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_process *process;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen process = hash_table_lookup(service_pids, &status->pid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we've probably wait()ed it away already. ignore */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (process->uid != status->uid || process->service != service) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* a) Process was closed and another process was created with
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen the same PID, but we're still receiving status update from
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen the old process.
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen b) Some process is trying to corrupt our internal state by
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen trying to pretend to be someone else. We could use stronger
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen randomness here, but the worst they can do is DoS and there
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen are already more serious problems if someone is able to do
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen this.. */
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "Ignoring invalid update from child %s "
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen "(UID=%u)", dec2str(status->pid), status->uid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process->to_status != NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* first status notification */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&process->to_status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (process->available_count == status->available_count)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (process->available_count > status->available_count) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen /* process started servicing some more clients */
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen service_status_more(process, status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen /* process finished servicing some clients */
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen service_status_less(process, status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen process->available_count = status->available_count;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen}
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainenstatic void service_status_input(struct service *service)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen{
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen struct master_status status[1024/sizeof(struct master_status)];
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen unsigned int i, count;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen ssize_t ret;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen ret = read(service->status_fd[0], &status, sizeof(status));
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (ret <= 0) {
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if (ret == 0)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen service_error(service, "read(status) failed: EOF");
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen else
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen service_error(service, "read(status) failed: %m");
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen service_monitor_stop(service);
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen return;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen }
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen if ((ret % sizeof(struct master_status)) != 0) {
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen service_error(service, "service sent partial status update "
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen "(%d bytes)", (int)ret);
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen return;
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen }
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen count = ret / sizeof(struct master_status);
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen for (i = 0; i < count; i++)
9cd232cda7563ad81c01776e5ebc5ed2b3cef898Timo Sirainen service_status_input_one(service, &status[i]);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_monitor_throttle(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->to_throttle != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service, "command startup failed, throttling");
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen service_throttle(service, SERVICE_STARTUP_FAILURE_THROTTLE_SECS);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainenstatic void service_drop_connections(struct service *service)
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen{
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->last_drop_warning +
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen SERVICE_DROP_WARN_INTERVAL_SECS < ioloop_time) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service->last_drop_warning = ioloop_time;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen i_warning("service(%s): process_limit reached, "
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen "client connections are being dropped",
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service->set->name);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service->listen_pending = TRUE;
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service_monitor_listen_stop(service);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->type == SERVICE_TYPE_LOGIN) {
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen /* reached process limit, notify processes that they
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen need to start killing existing connections if they
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen reach connection limit */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service_login_notify(service, TRUE);
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen }
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen}
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenstatic void service_accept(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_assert(service->process_avail == 0);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->process_count == service->process_limit) {
d8552f9f65e5ff64be5de9faf9a8171799a0bbecTimo Sirainen /* we've reached our limits, new clients will have to
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen wait until there are more processes available */
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service_drop_connections(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen return;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* create a child process and let it accept() this connection */
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service_process_create(service) == NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_monitor_throttle(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen else
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_monitor_listen_stop(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainenstatic void service_monitor_start_extra_avail(struct service *service)
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen{
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen unsigned int i, count;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (service->process_avail >= service->set->process_min_avail)
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen return;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen count = service->set->process_min_avail - service->process_avail;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (service->process_count + count > service->process_limit)
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen count = service->process_limit - service->process_count;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen for (i = 0; i < count; i++) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service_process_create(service) == NULL) {
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen service_monitor_throttle(service);
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen break;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen }
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen }
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen if (i > 0 && service->listening) {
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen /* we created some processes, they'll do the listening now */
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen service_monitor_listen_stop(service);
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen }
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen}
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainenvoid service_monitor_listen_start(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen if (service->process_avail > 0 ||
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen (service->process_count == service->process_limit &&
6fdfa4d4cf14d1d7764d7faa8258f112e39c8dbeTimo Sirainen service->listen_pending))
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen return;
cdc8485491045d82bb98405d4b995f277d12838eTimo Sirainen
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen service->listening = TRUE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service->listen_pending = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service->listeners, listeners) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct service_listener *l = *listeners;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (l->io == NULL && l->fd != -1)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen l->io = io_add(l->fd, IO_READ, service_accept, service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainenvoid service_monitor_listen_stop(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_listener *const *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service->listeners, listeners) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct service_listener *l = *listeners;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (l->io != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_remove(&l->io);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainen service->listening = FALSE;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainenstatic int service_login_create_notify_fd(struct service *service)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen{
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen int fd;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->login_notify_fd != -1)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen T_BEGIN {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen string_t *prefix = t_str_new(128);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen const char *path;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen str_append(prefix, "/tmp/dovecot-master");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen fd = safe_mkstemp(prefix, 0600, (uid_t)-1, (gid_t)-1);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen path = str_c(prefix);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (fd == -1) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service_error(service, "safe_mkstemp(%s) failed: %m",
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen path);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else if (unlink(path) < 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service_error(service, "unlink(%s) failed: %m", path);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } else {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen fd_close_on_exec(fd, TRUE);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service->login_notify_fd = fd;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen } T_END;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (fd != service->login_notify_fd)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen (void)close(fd);
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen return fd == -1 ? -1 : 0;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen}
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid services_monitor_start(struct service_list *service_list)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *const *services;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services_log_init(service_list);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen service_anvil_monitor_start(service_list);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service_list->services, services) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen struct service *service = *services;
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (service->type == SERVICE_TYPE_LOGIN) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (service_login_create_notify_fd(service) < 0)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen continue;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (service->status_fd[0] == -1) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* we haven't yet created status pipe */
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (pipe(service->status_fd) < 0) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen service_error(service, "pipe() failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen net_set_nonblock(service->status_fd[0], TRUE);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen fd_close_on_exec(service->status_fd[0], TRUE);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen net_set_nonblock(service->status_fd[1], TRUE);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen fd_close_on_exec(service->status_fd[1], TRUE);
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen }
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen if (service->io_status == NULL) {
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen service->io_status =
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen io_add(service->status_fd[0], IO_READ,
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen service_status_input, service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen service_monitor_start_extra_avail(service);
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen service_monitor_listen_start(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service_process_create(service_list->log) != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_monitor_listen_stop(service_list->log);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
b2ed2b25c4c457ec1c99ebe5e9bd66a2e2f89cfdTimo Sirainenvoid service_monitor_stop(struct service *service)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int i;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->io_status != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen io_remove(&service->io_status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (service->status_fd[0] != -1 &&
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen service->type != SERVICE_TYPE_ANVIL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen for (i = 0; i < 2; i++) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (close(service->status_fd[i]) < 0) {
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service_error(service,
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen "close(status fd) failed: %m");
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
55bc6a7a0940ec48a68558ef70838991c5d301d2Timo Sirainen service->status_fd[i] = -1;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->login_notify_fd != -1) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (close(service->login_notify_fd) < 0) {
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service_error(service,
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen "close(login notify fd) failed: %m");
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen service->login_notify_fd = -1;
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen }
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen if (service->to_login_notify != NULL)
cf0ad1a0bddb0787f3d7b408a96d721a8b2a98a3Timo Sirainen timeout_remove(&service->to_login_notify);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_monitor_listen_stop(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->to_throttle != NULL)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen timeout_remove(&service->to_throttle);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainenvoid services_monitor_stop(struct service_list *service_list)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *const *services;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen array_foreach(&service_list->services, services)
7bd72e4deca3cbf757dd1ea298486d9f3bc24226Timo Sirainen service_monitor_stop(*services);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen services_log_deinit(service_list);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainenstatic void service_process_failure(struct service_process *process, int status)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen{
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen struct service *service = process->service;
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen service_process_log_status_error(process, status);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen if (process->total_count == 0)
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen service_monitor_throttle(service);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen service_process_notify_add(service_anvil_global->kills, process);
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen}
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainenvoid services_monitor_reap_children(void)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen{
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service_process *process;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen struct service *service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen pid_t pid;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen int status;
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen bool service_stopped;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen while ((pid = waitpid(-1, &status, WNOHANG)) > 0) {
bad5fa318c6c1384ab83bd72d53ce06593274c18Timo Sirainen process = hash_table_lookup(service_pids, &pid);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (process == NULL) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen i_error("waitpid() returned unknown PID %s",
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen dec2str(pid));
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen continue;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service = process->service;
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (status == 0) {
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen /* success */
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen if (service->listen_pending)
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_monitor_listen_start(service);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen } else {
6c2ce1d5bf17b21e804a079eb0f973b7ab83e0d8Timo Sirainen service_process_failure(process, status);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen service_stopped = service->status_fd[0] == -1;
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen if (service->type == SERVICE_TYPE_ANVIL)
4f4943f6ef1bc45c23de73eebe83779712b3c8cbTimo Sirainen service_anvil_process_destroyed(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen service_process_destroy(process);
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen
601b455f4d5e780044b9e4fac5f687c1b07ae145Timo Sirainen if (!service_stopped) {
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen service_monitor_start_extra_avail(service);
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen if (service->to_throttle == NULL)
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen service_monitor_listen_start(service);
3b959c98e05e780de2a063a4a9d8d393dc61ed58Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen }
d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76Timo Sirainen}