1 /* source: xioinitialize.c */
2 /* Copyright Gerhard Rieger 2001-2008 */
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]);
65 #if HAVE_TERMIOS_ISPEED
66 tdata
.termarg
.c_ispeed
= 0x56789abc;
67 tdata
.termarg
.c_ospeed
= 0x6789abcd;
68 assert(tdata
.termarg
.c_ispeed
== tdata
.speeds
[ISPEED_OFFSET
]);
69 assert(tdata
.termarg
.c_ospeed
== tdata
.speeds
[OSPEED_OFFSET
]);
74 /* these dependencies required in applyopts() for OFUNC_FCNTL */
75 assert(F_GETFD
== F_SETFD
-1);
76 assert(F_GETFL
== F_SETFL
-1);
79 const char *default_ip
;
80 default_ip
= getenv("SOCAT_DEFAULT_LISTEN_IP");
81 if (default_ip
!= NULL
) {
82 switch (default_ip
[0]) {
85 xioopts
.default_ip
= default_ip
[0]; break;
90 const char *preferred_ip
;
91 preferred_ip
= getenv("SOCAT_PREFERRED_RESOLVE_IP");
92 if (preferred_ip
!= NULL
) {
93 switch (preferred_ip
[0]) {
96 xioopts
.preferred_ip
= preferred_ip
[0]; break;
98 xioopts
.preferred_ip
= '0'; break;
103 if (Atexit(xioexit
) < 0) {
104 Error("atexit(xioexit) failed");
112 /* call this function when option -lp (reset program name) has been applied */
113 int xioinitialize2(void) {
114 pid_t pid
= Getpid();
115 xiosetenvulong("PID", pid
, 1);
116 xiosetenvulong("PPID", pid
, 1);
121 /* well, this function is not for initialization, but I could not find a better
123 it is called in the child process after fork
124 it drops the locks of the xiofile's so only the parent owns them
126 void xiodroplocks(void) {
129 for (i
= 0; i
< XIO_MAXSOCK
; ++i
) {
130 if (sock
[i
] != NULL
&& sock
[i
]->tag
!= XIO_TAG_INVALID
) {
131 xiofiledroplock(sock
[i
]);
137 /* consider an invokation like this:
138 socat -u exec:'some program that accepts data' tcp-l:...,fork
139 we do not want the program to be killed by the first tcp-l sub process, it's
140 better if it survives all sub processes. Thus, it must not be killed when
141 the sub process delivers EOF. Also, a socket that is reused in sub processes
142 should not be shut down (affects the connection), but closed (affects only
143 sub processes copy of file descriptor) */
144 static int xio_nokill(xiofile_t
*sock
) {
147 case XIO_TAG_INVALID
:
151 if ((result
= xio_nokill((xiofile_t
*)sock
->dual
.stream
[0])) != 0)
153 result
= xio_nokill((xiofile_t
*)sock
->dual
.stream
[1]);
158 /* here is the core of this function */
159 switch (sock
->stream
.howtoend
) {
160 case END_SHUTDOWN_KILL
: sock
->stream
.howtoend
= END_CLOSE
; break;
161 case END_CLOSE_KILL
: sock
->stream
.howtoend
= END_CLOSE
; break;
162 case END_SHUTDOWN
: sock
->stream
.howtoend
= END_CLOSE
; break;
170 /* call this function immediately after fork() in child process */
171 /* it performs some neccessary actions
172 returns 0 on success or != 0 if an error occurred */
173 int xio_forked_inchild(void) {
179 if (xio_reset_fips_mode() != 0) {
182 #endif /* WITH_FIPS */
183 /* some locks belong to parent process, so "drop" them now */
184 if (xiohook_newchild
) {
185 if ((*xiohook_newchild
)() != 0) {
190 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
193 result2
= xio_nokill(sock1
);
194 if (result2
< 0) Exit(1);
201 /* subchild != 0 means that the current process is already a child process of
202 the master process and thus the new sub child process should not set the
203 SOCAT_PID variable */
204 pid_t
xio_fork(bool subchild
, int level
) {
206 const char *forkwaitstring
;
207 int forkwaitsecs
= 0;
209 if ((pid
= Fork()) < 0) {
210 Msg1(level
, "fork(): %s", strerror(errno
));
214 if (pid
== 0) { /* child process */
215 pid_t cpid
= Getpid();
217 Info1("just born: client process "F_pid
, cpid
);
219 /* set SOCAT_PID to new value */
220 xiosetenvulong("PID", pid
, 1);
222 /* gdb recommends to have env controlled sleep after fork */
223 if (forkwaitstring
= getenv("SOCAT_FORK_WAIT")) {
224 forkwaitsecs
= atoi(forkwaitstring
);
227 if (xio_forked_inchild() != 0) {
235 Notice1("forked off child process "F_pid
, pid
);
236 /* gdb recommends to have env controlled sleep after fork */
237 if (forkwaitstring
= getenv("SOCAT_FORK_WAIT")) {
238 forkwaitsecs
= atoi(forkwaitstring
);