2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this is the main source, including command line option parsing, general
6 control, and the data shuffler */
9 #include "xioconfig.h" /* what features are enabled */
11 #include "sysincludes.h"
23 #include "xiolockfile.h"
26 /* command line options */
31 struct timeval pollintv
; /* with ignoreeof, reread after seconds */
32 struct timeval closwait
; /* after close of x, die after seconds */
33 struct timeval total_timeout
;/* when nothing happens, die after seconds */
35 bool strictopts
; /* stop on errors in address options */
36 char logopt
; /* y..syslog; s..stderr; f..file; m..mixed */
37 bool lefttoright
; /* first addr ro, second addr wo */
38 bool righttoleft
; /* first addr wo, second addr ro */
39 xiolock_t lock
; /* a lock file */
45 {0,500000}, /* closwait */
46 {0,0}, /* total_timeout */
50 false, /* lefttoright */
51 false, /* righttoleft */
52 { NULL
, 0 }, /* lock */
55 void socat_usage(FILE *fd
);
56 void socat_opt_hint(FILE *fd
, char a
, char b
);
57 void socat_version(FILE *fd
);
58 int socat(const char *address1
, const char *address2
);
60 int cv_newline(unsigned char *buff
, ssize_t
*bytes
, int lineterm1
, int lineterm2
);
61 void socat_signal(int sig
);
62 static int socat_sigchild(struct single
*file
);
64 void lftocrlf(char **in
, ssize_t
*len
, size_t bufsiz
);
65 void crlftolf(char **in
, ssize_t
*len
, size_t bufsiz
);
67 static int socat_lock(void);
68 static void socat_unlock(void);
69 static int socat_newchild(void);
71 static const char socatversion
[] =
74 static const char timestamp
[] = BUILD_DATE
;
76 const char copyright_socat
[] = "socat by Gerhard Rieger and contributors - see www.dest-unreach.org";
78 const char copyright_openssl
[] = "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)";
79 const char copyright_ssleay
[] = "This product includes software written by Tim Hudson (tjh@cryptsoft.com)";
85 int main(int argc
, const char *argv
[]) {
86 const char **arg1
, *a
;
94 if (mainwaitstring
= getenv("SOCAT_MAIN_WAIT")) {
95 sleep(atoi(mainwaitstring
));
97 diag_set('p', strchr(argv
[0], '/') ? strrchr(argv
[0], '/')+1 : argv
[0]);
99 /* we must init before applying options because env settings have lower
100 priority and are to be overridden by options */
101 if (xioinitialize() != 0) {
105 xiosetopt('p', "!!");
108 argc0
= argc
; /* save for later use */
109 arg1
= argv
+1; --argc
;
110 while (arg1
[0] && (arg1
[0][0] == '-')) {
111 switch (arg1
[0][1]) {
112 case 'V': if (arg1
[0][2]) { socat_usage(stderr
); Exit(1); }
113 socat_version(stdout
); Exit(0);
118 xioopenhelp(stdout
, (arg1
[0][2]=='?'||arg1
[0][2]=='h') ? (arg1
[0][3]=='?'||arg1
[0][3]=='h') ? 2 : 1 : 0);
120 #endif /* WITH_HELP */
134 case 'D': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
135 socat_opts
.debug
= true; break;
138 switch (arg1
[0][2]) {
139 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
142 socat_opts
.logopt
= arg1
[0][2];
143 xiosetopt('y', &arg1
[0][3]);
145 case 'y': /* syslog + facility */
146 diag_set(arg1
[0][2], &arg1
[0][3]);
148 case 'f': /* to file, +filename */
149 case 'p': /* artificial program name */
151 diag_set(arg1
[0][2], &arg1
[0][3]);
152 } else if (arg1
[1]) {
153 diag_set(arg1
[0][2], arg1
[1]);
156 Error1("option -l%c requires an argument; use option \"-h\" for help", arg1
[0][2]);
159 case 's': /* stderr */
160 diag_set(arg1
[0][2], NULL
);
166 diag_set_int('h', true);
169 Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1
[0]);
173 case 'v': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
174 socat_opts
.verbose
= true; break;
175 case 'x': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
176 socat_opts
.verbhex
= true; break;
177 case 'b': if (arg1
[0][2]) {
181 if ((a
= *arg1
) == NULL
) {
182 Error("option -b requires an argument; use option \"-h\" for help");
186 socat_opts
.bufsiz
= strtoul(a
, (char **)&a
, 0);
188 case 's': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
189 diag_set_int('e', E_FATAL
); break;
190 case 't': if (arg1
[0][2]) {
194 if ((a
= *arg1
) == NULL
) {
195 Error("option -t requires an argument; use option \"-h\" for help");
199 rto
= strtod(a
, (char **)&a
);
200 socat_opts
.closwait
.tv_sec
= rto
;
201 socat_opts
.closwait
.tv_usec
=
202 (rto
-socat_opts
.closwait
.tv_sec
) * 1000000;
204 case 'T': if (arg1
[0][2]) {
208 if ((a
= *arg1
) == NULL
) {
209 Error("option -T requires an argument; use option \"-h\" for help");
213 rto
= strtod(a
, (char **)&a
);
214 socat_opts
.total_timeout
.tv_sec
= rto
;
215 socat_opts
.total_timeout
.tv_usec
=
216 (rto
-socat_opts
.total_timeout
.tv_sec
) * 1000000;
218 case 'u': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
219 socat_opts
.lefttoright
= true; break;
220 case 'U': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
221 socat_opts
.righttoleft
= true; break;
222 case 'g': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
223 xioopts_ignoregroups
= true; break;
224 case 'L': if (socat_opts
.lock
.lockfile
)
225 Error("only one -L and -W option allowed");
227 socat_opts
.lock
.lockfile
= *arg1
+2;
230 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
231 Error("option -L requires an argument; use option \"-h\" for help");
236 case 'W': if (socat_opts
.lock
.lockfile
)
237 Error("only one -L and -W option allowed");
239 socat_opts
.lock
.lockfile
= *arg1
+2;
242 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
243 Error("option -W requires an argument; use option \"-h\" for help");
247 socat_opts
.lock
.waitlock
= true;
248 socat_opts
.lock
.intervall
.tv_sec
= 1;
249 socat_opts
.lock
.intervall
.tv_nsec
= 0;
251 #if WITH_IP4 || WITH_IP6
258 if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
259 xioopts
.default_ip
= arg1
[0][1];
260 xioopts
.preferred_ip
= arg1
[0][1];
262 #endif /* WITH_IP4 || WITH_IP6 */
265 case ':': break; /* this "-" is a variation of STDIO */
267 xioinqopt('p', buff
, sizeof(buff
));
268 if (arg1
[0][1] == buff
[0]) {
271 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1
[0]);
274 /* the leading "-" might be a form of the first address */
275 xioinqopt('p', buff
, sizeof(buff
));
276 if (arg1
[0][0] == '-' &&
277 (arg1
[0][1] == '\0' || arg1
[0][1] == ':' ||
278 arg1
[0][1] == ',' || arg1
[0][1] == buff
[0]))
283 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc
);
286 if (socat_opts
.lefttoright
&& socat_opts
.righttoleft
) {
287 Error("-U and -u must not be combined");
291 Info(copyright_socat
);
293 Info(copyright_openssl
);
294 Info(copyright_ssleay
);
296 Debug2("socat version %s on %s", socatversion
, timestamp
);
297 xiosetenv("VERSION", socatversion
, 1, NULL
); /* SOCAT_VERSION */
298 uname(&ubuf
); /* ! here we circumvent internal tracing (Uname) */
299 Debug4("running on %s version %s, release %s, machine %s\n",
300 ubuf
.sysname
, ubuf
.version
, ubuf
.release
, ubuf
.machine
);
302 #if WITH_MSGLEVEL <= E_DEBUG
303 for (i
= 0; i
< argc0
; ++i
) {
304 Debug2("argv[%d]: \"%s\"", i
, argv
[i
]);
306 #endif /* WITH_MSGLEVEL <= E_DEBUG */
309 struct sigaction act
;
310 sigfillset(&act
.sa_mask
);
312 act
.sa_handler
= socat_signal
;
313 /* not sure which signals should be caught and print a message */
314 Sigaction(SIGHUP
, &act
, NULL
);
315 Sigaction(SIGINT
, &act
, NULL
);
316 Sigaction(SIGQUIT
, &act
, NULL
);
317 Sigaction(SIGILL
, &act
, NULL
);
318 Sigaction(SIGABRT
, &act
, NULL
);
319 Sigaction(SIGBUS
, &act
, NULL
);
320 Sigaction(SIGFPE
, &act
, NULL
);
321 Sigaction(SIGSEGV
, &act
, NULL
);
322 Sigaction(SIGTERM
, &act
, NULL
);
324 Signal(SIGPIPE
, SIG_IGN
);
327 xiohook_newchild
= &socat_newchild
;
329 if (lockrc
= socat_lock()) {
330 /* =0: goon; >0: locked; <0: error, printed in sub */
332 Error1("could not obtain lock \"%s\"", socat_opts
.lock
.lockfile
);
336 Atexit(socat_unlock
);
338 result
= socat(arg1
[0], arg1
[1]);
339 Notice1("exiting with status %d", result
);
341 return 0; /* not reached, just for gcc -Wall */
345 void socat_usage(FILE *fd
) {
346 fputs(copyright_socat
, fd
); fputc('\n', fd
);
347 fputs("Usage:\n", fd
);
348 fputs("socat [options] <bi-address> <bi-address>\n", fd
);
349 fputs(" options:\n", fd
);
350 fputs(" -V print version and feature information to stdout, and exit\n", fd
);
352 fputs(" -h|-? print a help text describing command line options and addresses\n", fd
);
353 fputs(" -hh like -h, plus a list of all common address option names\n", fd
);
354 fputs(" -hhh like -hh, plus a list of all available address option names\n", fd
);
355 #endif /* WITH_HELP */
356 fputs(" -d[ddd] increase verbosity (use up to 4 times; 2 are recommended)\n", fd
);
358 fputs(" -D analyze file descriptors before loop\n", fd
);
360 fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd
);
361 fputs(" -lf<logfile> log to file\n", fd
);
362 fputs(" -ls log to stderr (default if no other log)\n", fd
);
363 fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd
);
364 fputs(" -lp<progname> set the program name used for logging\n", fd
);
365 fputs(" -lu use microseconds for logging timestamps\n", fd
);
366 fputs(" -lh add hostname to log messages\n", fd
);
367 fputs(" -v verbose data traffic, text\n", fd
);
368 fputs(" -x verbose data traffic, hexadecimal\n", fd
);
369 fputs(" -b<size_t> set data buffer size (8192)\n", fd
);
370 fputs(" -s sloppy (continue on error)\n", fd
);
371 fputs(" -t<timeout> wait seconds before closing second channel\n", fd
);
372 fputs(" -T<timeout> total inactivity timeout in seconds\n", fd
);
373 fputs(" -u unidirectional mode (left to right)\n", fd
);
374 fputs(" -U unidirectional mode (right to left)\n", fd
);
375 fputs(" -g do not check option groups\n", fd
);
376 fputs(" -L <lockfile> try to obtain lock, or fail\n", fd
);
377 fputs(" -W <lockfile> try to obtain lock, or wait\n", fd
);
379 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd
);
382 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd
);
386 void socat_opt_hint(FILE *fd
, char a
, char b
) {
387 fprintf(fd
, "Do not merge single character options, i.e. use \"-%c -%c\" instead of \"-%c%c\"\n",
392 void socat_version(FILE *fd
) {
395 fputs(copyright_socat
, fd
); fputc('\n', fd
);
396 fprintf(fd
, "socat version %s on %s\n", socatversion
, timestamp
);
398 fprintf(fd
, " running on %s version %s, release %s, machine %s\n",
399 ubuf
.sysname
, ubuf
.version
, ubuf
.release
, ubuf
.machine
);
400 fputs("features:\n", fd
);
402 fprintf(fd
, " #define WITH_STDIO %d\n", WITH_STDIO
);
404 fputs(" #undef WITH_STDIO\n", fd
);
407 fprintf(fd
, " #define WITH_FDNUM %d\n", WITH_FDNUM
);
409 fputs(" #undef WITH_FDNUM\n", fd
);
412 fprintf(fd
, " #define WITH_FILE %d\n", WITH_FILE
);
414 fputs(" #undef WITH_FILE\n", fd
);
417 fprintf(fd
, " #define WITH_CREAT %d\n", WITH_CREAT
);
419 fputs(" #undef WITH_CREAT\n", fd
);
422 fprintf(fd
, " #define WITH_GOPEN %d\n", WITH_GOPEN
);
424 fputs(" #undef WITH_GOPEN\n", fd
);
427 fprintf(fd
, " #define WITH_TERMIOS %d\n", WITH_TERMIOS
);
429 fputs(" #undef WITH_TERMIOS\n", fd
);
432 fprintf(fd
, " #define WITH_PIPE %d\n", WITH_PIPE
);
434 fputs(" #undef WITH_PIPE\n", fd
);
437 fprintf(fd
, " #define WITH_UNIX %d\n", WITH_UNIX
);
439 fputs(" #undef WITH_UNIX\n", fd
);
440 #endif /* WITH_UNIX */
441 #ifdef WITH_ABSTRACT_UNIXSOCKET
442 fprintf(fd
, " #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET
);
444 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd
);
445 #endif /* WITH_ABSTRACT_UNIXSOCKET */
447 fprintf(fd
, " #define WITH_IP4 %d\n", WITH_IP4
);
449 fputs(" #undef WITH_IP4\n", fd
);
452 fprintf(fd
, " #define WITH_IP6 %d\n", WITH_IP6
);
454 fputs(" #undef WITH_IP6\n", fd
);
457 fprintf(fd
, " #define WITH_RAWIP %d\n", WITH_RAWIP
);
459 fputs(" #undef WITH_RAWIP\n", fd
);
461 #ifdef WITH_GENERICSOCKET
462 fprintf(fd
, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET
);
464 fputs(" #undef WITH_GENERICSOCKET\n", fd
);
466 #ifdef WITH_INTERFACE
467 fprintf(fd
, " #define WITH_INTERFACE %d\n", WITH_INTERFACE
);
469 fputs(" #undef WITH_INTERFACE\n", fd
);
472 fprintf(fd
, " #define WITH_TCP %d\n", WITH_TCP
);
474 fputs(" #undef WITH_TCP\n", fd
);
477 fprintf(fd
, " #define WITH_UDP %d\n", WITH_UDP
);
479 fputs(" #undef WITH_UDP\n", fd
);
482 fprintf(fd
, " #define WITH_SCTP %d\n", WITH_SCTP
);
484 fputs(" #undef WITH_SCTP\n", fd
);
487 fprintf(fd
, " #define WITH_LISTEN %d\n", WITH_LISTEN
);
489 fputs(" #undef WITH_LISTEN\n", fd
);
492 fprintf(fd
, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4
);
494 fputs(" #undef WITH_SOCKS4\n", fd
);
497 fprintf(fd
, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A
);
499 fputs(" #undef WITH_SOCKS4A\n", fd
);
502 fprintf(fd
, " #define WITH_PROXY %d\n", WITH_PROXY
);
504 fputs(" #undef WITH_PROXY\n", fd
);
507 fprintf(fd
, " #define WITH_SYSTEM %d\n", WITH_SYSTEM
);
509 fputs(" #undef WITH_SYSTEM\n", fd
);
512 fprintf(fd
, " #define WITH_EXEC %d\n", WITH_EXEC
);
514 fputs(" #undef WITH_EXEC\n", fd
);
517 fprintf(fd
, " #define WITH_READLINE %d\n", WITH_READLINE
);
519 fputs(" #undef WITH_READLINE\n", fd
);
522 fprintf(fd
, " #define WITH_TUN %d\n", WITH_TUN
);
524 fputs(" #undef WITH_TUN\n", fd
);
527 fprintf(fd
, " #define WITH_PTY %d\n", WITH_PTY
);
529 fputs(" #undef WITH_PTY\n", fd
);
532 fprintf(fd
, " #define WITH_OPENSSL %d\n", WITH_OPENSSL
);
534 fputs(" #undef WITH_OPENSSL\n", fd
);
537 fprintf(fd
, " #define WITH_FIPS %d\n", WITH_FIPS
);
539 fputs(" #undef WITH_FIPS\n", fd
);
542 fprintf(fd
, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP
);
544 fputs(" #undef WITH_LIBWRAP\n", fd
);
547 fprintf(fd
, " #define WITH_SYCLS %d\n", WITH_SYCLS
);
549 fputs(" #undef WITH_SYCLS\n", fd
);
552 fprintf(fd
, " #define WITH_FILAN %d\n", WITH_FILAN
);
554 fputs(" #undef WITH_FILAN\n", fd
);
557 fprintf(fd
, " #define WITH_RETRY %d\n", WITH_RETRY
);
559 fputs(" #undef WITH_RETRY\n", fd
);
562 fprintf(fd
, " #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL
,
563 &"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL
<<3]);
565 fputs(" #undef WITH_MSGLEVEL\n", fd
);
570 xiofile_t
*sock1
, *sock2
;
571 int closing
= 0; /* 0..no eof yet, 1..first eof just occurred,
572 2..counting down closing timeout */
574 /* call this function when the common command line options are parsed, and the
575 addresses are extracted (but not resolved). */
576 int socat(const char *address1
, const char *address2
) {
579 if (socat_opts
.lefttoright
) {
580 if ((sock1
= xioopen(address1
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
583 xiosetsigchild(sock1
, socat_sigchild
);
584 } else if (socat_opts
.righttoleft
) {
585 if ((sock1
= xioopen(address1
, XIO_WRONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
588 xiosetsigchild(sock1
, socat_sigchild
);
590 if ((sock1
= xioopen(address1
, XIO_RDWR
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
593 xiosetsigchild(sock1
, socat_sigchild
);
596 if (XIO_READABLE(sock1
) &&
597 (XIO_RDSTREAM(sock1
)->howtoend
== END_KILL
||
598 XIO_RDSTREAM(sock1
)->howtoend
== END_CLOSE_KILL
||
599 XIO_RDSTREAM(sock1
)->howtoend
== END_SHUTDOWN_KILL
)) {
601 for (i
= 0; i
< NUMUNKNOWN
; ++i
) {
602 if (XIO_RDSTREAM(sock1
)->para
.exec
.pid
== diedunknown
[i
]) {
603 /* child has alread died... but it might have put regular data into
604 the communication channel, so continue */
605 Info2("child "F_pid
" has already died with status %d",
606 XIO_RDSTREAM(sock1
)->para
.exec
.pid
, statunknown
[i
]);
607 if (statunknown
[i
] != 0) {
611 XIO_RDSTREAM(sock1
)->para
.exec
.pid
= 0;
612 /* return STAT_RETRYLATER; */
618 mayexec
= (sock1
->common
.flags
&XIO_DOESCONVERT
? 0 : XIO_MAYEXEC
);
619 if (XIO_WRITABLE(sock1
)) {
620 if (XIO_READABLE(sock1
)) {
621 if ((sock2
= xioopen(address2
, XIO_RDWR
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
624 xiosetsigchild(sock2
, socat_sigchild
);
626 if ((sock2
= xioopen(address2
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
629 xiosetsigchild(sock2
, socat_sigchild
);
631 } else { /* assuming sock1 is readable */
632 if ((sock2
= xioopen(address2
, XIO_WRONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
635 xiosetsigchild(sock2
, socat_sigchild
);
638 if (XIO_READABLE(sock2
) &&
639 (XIO_RDSTREAM(sock2
)->howtoend
== END_KILL
||
640 XIO_RDSTREAM(sock2
)->howtoend
== END_CLOSE_KILL
||
641 XIO_RDSTREAM(sock2
)->howtoend
== END_SHUTDOWN_KILL
)) {
643 for (i
= 0; i
< NUMUNKNOWN
; ++i
) {
644 if (XIO_RDSTREAM(sock2
)->para
.exec
.pid
== diedunknown
[i
]) {
645 /* child has alread died... but it might have put regular data into
646 the communication channel, so continue */
647 Info2("child "F_pid
" has already died with status %d",
648 XIO_RDSTREAM(sock2
)->para
.exec
.pid
, statunknown
[i
]);
649 if (statunknown
[i
] != 0) {
653 XIO_RDSTREAM(sock2
)->para
.exec
.pid
= 0;
654 /* return STAT_RETRYLATER; */
660 Info("resolved and opened all sock addresses");
662 _socat(); /* nsocks, sockets are visible outside function */
665 /* checks if this is a connection to a child process, and if so, sees if the
666 child already died, leaving some data for us.
667 returns <0 if an error occurred;
668 returns 0 if no child or not yet died or died without data (sets eof);
669 returns >0 if child died and left data
671 int childleftdata(xiofile_t
*xfd
) {
675 /* have to check if a child process died before, but left read data */
676 if (XIO_READABLE(xfd
) &&
677 (XIO_RDSTREAM(xfd
)->howtoend
== END_KILL
||
678 XIO_RDSTREAM(xfd
)->howtoend
== END_CLOSE_KILL
||
679 XIO_RDSTREAM(xfd
)->howtoend
== END_SHUTDOWN_KILL
) &&
680 XIO_RDSTREAM(xfd
)->para
.exec
.pid
== 0) {
681 struct timeval timeout
= { 0, 0 };
683 if (XIO_READABLE(xfd
) && !(XIO_RDSTREAM(xfd
)->eof
>= 2 && !XIO_RDSTREAM(xfd
)->ignoreeof
)) {
684 in
.fd
= XIO_GETRDFD(xfd
);
685 in
.events
= POLLIN
/*|POLLRDBAND*/;
690 retval
= xiopoll(&in
, 1, &timeout
);
691 _errno
= errno
; diag_flush(); errno
= _errno
; /* just in case it's not debug level and Msg() not been called */
692 } while (retval
< 0 && errno
== EINTR
);
695 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec
"."F_tv_usec
"}): %s",
696 in
.fd
, in
.events
, timeout
.tv_sec
, timeout
.tv_usec
,
701 Info("terminated child did not leave data for us");
702 XIO_RDSTREAM(xfd
)->eof
= 2;
704 closing
= MAX(closing
, 1);
710 int xiotransfer(xiofile_t
*inpipe
, xiofile_t
*outpipe
,
711 unsigned char *buff
, size_t bufsiz
, bool righttoleft
);
713 bool mayrd1
; /* sock1 has read data or eof, according to poll() */
714 bool mayrd2
; /* sock2 has read data or eof, according to poll() */
715 bool maywr1
; /* sock1 can be written to, according to poll() */
716 bool maywr2
; /* sock2 can be written to, according to poll() */
718 /* here we come when the sockets are opened (in the meaning of C language),
719 and their options are set/applied
720 returns -1 on error or 0 on success */
722 struct pollfd fds
[4],
729 ssize_t bytes1
, bytes2
;
730 int polling
= 0; /* handling ignoreeof */
731 int wasaction
= 1; /* last poll was active, do NOT sleep before next */
732 struct timeval total_timeout
; /* the actual total timeout timer */
735 if (socat_opts
.debug
) {
737 int msglevel
, exitlevel
;
739 msglevel
= diag_get_int('D'); /* save current message level */
740 diag_set_int('D', E_ERROR
); /* only print errors and fatals in filan */
741 exitlevel
= diag_get_int('e'); /* save current exit level */
742 diag_set_int('e', E_FATAL
); /* only exit on fatals */
744 fdi
= XIO_GETRDFD(sock1
);
745 fdo
= XIO_GETWRFD(sock1
);
746 filan_fd(fdi
, stderr
);
748 filan_fd(fdo
, stderr
);
751 fdi
= XIO_GETRDFD(sock2
);
752 fdo
= XIO_GETWRFD(sock2
);
753 filan_fd(fdi
, stderr
);
755 filan_fd(fdo
, stderr
);
758 diag_set_int('e', exitlevel
); /* restore old exit level */
759 diag_set_int('D', msglevel
); /* restore old message level */
761 #endif /* WITH_FILAN */
763 /* when converting nl to crnl, size might double */
764 if (socat_opts
.bufsiz
> (SIZE_MAX
-1)/2) {
765 Error2("buffer size option (-b) to big - "F_Zu
" (max is "F_Zu
")", socat_opts
.bufsiz
, (SIZE_MAX
-1)/2);
766 socat_opts
.bufsiz
= (SIZE_MAX
-1)/2;
769 #if HAVE_PROTOTYPE_LIB_posix_memalign
770 /* Operations on files with flag O_DIRECT might need buffer alignment.
771 Without this, eg.read() fails with "Invalid argument" */
774 if ((_errno
= Posix_memalign((void **)&buff
, getpagesize(), 2*socat_opts
.bufsiz
+1)) != 0) {
775 Error1("posix_memalign(): %s", strerror(_errno
));
779 #else /* !HAVE_PROTOTYPE_LIB_posix_memalign */
780 buff
= Malloc(2*socat_opts
.bufsiz
+1);
781 if (buff
== NULL
) return -1;
782 #endif /* !HAVE_PROTOTYPE_LIB_posix_memalign */
784 if (socat_opts
.logopt
== 'm' && xioinqopt('l', NULL
, 0) == 'm') {
785 Info("switching to syslog");
786 diag_set('y', xioopts
.syslogfac
);
787 xiosetopt('l', "\0");
789 total_timeout
= socat_opts
.total_timeout
;
791 Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
792 XIO_GETRDFD(sock1
), XIO_GETWRFD(sock1
),
793 XIO_GETRDFD(sock2
), XIO_GETWRFD(sock2
));
794 while (XIO_RDSTREAM(sock1
)->eof
<= 1 ||
795 XIO_RDSTREAM(sock2
)->eof
<= 1) {
796 struct timeval timeout
, *to
= NULL
;
798 Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec
"."F_tv_usec
"}",
799 XIO_RDSTREAM(sock1
)->eof
, XIO_RDSTREAM(sock2
)->eof
,
801 total_timeout
.tv_sec
, total_timeout
.tv_usec
);
806 if (socat_opts
.total_timeout
.tv_sec
!= 0 ||
807 socat_opts
.total_timeout
.tv_usec
!= 0) {
808 if (total_timeout
.tv_usec
< socat_opts
.pollintv
.tv_usec
) {
809 total_timeout
.tv_usec
+= 1000000;
810 total_timeout
.tv_sec
-= 1;
812 total_timeout
.tv_sec
-= socat_opts
.pollintv
.tv_sec
;
813 total_timeout
.tv_usec
-= socat_opts
.pollintv
.tv_usec
;
814 if (total_timeout
.tv_sec
< 0 ||
815 total_timeout
.tv_sec
== 0 && total_timeout
.tv_usec
< 0) {
816 Notice("inactivity timeout triggered");
828 /* there is a ignoreeof poll timeout, use it */
829 timeout
= socat_opts
.pollintv
;
831 } else if (socat_opts
.total_timeout
.tv_sec
!= 0 ||
832 socat_opts
.total_timeout
.tv_usec
!= 0) {
833 /* there might occur a total inactivity timeout */
834 timeout
= socat_opts
.total_timeout
;
841 /* first eof already occurred, start end timer */
842 timeout
= socat_opts
.pollintv
;
847 /* frame 1: set the poll parameters and loop over poll() EINTR) */
848 do { /* loop over poll() EINTR */
851 childleftdata(sock1
);
852 childleftdata(sock2
);
855 /* first eof already occurred, start end timer */
856 timeout
= socat_opts
.closwait
;
861 /* use the ignoreeof timeout if appropriate */
864 (socat_opts
.pollintv
.tv_sec
< timeout
.tv_sec
) ||
865 ((socat_opts
.pollintv
.tv_sec
== timeout
.tv_sec
) &&
866 socat_opts
.pollintv
.tv_usec
< timeout
.tv_usec
)) {
867 timeout
= socat_opts
.pollintv
;
871 /* now the fds will be assigned */
872 if (XIO_READABLE(sock1
) &&
873 !(XIO_RDSTREAM(sock1
)->eof
> 1 && !XIO_RDSTREAM(sock1
)->ignoreeof
) &&
874 !socat_opts
.righttoleft
) {
875 if (!mayrd1
&& !(XIO_RDSTREAM(sock1
)->eof
> 1)) {
876 fd1in
->fd
= XIO_GETRDFD(sock1
);
877 fd1in
->events
= POLLIN
;
882 fd2out
->fd
= XIO_GETWRFD(sock2
);
883 fd2out
->events
= POLLOUT
;
891 if (XIO_READABLE(sock2
) &&
892 !(XIO_RDSTREAM(sock2
)->eof
> 1 && !XIO_RDSTREAM(sock2
)->ignoreeof
) &&
893 !socat_opts
.lefttoright
) {
894 if (!mayrd2
&& !(XIO_RDSTREAM(sock2
)->eof
> 1)) {
895 fd2in
->fd
= XIO_GETRDFD(sock2
);
896 fd2in
->events
= POLLIN
;
901 fd1out
->fd
= XIO_GETWRFD(sock1
);
902 fd1out
->events
= POLLOUT
;
910 /* frame 0: innermost part of the transfer loop: check FD status */
911 retval
= xiopoll(fds
, 4, to
);
912 if (retval
>= 0 || errno
!= EINTR
) {
916 Info1("poll(): %s", strerror(errno
));
921 when an exec'd process sends data and terminates, it is unpredictable
922 whether the data or the sigchild arrives first.
926 Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec
"."F_tv_usec
"}): %s",
927 fds
[0].fd
, fds
[0].events
, fds
[1].fd
, fds
[1].events
,
928 fds
[2].fd
, fds
[2].events
, fds
[3].fd
, fds
[3].events
,
929 timeout
.tv_sec
, timeout
.tv_usec
, strerror(errno
));
932 } else if (retval
== 0) {
933 Info2("poll timed out (no data within %ld.%06ld seconds)",
934 closing
>=1?socat_opts
.closwait
.tv_sec
:socat_opts
.total_timeout
.tv_sec
,
935 closing
>=1?socat_opts
.closwait
.tv_usec
:socat_opts
.total_timeout
.tv_usec
);
936 if (polling
&& !wasaction
) {
937 /* there was a ignoreeof poll timeout, use it */
939 if (XIO_RDSTREAM(sock1
)->ignoreeof
) {
942 if (XIO_RDSTREAM(sock2
)->ignoreeof
) {
945 } else if (polling
&& wasaction
) {
948 } else if (socat_opts
.total_timeout
.tv_sec
!= 0 ||
949 socat_opts
.total_timeout
.tv_usec
!= 0) {
950 /* there was a total inactivity timeout */
951 Notice("inactivity timeout triggered");
959 /* one possibility to come here is ignoreeof on some fd, but no EOF
960 and no data on any descriptor - this is no indication for end! */
964 if (XIO_READABLE(sock1
) && XIO_GETRDFD(sock1
) >= 0 &&
965 (fd1in
->revents
/*&(POLLIN|POLLHUP|POLLERR)*/)) {
966 if (fd1in
->revents
& POLLNVAL
) {
967 /* this is what we find on Mac OS X when poll()'ing on a device or
968 named pipe. a read() might imm. return with 0 bytes, resulting
970 Error1("poll(...[%d]: invalid request", fd1in
->fd
);
976 if (XIO_READABLE(sock2
) && XIO_GETRDFD(sock2
) >= 0 &&
978 if (fd2in
->revents
& POLLNVAL
) {
979 Error1("poll(...[%d]: invalid request", fd2in
->fd
);
985 if (XIO_GETWRFD(sock1
) >= 0 && fd1out
->fd
>= 0 && fd1out
->revents
) {
986 if (fd1out
->revents
& POLLNVAL
) {
987 Error1("poll(...[%d]: invalid request", fd1out
->fd
);
993 if (XIO_GETWRFD(sock2
) >= 0 && fd2out
->fd
>= 0 && fd2out
->revents
) {
994 if (fd2out
->revents
& POLLNVAL
) {
995 Error1("poll(...[%d]: invalid request", fd2out
->fd
);
1002 if (mayrd1
&& maywr2
) {
1004 if ((bytes1
= xiotransfer(sock1
, sock2
, buff
, socat_opts
.bufsiz
, false))
1006 if (errno
!= EAGAIN
) {
1007 closing
= MAX(closing
, 1);
1008 Notice("socket 1 to socket 2 is in error");
1009 if (socat_opts
.lefttoright
) {
1013 } else if (bytes1
> 0) {
1015 total_timeout
= socat_opts
.total_timeout
;
1017 /* is more data available that has already passed poll()? */
1018 mayrd1
= (xiopending(sock1
) > 0);
1019 if (XIO_RDSTREAM(sock1
)->readbytes
!= 0 &&
1020 XIO_RDSTREAM(sock1
)->actbytes
== 0) {
1021 /* avoid idle when all readbytes already there */
1024 /* escape char occurred? */
1025 if (XIO_RDSTREAM(sock1
)->actescape
) {
1026 bytes1
= 0; /* indicate EOF */
1029 /* (bytes1 == 0) handled later */
1034 if (mayrd2
&& maywr1
) {
1036 if ((bytes2
= xiotransfer(sock2
, sock1
, buff
, socat_opts
.bufsiz
, true))
1038 if (errno
!= EAGAIN
) {
1039 closing
= MAX(closing
, 1);
1040 Notice("socket 2 to socket 1 is in error");
1041 if (socat_opts
.righttoleft
) {
1045 } else if (bytes2
> 0) {
1047 total_timeout
= socat_opts
.total_timeout
;
1049 /* is more data available that has already passed poll()? */
1050 mayrd2
= (xiopending(sock2
) > 0);
1051 if (XIO_RDSTREAM(sock2
)->readbytes
!= 0 &&
1052 XIO_RDSTREAM(sock2
)->actbytes
== 0) {
1053 /* avoid idle when all readbytes already there */
1056 /* escape char occurred? */
1057 if (XIO_RDSTREAM(sock2
)->actescape
) {
1058 bytes2
= 0; /* indicate EOF */
1061 /* (bytes2 == 0) handled later */
1066 /* NOW handle EOFs */
1068 /*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
1069 bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
1071 if (bytes1
== 0 || XIO_RDSTREAM(sock1
)->eof
>= 2) {
1072 if (XIO_RDSTREAM(sock1
)->ignoreeof
&&
1073 !XIO_RDSTREAM(sock1
)->actescape
&& !closing
) {
1074 Debug1("socket 1 (fd %d) is at EOF, ignoring",
1075 XIO_RDSTREAM(sock1
)->fd
); /*! */
1077 polling
= 1; /* do not hook this eof fd to poll for pollintv*/
1078 } else if (XIO_RDSTREAM(sock1
)->eof
<= 2) {
1079 Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1
));
1080 xioshutdown(sock2
, SHUT_WR
);
1081 XIO_RDSTREAM(sock1
)->eof
= 3;
1082 XIO_RDSTREAM(sock1
)->ignoreeof
= false;
1084 } else if (polling
&& XIO_RDSTREAM(sock1
)->ignoreeof
) {
1087 if (XIO_RDSTREAM(sock1
)->eof
>= 2) {
1088 if (socat_opts
.lefttoright
) {
1094 if (bytes2
== 0 || XIO_RDSTREAM(sock2
)->eof
>= 2) {
1095 if (XIO_RDSTREAM(sock2
)->ignoreeof
&&
1096 !XIO_RDSTREAM(sock2
)->actescape
&& !closing
) {
1097 Debug1("socket 2 (fd %d) is at EOF, ignoring",
1098 XIO_RDSTREAM(sock2
)->fd
);
1100 polling
= 1; /* do not hook this eof fd to poll for pollintv*/
1101 } else if (XIO_RDSTREAM(sock2
)->eof
<= 2) {
1102 Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2
));
1103 xioshutdown(sock1
, SHUT_WR
);
1104 XIO_RDSTREAM(sock2
)->eof
= 3;
1105 XIO_RDSTREAM(sock2
)->ignoreeof
= false;
1107 } else if (polling
&& XIO_RDSTREAM(sock2
)->ignoreeof
) {
1110 if (XIO_RDSTREAM(sock2
)->eof
>= 2) {
1111 if (socat_opts
.righttoleft
) {
1118 /* close everything that's still open */
1127 #define MAXTIMESTAMPLEN 128
1128 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
1129 should be at least MAXTIMESTAMPLEN bytes long.
1130 returns 0 on success or -1 if an error occurred */
1131 int gettimestamp(char *timestamp
) {
1133 #if HAVE_GETTIMEOFDAY || 1
1137 #else /* !HAVE_GETTIMEOFDAY */
1139 #endif /* !HAVE_GETTIMEOFDAY */
1141 #if HAVE_GETTIMEOFDAY || 1
1142 result
= gettimeofday(&now
, NULL
);
1148 bytes
= strftime(timestamp
, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt
));
1149 bytes
+= sprintf(timestamp
+19, "."F_tv_usec
" ", now
.tv_usec
);
1151 strcpy(timestamp
, ctime(&nowt
));
1152 bytes
= strlen(timestamp
);
1155 #else /* !HAVE_GETTIMEOFDAY */
1156 now
= time(NULL
); if (now
== (time_t)-1) {
1160 bytes
= strftime(timestamp
, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now
));
1162 strcpy(timestamp
, ctime(&now
));
1163 bytes
= strlen(timestamp
);
1166 #endif /* !HAVE_GETTIMEOFDAY */
1170 static const char *prefixltor
= "> ";
1171 static const char *prefixrtol
= "< ";
1172 static unsigned long numltor
;
1173 static unsigned long numrtol
;
1174 /* print block header (during verbose or hex dump)
1175 returns 0 on success or -1 if an error occurred */
1177 xioprintblockheader(FILE *file
, size_t bytes
, bool righttoleft
) {
1178 char timestamp
[MAXTIMESTAMPLEN
];
1179 char buff
[128+MAXTIMESTAMPLEN
];
1180 if (gettimestamp(timestamp
) < 0) {
1184 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1185 prefixrtol
, timestamp
, bytes
, numrtol
, numrtol
+bytes
-1);
1188 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1189 prefixltor
, timestamp
, bytes
, numltor
, numltor
+bytes
-1);
1197 /* inpipe is suspected to have read data available; read at most bufsiz bytes
1198 and transfer them to outpipe. Perform required data conversions.
1199 buff must be a malloc()'ed storage and might be realloc()'ed in this
1200 function if more space is required after conversions.
1201 Returns the number of bytes written, or 0 on EOF or <0 if an
1202 error occurred or when data was read but none written due to conversions
1203 (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
1204 the file has a mandatory lock.
1205 If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
1206 does NOT write a zero bytes block.
1208 /* inpipe, outpipe must be single descriptors (not dual!) */
1209 int xiotransfer(xiofile_t
*inpipe
, xiofile_t
*outpipe
,
1210 unsigned char *buff
, size_t bufsiz
, bool righttoleft
) {
1211 ssize_t bytes
, writt
= 0;
1213 bytes
= xioread(inpipe
, buff
, bufsiz
);
1215 if (errno
!= EAGAIN
)
1216 XIO_RDSTREAM(inpipe
)->eof
= 2;
1217 /*xioshutdown(inpipe, SHUT_RD);*/
1220 if (bytes
== 0 && XIO_RDSTREAM(inpipe
)->ignoreeof
&& !closing
) {
1222 } else if (bytes
== 0) {
1223 XIO_RDSTREAM(inpipe
)->eof
= 2;
1224 closing
= MAX(closing
, 1);
1228 /* handle escape char */
1229 if (XIO_RDSTREAM(inpipe
)->escape
!= -1) {
1230 /* check input data for escape char */
1231 unsigned char *ptr
= buff
;
1233 while (ctr
< bytes
) {
1234 if (*ptr
== XIO_RDSTREAM(inpipe
)->escape
) {
1235 /* found: set flag, truncate input data */
1236 XIO_RDSTREAM(inpipe
)->actescape
= true;
1238 Info("escape char found in input");
1244 XIO_RDSTREAM(inpipe
)->eof
= 2;
1251 if (XIO_RDSTREAM(inpipe
)->lineterm
!=
1252 XIO_WRSTREAM(outpipe
)->lineterm
) {
1253 cv_newline(buff
, &bytes
,
1254 XIO_RDSTREAM(inpipe
)->lineterm
,
1255 XIO_WRSTREAM(outpipe
)->lineterm
);
1258 errno
= EAGAIN
; return -1;
1261 if (socat_opts
.verbose
&& socat_opts
.verbhex
) {
1266 const unsigned char *end
, *s
, *t
;
1269 xioprintblockheader(stderr
, bytes
, righttoleft
);
1272 j
= Min(N
, (size_t)(end
-s
));
1279 fprintf(stderr
, " %02x", c
);
1281 if (c
== '\n') break;
1284 /* fill hex column */
1306 fputc('\n', stderr
);
1309 fputs("--\n", stderr
);
1310 } else if (socat_opts
.verbose
) {
1312 xioprintblockheader(stderr
, bytes
, righttoleft
);
1313 while (i
< (size_t)bytes
) {
1315 if (i
> 0 && buff
[i
-1] == '\n')
1318 case '\a' : fputs("\\a", stderr
); break;
1319 case '\b' : fputs("\\b", stderr
); break;
1320 case '\t' : fputs("\t", stderr
); break;
1321 case '\n' : fputs("\n", stderr
); break;
1322 case '\v' : fputs("\\v", stderr
); break;
1323 case '\f' : fputs("\\f", stderr
); break;
1324 case '\r' : fputs("\\r", stderr
); break;
1325 case '\\' : fputs("\\\\", stderr
); break;
1334 } else if (socat_opts
.verbhex
) {
1337 xioprintblockheader(stderr
, bytes
, righttoleft
);
1338 for (i
= 0; i
< bytes
; ++i
) {
1339 fprintf(stderr
, " %02x", buff
[i
]);
1341 fputc('\n', stderr
);
1344 writt
= xiowrite(outpipe
, buff
, bytes
);
1346 /* EAGAIN when nonblocking but a mandatory lock is on file.
1347 the problem with EAGAIN is that the read cannot be repeated,
1348 so we need to buffer the data and try to write it later
1349 again. not yet implemented, sorry. */
1351 if (errno
== EPIPE
) {
1352 return 0; /* can no longer write; handle like EOF */
1357 Info3("transferred "F_Zu
" bytes from %d to %d",
1358 writt
, XIO_GETRDFD(inpipe
), XIO_GETWRFD(outpipe
));
1368 /* converts the newline characters (or character sequences) from the one
1369 specified in lineterm1 to that of lineterm2. Possible values are
1370 LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
1371 bytes specifies the number of bytes input and output */
1372 int cv_newline(unsigned char *buff
, ssize_t
*bytes
,
1373 int lineterm1
, int lineterm2
) {
1374 /* must perform newline changes */
1375 if (lineterm1
<= LINETERM_CR
&& lineterm2
<= LINETERM_CR
) {
1376 /* no change in data length */
1377 unsigned char from
, to
, *p
, *z
;
1378 if (lineterm1
== LINETERM_RAW
) {
1379 from
= '\n'; to
= '\r';
1381 from
= '\r'; to
= '\n';
1386 if (*p
== from
) *p
= to
;
1390 } else if (lineterm1
== LINETERM_CRNL
) {
1391 /* buffer might become shorter */
1392 unsigned char to
, *s
, *t
, *z
;
1393 if (lineterm2
== LINETERM_RAW
) {
1413 /* buffer becomes longer (up to double length), must alloc another space */
1414 static unsigned char *buf2
; /*! not threadsafe */
1415 unsigned char from
; unsigned char *s
, *t
, *z
;
1417 if (lineterm1
== LINETERM_RAW
) {
1423 if ((buf2
= Malloc(socat_opts
.bufsiz
)) == NULL
) {
1427 memcpy(buf2
, buff
, *bytes
);
1428 s
= buf2
; t
= buff
; z
= buf2
+ *bytes
;
1431 *t
++ = '\r'; *t
++ = '\n';
1443 void socat_signal(int signum
) {
1446 diag_in_handler
= 1;
1447 Notice1("socat_signal(): handling signal %d", signum
);
1454 diag_immediate_exit
= 1;
1457 diag_set_int('x', 128+signum
); /* in case Error exits for us */
1458 Error1("exiting on signal %d", signum
);
1459 diag_set_int('x', 0); /* in case Error did not exit */
1462 Warn1("exiting on signal %d", signum
); break;
1465 Notice1("exiting on signal %d", signum
); break;
1468 Notice1("socat_signal(): finishing signal %d", signum
);
1469 diag_exit(128+signum
); /*!!! internal cleanup + _exit() */
1470 diag_in_handler
= 0;
1474 /* this is the callback when the child of an address died */
1475 static int socat_sigchild(struct single
*file
) {
1476 if (file
->ignoreeof
&& !closing
) {
1479 file
->eof
= MAX(file
->eof
, 1);
1485 static int socat_lock(void) {
1489 if ((lockrc
= xiolock(&socat_opts
.lock
)) < 0) {
1497 if (socat_opts
.lock
.lockfile
) {
1498 if ((lockrc
= xiolock(socat_opts
.lock
.lockfile
)) < 0) {
1499 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1506 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/
1509 if (socat_opts
.lock
.waitlock
) {
1510 if (xiowaitlock(socat_opts
.lock
.waitlock
, socat_opts
.lock
.intervall
)) {
1511 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1515 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1522 static void socat_unlock(void) {
1523 if (!havelock
) return;
1524 if (socat_opts
.lock
.lockfile
) {
1525 if (Unlink(socat_opts
.lock
.lockfile
) < 0) {
1526 if (!diag_in_handler
) {
1527 Warn2("unlink(\"%s\"): %s",
1528 socat_opts
.lock
.lockfile
, strerror(errno
));
1530 Warn1("unlink(\"%s\"): "F_strerror
,
1531 socat_opts
.lock
.lockfile
);
1534 Info1("released lock \"%s\"", socat_opts
.lock
.lockfile
);
1539 /* this is a callback function that may be called by the newchild hook of xio
1541 static int socat_newchild(void) {