masqmail-0.2

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