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 */
4
5 /* this file contains the source for the initialize function */
6
7 #include "xiosysincludes.h"
8
9 #include "xioopen.h"
10 #include "xiolockfile.h"
11
12 #include "xio-openssl.h" /* xio_reset_fips_mode() */
13
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;
19
20 /* returns 0 on success or != if an error occurred */
xioinitialize(void)21 int xioinitialize(void) {
22 if (xioinitialized) return 0;
23
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);
28
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);
33
34 assert(SHUT_RD==0);
35 assert(SHUT_WR==1);
36 assert(SHUT_RDWR==2);
37
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
49 {
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 }
66 #endif
67
68 /* these dependencies required in applyopts() for OFUNC_FCNTL */
69 assert(F_GETFD == F_SETFD-1);
70 assert(F_GETFL == F_SETFL-1);
71
72 {
73 const char *default_ip;
74 default_ip = getenv("SOCAT_DEFAULT_LISTEN_IP");
75 if (default_ip != NULL) {
76 switch (default_ip[0]) {
77 case '4':
78 case '6':
79 xioopts.default_ip = default_ip[0]; break;
80 }
81 }
82 }
83 {
84 const char *preferred_ip;
85 preferred_ip = getenv("SOCAT_PREFERRED_RESOLVE_IP");
86 if (preferred_ip != NULL) {
87 switch (preferred_ip[0]) {
88 case '4':
89 case '6':
90 xioopts.preferred_ip = preferred_ip[0]; break;
91 default:
92 xioopts.preferred_ip = '0'; break;
93 }
94 }
95 }
96
97 if (Atexit(xioexit) < 0) {
98 Error("atexit(xioexit) failed");
99 return -1;
100 }
101
102 xioinitialized = 1;
103 return 0;
104 }
105
106 /* call this function when option -lp (reset program name) has been applied */
xioinitialize2(void)107 int xioinitialize2(void) {
108 pid_t pid = Getpid();
109 xiosetenvulong("PID", pid, 1);
110 xiosetenvulong("PPID", pid, 1);
111 return 0;
112 }
113
114
115 /* well, this function is not for initialization, but I could not find a better
116 place for it
117 it is called in the child process after fork
118 it drops the locks of the xiofile's so only the parent owns them
119 */
xiodroplocks(void)120 void xiodroplocks(void) {
121 int i;
122
123 for (i = 0; i < XIO_MAXSOCK; ++i) {
124 if (sock[i] != NULL && sock[i]->tag != XIO_TAG_INVALID) {
125 xiofiledroplock(sock[i]);
126 }
127 }
128 }
129
130
131 /* consider an invokation like this:
132 socat -u exec:'some program that accepts data' tcp-l:...,fork
133 we do not want the program to be killed by the first tcp-l sub process, it's
134 better if it survives all sub processes. Thus, it must not be killed when
135 the sub process delivers EOF. Also, a socket that is reused in sub processes
136 should not be shut down (affects the connection), but closed (affects only
137 sub processes copy of file descriptor) */
xio_nokill(xiofile_t * sock)138 static int xio_nokill(xiofile_t *sock) {
139 int result = 0;
140 switch (sock->tag) {
141 case XIO_TAG_INVALID:
142 default:
143 return -1;
144 case XIO_TAG_DUAL:
145 if ((result = xio_nokill((xiofile_t *)sock->dual.stream[0])) != 0)
146 return result;
147 result = xio_nokill((xiofile_t *)sock->dual.stream[1]);
148 break;
149 case XIO_TAG_RDONLY:
150 case XIO_TAG_WRONLY:
151 case XIO_TAG_RDWR:
152 /* here is the core of this function */
153 switch (sock->stream.howtoend) {
154 case END_SHUTDOWN_KILL: sock->stream.howtoend = END_CLOSE; break;
155 case END_CLOSE_KILL: sock->stream.howtoend = END_CLOSE; break;
156 case END_SHUTDOWN: sock->stream.howtoend = END_CLOSE; break;
157 default: break;
158 }
159 break;
160 }
161 return result;
162 }
163
164 /* call this function immediately after fork() in child process */
165 /* it performs some neccessary actions
166 returns 0 on success or != 0 if an error occurred */
xio_forked_inchild(void)167 int xio_forked_inchild(void) {
168 int result = 0;
169 int i;
170
171 diag_fork();
172 for (i=0; i<NUMUNKNOWN; ++i) {
173 diedunknown[i] = 0;
174 }
175 num_child = 0;
176 xiodroplocks();
177 #if WITH_FIPS
178 if (xio_reset_fips_mode() != 0) {
179 result = 1;
180 }
181 #endif /* WITH_FIPS */
182 /* some locks belong to parent process, so "drop" them now */
183 if (xiohook_newchild) {
184 if ((*xiohook_newchild)() != 0) {
185 Exit(1);
186 }
187 }
188
189 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
190 if (sock1 != NULL) {
191 int result2;
192 result2 = xio_nokill(sock1);
193 if (result2 < 0) Exit(1);
194 result |= result2;
195 }
196
197 return result;
198 }
199
200 /* subchild != 0 means that the current process is already a child process of
201 the master process and thus the new sub child process should not set the
202 SOCAT_PID variable */
xio_fork(bool subchild,int level)203 pid_t xio_fork(bool subchild, int level) {
204 pid_t pid;
205 const char *forkwaitstring;
206 int forkwaitsecs = 0;
207
208 if ((pid = Fork()) < 0) {
209 Msg1(level, "fork(): %s", strerror(errno));
210 return pid;
211 }
212
213 if (pid == 0) { /* child process */
214 pid_t cpid = Getpid();
215
216 Info1("just born: child process "F_pid, cpid);
217 if (!subchild) {
218 /* set SOCAT_PID to new value */
219 xiosetenvulong("PID", pid, 1);
220 }
221 /* gdb recommends to have env controlled sleep after fork */
222 if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
223 forkwaitsecs = atoi(forkwaitstring);
224 Sleep(forkwaitsecs);
225 }
226 if (xio_forked_inchild() != 0) {
227 Exit(1);
228 }
229 return 0;
230 }
231
232 num_child++;
233 /* parent process */
234 Notice1("forked off child process "F_pid, pid);
235 /* gdb recommends to have env controlled sleep after fork */
236 if (forkwaitstring = getenv("SOCAT_FORK_WAIT")) {
237 forkwaitsecs = atoi(forkwaitstring);
238 Sleep(forkwaitsecs);
239 }
240 return pid;
241 }
242