service-monitor.c revision d176f84ce5ca2073f4dfbafb457b9c74f6bf0d76
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes/* Copyright (c) 2005-2009 Dovecot authors, see the included COPYING file */
70953fb44a7140fe206c3a5f011e24209c8c5c6abnicholesstatic void service_monitor_stop(struct service *service);
70953fb44a7140fe206c3a5f011e24209c8c5c6abnicholesstatic void service_monitor_listen_start(struct service *service);
16b55a35cff91315d261d1baa776138af465c4e4fuankgstatic void service_monitor_listen_stop(struct service *service);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholesstatic void service_status_input(struct service *service)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes ret = read(service->status_fd[0], &status, sizeof(status));
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes i_error("service(%s): read(status) failed: EOF", service->name);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes i_error("service(%s): read(status) failed: %m", service->name);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes i_error("service(%s): child %s sent partial status update "
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes case sizeof(status):
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes process = hash_table_lookup(service->list->pids, &status.pid);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes /* we've probably wait()ed it away already. ignore */
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes if (process->uid != status.uid || process->service != service) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes /* a) Process was closed and another process was created with
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes the same PID, but we're still receiving status update from
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg the old process.
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes b) Some process is trying to corrupt our internal state by
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes trying to pretend to be someone else. We could use stronger
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes randomness here, but the worst they can do is DoS and there
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes are already more serious problems if someone is able to do
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes i_error("service(%s): Ignoring invalid update from child %s "
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg /* first status notification */
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes if (process->available_count == status.available_count)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes if (process->available_count > status.available_count) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes /* process started servicing requests */
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes process->available_count - status.available_count;
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes /* process finished servicing requests */
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg if (status.available_count == service->set->client_limit)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes process->available_count = status.available_count;
405f61494d3ed3ca9c054dacc05a53513e172145bnicholesstatic void service_throttle_timeout(struct service *service)
ac7985784d08a3655291f24f711812b4d8b1cbcffuankgstatic void service_monitor_throttle(struct service *service)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes i_error("service(%s): command startup failed, throttling",
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes service->to_throttle = timeout_add(THROTTLE_TIMEOUT,
405f61494d3ed3ca9c054dacc05a53513e172145bnicholesstatic void service_accept(struct service *service)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes if (service->process_count == service->process_limit) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes /* we've reached our limits, new connections will have to
0662ed52e814f8f08ef0e09956413a792584eddffuankg wait until there are more processes available */
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes /* create a child process and let it accept() this connection */
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes if (service_process_create(service, NULL, -1, NULL, 0) == NULL)
ac7985784d08a3655291f24f711812b4d8b1cbcffuankgstatic void service_monitor_listen_start(struct service *service)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes unsigned int i, count;
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes listeners = array_get(&service->listeners, &count);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes for (i = 0; i < count; i++) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes if (listeners[i]->io == NULL && listeners[i]->fd != -1) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes listeners[i]->io = io_add(listeners[i]->fd, IO_READ,
405f61494d3ed3ca9c054dacc05a53513e172145bnicholesstatic void service_monitor_listen_stop(struct service *service)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes unsigned int i, count;
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes listeners = array_get(&service->listeners, &count);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes for (i = 0; i < count; i++) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholesvoid services_monitor_start(struct service_list *service_list)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes unsigned int i, count;
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes services = array_get(&service_list->services, &count);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes for (i = 0; i < count; i++) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes /* we haven't yet created status pipe */
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes net_set_nonblock(services[i]->status_fd[0], TRUE);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes net_set_nonblock(services[i]->status_fd[1], TRUE);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes fd_close_on_exec(services[i]->status_fd[1], TRUE);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes if (service_process_create(service_list->log, NULL, -1, NULL, 0) != NULL)
8ffac2c334103c0336602aaede650cb578611151fuankg if (service_process_create(service_list->config, NULL, -1, NULL, 0) != NULL)
ac7985784d08a3655291f24f711812b4d8b1cbcffuankgstatic void service_monitor_stop(struct service *service)
ac7985784d08a3655291f24f711812b4d8b1cbcffuankg for (i = 0; i < 2; i++) {
405f61494d3ed3ca9c054dacc05a53513e172145bnicholesvoid services_monitor_stop(struct service_list *service_list)
0662ed52e814f8f08ef0e09956413a792584eddffuankg unsigned int i, count;
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes services = array_get(&service_list->services, &count);
405f61494d3ed3ca9c054dacc05a53513e172145bnicholes for (i = 0; i < count; i++)
405f61494d3ed3ca9c054dacc05a53513e172145bnicholesvoid services_monitor_reap_children(struct service_list *service_list)
if (status == 0) {