OpenSSL options min-version, max-version
[socat.git] / xiosigchld.c
blobd09947fc74159e0ec6e2deaf7f20e86699b53ab9
1 /* source: xiosigchld.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 is the source of the extended child signal handler */
8 #include "xiosysincludes.h"
9 #include "xioopen.h"
12 /*!! with socat, at most 4 exec children exist */
13 pid_t diedunknown[NUMUNKNOWN]; /* children that died before they were registered */
14 int statunknown[NUMUNKNOWN]; /* exit state of unknown dead child */
15 size_t nextunknown;
18 /* register for a xio filedescriptor a callback (handler).
19 when a SIGCHLD occurs, the signal handler will ??? */
20 int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
21 if (xfd->tag != XIO_TAG_DUAL) {
22 xfd->stream.sigchild = callback;
23 } else {
24 xfd->dual.stream[0]->sigchild = callback;
25 xfd->dual.stream[1]->sigchild = callback;
27 return 0;
30 /* exec'd child has died, perform appropriate changes to descriptor */
31 /* is async-signal-safe */
32 static int sigchld_stream(struct single *file) {
33 /*!! call back to application */
34 file->para.exec.pid = 0;
35 if (file->sigchild) {
36 return (*file->sigchild)(file);
38 return 0;
41 /* return 0 if socket is not responsible for deadchild */
42 static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
43 int retval;
44 if (socket != NULL) {
45 if (socket->tag != XIO_TAG_DUAL) {
46 if ((socket->stream.howtoend == END_KILL ||
47 socket->stream.howtoend == END_CLOSE_KILL ||
48 socket->stream.howtoend == END_SHUTDOWN_KILL) &&
49 socket->stream.para.exec.pid == deadchild) {
50 Info2("exec'd process %d on socket %d terminated",
51 socket->stream.para.exec.pid, socknum);
52 sigchld_stream(&socket->stream); /* is async-signal-safe */
53 return 1;
55 } else {
56 if (retval = xio_checkchild((xiofile_t *)socket->dual.stream[0], socknum, deadchild))
57 return retval;
58 else
59 return xio_checkchild((xiofile_t *)socket->dual.stream[1], socknum, deadchild);
62 return 0;
65 /* this is the "physical" signal handler for SIGCHLD */
66 /* the current socat/xio implementation knows two kinds of children:
67 exec/system addresses perform a fork: these children are registered and
68 there death influences the parents flow;
69 listen-socket with fork children: these children are "anonymous" and their
70 death does not affect the parent process (now; maybe we have a child
71 process counter later) */
72 void childdied(int signum) {
73 pid_t pid;
74 int _errno;
75 int status = 0;
76 bool wassig = false;
77 int i;
79 _errno = errno; /* save current value; e.g., select() on Cygwin seems
80 to set it to EINTR _before_ handling the signal, and
81 then passes the value left by the signal handler to
82 the caller of select(), accept() etc. */
83 diag_in_handler = 1;
84 Notice1("childdied(): handling signal %d", signum);
85 Info1("childdied(signum=%d)", signum);
86 do {
87 pid = Waitpid(-1, &status, WNOHANG);
88 if (pid == 0) {
89 Msg(wassig?E_INFO:E_WARN,
90 "waitpid(-1, {}, WNOHANG): no child has exited");
91 Info("childdied() finished");
92 diag_in_handler = 0;
93 errno = _errno;
94 return;
95 } else if (pid < 0 && errno == ECHILD) {
96 Msg(wassig?E_INFO:E_WARN,
97 "waitpid(-1, {}, WNOHANG): "F_strerror);
98 Info("childdied() finished");
99 diag_in_handler = 0;
100 errno = _errno;
101 return;
103 wassig = true;
104 if (pid < 0) {
105 Warn1("waitpid(-1, {%d}, WNOHANG): "F_strerror, status);
106 Info("childdied() finished");
107 diag_in_handler = 0;
108 errno = _errno;
109 return;
111 /*! indent */
112 if (num_child) num_child--;
113 /* check if it was a registered child process */
114 i = 0;
115 while (i < XIO_MAXSOCK) {
116 if (xio_checkchild(sock[i], i, pid)) break;
117 ++i;
119 if (i == XIO_MAXSOCK) {
120 Info2("childdied(%d): cannot identify child %d", signum, pid);
121 if (nextunknown == NUMUNKNOWN) {
122 nextunknown = 0;
124 diedunknown[nextunknown] = pid;
125 statunknown[nextunknown++] = WEXITSTATUS(status);
126 Debug1("saving pid in diedunknown"F_Zu,
127 nextunknown/*sic, for compatibility*/);
130 if (WIFEXITED(status)) {
131 if (WEXITSTATUS(status) == 0) {
132 Info2("waitpid(): child %d exited with status %d",
133 pid, WEXITSTATUS(status));
134 } else {
135 if (i == XIO_MAXSOCK) {
136 Info2("waitpid(): child %d exited with status %d",
137 pid, WEXITSTATUS(status));
138 } else {
139 Error2("waitpid(): child %d exited with status %d",
140 pid, WEXITSTATUS(status));
143 } else if (WIFSIGNALED(status)) {
144 if (i == XIO_MAXSOCK) {
145 Info2("waitpid(): child %d exited on signal %d",
146 pid, WTERMSIG(status));
147 } else {
148 Error2("waitpid(): child %d exited on signal %d",
149 pid, WTERMSIG(status));
151 } else if (WIFSTOPPED(status)) {
152 Info2("waitpid(): child %d stopped on signal %d",
153 pid, WSTOPSIG(status));
154 } else {
155 Warn1("waitpid(): cannot determine status of child %d", pid);
158 #if !HAVE_SIGACTION
159 /* we might need to re-register our handler */
160 if (Signal(SIGCHLD, childdied) == SIG_ERR) {
161 Warn("signal(SIGCHLD, childdied): "F_strerror);
163 #endif /* !HAVE_SIGACTION */
164 } while (1);
165 Info("childdied() finished");
166 diag_in_handler = 0;
167 errno = _errno;
171 int xiosetchilddied(void) {
172 #if HAVE_SIGACTION
173 struct sigaction act;
174 memset(&act, 0, sizeof(struct sigaction));
175 act.sa_flags = SA_NOCLDSTOP/*|SA_RESTART*/
176 #ifdef SA_NOMASK
177 |SA_NOMASK
178 #endif
180 act.sa_handler = childdied;
181 sigfillset(&act.sa_mask);
182 if (Sigaction(SIGCHLD, &act, NULL) < 0) {
183 /*! man does not say that errno is defined */
184 Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
186 #else /* HAVE_SIGACTION */
187 if (Signal(SIGCHLD, childdied) == SIG_ERR) {
188 Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
190 #endif /* !HAVE_SIGACTION */
191 return 0;