Version 1.8.0.1
[socat.git] / xioinitialize.c
blobb06915e75bf2b9fa766477743d6eedd05a2a6c73
1 /* source: xioinitialize.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 the initialize function */
7 #include "xiosysincludes.h"
9 #include "xioopen.h"
10 #include "xiolockfile.h"
12 #include "xio-openssl.h" /* xio_reset_fips_mode() */
14 static int xioinitialized;
15 xiofile_t *sock[XIO_MAXSOCK];
16 int (*xiohook_newchild)(void); /* xio calls this function from a new child
17 process */
18 int num_child = 0; /* actual number of "general" child processes */
19 bool first_child = true; /* only first child shall print general warnings */
21 /* returns 0 on success or != if an error occurred */
22 int xioinitialize(void) {
23 if (xioinitialized) return 0;
25 /* configure and .h's cannot guarantee this */
26 assert(sizeof(uint8_t)==1);
27 assert(sizeof(uint16_t)==2);
28 assert(sizeof(uint32_t)==4);
30 /* assertions regarding O_ flags - important for XIO_READABLE() etc. */
31 assert(O_RDONLY==0);
32 assert(O_WRONLY==1);
33 assert(O_RDWR==2);
35 assert(SHUT_RD==0);
36 assert(SHUT_WR==1);
37 assert(SHUT_RDWR==2);
39 /* some assertions about termios */
40 #if WITH_TERMIOS
41 #if defined(CRDLY) && CRDLY_SHIFT >= 0
42 assert(3 << opt_crdly.arg3 == CRDLY);
43 #endif
44 #if defined(TABDLY) && TABDLY_SHIFT >= 0
45 assert(3 << opt_tabdly.arg3 == TABDLY);
46 #endif
47 #if CSIZE_SHIFT >= 0
48 assert(3 << opt_csize.arg3 == CSIZE);
49 #endif
51 union {
52 struct termios termarg;
53 tcflag_t flags[4];
54 #if HAVE_TERMIOS_ISPEED
55 speed_t speeds[sizeof(struct termios)/sizeof(speed_t)];
56 #endif
57 } tdata;
58 tdata.termarg.c_iflag = 0x12345678;
59 tdata.termarg.c_oflag = 0x23456789;
60 tdata.termarg.c_cflag = 0x3456789a;
61 tdata.termarg.c_lflag = 0x456789ab;
62 assert(tdata.termarg.c_iflag == tdata.flags[0]);
63 assert(tdata.termarg.c_oflag == tdata.flags[1]);
64 assert(tdata.termarg.c_cflag == tdata.flags[2]);
65 assert(tdata.termarg.c_lflag == tdata.flags[3]);
67 #endif
69 /* these dependencies required in applyopts() for OFUNC_FCNTL */
70 assert(F_GETFD == F_SETFD-1);
71 assert(F_GETFL == F_SETFL-1);
74 const char *default_ip;
76 default_ip = getenv("SOCAT_DEFAULT_LISTEN_IP");
77 if (default_ip != NULL) {
78 switch (default_ip[0]) {
79 case '4':
80 case '6':
81 xioparms.default_ip = default_ip[0];
82 break;
83 default:
84 xioparms.default_ip = '0';
85 break;
90 const char *preferred_ip;
92 preferred_ip = getenv("SOCAT_PREFERRED_RESOLVE_IP");
93 if (preferred_ip != NULL) {
94 switch (preferred_ip[0]) {
95 case '4':
96 case '6':
97 xioparms.preferred_ip = preferred_ip[0];
98 break;
99 default:
100 xioparms.preferred_ip = '0';
101 break;
106 if (Atexit(xioexit) < 0) {
107 Error("atexit(xioexit) failed");
108 return -1;
111 xioinitialized = 1;
112 return 0;
115 /* call this function when option -lp (reset program name) has been applied */
116 int xioinitialize2(void) {
117 pid_t pid = Getpid();
118 xiosetenvulong("PID", pid, 1);
119 xiosetenvulong("PPID", pid, 1);
120 return 0;
124 /* well, this function is not for initialization, but I could not find a better
125 place for it
126 it is called in the child process after fork
127 it drops the locks of the xiofile's so only the parent owns them
129 void xiodroplocks(void) {
130 int i;
132 for (i = 0; i < XIO_MAXSOCK; ++i) {
133 if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID &&
134 !(sock[i]->tag & XIO_TAG_CLOSED)) {
135 xiofiledroplock(sock[i]);
141 /* Consider an invocation like this:
142 socat -u EXEC:'some program that accepts data' TCP-L:...,fork
143 we do not want the program to be killed by the first TCP-L sub process, it's
144 better if it survives all sub processes. Thus, it must not be killed when
145 the sub process delivers EOF. Also, a socket that is reused in sub processes
146 should not be shut down (affects the connection), but closed (affects only
147 sub processes copy of file descriptor) */
148 static int xio_nokill(xiofile_t *sock) {
149 int result = 0;
151 if (sock->tag & XIO_TAG_CLOSED) {
152 return -1;
154 switch (sock->tag) {
155 case XIO_TAG_INVALID:
156 default:
157 return -1;
158 case XIO_TAG_DUAL:
159 if ((result = xio_nokill((xiofile_t *)sock->dual.stream[0])) != 0)
160 return result;
161 result = xio_nokill((xiofile_t *)sock->dual.stream[1]);
162 break;
163 case XIO_TAG_RDONLY:
164 case XIO_TAG_WRONLY:
165 case XIO_TAG_RDWR:
166 /* here is the core of this function */
167 switch (sock->stream.howtoend) {
168 case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break;
169 case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break;
170 case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break;
171 default: break;
173 break;
175 return result;
178 /* call this function immediately after fork() in child process */
179 /* it performs some neccessary actions
180 returns 0 on success or != 0 if an error occurred */
181 int xio_forked_inchild(void) {
182 int result = 0;
183 int i;
185 diag_fork();
186 for (i=0; i<NUMUNKNOWN; ++i) {
187 diedunknown[i] = 0;
189 num_child = 0;
190 xiodroplocks();
191 #if WITH_FIPS
192 if (xio_reset_fips_mode() != 0) {
193 result = 1;
195 #endif /* WITH_FIPS */
196 /* some locks belong to parent process, so "drop" them now */
197 if (xiohook_newchild) {
198 if ((*xiohook_newchild)() != 0) {
199 Exit(1);
203 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
204 if (sock1 != NULL) {
205 int result2;
206 result2 = xio_nokill(sock1);
207 if (result2 < 0) Exit(1);
208 result |= result2;
211 return result;
214 /* subchild != 0 means that the current process is already a child process of
215 the master process and thus the new sub child process should not set the
216 SOCAT_PID variable */
217 pid_t xio_fork(bool subchild,
218 int level, /* log level */
219 int shutup) /* decrease log level in child process */
221 pid_t pid;
222 const char *forkwaitstring;
223 int forkwaitsecs = 0;
225 if ((pid = Fork()) < 0) {
226 Msg1(level, "fork(): %s", strerror(errno));
227 return pid;
230 if (pid == 0) { /* child process */
231 pid_t cpid = Getpid();
233 Info1("just born: child process "F_pid, cpid);
234 if (!subchild) {
235 /* set SOCAT_PID to new value */
236 xiosetenvulong("PID", pid, 1);
237 } else {
238 /* Make sure the sub process does not hold the trigger pipe open */
239 if (sock1 != NULL) {
240 struct single *sfd;
241 sfd = XIO_RDSTREAM(sock1);
242 if (sfd->triggerfd >= 0) Close(sfd->triggerfd);
243 sfd = XIO_WRSTREAM(sock1);
244 if (sfd->triggerfd >= 0) Close(sfd->triggerfd);
247 /* gdb recommends to have env controlled sleep after fork */
248 if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
249 forkwaitsecs = atoi(forkwaitstring);
250 Sleep(forkwaitsecs);
252 if (xio_forked_inchild() != 0) {
253 Exit(1);
255 diag_set_int('u', shutup);
256 return 0;
259 /* parent process */
260 if (!subchild) {
261 ++num_child;
262 first_child = false;
264 Info1("number of children increased to %d", num_child);
265 Notice1("forked off child process "F_pid, pid);
266 /* gdb recommends to have env controlled sleep after fork */
267 if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
268 forkwaitsecs = atoi(forkwaitstring);
269 Sleep(forkwaitsecs);
271 return pid;