mirror of
https://repo.or.cz/socat.git
synced 2025-07-12 22:53:24 +00:00
socat V1.6.0.0 (initial GIT commit)
This commit is contained in:
commit
b819572f5e
170 changed files with 59193 additions and 0 deletions
159
xiosigchld.c
Normal file
159
xiosigchld.c
Normal file
|
@ -0,0 +1,159 @@
|
|||
/* $Id: xiosigchld.c,v 1.21 2006/12/28 14:38:38 gerhard Exp $ */
|
||||
/* Copyright Gerhard Rieger 2001-2006 */
|
||||
/* Published under the GNU General Public License V.2, see file COPYING */
|
||||
|
||||
/* this is the source of the extended child signal handler */
|
||||
|
||||
|
||||
#include "xiosysincludes.h"
|
||||
#include "xioopen.h"
|
||||
|
||||
|
||||
/*!! with socat, at most 4 exec children exist */
|
||||
pid_t diedunknown1; /* child died before it is registered */
|
||||
pid_t diedunknown2;
|
||||
pid_t diedunknown3;
|
||||
pid_t diedunknown4;
|
||||
|
||||
|
||||
/* register for a xio filedescriptor a callback (handler).
|
||||
when a SIGCHLD occurs, the signal handler will ??? */
|
||||
int xiosetsigchild(xiofile_t *xfd, int (*callback)(struct single *)) {
|
||||
if (xfd->tag != XIO_TAG_DUAL) {
|
||||
xfd->stream.sigchild = callback;
|
||||
} else {
|
||||
xfd->dual.stream[0]->sigchild = callback;
|
||||
xfd->dual.stream[1]->sigchild = callback;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* exec'd child has died, perform appropriate changes to descriptor */
|
||||
static int sigchld_stream(struct single *file) {
|
||||
/*!! call back to application */
|
||||
file->para.exec.pid = 0;
|
||||
if (file->sigchild) {
|
||||
return (*file->sigchild)(file);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* return 0 if socket is not responsible for deadchild */
|
||||
static int xio_checkchild(xiofile_t *socket, int socknum, pid_t deadchild) {
|
||||
int retval;
|
||||
if (socket != NULL) {
|
||||
if (socket->tag != XIO_TAG_DUAL) {
|
||||
if ((socket->stream.howtoend == END_KILL ||
|
||||
socket->stream.howtoend == END_CLOSE_KILL ||
|
||||
socket->stream.howtoend == END_SHUTDOWN_KILL) &&
|
||||
socket->stream.para.exec.pid == deadchild) {
|
||||
Info2("exec'd process %d on socket %d terminated",
|
||||
socket->stream.para.exec.pid, socknum);
|
||||
sigchld_stream(&socket->stream);
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
if (retval = xio_checkchild((xiofile_t *)socket->dual.stream[0], socknum, deadchild))
|
||||
return retval;
|
||||
else
|
||||
return xio_checkchild((xiofile_t *)socket->dual.stream[1], socknum, deadchild);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* this is the "physical" signal handler for SIGCHLD */
|
||||
/* the current socat/xio implementation knows two kinds of children:
|
||||
exec/system addresses perform a fork: these children are registered and
|
||||
there death influences the parents flow;
|
||||
listen-socket with fork children: these children are "anonymous" and their
|
||||
death does not affect the parent process (now; maybe we have a child
|
||||
process counter later) */
|
||||
void childdied(int signum) {
|
||||
pid_t pid;
|
||||
int _errno;
|
||||
int status = 0;
|
||||
bool wassig = false;
|
||||
int i;
|
||||
|
||||
_errno = errno; /* save current value; e.g., select() on Cygwin seems
|
||||
to set it to EINTR _before_ handling the signal, and
|
||||
then passes the value left by the signal handler to
|
||||
the caller of select(), accept() etc. */
|
||||
/* is not thread/signal save, but confused messages in rare cases are better
|
||||
than no messages at all */
|
||||
Info1("childdied(signum=%d)", signum);
|
||||
do {
|
||||
pid = Waitpid(-1, &status, WNOHANG);
|
||||
if (pid == 0) {
|
||||
Msg(wassig?E_INFO:E_WARN,
|
||||
"waitpid(-1, {}, WNOHANG): no child has exited");
|
||||
Info("childdied() finished");
|
||||
errno = _errno;
|
||||
return;
|
||||
} else if (pid < 0 && errno == ECHILD) {
|
||||
Msg1(wassig?E_INFO:E_WARN,
|
||||
"waitpid(-1, {}, WNOHANG): %s", strerror(errno));
|
||||
Info("childdied() finished");
|
||||
errno = _errno;
|
||||
return;
|
||||
}
|
||||
wassig = true;
|
||||
if (pid < 0) {
|
||||
Warn2("waitpid(-1, {%d}, WNOHANG): %s", status, strerror(errno));
|
||||
Info("childdied() finished");
|
||||
errno = _errno;
|
||||
return;
|
||||
}
|
||||
/*! indent */
|
||||
/* check if it was a registered child process */
|
||||
i = 0;
|
||||
while (i < XIO_MAXSOCK) {
|
||||
if (xio_checkchild(sock[i], i, pid)) break;
|
||||
++i;
|
||||
}
|
||||
if (i == XIO_MAXSOCK) {
|
||||
Info2("childdied(%d): cannot identify child %d", signum, pid);
|
||||
if (diedunknown1 == 0) {
|
||||
diedunknown1 = pid;
|
||||
Debug("saving pid in diedunknown1");
|
||||
} else if (diedunknown2 == 0) {
|
||||
diedunknown2 = pid;
|
||||
Debug("saving pid in diedunknown2");
|
||||
} else if (diedunknown3 == 0) {
|
||||
diedunknown3 = pid;
|
||||
Debug("saving pid in diedunknown3");
|
||||
} else {
|
||||
diedunknown4 = pid;
|
||||
Debug("saving pid in diedunknown4");
|
||||
}
|
||||
}
|
||||
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) == 0) {
|
||||
Info2("waitpid(): child %d exited with status %d",
|
||||
pid, WEXITSTATUS(status));
|
||||
} else {
|
||||
Warn2("waitpid(): child %d exited with status %d",
|
||||
pid, WEXITSTATUS(status));
|
||||
}
|
||||
} else if (WIFSIGNALED(status)) {
|
||||
Info2("waitpid(): child %d exited on signal %d",
|
||||
pid, WTERMSIG(status));
|
||||
} else if (WIFSTOPPED(status)) {
|
||||
Info2("waitpid(): child %d stopped on signal %d",
|
||||
pid, WSTOPSIG(status));
|
||||
} else {
|
||||
Warn1("waitpid(): cannot determine status of child %d", pid);
|
||||
}
|
||||
|
||||
#if !HAVE_SIGACTION
|
||||
/* we might need to re-register our handler */
|
||||
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
|
||||
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
|
||||
}
|
||||
#endif /* !HAVE_SIGACTION */
|
||||
} while (1);
|
||||
Info("childdied() finished");
|
||||
errno = _errno;
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue