Mercurial > masqmail
comparison src/listen.c @ 0:08114f7dcc23 0.2.21
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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:08114f7dcc23 |
---|---|
1 /* MasqMail | |
2 Copyright (C) 1999/2000 Oliver Kurth | |
3 | |
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. | |
8 | |
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. | |
13 | |
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 */ | |
18 | |
19 #include "masqmail.h" | |
20 #include <sys/wait.h> | |
21 #include <sys/types.h> | |
22 | |
23 static int volatile sighup_seen = 0; | |
24 | |
25 static | |
26 void sighup_handler(int sig) | |
27 { | |
28 sighup_seen = 1; | |
29 signal(SIGHUP, sighup_handler); | |
30 } | |
31 | |
32 static | |
33 void sigchld_handler(int sig) | |
34 { | |
35 pid_t pid; | |
36 int status; | |
37 | |
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 } | |
50 | |
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; | |
59 | |
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 | |
77 | |
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"); | |
85 | |
86 smtp_in(in, out, rem_host, ident); | |
87 | |
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 } | |
93 | |
94 #ifdef ENABLE_IDENT | |
95 if(ident != NULL) g_free(ident); | |
96 #endif | |
97 | |
98 close(sock); | |
99 close(dup_sock); | |
100 } | |
101 #endif /*ifdef ENABLE_SMTP_SERVER*/ | |
102 | |
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; | |
113 | |
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; | |
122 | |
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 | |
139 | |
140 /* setup handler for HUP signal: */ | |
141 signal(SIGHUP, sighup_handler); | |
142 signal(SIGCHLD, sigchld_handler); | |
143 | |
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 } | |
158 | |
159 /* sel_ret = 0;*/ | |
160 time(&time_before); | |
161 time_before -= qival; | |
162 sel_ret = -1; | |
163 | |
164 while (1){ | |
165 | |
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; | |
179 | |
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"); | |
197 | |
198 for(i = 0; i < FD_SETSIZE; i++) | |
199 if(FD_ISSET(i, &active_fd_set)) | |
200 close(i); | |
201 | |
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(); | |
235 | |
236 _exit(EXIT_SUCCESS); | |
237 } | |
238 else if(pid < 0){ | |
239 logwrite(LOG_ALERT, "could not fork for queue run"); | |
240 } | |
241 } | |
242 } | |
243 } |