1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
|
/* source: xioinitialize.c */
/* Copyright Gerhard Rieger and contributors (see file CHANGES) */
/* 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 "xioopen.h"
#include "xiolockfile.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 from a new child
process */
int num_child = 0; /* actual number of "general" child processes */
bool first_child = true; /* only first child shall print general warnings */
/* returns 0 on success or != if an error occurred */
int xioinitialize(void) {
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. */
#ifdef __GNU__
assert(O_RDONLY==1);
assert(O_WRONLY==2);
assert(O_RDWR==3);
#else
assert(O_RDONLY==0);
assert(O_WRONLY==1);
assert(O_RDWR==2);
#endif
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]);
}
#endif
/* 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':
xioparms.default_ip = default_ip[0];
break;
default:
xioparms.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':
xioparms.preferred_ip = preferred_ip[0];
break;
default:
xioparms.preferred_ip = '0';
break;
}
}
}
if (Atexit(xioexit) < 0) {
Error("atexit(xioexit) failed");
return -1;
}
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
place for it
it is called in the child process after fork
it drops the locks 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 &&
!(sock[i]->tag & XIO_TAG_CLOSED)) {
xiofiledroplock(sock[i]);
}
}
}
/* Consider an invocation 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;
if (sock->tag & XIO_TAG_CLOSED) {
return -1;
}
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.howtoend) {
case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break;
case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break;
case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break;
default: break;
}
break;
}
return result;
}
/* Call this function immediately after fork() in child process */
/* It performs some necessary actions
returns 0 on success or != 0 if an error occurred */
int xio_forked_inchild(void) {
int result = 0;
int i;
diag_fork();
for (i=0; i<NUMUNKNOWN; ++i) {
diedunknown[i] = 0;
}
num_child = 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);
}
}
/* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
if (sock1 != NULL) {
int result2;
result2 = xio_nokill(sock1);
if (result2 < 0) Exit(1);
result |= result2;
}
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, /* log level */
int shutup) /* decrease log level in child process */
{
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: child process "F_pid, cpid);
if (!subchild) {
/* set SOCAT_PID to new value */
xiosetenvulong("PID", pid, 1);
} else {
/* Make sure the sub process does not hold the trigger pipe open */
if (sock1 != NULL) {
struct single *sfd;
sfd = XIO_RDSTREAM(sock1);
if (sfd->triggerfd >= 0) Close(sfd->triggerfd);
sfd = XIO_WRSTREAM(sock1);
if (sfd->triggerfd >= 0) Close(sfd->triggerfd);
}
}
/* 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);
}
diag_set_int('u', shutup);
return 0;
}
/* parent process */
if (!subchild) {
++num_child;
first_child = false;
}
Info1("number of children increased to %d", num_child);
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;
}
|