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"
28 /* command line options */
32 struct timeval pollintv
; /* with ignoreeof, reread after seconds */
33 struct timeval closwait
; /* after close of x, die after seconds */
34 struct timeval total_timeout
;/* when nothing happens, die after seconds */
36 bool strictopts
; /* stop on errors in address options */
37 char logopt
; /* y..syslog; s..stderr; f..file; m..mixed */
38 bool lefttoright
; /* first addr ro, second addr wo */
39 bool righttoleft
; /* first addr wo, second addr ro */
40 xiolock_t lock
; /* a lock file */
41 unsigned long log_sigs
; /* signals to be caught just for logging */
42 bool statistics
; /* log statistics on exit */
47 {0,500000}, /* closwait */
48 {0,0}, /* total_timeout */
52 false, /* lefttoright */
53 false, /* righttoleft */
54 { NULL
, 0 }, /* lock */
55 1<<SIGHUP
| 1<<SIGINT
| 1<<SIGQUIT
| 1<<SIGILL
| 1<<SIGABRT
| 1<<SIGBUS
| 1<<SIGFPE
| 1<<SIGSEGV
| 1<<SIGTERM
, /* log_sigs */
56 false /* statistics */
59 void socat_usage(FILE *fd
);
60 void socat_opt_hint(FILE *fd
, char a
, char b
);
61 void socat_version(FILE *fd
);
62 int socat(const char *address1
, const char *address2
);
64 int cv_newline(unsigned char *buff
, ssize_t
*bytes
, int lineterm1
, int lineterm2
);
65 void socat_signal(int sig
);
66 void socat_signal_logstats(int sig
);
67 static int socat_sigchild(struct single
*file
);
69 void lftocrlf(char **in
, ssize_t
*len
, size_t bufsiz
);
70 void crlftolf(char **in
, ssize_t
*len
, size_t bufsiz
);
72 static int socat_lock(void);
73 static void socat_unlock(void);
74 static int socat_newchild(void);
75 static void socat_print_stats(void);
77 static const char socatversion
[] =
80 static const char timestamp
[] = BUILD_DATE
;
82 const char copyright_socat
[] = "socat by Gerhard Rieger and contributors - see www.dest-unreach.org";
84 const char copyright_openssl
[] = "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)";
85 const char copyright_ssleay
[] = "This product includes software written by Tim Hudson (tjh@cryptsoft.com)";
90 int main(int argc
, const char *argv
[]) {
91 const char **arg1
, *a
;
101 if (mainwaitstring
= getenv("SOCAT_MAIN_WAIT")) {
102 sleep(atoi(mainwaitstring
));
104 diag_set('p', strchr(argv
[0], '/') ? strrchr(argv
[0], '/')+1 : argv
[0]);
106 /* we must init before applying options because env settings have lower
107 priority and are to be overridden by options */
108 if (xioinitialize() != 0) {
112 xiosetopt('p', "!!");
115 argc0
= argc
; /* save for later use */
116 arg1
= argv
+1; --argc
;
117 while (arg1
[0] && (arg1
[0][0] == '-')) {
118 switch (arg1
[0][1]) {
119 case 'V': if (arg1
[0][2]) { socat_usage(stderr
); Exit(1); }
120 socat_version(stdout
); Exit(0);
125 xioopenhelp(stdout
, (arg1
[0][2]=='?'||arg1
[0][2]=='h') ? (arg1
[0][3]=='?'||arg1
[0][3]=='h') ? 2 : 1 : 0);
127 #endif /* WITH_HELP */
133 case '-': case '0': case '1': case '2': case '3': case '4':
136 msglevel
= strtol(a
, &endptr
, 0);
137 if (endptr
== a
|| *endptr
) {
138 Error2("Invalid (trailing) character(s) \"%c\" in \"%s\"option", *a
, *arg1
);
140 diag_set_int('d', 4-msglevel
);
145 diag_set_int('d', 4-msglevel
);
147 default: socat_usage(stderr
);
149 if (*a
!= 'd') break;
154 diag_set_int('d', 4-msglevel
);
163 case 'D': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
164 socat_opts
.debug
= true; break;
167 switch (arg1
[0][2]) {
168 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
171 socat_opts
.logopt
= arg1
[0][2];
172 xiosetopt('y', &arg1
[0][3]);
174 case 'y': /* syslog + facility */
175 diag_set(arg1
[0][2], &arg1
[0][3]);
177 case 'f': /* to file, +filename */
178 case 'p': /* artificial program name */
180 diag_set(arg1
[0][2], &arg1
[0][3]);
181 } else if (arg1
[1]) {
182 diag_set(arg1
[0][2], arg1
[1]);
185 Error1("option -l%c requires an argument; use option \"-h\" for help", arg1
[0][2]);
188 case 's': /* stderr */
189 diag_set(arg1
[0][2], NULL
);
195 diag_set_int('h', true);
198 Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1
[0]);
202 case 'v': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
203 socat_opts
.verbose
= true; break;
204 case 'x': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
205 socat_opts
.verbhex
= true; break;
206 case 'r': if (arg1
[0][2]) {
210 if ((a
= *arg1
) == NULL
) {
211 Error("option -r requires an argument; use option \"-h\" for help");
217 case 'R': if (arg1
[0][2]) {
221 if ((a
= *arg1
) == NULL
) {
222 Error("option -R requires an argument; use option \"-h\" for help");
228 case 'b': if (arg1
[0][2]) {
232 if ((a
= *arg1
) == NULL
) {
233 Error("option -b requires an argument; use option \"-h\" for help");
237 xioparms
.bufsiz
= Strtoul(a
, (char **)&a
, 0, "-b");
239 case 's': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
240 diag_set_int('e', E_FATAL
); break;
241 case 'S': /* do not catch signals */
246 if ((a
= *arg1
) == NULL
) {
247 Error("option -S requires an argument; use option \"-h\" for help");
251 socat_opts
.log_sigs
= Strtoul(a
, (char **)&a
, 0, "-S");
253 case 't': if (arg1
[0][2]) {
257 if ((a
= *arg1
) == NULL
) {
258 Error("option -t requires an argument; use option \"-h\" for help");
262 rto
= Strtod(a
, (char **)&a
, "-t");
263 socat_opts
.closwait
.tv_sec
= rto
;
264 socat_opts
.closwait
.tv_usec
=
265 (rto
-socat_opts
.closwait
.tv_sec
) * 1000000;
267 case 'T': if (arg1
[0][2]) {
271 if ((a
= *arg1
) == NULL
) {
272 Error("option -T requires an argument; use option \"-h\" for help");
276 rto
= Strtod(a
, (char **)&a
, "-T");
277 socat_opts
.total_timeout
.tv_sec
= rto
;
278 socat_opts
.total_timeout
.tv_usec
=
279 (rto
-socat_opts
.total_timeout
.tv_sec
) * 1000000;
281 case 'u': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
282 socat_opts
.lefttoright
= true; break;
283 case 'U': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
284 socat_opts
.righttoleft
= true; break;
285 case 'g': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
286 xioopts_ignoregroups
= true; break;
287 case 'L': if (socat_opts
.lock
.lockfile
)
288 Error("only one -L and -W option allowed");
290 socat_opts
.lock
.lockfile
= *arg1
+2;
293 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
294 Error("option -L requires an argument; use option \"-h\" for help");
299 case 'W': if (socat_opts
.lock
.lockfile
) {
300 Error("only one -L and -W option allowed");
303 socat_opts
.lock
.lockfile
= *arg1
+2;
306 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
307 Error("option -W requires an argument; use option \"-h\" for help");
311 socat_opts
.lock
.waitlock
= true;
312 socat_opts
.lock
.intervall
.tv_sec
= 1;
313 socat_opts
.lock
.intervall
.tv_nsec
= 0;
315 #if WITH_IP4 || WITH_IP6
322 if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
323 xioparms
.default_ip
= arg1
[0][1];
324 xioparms
.preferred_ip
= arg1
[0][1];
326 #endif /* WITH_IP4 || WITH_IP6 */
328 if (!strcmp("experimental", &arg1
[0][2])) {
329 xioparms
.experimental
= true;
330 } else if (!strcmp("statistics", &arg1
[0][2])) {
331 socat_opts
.statistics
= true;
333 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1
[0]);
340 break; /* this "-" is a variation of STDIO */
342 xioinqopt('p', buff
, sizeof(buff
)); /* fetch pipe separator char */
343 if (arg1
[0][1] == buff
[0]) {
347 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1
[0]);
351 /* the leading "-" is a form of the first address */
357 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc
);
360 if (socat_opts
.lefttoright
&& socat_opts
.righttoleft
) {
361 Error("-U and -u must not be combined");
365 Info(copyright_socat
);
367 Info(copyright_openssl
);
368 Info(copyright_ssleay
);
370 Debug2("socat version %s on %s", socatversion
, timestamp
);
371 xiosetenv("VERSION", socatversion
, 1, NULL
); /* SOCAT_VERSION */
372 uname(&ubuf
); /* ! here we circumvent internal tracing (Uname) */
373 Debug4("running on %s version %s, release %s, machine %s\n",
374 ubuf
.sysname
, ubuf
.version
, ubuf
.release
, ubuf
.machine
);
376 #if WITH_MSGLEVEL <= E_DEBUG
377 for (i
= 0; i
< argc0
; ++i
) {
378 Debug2("argv[%d]: \"%s\"", i
, argv
[i
]);
380 #endif /* WITH_MSGLEVEL <= E_DEBUG */
384 struct sigaction act
;
388 sigfillset(&act
.sa_mask
); /* while in sighandler block all signals */
390 act
.sa_handler
= socat_signal
;
391 /* not sure which signals should be caught and print a message */
392 for (i
= 0, m
= 1; i
< 8*sizeof(unsigned long); ++i
, m
<<= 1) {
393 if (socat_opts
.log_sigs
& m
) {
395 Sigaction(i
, &act
, NULL
);
397 Signal(i
, socat_signal
);
404 act
.sa_handler
= socat_signal_logstats
;
405 Sigaction(SIGUSR1
, &act
, NULL
);
407 Signal(SIGUSR1
, socat_signal_logstats
);
409 #endif /* WITH_STATS */
411 Signal(SIGPIPE
, SIG_IGN
);
414 xiohook_newchild
= &socat_newchild
;
416 if (lockrc
= socat_lock()) {
417 /* =0: goon; >0: locked; <0: error, printed in sub */
419 Error1("could not obtain lock \"%s\"", socat_opts
.lock
.lockfile
);
423 Atexit(socat_unlock
);
425 if (socat_opts
.statistics
) {
426 Atexit(socat_print_stats
);
428 #endif /* WITH_STATS */
430 result
= socat(arg1
[0], arg1
[1]);
431 if (result
== EXIT_SUCCESS
&& engine_result
!= EXIT_SUCCESS
) {
432 result
= engine_result
; /* a signal handler reports failure */
434 Notice1("exiting with status %d", result
);
436 return 0; /* not reached, just for gcc -Wall */
440 void socat_usage(FILE *fd
) {
441 fputs(copyright_socat
, fd
); fputc('\n', fd
);
442 fputs("Usage:\n", fd
);
443 fputs("socat [options] <bi-address> <bi-address>\n", fd
);
444 fputs(" options (general command line options):\n", fd
);
445 fputs(" -V print version and feature information to stdout, and exit\n", fd
);
447 fputs(" -h|-? print a help text describing command line options and addresses\n", fd
);
448 fputs(" -hh like -h, plus a list of all common address option names\n", fd
);
449 fputs(" -hhh like -hh, plus a list of all available address option names\n", fd
);
450 #endif /* WITH_HELP */
451 fputs(" -d[ddd] increase verbosity (use up to 4 times; 2 are recommended)\n", fd
);
452 fputs(" -d0|1|2|3|4 set verbosity level (0: Errors; 4 all including Debug)\n", fd
);
454 fputs(" -D analyze file descriptors before loop\n", fd
);
456 fputs(" --experimental enable experimental features\n", fd
);
457 fputs(" --statistics output transfer statistics on exit\n", fd
);
458 fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd
);
459 fputs(" -lf<logfile> log to file\n", fd
);
460 fputs(" -ls log to stderr (default if no other log)\n", fd
);
461 fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd
);
462 fputs(" -lp<progname> set the program name used for logging and vars\n", fd
);
463 fputs(" -lu use microseconds for logging timestamps\n", fd
);
464 fputs(" -lh add hostname to log messages\n", fd
);
465 fputs(" -v verbose text dump of data traffic\n", fd
);
466 fputs(" -x verbose hexadecimal dump of data traffic\n", fd
);
467 fputs(" -r <file> raw dump of data flowing from left to right\n", fd
);
468 fputs(" -R <file> raw dump of data flowing from right to left\n", fd
);
469 fputs(" -b<size_t> set data buffer size (8192)\n", fd
);
470 fputs(" -s sloppy (continue on error)\n", fd
);
471 fputs(" -S<sigmask> log these signals, override default\n", fd
);
472 fputs(" -t<timeout> wait seconds before closing second channel\n", fd
);
473 fputs(" -T<timeout> total inactivity timeout in seconds\n", fd
);
474 fputs(" -u unidirectional mode (left to right)\n", fd
);
475 fputs(" -U unidirectional mode (right to left)\n", fd
);
476 fputs(" -g do not check option groups\n", fd
);
477 fputs(" -L <lockfile> try to obtain lock, or fail\n", fd
);
478 fputs(" -W <lockfile> try to obtain lock, or wait\n", fd
);
480 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd
);
483 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd
);
487 void socat_opt_hint(FILE *fd
, char a
, char b
) {
488 fprintf(fd
, "Do not merge single character options, i.e. use \"-%c -%c\" instead of \"-%c%c\"\n",
493 void socat_version(FILE *fd
) {
496 fputs(copyright_socat
, fd
); fputc('\n', fd
);
497 fprintf(fd
, "socat version %s on %s\n", socatversion
, timestamp
);
499 fprintf(fd
, " running on %s version %s, release %s, machine %s\n",
500 ubuf
.sysname
, ubuf
.version
, ubuf
.release
, ubuf
.machine
);
501 fputs("features:\n", fd
);
503 fprintf(fd
, " #define WITH_HELP %d\n", WITH_HELP
);
505 fputs(" #undef WITH_HELP\n", fd
);
508 fprintf(fd
, " #define WITH_STATS %d\n", WITH_STATS
);
510 fputs(" #undef WITH_STATS\n", fd
);
513 fprintf(fd
, " #define WITH_STDIO %d\n", WITH_STDIO
);
515 fputs(" #undef WITH_STDIO\n", fd
);
518 fprintf(fd
, " #define WITH_FDNUM %d\n", WITH_FDNUM
);
520 fputs(" #undef WITH_FDNUM\n", fd
);
523 fprintf(fd
, " #define WITH_FILE %d\n", WITH_FILE
);
525 fputs(" #undef WITH_FILE\n", fd
);
528 fprintf(fd
, " #define WITH_CREAT %d\n", WITH_CREAT
);
530 fputs(" #undef WITH_CREAT\n", fd
);
533 fprintf(fd
, " #define WITH_GOPEN %d\n", WITH_GOPEN
);
535 fputs(" #undef WITH_GOPEN\n", fd
);
538 fprintf(fd
, " #define WITH_TERMIOS %d\n", WITH_TERMIOS
);
540 fputs(" #undef WITH_TERMIOS\n", fd
);
543 fprintf(fd
, " #define WITH_PIPE %d\n", WITH_PIPE
);
545 fputs(" #undef WITH_PIPE\n", fd
);
547 #ifdef WITH_SOCKETPAIR
548 fprintf(fd
, " #define WITH_SOCKETPAIR %d\n", WITH_SOCKETPAIR
);
550 fputs(" #undef WITH_SOCKETPAIR\n", fd
);
553 fprintf(fd
, " #define WITH_UNIX %d\n", WITH_UNIX
);
555 fputs(" #undef WITH_UNIX\n", fd
);
556 #endif /* WITH_UNIX */
557 #ifdef WITH_ABSTRACT_UNIXSOCKET
558 fprintf(fd
, " #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET
);
560 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd
);
561 #endif /* WITH_ABSTRACT_UNIXSOCKET */
563 fprintf(fd
, " #define WITH_IP4 %d\n", WITH_IP4
);
565 fputs(" #undef WITH_IP4\n", fd
);
568 fprintf(fd
, " #define WITH_IP6 %d\n", WITH_IP6
);
570 fputs(" #undef WITH_IP6\n", fd
);
573 fprintf(fd
, " #define WITH_RAWIP %d\n", WITH_RAWIP
);
575 fputs(" #undef WITH_RAWIP\n", fd
);
577 #ifdef WITH_GENERICSOCKET
578 fprintf(fd
, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET
);
580 fputs(" #undef WITH_GENERICSOCKET\n", fd
);
582 #ifdef WITH_INTERFACE
583 fprintf(fd
, " #define WITH_INTERFACE %d\n", WITH_INTERFACE
);
585 fputs(" #undef WITH_INTERFACE\n", fd
);
588 fprintf(fd
, " #define WITH_TCP %d\n", WITH_TCP
);
590 fputs(" #undef WITH_TCP\n", fd
);
593 fprintf(fd
, " #define WITH_UDP %d\n", WITH_UDP
);
595 fputs(" #undef WITH_UDP\n", fd
);
598 fprintf(fd
, " #define WITH_SCTP %d\n", WITH_SCTP
);
600 fputs(" #undef WITH_SCTP\n", fd
);
603 fprintf(fd
, " #define WITH_DCCP %d\n", WITH_DCCP
);
605 fputs(" #undef WITH_DCCP\n", fd
);
608 fprintf(fd
, " #define WITH_UDPLITE %d\n", WITH_UDPLITE
);
610 fputs(" #undef WITH_UDPLITE\n", fd
);
613 fprintf(fd
, " #define WITH_LISTEN %d\n", WITH_LISTEN
);
615 fputs(" #undef WITH_LISTEN\n", fd
);
618 fprintf(fd
, " #define WITH_POSIXMQ %d\n", WITH_POSIXMQ
);
620 fputs(" #undef WITH_POSIXMQ\n", fd
);
623 fprintf(fd
, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4
);
625 fputs(" #undef WITH_SOCKS4\n", fd
);
628 fprintf(fd
, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A
);
630 fputs(" #undef WITH_SOCKS4A\n", fd
);
633 fprintf(fd
, " #define WITH_SOCKS5 %d\n", WITH_SOCKS5
);
635 fputs(" #undef WITH_SOCKS5\n", fd
);
638 fprintf(fd
, " #define WITH_VSOCK %d\n", WITH_VSOCK
);
640 fputs(" #undef WITH_VSOCK\n", fd
);
642 #ifdef WITH_NAMESPACES
643 fprintf(fd
, " #define WITH_NAMESPACES %d\n", WITH_NAMESPACES
);
645 fputs(" #undef WITH_NAMESPACES\n", fd
);
648 fprintf(fd
, " #define WITH_PROXY %d\n", WITH_PROXY
);
650 fputs(" #undef WITH_PROXY\n", fd
);
653 fprintf(fd
, " #define WITH_SYSTEM %d\n", WITH_SYSTEM
);
655 fputs(" #undef WITH_SYSTEM\n", fd
);
658 fprintf(fd
, " #define WITH_SHELL %d\n", WITH_SHELL
);
660 fputs(" #undef WITH_SHELL\n", fd
);
663 fprintf(fd
, " #define WITH_EXEC %d\n", WITH_EXEC
);
665 fputs(" #undef WITH_EXEC\n", fd
);
668 fprintf(fd
, " #define WITH_READLINE %d\n", WITH_READLINE
);
670 fputs(" #undef WITH_READLINE\n", fd
);
673 fprintf(fd
, " #define WITH_TUN %d\n", WITH_TUN
);
675 fputs(" #undef WITH_TUN\n", fd
);
678 fprintf(fd
, " #define WITH_PTY %d\n", WITH_PTY
);
680 fputs(" #undef WITH_PTY\n", fd
);
683 fprintf(fd
, " #define WITH_OPENSSL %d\n", WITH_OPENSSL
);
685 fputs(" #undef WITH_OPENSSL\n", fd
);
688 fprintf(fd
, " #define WITH_FIPS %d\n", WITH_FIPS
);
690 fputs(" #undef WITH_FIPS\n", fd
);
693 fprintf(fd
, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP
);
695 fputs(" #undef WITH_LIBWRAP\n", fd
);
698 fprintf(fd
, " #define WITH_SYCLS %d\n", WITH_SYCLS
);
700 fputs(" #undef WITH_SYCLS\n", fd
);
703 fprintf(fd
, " #define WITH_FILAN %d\n", WITH_FILAN
);
705 fputs(" #undef WITH_FILAN\n", fd
);
708 fprintf(fd
, " #define WITH_RETRY %d\n", WITH_RETRY
);
710 fputs(" #undef WITH_RETRY\n", fd
);
713 fprintf(fd
, " #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL
,
714 &"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL
<<3]);
716 fputs(" #undef WITH_MSGLEVEL\n", fd
);
718 #ifdef WITH_DEFAULT_IPV
719 # if WITH_DEFAULT_IPV
720 fprintf(fd
, " #define WITH_DEFAULT_IPV %c\n", WITH_DEFAULT_IPV
);
722 fprintf(fd
, " #define WITH_DEFAULT_IPV '\\0'\n");
725 fputs(" #undef WITH_DEFAULT_IPV\n", fd
);
730 xiofile_t
*sock1
, *sock2
;
731 int closing
= 0; /* 0..no eof yet, 1..first eof just occurred,
732 2..counting down closing timeout */
733 int sniffleft
= -1; /* -1 or an FD for teeing data arriving on xfd1 */
734 int sniffright
= -1; /* -1 or an FD for teeing data arriving on xfd2 */
736 /* call this function when the common command line options are parsed, and the
737 addresses are extracted (but not resolved). */
738 int socat(const char *address1
, const char *address2
) {
741 if (socat_opts
.lefttoright
) {
742 if ((sock1
= xioopen(address1
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
745 xiosetsigchild(sock1
, socat_sigchild
);
746 } else if (socat_opts
.righttoleft
) {
747 if ((sock1
= xioopen(address1
, XIO_WRONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
750 xiosetsigchild(sock1
, socat_sigchild
);
752 if ((sock1
= xioopen(address1
, XIO_RDWR
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
755 xiosetsigchild(sock1
, socat_sigchild
);
758 if (XIO_READABLE(sock1
) &&
759 (XIO_RDSTREAM(sock1
)->howtoend
== END_KILL
||
760 XIO_RDSTREAM(sock1
)->howtoend
== END_CLOSE_KILL
||
761 XIO_RDSTREAM(sock1
)->howtoend
== END_SHUTDOWN_KILL
)) {
763 for (i
= 0; i
< NUMUNKNOWN
; ++i
) {
764 if (XIO_RDSTREAM(sock1
)->para
.exec
.pid
== diedunknown
[i
]) {
765 /* child has alread died... but it might have put regular data into
766 the communication channel, so continue */
767 Info2("child "F_pid
" has already died with status %d",
768 XIO_RDSTREAM(sock1
)->para
.exec
.pid
, statunknown
[i
]);
769 ++num_child
; /* it was counted as anonymous child, undo */
770 if (statunknown
[i
] != 0) {
774 XIO_RDSTREAM(sock1
)->para
.exec
.pid
= 0;
775 /* return STAT_RETRYLATER; */
781 mayexec
= (sock1
->common
.flags
&XIO_DOESCONVERT
? 0 : XIO_MAYEXEC
);
782 if (XIO_WRITABLE(sock1
)) {
783 if (XIO_READABLE(sock1
)) {
784 if ((sock2
= xioopen(address2
, XIO_RDWR
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
787 xiosetsigchild(sock2
, socat_sigchild
);
789 if ((sock2
= xioopen(address2
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
792 xiosetsigchild(sock2
, socat_sigchild
);
794 } else { /* assuming sock1 is readable */
795 if ((sock2
= xioopen(address2
, XIO_WRONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
798 xiosetsigchild(sock2
, socat_sigchild
);
801 if (XIO_READABLE(sock2
) &&
802 (XIO_RDSTREAM(sock2
)->howtoend
== END_KILL
||
803 XIO_RDSTREAM(sock2
)->howtoend
== END_CLOSE_KILL
||
804 XIO_RDSTREAM(sock2
)->howtoend
== END_SHUTDOWN_KILL
)) {
806 for (i
= 0; i
< NUMUNKNOWN
; ++i
) {
807 if (XIO_RDSTREAM(sock2
)->para
.exec
.pid
== diedunknown
[i
]) {
808 /* child has alread died... but it might have put regular data into
809 the communication channel, so continue */
810 Info2("child "F_pid
" has already died with status %d",
811 XIO_RDSTREAM(sock2
)->para
.exec
.pid
, statunknown
[i
]);
812 if (statunknown
[i
] != 0) {
816 XIO_RDSTREAM(sock2
)->para
.exec
.pid
= 0;
817 /* return STAT_RETRYLATER; */
823 Info("resolved and opened all sock addresses");
824 return _socat(); /* nsocks, sockets are visible outside function */
827 /* checks if this is a connection to a child process, and if so, sees if the
828 child already died, leaving some data for us.
829 returns <0 if an error occurred;
830 returns 0 if no child or not yet died or died without data (sets eof);
831 returns >0 if child died and left data
833 int childleftdata(xiofile_t
*xfd
) {
837 /* have to check if a child process died before, but left read data */
838 if (XIO_READABLE(xfd
) &&
839 (XIO_RDSTREAM(xfd
)->howtoend
== END_KILL
||
840 XIO_RDSTREAM(xfd
)->howtoend
== END_CLOSE_KILL
||
841 XIO_RDSTREAM(xfd
)->howtoend
== END_SHUTDOWN_KILL
) &&
842 XIO_RDSTREAM(xfd
)->para
.exec
.pid
== 0) {
843 struct timeval timeout
= { 0, 0 };
845 if (XIO_READABLE(xfd
) && !(XIO_RDSTREAM(xfd
)->eof
>= 2 && !XIO_RDSTREAM(xfd
)->ignoreeof
)) {
846 in
.fd
= XIO_GETRDFD(xfd
);
847 in
.events
= POLLIN
/*|POLLRDBAND*/;
852 retval
= xiopoll(&in
, 1, &timeout
);
853 _errno
= errno
; diag_flush(); errno
= _errno
; /* just in case it's not debug level and Msg() not been called */
854 } while (retval
< 0 && errno
== EINTR
);
857 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec
"."F_tv_usec
"}): %s",
858 in
.fd
, in
.events
, timeout
.tv_sec
, timeout
.tv_usec
,
863 Info("terminated child did not leave data for us");
864 XIO_RDSTREAM(xfd
)->eof
= 2;
866 closing
= MAX(closing
, 1);
872 int xiotransfer(xiofile_t
*inpipe
, xiofile_t
*outpipe
,
873 unsigned char *buff
, size_t bufsiz
, bool righttoleft
);
875 bool mayrd1
; /* sock1 has read data or eof, according to poll() */
876 bool mayrd2
; /* sock2 has read data or eof, according to poll() */
877 bool maywr1
; /* sock1 can be written to, according to poll() */
878 bool maywr2
; /* sock2 can be written to, according to poll() */
880 /* here we come when the sockets are opened (in the meaning of C language),
881 and their options are set/applied
882 returns -1 on error or 0 on success */
884 char *transferwaitstring
;
885 struct pollfd fds
[4],
892 ssize_t bytes1
, bytes2
;
893 int polling
= 0; /* handling ignoreeof */
894 int wasaction
= 1; /* last poll was active, do NOT sleep before next */
895 struct timeval total_timeout
; /* the actual total timeout timer */
898 /* Open sniff file(s) */
900 struct timeval tv
= { 0 }; /* 'cache' to have same time in both */
902 if (xioinqopt('r', name
, sizeof(name
)) == 0) {
903 if (sniffleft
>= 0) Close(sniffleft
);
904 sniffleft
= xio_opensnifffile(name
, &tv
);
906 Error2("option -r \"%s\": %s", name
, strerror(errno
));
910 if (xioinqopt('R', name
, sizeof(name
)) == 0) {
911 if (sniffright
>= 0) Close(sniffright
);
912 sniffright
= xio_opensnifffile(name
, &tv
);
913 if (sniffright
< 0) {
914 Error2("option -R \"%s\": %s", name
, strerror(errno
));
920 if (socat_opts
.debug
) {
922 int msglevel
, exitlevel
;
924 msglevel
= diag_get_int('D'); /* save current message level */
925 diag_set_int('D', E_ERROR
); /* only print errors and fatals in filan */
926 exitlevel
= diag_get_int('e'); /* save current exit level */
927 diag_set_int('e', E_FATAL
); /* only exit on fatals */
929 fdi
= XIO_GETRDFD(sock1
);
930 fdo
= XIO_GETWRFD(sock1
);
931 filan_fd(fdi
, stderr
);
933 filan_fd(fdo
, stderr
);
936 fdi
= XIO_GETRDFD(sock2
);
937 fdo
= XIO_GETWRFD(sock2
);
938 filan_fd(fdi
, stderr
);
940 filan_fd(fdo
, stderr
);
943 diag_set_int('e', exitlevel
); /* restore old exit level */
944 diag_set_int('D', msglevel
); /* restore old message level */
946 #endif /* WITH_FILAN */
948 /* when converting nl to crnl, size might double */
949 if (xioparms
.bufsiz
> (SIZE_MAX
-1)/2) {
950 Error2("buffer size option (-b) to big - "F_Zu
" (max is "F_Zu
")", xioparms
.bufsiz
, (SIZE_MAX
-1)/2);
951 xioparms
.bufsiz
= (SIZE_MAX
-1)/2;
954 #if HAVE_PROTOTYPE_LIB_posix_memalign
955 /* Operations on files with flag O_DIRECT might need buffer alignment.
956 Without this, eg.read() fails with "Invalid argument" */
959 if ((_errno
= Posix_memalign((void **)&buff
, getpagesize(), 2*xioparms
.bufsiz
+1)) != 0) {
960 Error1("posix_memalign(): %s", strerror(_errno
));
964 #else /* !HAVE_PROTOTYPE_LIB_posix_memalign */
965 buff
= Malloc(2*xioparms
.bufsiz
+1);
966 if (buff
== NULL
) return -1;
967 #endif /* !HAVE_PROTOTYPE_LIB_posix_memalign */
969 if (socat_opts
.logopt
== 'm' && xioinqopt('l', NULL
, 0) == 'm') {
970 Info("switching to syslog");
971 diag_set('y', xioparms
.syslogfac
);
972 xiosetopt('l', "\0");
974 total_timeout
= socat_opts
.total_timeout
;
976 if (transferwaitstring
= getenv("SOCAT_TRANSFER_WAIT")) {
977 Info1("before starting data transfer loop: sleeping %ds (env:SOCAT_TRANSFER_WAIT)", atoi(transferwaitstring
));
978 sleep(atoi(transferwaitstring
));
980 Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
981 XIO_GETRDFD(sock1
), XIO_GETWRFD(sock1
),
982 XIO_GETRDFD(sock2
), XIO_GETWRFD(sock2
));
983 while (XIO_RDSTREAM(sock1
)->eof
<= 1 ||
984 XIO_RDSTREAM(sock2
)->eof
<= 1) {
985 struct timeval timeout
, *to
= NULL
;
987 Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec
"."F_tv_usec
"}",
988 XIO_RDSTREAM(sock1
)->eof
, XIO_RDSTREAM(sock2
)->eof
,
990 total_timeout
.tv_sec
, total_timeout
.tv_usec
);
995 if (socat_opts
.total_timeout
.tv_sec
!= 0 ||
996 socat_opts
.total_timeout
.tv_usec
!= 0) {
997 if (total_timeout
.tv_usec
< socat_opts
.pollintv
.tv_usec
) {
998 total_timeout
.tv_usec
+= 1000000;
999 total_timeout
.tv_sec
-= 1;
1001 total_timeout
.tv_sec
-= socat_opts
.pollintv
.tv_sec
;
1002 total_timeout
.tv_usec
-= socat_opts
.pollintv
.tv_usec
;
1003 if (total_timeout
.tv_sec
< 0 ||
1004 total_timeout
.tv_sec
== 0 && total_timeout
.tv_usec
< 0) {
1005 Notice("inactivity timeout triggered");
1017 /* there is a ignoreeof poll timeout, use it */
1018 timeout
= socat_opts
.pollintv
;
1020 } else if (socat_opts
.total_timeout
.tv_sec
!= 0 ||
1021 socat_opts
.total_timeout
.tv_usec
!= 0) {
1022 /* there might occur a total inactivity timeout */
1023 timeout
= socat_opts
.total_timeout
;
1030 /* first eof already occurred, start end timer */
1031 timeout
= socat_opts
.pollintv
;
1036 /* frame 1: set the poll parameters and loop over poll() EINTR) */
1037 do { /* loop over poll() EINTR */
1040 childleftdata(sock1
);
1041 childleftdata(sock2
);
1044 /* first eof already occurred, start end timer */
1045 timeout
= socat_opts
.closwait
;
1050 /* use the ignoreeof timeout if appropriate */
1053 (socat_opts
.pollintv
.tv_sec
< timeout
.tv_sec
) ||
1054 ((socat_opts
.pollintv
.tv_sec
== timeout
.tv_sec
) &&
1055 socat_opts
.pollintv
.tv_usec
< timeout
.tv_usec
)) {
1056 timeout
= socat_opts
.pollintv
;
1060 /* now the fds will be assigned */
1061 if (XIO_READABLE(sock1
) &&
1062 !(XIO_RDSTREAM(sock1
)->eof
> 1 && !XIO_RDSTREAM(sock1
)->ignoreeof
) &&
1063 !socat_opts
.righttoleft
) {
1064 if (!mayrd1
&& !(XIO_RDSTREAM(sock1
)->eof
> 1)) {
1065 fd1in
->fd
= XIO_GETRDFD(sock1
);
1066 fd1in
->events
= POLLIN
;
1071 fd2out
->fd
= XIO_GETWRFD(sock2
);
1072 fd2out
->events
= POLLOUT
;
1080 if (XIO_READABLE(sock2
) &&
1081 !(XIO_RDSTREAM(sock2
)->eof
> 1 && !XIO_RDSTREAM(sock2
)->ignoreeof
) &&
1082 !socat_opts
.lefttoright
) {
1083 if (!mayrd2
&& !(XIO_RDSTREAM(sock2
)->eof
> 1)) {
1084 fd2in
->fd
= XIO_GETRDFD(sock2
);
1085 fd2in
->events
= POLLIN
;
1090 fd1out
->fd
= XIO_GETWRFD(sock1
);
1091 fd1out
->events
= POLLOUT
;
1099 /* frame 0: innermost part of the transfer loop: check FD status */
1100 retval
= xiopoll(fds
, 4, to
);
1101 if (retval
>= 0 || errno
!= EINTR
) {
1105 Info1("poll(): %s", strerror(errno
));
1110 when an exec'd process sends data and terminates, it is unpredictable
1111 whether the data or the sigchild arrives first.
1115 Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec
"."F_tv_usec
"}): %s",
1116 fds
[0].fd
, fds
[0].events
, fds
[1].fd
, fds
[1].events
,
1117 fds
[2].fd
, fds
[2].events
, fds
[3].fd
, fds
[3].events
,
1118 timeout
.tv_sec
, timeout
.tv_usec
, strerror(errno
));
1121 } else if (retval
== 0) {
1122 Info2("poll timed out (no data within %ld.%06ld seconds)",
1123 closing
>=1?socat_opts
.closwait
.tv_sec
:socat_opts
.total_timeout
.tv_sec
,
1124 closing
>=1?socat_opts
.closwait
.tv_usec
:socat_opts
.total_timeout
.tv_usec
);
1125 if (polling
&& !wasaction
) {
1126 /* there was a ignoreeof poll timeout, use it */
1127 polling
= 0; /*%%%*/
1128 if (XIO_RDSTREAM(sock1
)->ignoreeof
) {
1131 if (XIO_RDSTREAM(sock2
)->ignoreeof
) {
1134 } else if (polling
&& wasaction
) {
1137 } else if (socat_opts
.total_timeout
.tv_sec
!= 0 ||
1138 socat_opts
.total_timeout
.tv_usec
!= 0) {
1139 /* there was a total inactivity timeout */
1140 Notice("inactivity timeout triggered");
1148 /* one possibility to come here is ignoreeof on some fd, but no EOF
1149 and no data on any descriptor - this is no indication for end! */
1153 if (XIO_READABLE(sock1
) && XIO_GETRDFD(sock1
) >= 0 &&
1154 (fd1in
->revents
/*&(POLLIN|POLLHUP|POLLERR)*/)) {
1155 if (fd1in
->revents
& POLLNVAL
) {
1156 /* this is what we find on Mac OS X when poll()'ing on a device or
1157 named pipe. a read() might imm. return with 0 bytes, resulting
1159 Error1("poll(...[%d]: invalid request", fd1in
->fd
);
1165 if (XIO_READABLE(sock2
) && XIO_GETRDFD(sock2
) >= 0 &&
1167 if (fd2in
->revents
& POLLNVAL
) {
1168 Error1("poll(...[%d]: invalid request", fd2in
->fd
);
1174 if (XIO_GETWRFD(sock1
) >= 0 && fd1out
->fd
>= 0 && fd1out
->revents
) {
1175 if (fd1out
->revents
& POLLNVAL
) {
1176 Error1("poll(...[%d]: invalid request", fd1out
->fd
);
1182 if (XIO_GETWRFD(sock2
) >= 0 && fd2out
->fd
>= 0 && fd2out
->revents
) {
1183 if (fd2out
->revents
& POLLNVAL
) {
1184 Error1("poll(...[%d]: invalid request", fd2out
->fd
);
1191 if (mayrd1
&& maywr2
) {
1193 if ((bytes1
= xiotransfer(sock1
, sock2
, buff
, xioparms
.bufsiz
, false))
1195 if (errno
!= EAGAIN
) {
1196 closing
= MAX(closing
, 1);
1197 Notice("socket 1 to socket 2 is in error");
1198 if (socat_opts
.lefttoright
) {
1202 } else if (bytes1
> 0) {
1204 total_timeout
= socat_opts
.total_timeout
;
1206 /* is more data available that has already passed poll()? */
1207 mayrd1
= (xiopending(sock1
) > 0);
1208 if (XIO_RDSTREAM(sock1
)->readbytes
!= 0 &&
1209 XIO_RDSTREAM(sock1
)->actbytes
== 0) {
1210 /* avoid idle when all readbytes already there */
1213 /* escape char occurred? */
1214 if (XIO_RDSTREAM(sock1
)->actescape
) {
1215 bytes1
= 0; /* indicate EOF */
1218 /* (bytes1 == 0) handled later */
1223 if (mayrd2
&& maywr1
) {
1225 if ((bytes2
= xiotransfer(sock2
, sock1
, buff
, xioparms
.bufsiz
, true))
1227 if (errno
!= EAGAIN
) {
1228 closing
= MAX(closing
, 1);
1229 Notice("socket 2 to socket 1 is in error");
1230 if (socat_opts
.righttoleft
) {
1234 } else if (bytes2
> 0) {
1236 total_timeout
= socat_opts
.total_timeout
;
1238 /* is more data available that has already passed poll()? */
1239 mayrd2
= (xiopending(sock2
) > 0);
1240 if (XIO_RDSTREAM(sock2
)->readbytes
!= 0 &&
1241 XIO_RDSTREAM(sock2
)->actbytes
== 0) {
1242 /* avoid idle when all readbytes already there */
1245 /* escape char occurred? */
1246 if (XIO_RDSTREAM(sock2
)->actescape
) {
1247 bytes2
= 0; /* indicate EOF */
1250 /* (bytes2 == 0) handled later */
1255 /* NOW handle EOFs */
1257 /*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
1258 bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
1260 if (bytes1
== 0 || XIO_RDSTREAM(sock1
)->eof
>= 2) {
1261 if (XIO_RDSTREAM(sock1
)->ignoreeof
&&
1262 !XIO_RDSTREAM(sock1
)->actescape
&& !closing
) {
1263 Debug1("socket 1 (fd %d) is at EOF, ignoring",
1264 XIO_RDSTREAM(sock1
)->fd
); /*! */
1266 polling
= 1; /* do not hook this eof fd to poll for pollintv*/
1267 } else if (XIO_RDSTREAM(sock1
)->eof
<= 2) {
1268 Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1
));
1269 xioshutdown(sock2
, SHUT_WR
);
1270 XIO_RDSTREAM(sock1
)->eof
= 3;
1271 XIO_RDSTREAM(sock1
)->ignoreeof
= false;
1273 } else if (polling
&& XIO_RDSTREAM(sock1
)->ignoreeof
) {
1276 if (XIO_RDSTREAM(sock1
)->eof
>= 2) {
1277 if (socat_opts
.lefttoright
) {
1283 if (bytes2
== 0 || XIO_RDSTREAM(sock2
)->eof
>= 2) {
1284 if (XIO_RDSTREAM(sock2
)->ignoreeof
&&
1285 !XIO_RDSTREAM(sock2
)->actescape
&& !closing
) {
1286 Debug1("socket 2 (fd %d) is at EOF, ignoring",
1287 XIO_RDSTREAM(sock2
)->fd
);
1289 polling
= 1; /* do not hook this eof fd to poll for pollintv*/
1290 } else if (XIO_RDSTREAM(sock2
)->eof
<= 2) {
1291 Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2
));
1292 xioshutdown(sock1
, SHUT_WR
);
1293 XIO_RDSTREAM(sock2
)->eof
= 3;
1294 XIO_RDSTREAM(sock2
)->ignoreeof
= false;
1296 } else if (polling
&& XIO_RDSTREAM(sock2
)->ignoreeof
) {
1299 if (XIO_RDSTREAM(sock2
)->eof
>= 2) {
1300 if (socat_opts
.righttoleft
) {
1307 /* close everything that's still open */
1316 #define MAXTIMESTAMPLEN 128
1317 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
1318 should be at least MAXTIMESTAMPLEN bytes long.
1319 returns 0 on success or -1 if an error occurred */
1320 int gettimestamp(char *timestamp
) {
1322 #if HAVE_CLOCK_GETTIME
1323 struct timespec now
;
1324 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1326 #endif /* !HAVE_PROTOTYPE_LIB_gettimeofday */
1330 #if HAVE_CLOCK_GETTIME
1331 result
= clock_gettime(CLOCK_REALTIME
, &now
);
1336 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1337 result
= Gettimeofday(&now
, NULL
);
1344 if (nowt
== (time_t)-1) {
1349 bytes
= strftime(timestamp
, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt
));
1350 #if HAVE_CLOCK_GETTIME
1351 bytes
+= sprintf(timestamp
+19, "."F_tv_nsec
" ", now
.tv_nsec
/1000);
1352 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1353 bytes
+= sprintf(timestamp
+19, "."F_tv_usec
" ", now
.tv_usec
);
1355 strncpy(×tamp
[bytes
++], " ", 2);
1358 strcpy(timestamp
, ctime(&nowt
));
1359 bytes
= strlen(timestamp
);
1364 static const char *prefixltor
= "> ";
1365 static const char *prefixrtol
= "< ";
1366 static unsigned long numltor
;
1367 static unsigned long numrtol
;
1368 /* print block header (during verbose or hex dump)
1369 returns 0 on success or -1 if an error occurred */
1371 xioprintblockheader(FILE *file
, size_t bytes
, bool righttoleft
) {
1372 char timestamp
[MAXTIMESTAMPLEN
];
1373 char buff
[128+MAXTIMESTAMPLEN
];
1374 if (gettimestamp(timestamp
) < 0) {
1378 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1379 prefixrtol
, timestamp
, bytes
, numrtol
, numrtol
+bytes
-1);
1382 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1383 prefixltor
, timestamp
, bytes
, numltor
, numltor
+bytes
-1);
1391 /* inpipe is suspected to have read data available; read at most bufsiz bytes
1392 and transfer them to outpipe. Perform required data conversions.
1393 buff must be a malloc()'ed storage and might be realloc()'ed in this
1394 function if more space is required after conversions.
1395 Returns the number of bytes written, or 0 on EOF or <0 if an
1396 error occurred or when data was read but none written due to conversions
1397 (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
1398 the file has a mandatory lock.
1399 If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
1400 does NOT write a zero bytes block.
1402 /* inpipe, outpipe must be single descriptors (not dual!) */
1403 int xiotransfer(xiofile_t
*inpipe
, xiofile_t
*outpipe
,
1404 unsigned char *buff
, size_t bufsiz
, bool righttoleft
) {
1405 ssize_t bytes
, writt
= 0;
1408 bytes
= xioread(inpipe
, buff
, bufsiz
);
1410 if (errno
!= EAGAIN
)
1411 XIO_RDSTREAM(inpipe
)->eof
= 2;
1412 /*xioshutdown(inpipe, SHUT_RD);*/
1415 if (bytes
== 0 && XIO_RDSTREAM(inpipe
)->ignoreeof
&& !closing
) {
1417 } else if (bytes
== 0) {
1418 XIO_RDSTREAM(inpipe
)->eof
= 2;
1419 closing
= MAX(closing
, 1);
1424 ++XIO_RDSTREAM(inpipe
)->blocks_read
;
1425 XIO_RDSTREAM(inpipe
)->bytes_read
+= bytes
;
1427 /* handle escape char */
1428 if (XIO_RDSTREAM(inpipe
)->escape
!= -1) {
1429 /* check input data for escape char */
1430 unsigned char *ptr
= buff
;
1432 while (ctr
< bytes
) {
1433 if (*ptr
== XIO_RDSTREAM(inpipe
)->escape
) {
1434 /* found: set flag, truncate input data */
1435 XIO_RDSTREAM(inpipe
)->actescape
= true;
1437 Info("escape char found in input");
1443 XIO_RDSTREAM(inpipe
)->eof
= 2;
1450 if (XIO_RDSTREAM(inpipe
)->lineterm
!=
1451 XIO_WRSTREAM(outpipe
)->lineterm
) {
1452 cv_newline(buff
, &bytes
,
1453 XIO_RDSTREAM(inpipe
)->lineterm
,
1454 XIO_WRSTREAM(outpipe
)->lineterm
);
1457 errno
= EAGAIN
; return -1;
1460 if (!righttoleft
&& sniffleft
>= 0) {
1461 if ((sniffed
= Write(sniffleft
, buff
, bytes
)) < bytes
) {
1463 Warn3("-r: write(%d, buff, "F_Zu
"): %s",
1464 sniffleft
, bytes
, strerror(errno
));
1465 else if (sniffed
< bytes
)
1466 Warn3("-r: write(%d, buff, "F_Zu
") -> "F_Zd
,
1467 sniffleft
, bytes
, sniffed
);
1469 } else if (righttoleft
&& sniffright
>= 0) {
1470 if ((sniffed
= Write(sniffright
, buff
, bytes
)) < bytes
) {
1472 Warn3("-R: write(%d, buff, "F_Zu
"): %s",
1473 sniffright
, bytes
, strerror(errno
));
1474 else if (sniffed
< bytes
)
1475 Warn3("-R: write(%d, buff, "F_Zu
") -> "F_Zd
,
1476 sniffright
, bytes
, sniffed
);
1480 if (socat_opts
.verbose
&& socat_opts
.verbhex
) {
1485 const unsigned char *end
, *s
, *t
;
1488 xioprintblockheader(stderr
, bytes
, righttoleft
);
1491 j
= Min(N
, (size_t)(end
-s
));
1498 fprintf(stderr
, " %02x", c
);
1500 if (c
== '\n') break;
1503 /* fill hex column */
1525 fputc('\n', stderr
);
1528 fputs("--\n", stderr
);
1529 } else if (socat_opts
.verbose
) {
1531 xioprintblockheader(stderr
, bytes
, righttoleft
);
1532 while (i
< (size_t)bytes
) {
1534 if (i
> 0 && buff
[i
-1] == '\n')
1537 case '\a' : fputs("\\a", stderr
); break;
1538 case '\b' : fputs("\\b", stderr
); break;
1539 case '\t' : fputs("\t", stderr
); break;
1540 case '\n' : fputs("\n", stderr
); break;
1541 case '\v' : fputs("\\v", stderr
); break;
1542 case '\f' : fputs("\\f", stderr
); break;
1543 case '\r' : fputs("\\r", stderr
); break;
1544 case '\\' : fputs("\\\\", stderr
); break;
1553 } else if (socat_opts
.verbhex
) {
1556 xioprintblockheader(stderr
, bytes
, righttoleft
);
1557 for (i
= 0; i
< bytes
; ++i
) {
1558 fprintf(stderr
, " %02x", buff
[i
]);
1560 fputc('\n', stderr
);
1563 writt
= xiowrite(outpipe
, buff
, bytes
);
1565 /* EAGAIN when nonblocking but a mandatory lock is on file.
1566 the problem with EAGAIN is that the read cannot be repeated,
1567 so we need to buffer the data and try to write it later
1568 again. not yet implemented, sorry. */
1570 if (errno
== EPIPE
) {
1571 return 0; /* can no longer write; handle like EOF */
1576 Info3("transferred "F_Zu
" bytes from %d to %d",
1577 writt
, XIO_GETRDFD(inpipe
), XIO_GETWRFD(outpipe
));
1579 ++XIO_WRSTREAM(outpipe
)->blocks_written
;
1580 XIO_WRSTREAM(outpipe
)->bytes_written
+= writt
;
1591 /* converts the newline characters (or character sequences) from the one
1592 specified in lineterm1 to that of lineterm2. Possible values are
1593 LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
1594 bytes specifies the number of bytes input and output */
1595 int cv_newline(unsigned char *buff
, ssize_t
*bytes
,
1596 int lineterm1
, int lineterm2
) {
1597 /* must perform newline changes */
1598 if (lineterm1
<= LINETERM_CR
&& lineterm2
<= LINETERM_CR
) {
1599 /* no change in data length */
1600 unsigned char from
, to
, *p
, *z
;
1601 if (lineterm1
== LINETERM_RAW
) {
1602 from
= '\n'; to
= '\r';
1604 from
= '\r'; to
= '\n';
1609 if (*p
== from
) *p
= to
;
1613 } else if (lineterm1
== LINETERM_CRNL
) {
1614 /* buffer might become shorter */
1615 unsigned char to
, *s
, *t
, *z
;
1616 if (lineterm2
== LINETERM_RAW
) {
1636 /* buffer becomes longer (up to double length), must alloc another space */
1637 static unsigned char *buf2
; /*! not threadsafe */
1638 unsigned char from
; unsigned char *s
, *t
, *z
;
1640 if (lineterm1
== LINETERM_RAW
) {
1646 if ((buf2
= Malloc(xioparms
.bufsiz
)) == NULL
) {
1650 memcpy(buf2
, buff
, *bytes
);
1651 s
= buf2
; t
= buff
; z
= buf2
+ *bytes
;
1654 *t
++ = '\r'; *t
++ = '\n';
1666 void socat_signal(int signum
) {
1669 diag_in_handler
= 1;
1670 Notice1("socat_signal(): handling signal %d", signum
);
1673 diag_immediate_exit
= 1;
1676 diag_set_int('x', 128+signum
); /* in case Error exits for us */
1677 Error1("exiting on signal %d", signum
);
1678 diag_set_int('x', 0); /* in case Error did not exit */
1681 Warn1("exiting on signal %d", signum
); break;
1684 Notice1("exiting on signal %d", signum
); break;
1686 Notice1("socat_signal(): finishing signal %d", signum
);
1687 diag_exit(128+signum
); /* internal cleanup + _exit() */
1688 diag_in_handler
= 0;
1692 /* this is the callback when the child of an address died */
1693 static int socat_sigchild(struct single
*file
) {
1694 if (file
->ignoreeof
&& !closing
) {
1697 file
->eof
= MAX(file
->eof
, 1);
1703 static int socat_lock(void) {
1707 if ((lockrc
= xiolock(&socat_opts
.lock
)) < 0) {
1715 if (socat_opts
.lock
.lockfile
) {
1716 if ((lockrc
= xiolock(socat_opts
.lock
.lockfile
)) < 0) {
1717 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1724 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/
1727 if (socat_opts
.lock
.waitlock
) {
1728 if (xiowaitlock(socat_opts
.lock
.waitlock
, socat_opts
.lock
.intervall
)) {
1729 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1733 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1740 static void socat_unlock(void) {
1741 if (!havelock
) return;
1742 if (socat_opts
.lock
.lockfile
) {
1743 if (Unlink(socat_opts
.lock
.lockfile
) < 0) {
1744 if (!diag_in_handler
) {
1745 Warn2("unlink(\"%s\"): %s",
1746 socat_opts
.lock
.lockfile
, strerror(errno
));
1748 Warn1("unlink(\"%s\"): "F_strerror
,
1749 socat_opts
.lock
.lockfile
);
1752 Info1("released lock \"%s\"", socat_opts
.lock
.lockfile
);
1757 /* this is a callback function that may be called by the newchild hook of xio
1759 static int socat_newchild(void) {
1766 void socat_signal_logstats(int signum
) {
1767 diag_in_handler
= 1;
1768 Notice1("socat_signal_logstats(): handling signal %d", signum
);
1769 socat_print_stats();
1770 Notice1("socat_signal_logstats(): finishing signal %d", signum
);
1771 diag_in_handler
= 0;
1773 #endif /* WITH_STATS */
1776 static void socat_print_stats(void)
1778 const char ltorf0
[] = "STATISTICS: left to right: %%%ullu packets(s), %%%ullu byte(s)";
1779 const char rtolf0
[] = "STATISTICS: right to left: %%%ullu packets(s), %%%ullu byte(s)";
1780 char ltorf1
[sizeof(ltorf0
)]; /* final printf format with lengths of number */
1781 char rtolf1
[sizeof(rtolf0
)]; /* final printf format with lengths of number */
1782 unsigned int blocksd
= 1, bytesd
= 1; /* number of digits in output */
1783 struct single
*sock1w
, *sock2w
;
1786 if (sock1
== NULL
|| sock2
== NULL
) {
1787 Warn("transfer engine not yet started, statistics not available");
1790 if ((sock1
->tag
& ~XIO_TAG_CLOSED
) == XIO_TAG_DUAL
) {
1791 sock1w
= sock1
->dual
.stream
[1];
1793 sock1w
= &sock1
->stream
;
1795 if ((sock2
->tag
& ~XIO_TAG_CLOSED
) == XIO_TAG_DUAL
) {
1796 sock2w
= sock2
->dual
.stream
[1];
1798 sock2w
= &sock2
->stream
;
1800 if (!socat_opts
.righttoleft
&& !socat_opts
.righttoleft
) {
1801 /* Both directions - format output */
1802 unsigned long long int maxblocks
=
1803 Max(sock1w
->blocks_written
, sock2w
->blocks_written
);
1804 unsigned long long int maxbytes
=
1805 Max(sock1w
->bytes_written
, sock2w
->bytes_written
);
1806 /* Calculate number of digits */
1807 while (maxblocks
>= 10) { ++blocksd
; maxblocks
/= 10; }
1808 while (maxbytes
>= 10) { ++bytesd
; maxbytes
/= 10; }
1810 snprintf(ltorf1
, sizeof(ltorf1
), ltorf0
, blocksd
, bytesd
);
1811 snprintf(rtolf1
, sizeof(rtolf1
), rtolf0
, blocksd
, bytesd
);
1812 /* Statistics are E_INFO level; make sure they are printed anyway */
1813 savelevel
= diag_get_int('d');
1814 diag_set_int('d', E_INFO
);
1815 Warn("statistics are experimental");
1816 if (!socat_opts
.righttoleft
) {
1817 Info2(ltorf1
, sock2w
->blocks_written
, sock2w
->bytes_written
);
1819 if (!socat_opts
.lefttoright
) {
1820 Info2(rtolf1
, sock1w
->blocks_written
, sock1w
->bytes_written
);
1822 diag_set_int('d', savelevel
);
1825 #endif /* WITH_STATs */