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