Mercurial > masqmail
view src/listen.c @ 0:08114f7dcc23 0.2.21
this is masqmail-0.2.21 from oliver kurth
author | meillo@marmaro.de |
---|---|
date | Fri, 26 Sep 2008 17:05:23 +0200 (2008-09-26) |
parents | |
children | 26e34ae9a3e3 |
line wrap: on
line source
/* MasqMail Copyright (C) 1999/2000 Oliver Kurth This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "masqmail.h" #include <sys/wait.h> #include <sys/types.h> static int volatile sighup_seen = 0; static void sighup_handler(int sig) { sighup_seen = 1; signal(SIGHUP, sighup_handler); } static void sigchld_handler(int sig) { pid_t pid; int status; pid = waitpid(0, &status, 0); if(pid > 0){ if(WEXITSTATUS(status) != EXIT_SUCCESS) logwrite(LOG_WARNING, "process %d exited with %d\n", pid, WEXITSTATUS(status)); if(WIFSIGNALED(status)) logwrite(LOG_WARNING, "process with pid %d got signal: %d\n", pid, WTERMSIG(status)); } signal(SIGCHLD, sigchld_handler); } #ifdef ENABLE_SMTP_SERVER void accept_connect(int listen_sock, int sock, struct sockaddr_in* sock_addr) { pid_t pid; int dup_sock = dup(sock); FILE *out, *in; gchar *rem_host; gchar *ident = NULL; rem_host = g_strdup(inet_ntoa(sock_addr->sin_addr)); #ifdef ENABLE_IDENT { gchar *id = NULL; if((id = (gchar *)ident_id(sock, 60))){ ident = g_strdup(id); } logwrite(LOG_NOTICE, "connect from host %s, port %hd ident=%s\n", rem_host, ntohs (sock_addr->sin_port), ident ? ident : "(unknown)"); } #else logwrite(LOG_NOTICE, "connect from host %s, port %hd\n", rem_host, ntohs (sock_addr->sin_port)); #endif // start child for connection: signal(SIGCHLD, sigchld_handler); pid = fork(); if(pid == 0){ close(listen_sock); out = fdopen(sock, "w"); in = fdopen(dup_sock, "r"); smtp_in(in, out, rem_host, ident); _exit(EXIT_SUCCESS); }else if(pid < 0){ logwrite(LOG_WARNING, "could not fork for incoming smtp connection: %s\n", strerror(errno)); } #ifdef ENABLE_IDENT if(ident != NULL) g_free(ident); #endif close(sock); close(dup_sock); } #endif /*ifdef ENABLE_SMTP_SERVER*/ void listen_port(GList *iface_list, gint qival, char *argv[]) { int i; fd_set active_fd_set, read_fd_set; struct timeval tm; time_t time_before, time_now; struct sockaddr_in clientname; size_t size; GList *node, *node_next; int sel_ret; /* Create the sockets and set them up to accept connections. */ FD_ZERO (&active_fd_set); #ifdef ENABLE_SMTP_SERVER for(node = g_list_first(iface_list); node; node = node_next){ interface *iface = (interface *)(node->data); int sock; node_next=g_list_next(node); if ((sock = make_server_socket (iface))<0){ iface_list= g_list_remove_link(iface_list, node); g_list_free_1(node); continue; } if (listen (sock, 1) < 0){ logwrite(LOG_ALERT, "listen: (terminating): %s\n", strerror(errno)); exit (EXIT_FAILURE); } logwrite(LOG_NOTICE, "listening on interface %s:%d\n", iface->address, iface->port); DEBUG(5) debugf("sock = %d\n", sock); FD_SET (sock, &active_fd_set); } #endif /* setup handler for HUP signal: */ signal(SIGHUP, sighup_handler); signal(SIGCHLD, sigchld_handler); /* now that we have our socket(s), we can give up root privileges */ if(!conf.run_as_user){ if(setegid(conf.mail_gid) != 0){ logwrite(LOG_ALERT, "could not change gid to %d: %s\n", conf.mail_gid, strerror(errno)); exit(EXIT_FAILURE); } if(seteuid(conf.mail_uid) != 0){ logwrite(LOG_ALERT, "could not change uid to %d: %s\n", conf.mail_uid, strerror(errno)); exit(EXIT_FAILURE); } } /* sel_ret = 0;*/ time(&time_before); time_before -= qival; sel_ret = -1; while (1){ /* if we were interrupted by an incoming connection (or a signal) we have to recalculate the time until the next queue run should occur. select may put a value into tm, but doc for select() says we should not use it.*/ if(qival > 0){ time(&time_now); if(sel_ret == 0){ /* we are either just starting or did a queue run */ tm.tv_sec = qival; tm.tv_usec = 0; time_before = time_now; }else{ tm.tv_sec = qival - (time_now - time_before); tm.tv_usec = 0; /* race condition, very unlikely (but possible): */ if(tm.tv_sec < 0) tm.tv_sec = 0; } } /* Block until input arrives on one or more active sockets, or signal arrives, or queuing interval time elapsed (if qival > 0) */ read_fd_set = active_fd_set; if ((sel_ret = select(FD_SETSIZE, &read_fd_set, NULL, NULL, qival > 0 ? &tm : NULL)) < 0){ if(errno != EINTR){ logwrite(LOG_ALERT, "select: (terminating): %s\n", strerror(errno)); exit (EXIT_FAILURE); }else{ if(sighup_seen){ logwrite(LOG_NOTICE, "HUP signal received. Restarting daemon\n"); for(i = 0; i < FD_SETSIZE; i++) if(FD_ISSET(i, &active_fd_set)) close(i); execv(argv[0], &(argv[0])); logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno)); exit(EXIT_FAILURE); } } } else if(sel_ret > 0){ #ifdef ENABLE_SMTP_SERVER for(i = 0; i < FD_SETSIZE; i++){ if (FD_ISSET (i, &read_fd_set)){ int sock = i; int new; size = sizeof (clientname); new = accept (sock, (struct sockaddr *) &clientname, &size); if (new < 0){ logwrite(LOG_ALERT, "accept: (ignoring): %s\n", strerror(errno)); }else accept_connect(sock, new, &clientname); } } #else ; #endif }else{ /* If select returns 0, the interval time has elapsed. We start a new queue runner process */ int pid; signal(SIGCHLD, sigchld_handler); if((pid = fork()) == 0){ queue_run(); _exit(EXIT_SUCCESS); } else if(pid < 0){ logwrite(LOG_ALERT, "could not fork for queue run"); } } } }