masqmail
diff src/listen.c @ 0:08114f7dcc23
this is masqmail-0.2.21 from oliver kurth
author | meillo@marmaro.de |
---|---|
date | Fri, 26 Sep 2008 17:05:23 +0200 |
parents | |
children | 26e34ae9a3e3 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/listen.c Fri Sep 26 17:05:23 2008 +0200 1.3 @@ -0,0 +1,243 @@ 1.4 +/* MasqMail 1.5 + Copyright (C) 1999/2000 Oliver Kurth 1.6 + 1.7 + This program is free software; you can redistribute it and/or modify 1.8 + it under the terms of the GNU General Public License as published by 1.9 + the Free Software Foundation; either version 2 of the License, or 1.10 + (at your option) any later version. 1.11 + 1.12 + This program is distributed in the hope that it will be useful, 1.13 + but WITHOUT ANY WARRANTY; without even the implied warranty of 1.14 + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1.15 + GNU General Public License for more details. 1.16 + 1.17 + You should have received a copy of the GNU General Public License 1.18 + along with this program; if not, write to the Free Software 1.19 + Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 1.20 +*/ 1.21 + 1.22 +#include "masqmail.h" 1.23 +#include <sys/wait.h> 1.24 +#include <sys/types.h> 1.25 + 1.26 +static int volatile sighup_seen = 0; 1.27 + 1.28 +static 1.29 +void sighup_handler(int sig) 1.30 +{ 1.31 + sighup_seen = 1; 1.32 + signal(SIGHUP, sighup_handler); 1.33 +} 1.34 + 1.35 +static 1.36 +void sigchld_handler(int sig) 1.37 +{ 1.38 + pid_t pid; 1.39 + int status; 1.40 + 1.41 + pid = waitpid(0, &status, 0); 1.42 + if(pid > 0){ 1.43 + if(WEXITSTATUS(status) != EXIT_SUCCESS) 1.44 + logwrite(LOG_WARNING, "process %d exited with %d\n", 1.45 + pid, WEXITSTATUS(status)); 1.46 + if(WIFSIGNALED(status)) 1.47 + logwrite(LOG_WARNING, 1.48 + "process with pid %d got signal: %d\n", 1.49 + pid, WTERMSIG(status)); 1.50 + } 1.51 + signal(SIGCHLD, sigchld_handler); 1.52 +} 1.53 + 1.54 +#ifdef ENABLE_SMTP_SERVER 1.55 +void accept_connect(int listen_sock, int sock, struct sockaddr_in* sock_addr) 1.56 +{ 1.57 + pid_t pid; 1.58 + int dup_sock = dup(sock); 1.59 + FILE *out, *in; 1.60 + gchar *rem_host; 1.61 + gchar *ident = NULL; 1.62 + 1.63 + rem_host = g_strdup(inet_ntoa(sock_addr->sin_addr)); 1.64 +#ifdef ENABLE_IDENT 1.65 + { 1.66 + gchar *id = NULL; 1.67 + if((id = (gchar *)ident_id(sock, 60))){ 1.68 + ident = g_strdup(id); 1.69 + } 1.70 + logwrite(LOG_NOTICE, "connect from host %s, port %hd ident=%s\n", 1.71 + rem_host, 1.72 + ntohs (sock_addr->sin_port), 1.73 + ident ? ident : "(unknown)"); 1.74 + } 1.75 +#else 1.76 + logwrite(LOG_NOTICE, "connect from host %s, port %hd\n", 1.77 + rem_host, 1.78 + ntohs (sock_addr->sin_port)); 1.79 +#endif 1.80 + 1.81 + // start child for connection: 1.82 + signal(SIGCHLD, sigchld_handler); 1.83 + pid = fork(); 1.84 + if(pid == 0){ 1.85 + close(listen_sock); 1.86 + out = fdopen(sock, "w"); 1.87 + in = fdopen(dup_sock, "r"); 1.88 + 1.89 + smtp_in(in, out, rem_host, ident); 1.90 + 1.91 + _exit(EXIT_SUCCESS); 1.92 + }else if(pid < 0){ 1.93 + logwrite(LOG_WARNING, "could not fork for incoming smtp connection: %s\n", 1.94 + strerror(errno)); 1.95 + } 1.96 + 1.97 +#ifdef ENABLE_IDENT 1.98 + if(ident != NULL) g_free(ident); 1.99 +#endif 1.100 + 1.101 + close(sock); 1.102 + close(dup_sock); 1.103 +} 1.104 +#endif /*ifdef ENABLE_SMTP_SERVER*/ 1.105 + 1.106 +void listen_port(GList *iface_list, gint qival, char *argv[]) 1.107 +{ 1.108 + int i; 1.109 + fd_set active_fd_set, read_fd_set; 1.110 + struct timeval tm; 1.111 + time_t time_before, time_now; 1.112 + struct sockaddr_in clientname; 1.113 + size_t size; 1.114 + GList *node, *node_next; 1.115 + int sel_ret; 1.116 + 1.117 + /* Create the sockets and set them up to accept connections. */ 1.118 + FD_ZERO (&active_fd_set); 1.119 +#ifdef ENABLE_SMTP_SERVER 1.120 + for(node = g_list_first(iface_list); 1.121 + node; 1.122 + node = node_next){ 1.123 + interface *iface = (interface *)(node->data); 1.124 + int sock; 1.125 + 1.126 + node_next=g_list_next(node); 1.127 + if ((sock = make_server_socket (iface))<0){ 1.128 + iface_list= g_list_remove_link(iface_list, node); 1.129 + g_list_free_1(node); 1.130 + continue; 1.131 + } 1.132 + if (listen (sock, 1) < 0){ 1.133 + logwrite(LOG_ALERT, "listen: (terminating): %s\n", strerror(errno)); 1.134 + exit (EXIT_FAILURE); 1.135 + } 1.136 + logwrite(LOG_NOTICE, "listening on interface %s:%d\n", 1.137 + iface->address, iface->port); 1.138 + DEBUG(5) debugf("sock = %d\n", sock); 1.139 + FD_SET (sock, &active_fd_set); 1.140 + } 1.141 +#endif 1.142 + 1.143 + /* setup handler for HUP signal: */ 1.144 + signal(SIGHUP, sighup_handler); 1.145 + signal(SIGCHLD, sigchld_handler); 1.146 + 1.147 + /* now that we have our socket(s), 1.148 + we can give up root privileges */ 1.149 + if(!conf.run_as_user){ 1.150 + if(setegid(conf.mail_gid) != 0){ 1.151 + logwrite(LOG_ALERT, "could not change gid to %d: %s\n", 1.152 + conf.mail_gid, strerror(errno)); 1.153 + exit(EXIT_FAILURE); 1.154 + } 1.155 + if(seteuid(conf.mail_uid) != 0){ 1.156 + logwrite(LOG_ALERT, "could not change uid to %d: %s\n", 1.157 + conf.mail_uid, strerror(errno)); 1.158 + exit(EXIT_FAILURE); 1.159 + } 1.160 + } 1.161 + 1.162 + /* sel_ret = 0;*/ 1.163 + time(&time_before); 1.164 + time_before -= qival; 1.165 + sel_ret = -1; 1.166 + 1.167 + while (1){ 1.168 + 1.169 + /* if we were interrupted by an incoming connection (or a signal) 1.170 + we have to recalculate the time until the next queue run should 1.171 + occur. select may put a value into tm, but doc for select() says 1.172 + we should not use it.*/ 1.173 + if(qival > 0){ 1.174 + time(&time_now); 1.175 + if(sel_ret == 0){ /* we are either just starting or did a queue run */ 1.176 + tm.tv_sec = qival; 1.177 + tm.tv_usec = 0; 1.178 + time_before = time_now; 1.179 + }else{ 1.180 + tm.tv_sec = qival - (time_now - time_before); 1.181 + tm.tv_usec = 0; 1.182 + 1.183 + /* race condition, very unlikely (but possible): */ 1.184 + if(tm.tv_sec < 0) 1.185 + tm.tv_sec = 0; 1.186 + } 1.187 + } 1.188 + /* Block until input arrives on one or more active sockets, 1.189 + or signal arrives, 1.190 + or queuing interval time elapsed (if qival > 0) */ 1.191 + read_fd_set = active_fd_set; 1.192 + if ((sel_ret = select(FD_SETSIZE, &read_fd_set, NULL, NULL, 1.193 + qival > 0 ? &tm : NULL)) < 0){ 1.194 + if(errno != EINTR){ 1.195 + logwrite(LOG_ALERT, "select: (terminating): %s\n", strerror(errno)); 1.196 + exit (EXIT_FAILURE); 1.197 + }else{ 1.198 + if(sighup_seen){ 1.199 + logwrite(LOG_NOTICE, "HUP signal received. Restarting daemon\n"); 1.200 + 1.201 + for(i = 0; i < FD_SETSIZE; i++) 1.202 + if(FD_ISSET(i, &active_fd_set)) 1.203 + close(i); 1.204 + 1.205 + execv(argv[0], &(argv[0])); 1.206 + logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno)); 1.207 + exit(EXIT_FAILURE); 1.208 + } 1.209 + } 1.210 + } 1.211 + else if(sel_ret > 0){ 1.212 +#ifdef ENABLE_SMTP_SERVER 1.213 + for(i = 0; i < FD_SETSIZE; i++){ 1.214 + if (FD_ISSET (i, &read_fd_set)){ 1.215 + int sock = i; 1.216 + int new; 1.217 + size = sizeof (clientname); 1.218 + new = accept (sock, 1.219 + (struct sockaddr *) &clientname, 1.220 + &size); 1.221 + if (new < 0){ 1.222 + logwrite(LOG_ALERT, "accept: (ignoring): %s\n", 1.223 + strerror(errno)); 1.224 + }else 1.225 + accept_connect(sock, new, &clientname); 1.226 + } 1.227 + } 1.228 +#else 1.229 + ; 1.230 +#endif 1.231 + }else{ 1.232 + /* If select returns 0, the interval time has elapsed. 1.233 + We start a new queue runner process */ 1.234 + int pid; 1.235 + signal(SIGCHLD, sigchld_handler); 1.236 + if((pid = fork()) == 0){ 1.237 + queue_run(); 1.238 + 1.239 + _exit(EXIT_SUCCESS); 1.240 + } 1.241 + else if(pid < 0){ 1.242 + logwrite(LOG_ALERT, "could not fork for queue run"); 1.243 + } 1.244 + } 1.245 + } 1.246 +}