add listen-timeout to function as an accept timeout
[socat/sam.git] / xioinitialize.c
blob48674ef537ae219bd9c29641abe90be63395c284
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"
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
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]);
70 #endif
72 #endif
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]) {
83 case '4':
84 case '6':
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]) {
94 case '4':
95 case '6':
96 xioopts.preferred_ip = preferred_ip[0]; break;
97 default:
98 xioopts.preferred_ip = '0'; break;
103 if (Atexit(xioexit) < 0) {
104 Error("atexit(xioexit) failed");
105 return -1;
108 xioinitialized = 1;
109 return 0;
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);
117 return 0;
121 /* well, this function is not for initialization, but I could not find a better
122 place for it
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) {
127 int i;
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) {
145 int result = 0;
146 switch (sock->tag) {
147 case XIO_TAG_INVALID:
148 default:
149 return -1;
150 case XIO_TAG_DUAL:
151 if ((result = xio_nokill((xiofile_t *)sock->dual.stream[0])) != 0)
152 return result;
153 result = xio_nokill((xiofile_t *)sock->dual.stream[1]);
154 break;
155 case XIO_TAG_RDONLY:
156 case XIO_TAG_WRONLY:
157 case XIO_TAG_RDWR:
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;
163 default: break;
165 break;
167 return result;
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) {
174 int result = 0;
176 num_child = 0;
177 xiodroplocks();
178 #if WITH_FIPS
179 if (xio_reset_fips_mode() != 0) {
180 result = 1;
182 #endif /* WITH_FIPS */
183 /* some locks belong to parent process, so "drop" them now */
184 if (xiohook_newchild) {
185 if ((*xiohook_newchild)() != 0) {
186 Exit(1);
190 /* change XIO_SHUTDOWN_KILL to XIO_SHUTDOWN */
191 if (sock1 != NULL) {
192 int result2;
193 result2 = xio_nokill(sock1);
194 if (result2 < 0) Exit(1);
195 result |= result2;
198 return result;
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) {
205 pid_t pid;
206 const char *forkwaitstring;
207 int forkwaitsecs = 0;
209 if ((pid = Fork()) < 0) {
210 Msg1(level, "fork(): %s", strerror(errno));
211 return pid;
214 if (pid == 0) { /* child process */
215 pid_t cpid = Getpid();
217 Info1("just born: client process "F_pid, cpid);
218 if (!subchild) {
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);
225 Sleep(forkwaitsecs);
227 if (xio_forked_inchild() != 0) {
228 Exit(1);
230 return 0;
233 num_child++;
234 /* parent process */
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);
239 Sleep(forkwaitsecs);
241 return pid;