masqmail-0.2

annotate src/listen.c @ 3:8c55886cacd8

man pages will be maintained in troff now
author meillo@marmaro.de
date Fri, 26 Sep 2008 21:40:10 +0200
parents
children 26e34ae9a3e3
rev   line source
meillo@0 1 /* MasqMail
meillo@0 2 Copyright (C) 1999/2000 Oliver Kurth
meillo@0 3
meillo@0 4 This program is free software; you can redistribute it and/or modify
meillo@0 5 it under the terms of the GNU General Public License as published by
meillo@0 6 the Free Software Foundation; either version 2 of the License, or
meillo@0 7 (at your option) any later version.
meillo@0 8
meillo@0 9 This program is distributed in the hope that it will be useful,
meillo@0 10 but WITHOUT ANY WARRANTY; without even the implied warranty of
meillo@0 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
meillo@0 12 GNU General Public License for more details.
meillo@0 13
meillo@0 14 You should have received a copy of the GNU General Public License
meillo@0 15 along with this program; if not, write to the Free Software
meillo@0 16 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
meillo@0 17 */
meillo@0 18
meillo@0 19 #include "masqmail.h"
meillo@0 20 #include <sys/wait.h>
meillo@0 21 #include <sys/types.h>
meillo@0 22
meillo@0 23 static int volatile sighup_seen = 0;
meillo@0 24
meillo@0 25 static
meillo@0 26 void sighup_handler(int sig)
meillo@0 27 {
meillo@0 28 sighup_seen = 1;
meillo@0 29 signal(SIGHUP, sighup_handler);
meillo@0 30 }
meillo@0 31
meillo@0 32 static
meillo@0 33 void sigchld_handler(int sig)
meillo@0 34 {
meillo@0 35 pid_t pid;
meillo@0 36 int status;
meillo@0 37
meillo@0 38 pid = waitpid(0, &status, 0);
meillo@0 39 if(pid > 0){
meillo@0 40 if(WEXITSTATUS(status) != EXIT_SUCCESS)
meillo@0 41 logwrite(LOG_WARNING, "process %d exited with %d\n",
meillo@0 42 pid, WEXITSTATUS(status));
meillo@0 43 if(WIFSIGNALED(status))
meillo@0 44 logwrite(LOG_WARNING,
meillo@0 45 "process with pid %d got signal: %d\n",
meillo@0 46 pid, WTERMSIG(status));
meillo@0 47 }
meillo@0 48 signal(SIGCHLD, sigchld_handler);
meillo@0 49 }
meillo@0 50
meillo@0 51 #ifdef ENABLE_SMTP_SERVER
meillo@0 52 void accept_connect(int listen_sock, int sock, struct sockaddr_in* sock_addr)
meillo@0 53 {
meillo@0 54 pid_t pid;
meillo@0 55 int dup_sock = dup(sock);
meillo@0 56 FILE *out, *in;
meillo@0 57 gchar *rem_host;
meillo@0 58 gchar *ident = NULL;
meillo@0 59
meillo@0 60 rem_host = g_strdup(inet_ntoa(sock_addr->sin_addr));
meillo@0 61 #ifdef ENABLE_IDENT
meillo@0 62 {
meillo@0 63 gchar *id = NULL;
meillo@0 64 if((id = (gchar *)ident_id(sock, 60))){
meillo@0 65 ident = g_strdup(id);
meillo@0 66 }
meillo@0 67 logwrite(LOG_NOTICE, "connect from host %s, port %hd ident=%s\n",
meillo@0 68 rem_host,
meillo@0 69 ntohs (sock_addr->sin_port),
meillo@0 70 ident ? ident : "(unknown)");
meillo@0 71 }
meillo@0 72 #else
meillo@0 73 logwrite(LOG_NOTICE, "connect from host %s, port %hd\n",
meillo@0 74 rem_host,
meillo@0 75 ntohs (sock_addr->sin_port));
meillo@0 76 #endif
meillo@0 77
meillo@0 78 // start child for connection:
meillo@0 79 signal(SIGCHLD, sigchld_handler);
meillo@0 80 pid = fork();
meillo@0 81 if(pid == 0){
meillo@0 82 close(listen_sock);
meillo@0 83 out = fdopen(sock, "w");
meillo@0 84 in = fdopen(dup_sock, "r");
meillo@0 85
meillo@0 86 smtp_in(in, out, rem_host, ident);
meillo@0 87
meillo@0 88 _exit(EXIT_SUCCESS);
meillo@0 89 }else if(pid < 0){
meillo@0 90 logwrite(LOG_WARNING, "could not fork for incoming smtp connection: %s\n",
meillo@0 91 strerror(errno));
meillo@0 92 }
meillo@0 93
meillo@0 94 #ifdef ENABLE_IDENT
meillo@0 95 if(ident != NULL) g_free(ident);
meillo@0 96 #endif
meillo@0 97
meillo@0 98 close(sock);
meillo@0 99 close(dup_sock);
meillo@0 100 }
meillo@0 101 #endif /*ifdef ENABLE_SMTP_SERVER*/
meillo@0 102
meillo@0 103 void listen_port(GList *iface_list, gint qival, char *argv[])
meillo@0 104 {
meillo@0 105 int i;
meillo@0 106 fd_set active_fd_set, read_fd_set;
meillo@0 107 struct timeval tm;
meillo@0 108 time_t time_before, time_now;
meillo@0 109 struct sockaddr_in clientname;
meillo@0 110 size_t size;
meillo@0 111 GList *node, *node_next;
meillo@0 112 int sel_ret;
meillo@0 113
meillo@0 114 /* Create the sockets and set them up to accept connections. */
meillo@0 115 FD_ZERO (&active_fd_set);
meillo@0 116 #ifdef ENABLE_SMTP_SERVER
meillo@0 117 for(node = g_list_first(iface_list);
meillo@0 118 node;
meillo@0 119 node = node_next){
meillo@0 120 interface *iface = (interface *)(node->data);
meillo@0 121 int sock;
meillo@0 122
meillo@0 123 node_next=g_list_next(node);
meillo@0 124 if ((sock = make_server_socket (iface))<0){
meillo@0 125 iface_list= g_list_remove_link(iface_list, node);
meillo@0 126 g_list_free_1(node);
meillo@0 127 continue;
meillo@0 128 }
meillo@0 129 if (listen (sock, 1) < 0){
meillo@0 130 logwrite(LOG_ALERT, "listen: (terminating): %s\n", strerror(errno));
meillo@0 131 exit (EXIT_FAILURE);
meillo@0 132 }
meillo@0 133 logwrite(LOG_NOTICE, "listening on interface %s:%d\n",
meillo@0 134 iface->address, iface->port);
meillo@0 135 DEBUG(5) debugf("sock = %d\n", sock);
meillo@0 136 FD_SET (sock, &active_fd_set);
meillo@0 137 }
meillo@0 138 #endif
meillo@0 139
meillo@0 140 /* setup handler for HUP signal: */
meillo@0 141 signal(SIGHUP, sighup_handler);
meillo@0 142 signal(SIGCHLD, sigchld_handler);
meillo@0 143
meillo@0 144 /* now that we have our socket(s),
meillo@0 145 we can give up root privileges */
meillo@0 146 if(!conf.run_as_user){
meillo@0 147 if(setegid(conf.mail_gid) != 0){
meillo@0 148 logwrite(LOG_ALERT, "could not change gid to %d: %s\n",
meillo@0 149 conf.mail_gid, strerror(errno));
meillo@0 150 exit(EXIT_FAILURE);
meillo@0 151 }
meillo@0 152 if(seteuid(conf.mail_uid) != 0){
meillo@0 153 logwrite(LOG_ALERT, "could not change uid to %d: %s\n",
meillo@0 154 conf.mail_uid, strerror(errno));
meillo@0 155 exit(EXIT_FAILURE);
meillo@0 156 }
meillo@0 157 }
meillo@0 158
meillo@0 159 /* sel_ret = 0;*/
meillo@0 160 time(&time_before);
meillo@0 161 time_before -= qival;
meillo@0 162 sel_ret = -1;
meillo@0 163
meillo@0 164 while (1){
meillo@0 165
meillo@0 166 /* if we were interrupted by an incoming connection (or a signal)
meillo@0 167 we have to recalculate the time until the next queue run should
meillo@0 168 occur. select may put a value into tm, but doc for select() says
meillo@0 169 we should not use it.*/
meillo@0 170 if(qival > 0){
meillo@0 171 time(&time_now);
meillo@0 172 if(sel_ret == 0){ /* we are either just starting or did a queue run */
meillo@0 173 tm.tv_sec = qival;
meillo@0 174 tm.tv_usec = 0;
meillo@0 175 time_before = time_now;
meillo@0 176 }else{
meillo@0 177 tm.tv_sec = qival - (time_now - time_before);
meillo@0 178 tm.tv_usec = 0;
meillo@0 179
meillo@0 180 /* race condition, very unlikely (but possible): */
meillo@0 181 if(tm.tv_sec < 0)
meillo@0 182 tm.tv_sec = 0;
meillo@0 183 }
meillo@0 184 }
meillo@0 185 /* Block until input arrives on one or more active sockets,
meillo@0 186 or signal arrives,
meillo@0 187 or queuing interval time elapsed (if qival > 0) */
meillo@0 188 read_fd_set = active_fd_set;
meillo@0 189 if ((sel_ret = select(FD_SETSIZE, &read_fd_set, NULL, NULL,
meillo@0 190 qival > 0 ? &tm : NULL)) < 0){
meillo@0 191 if(errno != EINTR){
meillo@0 192 logwrite(LOG_ALERT, "select: (terminating): %s\n", strerror(errno));
meillo@0 193 exit (EXIT_FAILURE);
meillo@0 194 }else{
meillo@0 195 if(sighup_seen){
meillo@0 196 logwrite(LOG_NOTICE, "HUP signal received. Restarting daemon\n");
meillo@0 197
meillo@0 198 for(i = 0; i < FD_SETSIZE; i++)
meillo@0 199 if(FD_ISSET(i, &active_fd_set))
meillo@0 200 close(i);
meillo@0 201
meillo@0 202 execv(argv[0], &(argv[0]));
meillo@0 203 logwrite(LOG_ALERT, "restarting failed: %s\n", strerror(errno));
meillo@0 204 exit(EXIT_FAILURE);
meillo@0 205 }
meillo@0 206 }
meillo@0 207 }
meillo@0 208 else if(sel_ret > 0){
meillo@0 209 #ifdef ENABLE_SMTP_SERVER
meillo@0 210 for(i = 0; i < FD_SETSIZE; i++){
meillo@0 211 if (FD_ISSET (i, &read_fd_set)){
meillo@0 212 int sock = i;
meillo@0 213 int new;
meillo@0 214 size = sizeof (clientname);
meillo@0 215 new = accept (sock,
meillo@0 216 (struct sockaddr *) &clientname,
meillo@0 217 &size);
meillo@0 218 if (new < 0){
meillo@0 219 logwrite(LOG_ALERT, "accept: (ignoring): %s\n",
meillo@0 220 strerror(errno));
meillo@0 221 }else
meillo@0 222 accept_connect(sock, new, &clientname);
meillo@0 223 }
meillo@0 224 }
meillo@0 225 #else
meillo@0 226 ;
meillo@0 227 #endif
meillo@0 228 }else{
meillo@0 229 /* If select returns 0, the interval time has elapsed.
meillo@0 230 We start a new queue runner process */
meillo@0 231 int pid;
meillo@0 232 signal(SIGCHLD, sigchld_handler);
meillo@0 233 if((pid = fork()) == 0){
meillo@0 234 queue_run();
meillo@0 235
meillo@0 236 _exit(EXIT_SUCCESS);
meillo@0 237 }
meillo@0 238 else if(pid < 0){
meillo@0 239 logwrite(LOG_ALERT, "could not fork for queue run");
meillo@0 240 }
meillo@0 241 }
meillo@0 242 }
meillo@0 243 }