Mercurial > dovecot > core-2.2
diff src/lmtp/main.c @ 9121:a957a6be4af5 HEAD
Initial implementation of LMTP server. Master process doesn't yet execute it though.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Thu, 16 Apr 2009 18:12:30 -0400 |
parents | |
children | 6324a79d3ee1 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lmtp/main.c Thu Apr 16 18:12:30 2009 -0400 @@ -0,0 +1,182 @@ +/* Copyright (c) 2002-2009 Dovecot authors, see the included COPYING file */ + +#include "lib.h" +#include "array.h" +#include "ioloop.h" +#include "restrict-access.h" +#include "fd-close-on-exec.h" +#include "process-title.h" +#include "master-service.h" +#include "mail-storage-service.h" +#include "lda-settings.h" +#include "client.h" +#include "main.h" + +#include <stdlib.h> +#include <unistd.h> + +#define LMTP_MASTER_FIRST_LISTEN_FD 3 + +#define IS_STANDALONE() \ + (getenv("MASTER_SERVICE") == NULL) + +struct lmtp_listener { + int fd; + struct io *io; +}; + +struct master_service *service; +struct mail_storage_service_multi_ctx *multi_service; + +static struct io *log_io = NULL; +static ARRAY_DEFINE(listeners, struct lmtp_listener *); + +static void log_error_callback(void *context ATTR_UNUSED) +{ + /* the log fd is closed, don't die when trying to log later */ + i_set_failure_ignore_errors(TRUE); + + master_service_stop(service); +} + +static void listen_connected(struct lmtp_listener *l) +{ + struct client *client; + struct ip_addr remote_ip; + unsigned int remote_port; + int fd; + + fd = net_accept(l->fd, &remote_ip, &remote_port); + if (fd < 0) { + if (fd < -1) + i_error("accept() failed: %m"); + return; + } + client = client_create(fd, fd); + client->remote_ip = remote_ip; + client->remote_port = remote_port; + + (void)net_getsockname(fd, &client->local_ip, &client->local_port); +} + +static void listen_start(void) +{ + struct lmtp_listener *const *l; + unsigned int i, count; + + l = array_get(&listeners, &count); + for (i = 0; i < count; i++) { + i_assert(l[i]->io == NULL); + l[i]->io = io_add(l[i]->fd, IO_READ, listen_connected, l[i]); + } +} + +static void listen_stop(void) +{ + struct lmtp_listener *const *l; + unsigned int i, count; + + l = array_get(&listeners, &count); + for (i = 0; i < count; i++) { + i_assert(l[i]->io != NULL); + io_remove(&l[i]->io); + } +} + +static void listen_free(void) +{ + struct lmtp_listener **l; + unsigned int i, count; + + l = array_get_modifiable(&listeners, &count); + for (i = 0; i < count; i++) { + if (l[i]->io != NULL) + io_remove(&l[i]->io); + i_free(l[i]); + } + array_free(&listeners); +} + +void listener_client_destroyed(void) +{ + if (array_count(&listeners) == 0) + master_service_stop(service); +} + +static void main_init(void) +{ + struct lmtp_listener *l; + const char *value; + unsigned int i, count; + + /* If master dies, the log fd gets closed and we'll quit */ + log_io = io_add(STDERR_FILENO, IO_ERROR, log_error_callback, NULL); + + value = getenv("LISTEN_FDS"); + count = value == NULL ? 0 : atoi(value); + i_array_init(&listeners, count + 1); + for (i = 0; i < count; i++) { + l = i_new(struct lmtp_listener, 1); + l->fd = LMTP_MASTER_FIRST_LISTEN_FD + i; + array_append(&listeners, &l, 1); + } + + if (count == 0) + (void)client_create(STDIN_FILENO, STDOUT_FILENO); + else + listen_start(); +} + +static void main_deinit(void) +{ + if (log_io != NULL) + io_remove(&log_io); + clients_destroy(); + listen_free(); +} + +int main(int argc, char *argv[], char *envp[]) +{ + const struct setting_parser_info *set_roots[] = { + &lda_setting_parser_info, + NULL + }; + enum master_service_flags service_flags = 0; + enum mail_storage_service_flags storage_service_flags = + MAIL_STORAGE_SERVICE_FLAG_DISALLOW_ROOT | + MAIL_STORAGE_SERVICE_FLAG_USERDB_LOOKUP; + int c; + +#ifdef DEBUG + if (!IS_STANDALONE() && getenv("GDB") == NULL) { + const char *env; + + env = getenv("LISTEN_FDS"); + fd_debug_verify_leaks(LMTP_MASTER_FIRST_LISTEN_FD + + (env == NULL ? 0 : atoi(env)), 1024); + } +#endif + + if (IS_STANDALONE()) + service_flags |= MASTER_SERVICE_FLAG_STANDALONE; + + service = master_service_init("lmtp", service_flags, argc, argv); + while ((c = getopt(argc, argv, master_service_getopt_string())) > 0) { + if (!master_service_parse_option(service, c, optarg)) + i_fatal("Unknown argument: %c", c); + } + + multi_service = mail_storage_service_multi_init(service, set_roots, + storage_service_flags); + restrict_access_allow_coredumps(TRUE); + + process_title_init(argv, envp); + + main_init(); + master_service_run(service); + + main_deinit(); + mail_storage_service_multi_deinit(&multi_service); + master_service_deinit(&service); + return 0; +}