version 1.7.3.0
[socat.git] / xioinitialize.c
blob9f501557e8ff81d8982991c028bd2b68c1f21fc8
1 /* source: xioinitialize.c */
2 /* Copyright Gerhard Rieger 2001-2011 */
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]);
65 #if HAVE_TERMIOS_ISPEED && (ISPEED_OFFSET != -1) && (OSPEED_OFFSET != -1)
66 #if defined(ISPEED_OFFSET) && (ISPEED_OFFSET != -1)
67 #if defined(OSPEED_OFFSET) && (OSPEED_OFFSET != -1)
68 tdata.termarg.c_ispeed = 0x56789abc;
69 tdata.termarg.c_ospeed = 0x6789abcd;
70 assert(tdata.termarg.c_ispeed == tdata.speeds[ISPEED_OFFSET]);
71 assert(tdata.termarg.c_ospeed == tdata.speeds[OSPEED_OFFSET]);
72 #endif
73 #endif
74 #endif
76 #endif
78 /* these dependencies required in applyopts() for OFUNC_FCNTL */
79 assert(F_GETFD == F_SETFD-1);
80 assert(F_GETFL == F_SETFL-1);
83 const char *default_ip;
84 default_ip = getenv("SOCAT_DEFAULT_LISTEN_IP");
85 if (default_ip != NULL) {
86 switch (default_ip[0]) {
87 case '4':
88 case '6':
89 xioopts.default_ip = default_ip[0]; break;
94 const char *preferred_ip;
95 preferred_ip = getenv("SOCAT_PREFERRED_RESOLVE_IP");
96 if (preferred_ip != NULL) {
97 switch (preferred_ip[0]) {
98 case '4':
99 case '6':
100 xioopts.preferred_ip = preferred_ip[0]; break;
101 default:
102 xioopts.preferred_ip = '0'; break;
107 if (Atexit(xioexit) < 0) {
108 Error("atexit(xioexit) failed");
109 return -1;
112 xioinitialized = 1;
113 return 0;
116 /* call this function when option -lp (reset program name) has been applied */
117 int xioinitialize2(void) {
118 pid_t pid = Getpid();
119 xiosetenvulong("PID", pid, 1);
120 xiosetenvulong("PPID", pid, 1);
121 return 0;
125 /* well, this function is not for initialization, but I could not find a better
126 place for it
127 it is called in the child process after fork
128 it drops the locks of the xiofile's so only the parent owns them
130 void xiodroplocks(void) {
131 int i;
133 for (i = 0; i < XIO_MAXSOCK; ++i) {
134 if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) {
135 xiofiledroplock(sock[i]);
141 /* consider an invokation 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;
150 switch (sock->tag) {
151 case XIO_TAG_INVALID:
152 default:
153 return -1;
154 case XIO_TAG_DUAL:
155 if ((result = xio_nokill((xiofile_t *)sock->dual.stream[0])) != 0)
156 return result;
157 result = xio_nokill((xiofile_t *)sock->dual.stream[1]);
158 break;
159 case XIO_TAG_RDONLY:
160 case XIO_TAG_WRONLY:
161 case XIO_TAG_RDWR:
162 /* here is the core of this function */
163 switch (sock->stream.howtoend) {
164 case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break;
165 case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break;
166 case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break;
167 default: break;
169 break;
171 return result;
174 /* call this function immediately after fork() in child process */
175 /* it performs some neccessary actions
176 returns 0 on success or != 0 if an error occurred */
177 int xio_forked_inchild(void) {
178 int result = 0;
179 int i;
181 for (i=0; i<NUMUNKNOWN; ++i) {
182 diedunknown[i] = 0;
184 num_child = 0;
185 xiodroplocks();
186 #if WITH_FIPS
187 if (xio_reset_fips_mode() != 0) {
188 result = 1;
190 #endif /* WITH_FIPS */
191 /* some locks belong to parent process, so "drop" them now */
192 if (xiohook_newchild) {
193 if ((*xiohook_newchild)() != 0) {
194 Exit(1);
198 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
199 if (sock1 != NULL) {
200 int result2;
201 result2 = xio_nokill(sock1);
202 if (result2 < 0) Exit(1);
203 result |= result2;
206 return result;
209 /* subchild != 0 means that the current process is already a child process of
210 the master process and thus the new sub child process should not set the
211 SOCAT_PID variable */
212 pid_t xio_fork(bool subchild, int level) {
213 pid_t pid;
214 const char *forkwaitstring;
215 int forkwaitsecs = 0;
217 if ((pid = Fork()) < 0) {
218 Msg1(level, "fork(): %s", strerror(errno));
219 return pid;
222 if (pid == 0) { /* child process */
223 pid_t cpid = Getpid();
225 Info1("just born: child process "F_pid, cpid);
226 if (!subchild) {
227 /* set SOCAT_PID to new value */
228 xiosetenvulong("PID", pid, 1);
230 /* gdb recommends to have env controlled sleep after fork */
231 if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
232 forkwaitsecs = atoi(forkwaitstring);
233 Sleep(forkwaitsecs);
235 if (xio_forked_inchild() != 0) {
236 Exit(1);
238 return 0;
241 num_child++;
242 /* parent process */
243 Notice1("forked off child process "F_pid, pid);
244 /* gdb recommends to have env controlled sleep after fork */
245 if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
246 forkwaitsecs = atoi(forkwaitstring);
247 Sleep(forkwaitsecs);
249 return pid;