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"
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
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. */
39 /* some assertions about termios */
41 #if defined(CRDLY) && CRDLY_SHIFT >= 0
42 assert(3 << opt_crdly
.arg3
== CRDLY
);
44 #if defined(TABDLY) && TABDLY_SHIFT >= 0
45 assert(3 << opt_tabdly
.arg3
== TABDLY
);
48 assert(3 << opt_csize
.arg3
== CSIZE
);
52 struct termios termarg
;
54 #if HAVE_TERMIOS_ISPEED
55 speed_t speeds
[sizeof(struct termios
)/sizeof(speed_t
)];
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]);
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]) {
81 xioparms
.default_ip
= default_ip
[0];
84 xioparms
.default_ip
= '0';
90 const char *preferred_ip
;
92 preferred_ip
= getenv("SOCAT_PREFERRED_RESOLVE_IP");
93 if (preferred_ip
!= NULL
) {
94 switch (preferred_ip
[0]) {
97 xioparms
.preferred_ip
= preferred_ip
[0];
100 xioparms
.preferred_ip
= '0';
106 if (Atexit(xioexit
) < 0) {
107 Error("atexit(xioexit) failed");
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);
124 /* well, this function is not for initialization, but I could not find a better
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) {
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
) {
151 if (sock
->tag
& XIO_TAG_CLOSED
) {
155 case XIO_TAG_INVALID
:
159 if ((result
= xio_nokill((xiofile_t
*)sock
->dual
.stream
[0])) != 0)
161 result
= xio_nokill((xiofile_t
*)sock
->dual
.stream
[1]);
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;
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) {
186 for (i
=0; i
<NUMUNKNOWN
; ++i
) {
192 if (xio_reset_fips_mode() != 0) {
195 #endif /* WITH_FIPS */
196 /* some locks belong to parent process, so "drop" them now */
197 if (xiohook_newchild
) {
198 if ((*xiohook_newchild
)() != 0) {
203 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
206 result2
= xio_nokill(sock1
);
207 if (result2
< 0) Exit(1);
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 */
222 const char *forkwaitstring
;
223 int forkwaitsecs
= 0;
225 if ((pid
= Fork()) < 0) {
226 Msg1(level
, "fork(): %s", strerror(errno
));
230 if (pid
== 0) { /* child process */
231 pid_t cpid
= Getpid();
233 Info1("just born: child process "F_pid
, cpid
);
235 /* set SOCAT_PID to new value */
236 xiosetenvulong("PID", pid
, 1);
238 /* Make sure the sub process does not hold the trigger pipe open */
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
);
252 if (xio_forked_inchild() != 0) {
255 diag_set_int('u', shutup
);
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
);