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
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. */
38 /* some assertions about termios */
40 #if defined(CRDLY) && CRDLY_SHIFT >= 0
41 assert(3 << opt_crdly
.arg3
== CRDLY
);
43 #if defined(TABDLY) && TABDLY_SHIFT >= 0
44 assert(3 << opt_tabdly
.arg3
== TABDLY
);
47 assert(3 << opt_csize
.arg3
== CSIZE
);
51 struct termios termarg
;
53 #if HAVE_TERMIOS_ISPEED
54 speed_t speeds
[sizeof(struct termios
)/sizeof(speed_t
)];
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]);
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]) {
80 xioparms
.default_ip
= default_ip
[0];
83 xioparms
.default_ip
= '0';
89 const char *preferred_ip
;
91 preferred_ip
= getenv("SOCAT_PREFERRED_RESOLVE_IP");
92 if (preferred_ip
!= NULL
) {
93 switch (preferred_ip
[0]) {
96 xioparms
.preferred_ip
= preferred_ip
[0];
99 xioparms
.preferred_ip
= '0';
105 if (Atexit(xioexit
) < 0) {
106 Error("atexit(xioexit) failed");
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);
123 /* well, this function is not for initialization, but I could not find a better
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) {
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
) {
150 if (sock
->tag
& XIO_TAG_CLOSED
) {
154 case XIO_TAG_INVALID
:
158 if ((result
= xio_nokill((xiofile_t
*)sock
->dual
.stream
[0])) != 0)
160 result
= xio_nokill((xiofile_t
*)sock
->dual
.stream
[1]);
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;
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) {
185 for (i
=0; i
<NUMUNKNOWN
; ++i
) {
191 if (xio_reset_fips_mode() != 0) {
194 #endif /* WITH_FIPS */
195 /* some locks belong to parent process, so "drop" them now */
196 if (xiohook_newchild
) {
197 if ((*xiohook_newchild
)() != 0) {
202 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
205 result2
= xio_nokill(sock1
);
206 if (result2
< 0) Exit(1);
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 */
221 const char *forkwaitstring
;
222 int forkwaitsecs
= 0;
224 if ((pid
= Fork()) < 0) {
225 Msg1(level
, "fork(): %s", strerror(errno
));
229 if (pid
== 0) { /* child process */
230 pid_t cpid
= Getpid();
232 Info1("just born: child process "F_pid
, cpid
);
234 /* set SOCAT_PID to new value */
235 xiosetenvulong("PID", pid
, 1);
237 /* Make sure the sub process does not hold the trigger pipe open */
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
);
251 if (xio_forked_inchild() != 0) {
254 diag_set_int('u', shutup
);
259 Info1("number of children increased to %d", num_child
);
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
);