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