masqmail-0.2

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 +}