masqmail

annotate src/listen.c @ 421:f37384470855

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