Version 1.8.0.0
[socat.git] / xio-listen.c
blob28b9f4266afa5806e1311ce1d0ccaeed32db21a8
1 /* source: xio-listen.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for listen socket options */
7 #include "xiosysincludes.h"
9 #if WITH_LISTEN
11 #include "xioopen.h"
12 #include "xio-named.h"
13 #include "xio-socket.h"
14 #include "xio-ip.h"
15 #include "xio-ip4.h"
16 #include "xio-listen.h"
17 #include "xio-tcpwrap.h"
19 /***** LISTEN options *****/
20 const struct optdesc opt_backlog = { "backlog", NULL, OPT_BACKLOG, GROUP_LISTEN, PH_LISTEN, TYPE_INT, OFUNC_SPEC };
21 const struct optdesc opt_fork = { "fork", NULL, OPT_FORK, GROUP_CHILD, PH_PASTACCEPT, TYPE_BOOL, OFUNC_SPEC };
22 const struct optdesc opt_max_children = { "max-children", NULL, OPT_MAX_CHILDREN, GROUP_CHILD, PH_PASTACCEPT, TYPE_INT, OFUNC_SPEC };
23 const struct optdesc opt_children_shutup = { "children-shutup", "child-shutup", OPT_CHILDREN_SHUTUP, GROUP_CHILD, PH_PASTACCEPT, TYPE_INT, OFUNC_OFFSET, XIO_OFFSETOF(shutup) };
24 /**/
25 #if (WITH_UDP || WITH_TCP)
26 const struct optdesc opt_range = { "range", NULL, OPT_RANGE, GROUP_RANGE, PH_ACCEPT, TYPE_STRING, OFUNC_SPEC };
27 #endif
28 const struct optdesc opt_accept_timeout = { "accept-timeout", "listen-timeout", OPT_ACCEPT_TIMEOUT, GROUP_LISTEN, PH_LISTEN, TYPE_TIMEVAL, OFUNC_OFFSET, XIO_OFFSETOF(para.socket.accept_timeout) };
31 applies and consumes the following option:
32 PH_INIT, PH_PASTSOCKET, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY,
33 PH_PREOPEN, PH_FD, PH_CONNECTED, PH_LATE, PH_LATE2
34 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_BACKLOG, OPT_RANGE, tcpwrap,
35 OPT_SOURCEPORT, OPT_LOWPORT, cloexec
37 int
38 xioopen_listen(struct single *sfd, int xioflags,
39 struct sockaddr *us, socklen_t uslen,
40 struct opt *opts, struct opt *opts0,
41 int pf, int socktype, int proto) {
42 int level;
43 int result;
45 #if WITH_RETRY
46 if (sfd->forever || sfd->retry) {
47 level = E_INFO;
48 } else
49 #endif /* WITH_RETRY */
50 level = E_ERROR;
52 while (true) { /* loop over failed attempts */
54 /* tcp listen; this can fork() for us; it only returns on error or on
55 successful establishment of tcp connection */
56 result = _xioopen_listen(sfd, xioflags,
57 (struct sockaddr *)us, uslen,
58 opts, pf, socktype, proto, level);
59 /*! not sure if we should try again on retry/forever */
60 switch (result) {
61 case STAT_OK: break;
62 #if WITH_RETRY
63 case STAT_RETRYLATER:
64 case STAT_RETRYNOW:
65 if (sfd->forever || sfd->retry) {
66 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
67 if (result == STAT_RETRYLATER) {
68 Nanosleep(&sfd->intervall, NULL);
70 dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
71 --sfd->retry;
72 continue;
74 return STAT_NORETRY;
75 #endif /* WITH_RETRY */
76 default:
77 return result;
80 break;
81 } /* drop out on success */
83 return result;
87 /* creates the listening socket, bind, applies options; waits for incoming
88 connection, checks its source address and port. Depending on fork option, it
89 may fork a subprocess.
90 pf specifies the syntax expected for range option. In the case of generic
91 socket it is 0 (expecting raw binary data), and the real pf can be obtained
92 from us->af_family; for other socket types pf == us->af_family
93 Returns 0 if a connection was accepted; with fork option, this is always in
94 a subprocess!
95 Other return values indicate a problem; this can happen in the master
96 process or in a subprocess.
97 This function does not retry. If you need retries, handle this in a
98 loop in the calling function (and always provide the options...)
99 After fork, we set the forever/retry of the child process to 0
100 applies and consumes the following option:
101 PH_INIT, PH_PASTSOCKET, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY,
102 PH_PREOPEN, PH_FD, PH_CONNECTED, PH_LATE, PH_LATE2
103 OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_BACKLOG, OPT_RANGE, tcpwrap,
104 OPT_SOURCEPORT, OPT_LOWPORT, cloexec
106 int _xioopen_listen(struct single *sfd, int xioflags, struct sockaddr *us, socklen_t uslen,
107 struct opt *opts, int pf, int socktype, int proto, int level) {
108 int backlog = 5; /* why? 1 seems to cause problems under some load */
109 char infobuff[256];
111 if (applyopts_single(sfd, opts, PH_INIT) < 0) return -1;
113 if ((sfd->fd = xiosocket(opts, pf?pf:us->sa_family, socktype, proto, level)) < 0) {
114 return STAT_RETRYLATER;
116 applyopts(sfd, -1, opts, PH_PASTSOCKET);
118 applyopts_offset(sfd, opts);
119 applyopts_cloexec(sfd->fd, opts);
121 /* Phase prebind */
122 xiosock_reuseaddr(sfd->fd, proto, opts);
123 applyopts(sfd, -1, opts, PH_PREBIND);
125 applyopts(sfd, -1, opts, PH_BIND);
126 if (Bind(sfd->fd, (struct sockaddr *)us, uslen) < 0) {
127 Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", sfd->fd,
128 sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
129 strerror(errno));
130 Close(sfd->fd);
131 return STAT_RETRYLATER;
134 #if WITH_UNIX
135 if (us->sa_family == AF_UNIX) {
136 if (((union sockaddr_union *)us)->un.sun_path[0] != '\0') {
137 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
138 } else {
139 applyopts(sfd, -1, opts, PH_FD);
142 #endif
144 applyopts(sfd, -1, opts, PH_PASTBIND);
145 #if WITH_UNIX
146 if (us->sa_family == AF_UNIX) {
147 if (((union sockaddr_union *)us)->un.sun_path[0] != '\0') {
148 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
149 applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
150 } else {
151 applyopts(sfd, -1, opts, PH_EARLY);
152 applyopts(sfd, -1, opts, PH_PREOPEN);
155 #endif /* WITH_UNIX */
157 applyopts(sfd, -1, opts, PH_PRELISTEN);
158 retropt_int(opts, OPT_BACKLOG, &backlog);
159 applyopts(sfd, -1, opts, PH_LISTEN);
160 if (Listen(sfd->fd, backlog) < 0) {
161 Error3("listen(%d, %d): %s", sfd->fd, backlog, strerror(errno));
162 return STAT_RETRYLATER;
164 return _xioopen_accept_fd(sfd, xioflags, us, uslen, opts, pf, proto,level);
167 int _xioopen_accept_fd(
168 struct single *sfd,
169 int xioflags,
170 struct sockaddr *us,
171 socklen_t uslen,
172 struct opt *opts,
173 int pf,
174 int proto,
175 int level)
177 struct sockaddr sa;
178 socklen_t salen;
179 char *rangename;
180 bool dofork = false;
181 int maxchildren = 0;
182 char infobuff[256];
183 char lisname[256];
184 union sockaddr_union _peername;
185 union sockaddr_union _sockname;
186 union sockaddr_union *pa = &_peername; /* peer address */
187 union sockaddr_union *la = &_sockname; /* local address */
188 socklen_t pas = sizeof(_peername); /* peer address size */
189 socklen_t las = sizeof(_sockname); /* local address size */
190 int result;
192 retropt_bool(opts, OPT_FORK, &dofork);
193 if (dofork) {
194 if (!(xioflags & XIO_MAYFORK)) {
195 Error("option fork not allowed here");
196 return STAT_NORETRY;
198 sfd->flags |= XIO_DOESFORK;
201 retropt_int(opts, OPT_MAX_CHILDREN, &maxchildren);
203 if (! dofork && maxchildren) {
204 Error("option max-children not allowed without option fork");
205 return STAT_NORETRY;
208 if (dofork) {
209 xiosetchilddied(); /* set SIGCHLD handler */
212 /* Under some circumstances (e.g., TCP listen on port 0) bind() fills empty
213 fields that we want to know. */
214 if (Getsockname(sfd->fd, us, &uslen) < 0) {
215 Warn4("getsockname(%d, %p, {%d}): %s",
216 sfd->fd, &us, uslen, strerror(errno));
219 #if WITH_IP4 /*|| WITH_IP6*/
220 if (retropt_string(opts, OPT_RANGE, &rangename) >= 0) {
221 if (xioparserange(rangename, pf, &sfd->para.socket.range,
222 sfd->para.socket.ip.ai_flags)
223 < 0) {
224 free(rangename);
225 return STAT_NORETRY;
227 free(rangename);
228 sfd->para.socket.dorange = true;
230 #endif
232 #if (WITH_TCP || WITH_UDP) && WITH_LIBWRAP
233 xio_retropt_tcpwrap(sfd, opts);
234 #endif /* && (WITH_TCP || WITH_UDP) && WITH_LIBWRAP */
236 #if WITH_TCP || WITH_UDP
237 if (retropt_ushort(opts, OPT_SOURCEPORT, &sfd->para.socket.ip.sourceport) >= 0) {
238 sfd->para.socket.ip.dosourceport = true;
240 retropt_bool(opts, OPT_LOWPORT, &sfd->para.socket.ip.lowport);
241 #endif /* WITH_TCP || WITH_UDP */
243 if (xioparms.logopt == 'm') {
244 Info("starting accept loop, switching to syslog");
245 diag_set('y', xioparms.syslogfac); xioparms.logopt = 'y';
246 } else {
247 Info("starting accept loop");
249 while (true) { /* but we only loop if fork option is set */
250 char peername[256];
251 char sockname[256];
252 int ps; /* peer socket */
254 pa = &_peername;
255 la = &_sockname;
256 do {
257 /*? int level = E_ERROR;*/
258 Notice1("listening on %s", sockaddr_info(us, uslen, lisname, sizeof(lisname)));
259 if (sfd->para.socket.accept_timeout.tv_sec > 0 ||
260 sfd->para.socket.accept_timeout.tv_usec > 0) {
261 fd_set rfd;
262 struct timeval tmo;
263 FD_ZERO(&rfd);
264 FD_SET(sfd->fd, &rfd);
265 tmo.tv_sec = sfd->para.socket.accept_timeout.tv_sec;
266 tmo.tv_usec = sfd->para.socket.accept_timeout.tv_usec;
267 while (1) {
268 if (Select(sfd->fd+1, &rfd, NULL, NULL, &tmo) < 0) {
269 if (errno != EINTR) {
270 Error5("Select(%d, &0x%lx, NULL, NULL, {%ld.%06ld}): %s", sfd->fd+1, 1L<<(sfd->fd+1),
271 sfd->para.socket.accept_timeout.tv_sec, sfd->para.socket.accept_timeout.tv_usec,
272 strerror(errno));
274 } else {
275 break;
278 if (!FD_ISSET(sfd->fd, &rfd)) {
279 struct sigaction act;
281 Warn1("accept: %s", strerror(ETIMEDOUT));
282 Close(sfd->fd);
283 Notice("Waiting for child processes to terminate");
284 memset(&act, 0, sizeof(struct sigaction));
285 act.sa_flags = SA_NOCLDSTOP/*|SA_RESTART*/
286 #ifdef SA_SIGINFO /* not on Linux 2.0(.33) */
287 |SA_SIGINFO
288 #endif
289 #ifdef SA_NOMASK
290 |SA_NOMASK
291 #endif
293 #if HAVE_STRUCT_SIGACTION_SA_SIGACTION && defined(SA_SIGINFO)
294 act.sa_sigaction = 0;
295 #else /* Linux 2.0(.33) does not have sigaction.sa_sigaction */
296 act.sa_handler = 0;
297 #endif
298 sigemptyset(&act.sa_mask);
299 Sigaction(SIGCHLD, &act, NULL);
300 wait(NULL);
301 Exit(0);
304 salen = sizeof(sa);
305 ps = Accept(sfd->fd, (struct sockaddr *)&sa, &salen);
306 if (ps >= 0) {
307 /*0 Info4("accept(%d, %p, {"F_Zu"}) -> %d", sfd->fd, &sa, salen, ps);*/
308 break; /* success, break out of loop */
310 if (errno == EINTR) {
311 continue;
313 if (errno == ECONNABORTED) {
314 Notice4("accept(%d, %p, {"F_socklen"}): %s",
315 sfd->fd, &sa, salen, strerror(errno));
316 continue;
318 Msg4(level, "accept(%d, %p, {"F_socklen"}): %s",
319 sfd->fd, &sa, salen, strerror(errno));
320 Close(sfd->fd);
321 return STAT_RETRYLATER;
322 } while (true);
323 applyopts_cloexec(ps, opts);
324 if (Getpeername(ps, &pa->soa, &pas) < 0) {
325 Notice4("getpeername(%d, %p, {"F_socklen"}): %s",
326 ps, pa, pas, strerror(errno));
327 pa = NULL;
329 if (Getsockname(ps, &la->soa, &las) < 0) {
330 Warn4("getsockname(%d, %p, {"F_socklen"}): %s",
331 ps, la, las, strerror(errno));
332 la = NULL;
334 Notice2("accepting connection from %s on %s",
336 sockaddr_info(&pa->soa, pas, peername, sizeof(peername)):"NULL",
338 sockaddr_info(&la->soa, las, sockname, sizeof(sockname)):"NULL");
340 if (pa != NULL && la != NULL && xiocheckpeer(sfd, pa, la) < 0) {
341 if (Shutdown(ps, 2) < 0) {
342 Info2("shutdown(%d, 2): %s", ps, strerror(errno));
344 Close(ps);
345 continue;
348 if (pa != NULL)
349 Info1("permitting connection from %s",
350 sockaddr_info((struct sockaddr *)pa, pas,
351 infobuff, sizeof(infobuff)));
353 if (dofork) {
354 pid_t pid; /* mostly int; only used with fork */
355 sigset_t mask_sigchld;
357 /* Block SIGCHLD until parent is ready to react */
358 sigemptyset(&mask_sigchld);
359 sigaddset(&mask_sigchld, SIGCHLD);
360 Sigprocmask(SIG_BLOCK, &mask_sigchld, NULL);
362 if ((pid =
363 xio_fork(false, level==E_ERROR?level:E_WARN,
364 sfd->shutup))
365 < 0) {
366 Close(sfd->fd);
367 Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
368 return STAT_RETRYLATER;
370 if (pid == 0) { /* child */
371 pid_t cpid = Getpid();
372 Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
374 Info1("just born: child process "F_pid, cpid);
375 xiosetenvulong("PID", cpid, 1);
377 if (Close(sfd->fd) < 0) {
378 Info2("close(%d): %s", sfd->fd, strerror(errno));
380 sfd->fd = ps;
382 #if WITH_RETRY
383 /* !? */
384 sfd->forever = false; sfd->retry = 0;
385 level = E_ERROR;
386 #endif /* WITH_RETRY */
388 break;
391 /* server: continue loop with listen */
392 /* shutdown() closes the socket even for the child process, but
393 close() does what we want */
394 if (Close(ps) < 0) {
395 Info2("close(%d): %s", ps, strerror(errno));
398 /* now we are ready to handle signals */
399 Sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL);
402 while (maxchildren) {
403 if (num_child < maxchildren) break;
404 Notice("maxchildren are active, waiting");
405 /* UINT_MAX would even be nicer, but Openindiana works only
406 with 31 bits */
407 while (!Sleep(INT_MAX)) ; /* any signal lets us continue */
409 Info("still listening");
410 } else {
411 if (Close(sfd->fd) < 0) {
412 Info2("close(%d): %s", sfd->fd, strerror(errno));
414 sfd->fd = ps;
415 break;
419 applyopts(sfd, -1, opts, PH_FD);
420 applyopts(sfd, -1, opts, PH_PASTSOCKET);
421 applyopts(sfd, -1, opts, PH_CONNECTED);
422 if ((result = _xio_openlate(sfd, opts)) < 0)
423 return result;
425 /* set the env vars describing the local and remote sockets */
426 if (la != NULL) xiosetsockaddrenv("SOCK", la, las, proto);
427 if (pa != NULL) xiosetsockaddrenv("PEER", pa, pas, proto);
429 return 0;
432 #endif /* WITH_LISTEN */