mirror of
https://github.com/moparisthebest/socat
synced 2024-11-16 05:55:11 -05:00
277 lines
7.6 KiB
C
277 lines
7.6 KiB
C
/* source: xioinitialize.c */
|
|
/* Copyright Gerhard Rieger 2001-2008 */
|
|
/* Published under the GNU General Public License V.2, see file COPYING */
|
|
|
|
/* this file contains the source for the initialize function */
|
|
|
|
#include "xiosysincludes.h"
|
|
|
|
#include "xiostatic.h"
|
|
#include "xioopen.h"
|
|
#include "xiolockfile.h"
|
|
#include "xiosigchld.h"
|
|
|
|
#include "xio-openssl.h" /* xio_reset_fips_mode() */
|
|
|
|
static int xioinitialized;
|
|
xiofile_t *sock[XIO_MAXSOCK];
|
|
int (*xiohook_newchild)(void); /* xio calls this function in every new child
|
|
process */
|
|
|
|
|
|
/* call this function before calling any other xio function.
|
|
With xioflags, you have to set the features that xio can make use of.
|
|
Use XIO_MAYALL for unrestricted use. */
|
|
/* returns 0 on success or != if an error occurred */
|
|
int xioinitialize(int xioflags) {
|
|
int xio_flags;
|
|
if (xioinitialized) return 0;
|
|
|
|
/* configure and .h's cannot guarantee this */
|
|
assert(sizeof(uint8_t)==1);
|
|
assert(sizeof(uint16_t)==2);
|
|
assert(sizeof(uint32_t)==4);
|
|
|
|
/* assertions regarding O_ flags - important for XIO_READABLE() etc. */
|
|
assert(O_RDONLY==0);
|
|
assert(O_WRONLY==1);
|
|
assert(O_RDWR==2);
|
|
|
|
assert(SHUT_RD==0);
|
|
assert(SHUT_WR==1);
|
|
assert(SHUT_RDWR==2);
|
|
|
|
/* some assertions about termios */
|
|
#if WITH_TERMIOS
|
|
#if defined(CRDLY) && CRDLY_SHIFT >= 0
|
|
assert(3 << opt_crdly.arg3 == CRDLY);
|
|
#endif
|
|
#if defined(TABDLY) && TABDLY_SHIFT >= 0
|
|
assert(3 << opt_tabdly.arg3 == TABDLY);
|
|
#endif
|
|
#if CSIZE_SHIFT >= 0
|
|
assert(3 << opt_csize.arg3 == CSIZE);
|
|
#endif
|
|
{
|
|
union {
|
|
struct termios termarg;
|
|
tcflag_t flags[4];
|
|
#if HAVE_TERMIOS_ISPEED
|
|
speed_t speeds[sizeof(struct termios)/sizeof(speed_t)];
|
|
#endif
|
|
} tdata;
|
|
tdata.termarg.c_iflag = 0x12345678;
|
|
tdata.termarg.c_oflag = 0x23456789;
|
|
tdata.termarg.c_cflag = 0x3456789a;
|
|
tdata.termarg.c_lflag = 0x456789ab;
|
|
assert(tdata.termarg.c_iflag == tdata.flags[0]);
|
|
assert(tdata.termarg.c_oflag == tdata.flags[1]);
|
|
assert(tdata.termarg.c_cflag == tdata.flags[2]);
|
|
assert(tdata.termarg.c_lflag == tdata.flags[3]);
|
|
#if HAVE_TERMIOS_ISPEED
|
|
tdata.termarg.c_ispeed = 0x56789abc;
|
|
tdata.termarg.c_ospeed = 0x6789abcd;
|
|
assert(tdata.termarg.c_ispeed == tdata.speeds[ISPEED_OFFSET]);
|
|
assert(tdata.termarg.c_ospeed == tdata.speeds[OSPEED_OFFSET]);
|
|
#endif
|
|
}
|
|
#endif /* WITH_TERMIOS */
|
|
|
|
/* these dependencies required in applyopts() for OFUNC_FCNTL */
|
|
assert(F_GETFD == F_SETFD-1);
|
|
assert(F_GETFL == F_SETFL-1);
|
|
|
|
{
|
|
const char *default_ip;
|
|
default_ip = getenv("SOCAT_DEFAULT_LISTEN_IP");
|
|
if (default_ip != NULL) {
|
|
switch (default_ip[0]) {
|
|
case '4':
|
|
case '6':
|
|
xioopts.default_ip = default_ip[0]; break;
|
|
}
|
|
}
|
|
}
|
|
{
|
|
const char *preferred_ip;
|
|
preferred_ip = getenv("SOCAT_PREFERRED_RESOLVE_IP");
|
|
if (preferred_ip != NULL) {
|
|
switch (preferred_ip[0]) {
|
|
case '4':
|
|
case '6':
|
|
xioopts.preferred_ip = preferred_ip[0]; break;
|
|
default:
|
|
xioopts.preferred_ip = '0'; break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Atexit(xioexit) < 0) {
|
|
Error("atexit(xioexit) failed");
|
|
return -1;
|
|
}
|
|
|
|
xio_flags = xioflags;
|
|
|
|
if ((xio_flags|XIO_MAYFORK) || (xio_flags|XIO_MAYCHILD) ||
|
|
(xio_flags|XIO_MAYCHAIN)) {
|
|
|
|
#if HAVE_SIGACTION
|
|
struct sigaction act;
|
|
memset(&act, 0, sizeof(struct sigaction));
|
|
act.sa_flags = SA_NOCLDSTOP|SA_RESTART|SA_SIGINFO
|
|
#ifdef SA_NOMASK
|
|
|SA_NOMASK
|
|
#endif
|
|
;
|
|
act.sa_sigaction = childdied;
|
|
if (Sigaction(SIGCHLD, &act, NULL) < 0) {
|
|
/*! Linux man does not explicitely say that errno is defined */
|
|
Warn2("sigaction(SIGCHLD, %p, NULL): %s", childdied, strerror(errno));
|
|
}
|
|
#else /* !HAVE_SIGACTION */
|
|
act.sa_handler = childdied;
|
|
if (Signal(SIGCHLD, childdied) == SIG_ERR) {
|
|
Warn2("signal(SIGCHLD, %p): %s", childdied, strerror(errno));
|
|
}
|
|
#endif /* !HAVE_SIGACTION */
|
|
}
|
|
|
|
xioinitialized = 1;
|
|
return 0;
|
|
}
|
|
|
|
/* call this function when option -lp (reset program name) has been applied */
|
|
int xioinitialize2(void) {
|
|
pid_t pid = Getpid();
|
|
xiosetenvulong("PID", pid, 1);
|
|
xiosetenvulong("PPID", pid, 1);
|
|
return 0;
|
|
}
|
|
|
|
|
|
/* well, this function is not for initialization, but I could not find a better
|
|
source file for it
|
|
it is called in the child process after fork
|
|
it drops the lock references of the xiofile's so only the parent owns them
|
|
*/
|
|
void xiodroplocks(void) {
|
|
int i;
|
|
|
|
for (i = 0; i < XIO_MAXSOCK; ++i) {
|
|
if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) {
|
|
xiofiledroplock(sock[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
#if 0
|
|
/* consider an invokation like this:
|
|
socat -u exec:'some program that accepts data' tcp-l:...,fork
|
|
we do not want the program to be killed by the first tcp-l sub process, it's
|
|
better if it survives all sub processes. Thus, it must not be killed when
|
|
the sub process delivers EOF. Also, a socket that is reused in sub processes
|
|
should not be shut down (affects the connection), but closed (affects only
|
|
sub processes copy of file descriptor) */
|
|
static int xio_nokill(xiofile_t *sock) {
|
|
int result = 0;
|
|
switch (sock->tag) {
|
|
case XIO_TAG_INVALID:
|
|
default:
|
|
return -1;
|
|
case XIO_TAG_DUAL:
|
|
if ((result = xio_nokill((xiofile_t *)sock->dual.stream[0])) != 0)
|
|
return result;
|
|
result = xio_nokill((xiofile_t *)sock->dual.stream[1]);
|
|
break;
|
|
case XIO_TAG_RDONLY:
|
|
case XIO_TAG_WRONLY:
|
|
case XIO_TAG_RDWR:
|
|
/* here is the core of this function */
|
|
switch (sock->stream.howtoclose) {
|
|
case END_SHUTDOWN_KILL: sock->stream.howtoclose = END_CLOSE; break;
|
|
case END_CLOSE_KILL: sock->stream.howtoclose = END_CLOSE; break;
|
|
case END_SHUTDOWN: sock->stream.howtoclose = END_CLOSE; break;
|
|
default: break;
|
|
}
|
|
break;
|
|
}
|
|
return result;
|
|
}
|
|
#endif /* 0 */
|
|
|
|
/* call this function immediately after fork() in child process */
|
|
/* it performs some neccessary actions
|
|
returns 0 on success or != 0 if an error occurred */
|
|
int xio_forked_inchild(void) {
|
|
int result = 0;
|
|
|
|
xiodroplocks();
|
|
#if WITH_FIPS
|
|
if (xio_reset_fips_mode() != 0) {
|
|
result = 1;
|
|
}
|
|
#endif /* WITH_FIPS */
|
|
/* some locks belong to parent process, so "drop" them now */
|
|
if (xiohook_newchild) {
|
|
if ((*xiohook_newchild)() != 0) {
|
|
Exit(1);
|
|
}
|
|
}
|
|
|
|
#if 0
|
|
/* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
|
|
if (sock1 != NULL) {
|
|
int result2;
|
|
result2 = xio_nokill(sock1);
|
|
if (result2 < 0) Exit(1);
|
|
result |= result2;
|
|
}
|
|
#endif
|
|
|
|
return result;
|
|
}
|
|
|
|
/* subchild != 0 means that the current process is already a child process of
|
|
the master process and thus the new sub child process should not set the
|
|
SOCAT_PID variable */
|
|
pid_t xio_fork(bool subchild, int level) {
|
|
pid_t pid;
|
|
const char *forkwaitstring;
|
|
int forkwaitsecs = 0;
|
|
|
|
if ((pid = Fork()) < 0) {
|
|
Msg1(level, "fork(): %s", strerror(errno));
|
|
return pid;
|
|
}
|
|
|
|
if (pid == 0) { /* child process */
|
|
pid_t cpid = Getpid();
|
|
|
|
Info1("just born: client process "F_pid, cpid);
|
|
if (!subchild) {
|
|
/* set SOCAT_PID to new value */
|
|
xiosetenvulong("PID", pid, 1);
|
|
}
|
|
/* gdb recommends to have env controlled sleep after fork */
|
|
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
|
|
forkwaitsecs = atoi(forkwaitstring);
|
|
Sleep(forkwaitsecs);
|
|
}
|
|
if (xio_forked_inchild() != 0) {
|
|
Exit(1);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* parent process */
|
|
Notice1("forked off child process "F_pid, pid);
|
|
/* gdb recommends to have env controlled sleep after fork */
|
|
if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
|
|
forkwaitsecs = atoi(forkwaitstring);
|
|
Sleep(forkwaitsecs);
|
|
}
|
|
return pid;
|
|
}
|