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,1000000}, /* total_timeout (this invalid default means no 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");
278 socat_opts
.total_timeout
.tv_sec
= 0; /* infinite */
279 socat_opts
.total_timeout
.tv_usec
= 1000000; /* by invalid */
281 socat_opts
.total_timeout
.tv_sec
= rto
;
282 socat_opts
.total_timeout
.tv_usec
=
283 (rto
-socat_opts
.total_timeout
.tv_sec
) * 1000000;
286 case 'u': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
287 socat_opts
.lefttoright
= true; break;
288 case 'U': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
289 socat_opts
.righttoleft
= true; break;
290 case 'g': if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
291 xioopts_ignoregroups
= true; break;
292 case 'L': if (socat_opts
.lock
.lockfile
)
293 Error("only one -L and -W option allowed");
295 socat_opts
.lock
.lockfile
= *arg1
+2;
298 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
299 Error("option -L requires an argument; use option \"-h\" for help");
304 case 'W': if (socat_opts
.lock
.lockfile
) {
305 Error("only one -L and -W option allowed");
308 socat_opts
.lock
.lockfile
= *arg1
+2;
311 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
312 Error("option -W requires an argument; use option \"-h\" for help");
316 socat_opts
.lock
.waitlock
= true;
317 socat_opts
.lock
.intervall
.tv_sec
= 1;
318 socat_opts
.lock
.intervall
.tv_nsec
= 0;
320 #if WITH_IP4 || WITH_IP6
328 if (arg1
[0][2]) { socat_opt_hint(stderr
, arg1
[0][1], arg1
[0][2]); Exit(1); }
329 xioparms
.default_ip
= arg1
[0][1];
330 xioparms
.preferred_ip
= arg1
[0][1];
332 #endif /* WITH_IP4 || WITH_IP6 */
334 if (!strcmp("experimental", &arg1
[0][2])) {
335 xioparms
.experimental
= true;
336 } else if (!strcmp("statistics", &arg1
[0][2])) {
337 socat_opts
.statistics
= true;
339 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1
[0]);
346 break; /* this "-" is a variation of STDIO */
348 xioinqopt('p', buff
, sizeof(buff
)); /* fetch pipe separator char */
349 if (arg1
[0][1] == buff
[0]) {
353 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1
[0]);
357 /* the leading "-" is a form of the first address */
363 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc
);
366 if (socat_opts
.lefttoright
&& socat_opts
.righttoleft
) {
367 Error("-U and -u must not be combined");
371 Info(copyright_socat
);
373 Info(copyright_openssl
);
374 Info(copyright_ssleay
);
376 Debug2("socat version %s on %s", socatversion
, timestamp
);
377 xiosetenv("VERSION", socatversion
, 1, NULL
); /* SOCAT_VERSION */
378 uname(&ubuf
); /* ! here we circumvent internal tracing (Uname) */
379 Debug4("running on %s version %s, release %s, machine %s\n",
380 ubuf
.sysname
, ubuf
.version
, ubuf
.release
, ubuf
.machine
);
382 #if WITH_MSGLEVEL <= E_DEBUG
383 for (i
= 0; i
< argc0
; ++i
) {
384 Debug2("argv[%d]: \"%s\"", i
, argv
[i
]);
386 #endif /* WITH_MSGLEVEL <= E_DEBUG */
390 struct sigaction act
;
394 sigfillset(&act
.sa_mask
); /* while in sighandler block all signals */
396 act
.sa_handler
= socat_signal
;
397 /* not sure which signals should be caught and print a message */
398 for (i
= 0, m
= 1; i
< 8*sizeof(unsigned long); ++i
, m
<<= 1) {
399 if (socat_opts
.log_sigs
& m
) {
401 Sigaction(i
, &act
, NULL
);
403 Signal(i
, socat_signal
);
410 act
.sa_handler
= socat_signal_logstats
;
411 Sigaction(SIGUSR1
, &act
, NULL
);
413 Signal(SIGUSR1
, socat_signal_logstats
);
415 #endif /* WITH_STATS */
417 Signal(SIGPIPE
, SIG_IGN
);
420 xiohook_newchild
= &socat_newchild
;
422 if (lockrc
= socat_lock()) {
423 /* =0: goon; >0: locked; <0: error, printed in sub */
425 Error1("could not obtain lock \"%s\"", socat_opts
.lock
.lockfile
);
429 Atexit(socat_unlock
);
431 if (socat_opts
.statistics
) {
432 Atexit(socat_print_stats
);
434 #endif /* WITH_STATS */
436 /* Display important info, values may be set by:
437 ./configure --enable-default-ipv=0|4|6
438 env SOCAT_PREFERRED_RESOLVE_IP, SOCAT_DEFAULT_LISTEN_IP
440 Info1("default listen IP version is %c", xioparms
.default_ip
);
441 Info1("preferred resolve IP version is %c", xioparms
.preferred_ip
);
443 result
= socat(arg1
[0], arg1
[1]);
444 if (result
== EXIT_SUCCESS
&& engine_result
!= EXIT_SUCCESS
) {
445 result
= engine_result
; /* a signal handler reports failure */
447 Notice1("exiting with status %d", result
);
449 return 0; /* not reached, just for gcc -Wall */
453 void socat_usage(FILE *fd
) {
454 fputs(copyright_socat
, fd
); fputc('\n', fd
);
455 fputs("Usage:\n", fd
);
456 fputs("socat [options] <bi-address> <bi-address>\n", fd
);
457 fputs(" options (general command line options):\n", fd
);
458 fputs(" -V print version and feature information to stdout, and exit\n", fd
);
460 fputs(" -h|-? print a help text describing command line options and addresses\n", fd
);
461 fputs(" -hh like -h, plus a list of all common address option names\n", fd
);
462 fputs(" -hhh like -hh, plus a list of all available address option names\n", fd
);
463 #endif /* WITH_HELP */
464 fputs(" -d[ddd] increase verbosity (use up to 4 times; 2 are recommended)\n", fd
);
465 fputs(" -d0|1|2|3|4 set verbosity level (0: Errors; 4 all including Debug)\n", fd
);
467 fputs(" -D analyze file descriptors before loop\n", fd
);
469 fputs(" --experimental enable experimental features\n", fd
);
470 fputs(" --statistics output transfer statistics on exit\n", fd
);
471 fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd
);
472 fputs(" -lf<logfile> log to file\n", fd
);
473 fputs(" -ls log to stderr (default if no other log)\n", fd
);
474 fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd
);
475 fputs(" -lp<progname> set the program name used for logging and vars\n", fd
);
476 fputs(" -lu use microseconds for logging timestamps\n", fd
);
477 fputs(" -lh add hostname to log messages\n", fd
);
478 fputs(" -v verbose text dump of data traffic\n", fd
);
479 fputs(" -x verbose hexadecimal dump of data traffic\n", fd
);
480 fputs(" -r <file> raw dump of data flowing from left to right\n", fd
);
481 fputs(" -R <file> raw dump of data flowing from right to left\n", fd
);
482 fputs(" -b<size_t> set data buffer size (8192)\n", fd
);
483 fputs(" -s sloppy (continue on error)\n", fd
);
484 fputs(" -S<sigmask> log these signals, override default\n", fd
);
485 fputs(" -t<timeout> wait seconds before closing second channel\n", fd
);
486 fputs(" -T<timeout> total inactivity timeout in seconds\n", fd
);
487 fputs(" -u unidirectional mode (left to right)\n", fd
);
488 fputs(" -U unidirectional mode (right to left)\n", fd
);
489 fputs(" -g do not check option groups\n", fd
);
490 fputs(" -L <lockfile> try to obtain lock, or fail\n", fd
);
491 fputs(" -W <lockfile> try to obtain lock, or wait\n", fd
);
492 #if WITH_IP4 || WITH_IP6
493 fputs(" -0 do not prefer an IP version\n", fd
);
496 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd
);
499 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd
);
503 void socat_opt_hint(FILE *fd
, char a
, char b
) {
504 fprintf(fd
, "Do not merge single character options, i.e. use \"-%c -%c\" instead of \"-%c%c\"\n",
509 void socat_version(FILE *fd
) {
512 fputs(copyright_socat
, fd
); fputc('\n', fd
);
513 fprintf(fd
, "socat version %s on %s\n", socatversion
, timestamp
);
515 fprintf(fd
, " running on %s version %s, release %s, machine %s\n",
516 ubuf
.sysname
, ubuf
.version
, ubuf
.release
, ubuf
.machine
);
517 fputs("features:\n", fd
);
519 fprintf(fd
, " #define WITH_HELP %d\n", WITH_HELP
);
521 fputs(" #undef WITH_HELP\n", fd
);
524 fprintf(fd
, " #define WITH_STATS %d\n", WITH_STATS
);
526 fputs(" #undef WITH_STATS\n", fd
);
529 fprintf(fd
, " #define WITH_STDIO %d\n", WITH_STDIO
);
531 fputs(" #undef WITH_STDIO\n", fd
);
534 fprintf(fd
, " #define WITH_FDNUM %d\n", WITH_FDNUM
);
536 fputs(" #undef WITH_FDNUM\n", fd
);
539 fprintf(fd
, " #define WITH_FILE %d\n", WITH_FILE
);
541 fputs(" #undef WITH_FILE\n", fd
);
544 fprintf(fd
, " #define WITH_CREAT %d\n", WITH_CREAT
);
546 fputs(" #undef WITH_CREAT\n", fd
);
549 fprintf(fd
, " #define WITH_GOPEN %d\n", WITH_GOPEN
);
551 fputs(" #undef WITH_GOPEN\n", fd
);
554 fprintf(fd
, " #define WITH_TERMIOS %d\n", WITH_TERMIOS
);
556 fputs(" #undef WITH_TERMIOS\n", fd
);
559 fprintf(fd
, " #define WITH_PIPE %d\n", WITH_PIPE
);
561 fputs(" #undef WITH_PIPE\n", fd
);
563 #ifdef WITH_SOCKETPAIR
564 fprintf(fd
, " #define WITH_SOCKETPAIR %d\n", WITH_SOCKETPAIR
);
566 fputs(" #undef WITH_SOCKETPAIR\n", fd
);
569 fprintf(fd
, " #define WITH_UNIX %d\n", WITH_UNIX
);
571 fputs(" #undef WITH_UNIX\n", fd
);
572 #endif /* WITH_UNIX */
573 #ifdef WITH_ABSTRACT_UNIXSOCKET
574 fprintf(fd
, " #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET
);
576 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd
);
577 #endif /* WITH_ABSTRACT_UNIXSOCKET */
579 fprintf(fd
, " #define WITH_IP4 %d\n", WITH_IP4
);
581 fputs(" #undef WITH_IP4\n", fd
);
584 fprintf(fd
, " #define WITH_IP6 %d\n", WITH_IP6
);
586 fputs(" #undef WITH_IP6\n", fd
);
589 fprintf(fd
, " #define WITH_RAWIP %d\n", WITH_RAWIP
);
591 fputs(" #undef WITH_RAWIP\n", fd
);
593 #ifdef WITH_GENERICSOCKET
594 fprintf(fd
, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET
);
596 fputs(" #undef WITH_GENERICSOCKET\n", fd
);
598 #ifdef WITH_INTERFACE
599 fprintf(fd
, " #define WITH_INTERFACE %d\n", WITH_INTERFACE
);
601 fputs(" #undef WITH_INTERFACE\n", fd
);
604 fprintf(fd
, " #define WITH_TCP %d\n", WITH_TCP
);
606 fputs(" #undef WITH_TCP\n", fd
);
609 fprintf(fd
, " #define WITH_UDP %d\n", WITH_UDP
);
611 fputs(" #undef WITH_UDP\n", fd
);
614 fprintf(fd
, " #define WITH_SCTP %d\n", WITH_SCTP
);
616 fputs(" #undef WITH_SCTP\n", fd
);
619 fprintf(fd
, " #define WITH_DCCP %d\n", WITH_DCCP
);
621 fputs(" #undef WITH_DCCP\n", fd
);
624 fprintf(fd
, " #define WITH_UDPLITE %d\n", WITH_UDPLITE
);
626 fputs(" #undef WITH_UDPLITE\n", fd
);
629 fprintf(fd
, " #define WITH_LISTEN %d\n", WITH_LISTEN
);
631 fputs(" #undef WITH_LISTEN\n", fd
);
634 fprintf(fd
, " #define WITH_POSIXMQ %d\n", WITH_POSIXMQ
);
636 fputs(" #undef WITH_POSIXMQ\n", fd
);
639 fprintf(fd
, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4
);
641 fputs(" #undef WITH_SOCKS4\n", fd
);
644 fprintf(fd
, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A
);
646 fputs(" #undef WITH_SOCKS4A\n", fd
);
649 fprintf(fd
, " #define WITH_SOCKS5 %d\n", WITH_SOCKS5
);
651 fputs(" #undef WITH_SOCKS5\n", fd
);
654 fprintf(fd
, " #define WITH_VSOCK %d\n", WITH_VSOCK
);
656 fputs(" #undef WITH_VSOCK\n", fd
);
658 #ifdef WITH_NAMESPACES
659 fprintf(fd
, " #define WITH_NAMESPACES %d\n", WITH_NAMESPACES
);
661 fputs(" #undef WITH_NAMESPACES\n", fd
);
664 fprintf(fd
, " #define WITH_PROXY %d\n", WITH_PROXY
);
666 fputs(" #undef WITH_PROXY\n", fd
);
669 fprintf(fd
, " #define WITH_SYSTEM %d\n", WITH_SYSTEM
);
671 fputs(" #undef WITH_SYSTEM\n", fd
);
674 fprintf(fd
, " #define WITH_SHELL %d\n", WITH_SHELL
);
676 fputs(" #undef WITH_SHELL\n", fd
);
679 fprintf(fd
, " #define WITH_EXEC %d\n", WITH_EXEC
);
681 fputs(" #undef WITH_EXEC\n", fd
);
684 fprintf(fd
, " #define WITH_READLINE %d\n", WITH_READLINE
);
686 fputs(" #undef WITH_READLINE\n", fd
);
689 fprintf(fd
, " #define WITH_TUN %d\n", WITH_TUN
);
691 fputs(" #undef WITH_TUN\n", fd
);
694 fprintf(fd
, " #define WITH_PTY %d\n", WITH_PTY
);
696 fputs(" #undef WITH_PTY\n", fd
);
699 fprintf(fd
, " #define WITH_OPENSSL %d\n", WITH_OPENSSL
);
701 fputs(" #undef WITH_OPENSSL\n", fd
);
704 fprintf(fd
, " #define WITH_FIPS %d\n", WITH_FIPS
);
706 fputs(" #undef WITH_FIPS\n", fd
);
709 fprintf(fd
, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP
);
711 fputs(" #undef WITH_LIBWRAP\n", fd
);
714 fprintf(fd
, " #define WITH_SYCLS %d\n", WITH_SYCLS
);
716 fputs(" #undef WITH_SYCLS\n", fd
);
719 fprintf(fd
, " #define WITH_FILAN %d\n", WITH_FILAN
);
721 fputs(" #undef WITH_FILAN\n", fd
);
724 fprintf(fd
, " #define WITH_RETRY %d\n", WITH_RETRY
);
726 fputs(" #undef WITH_RETRY\n", fd
);
729 fprintf(fd
, " #define WITH_DEVTESTS %d\n", WITH_DEVTESTS
);
731 fputs(" #undef WITH_DEVTESTS\n", fd
);
734 fprintf(fd
, " #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL
,
735 &"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL
<<3]);
737 fputs(" #undef WITH_MSGLEVEL\n", fd
);
739 #ifdef WITH_DEFAULT_IPV
740 # if WITH_DEFAULT_IPV
741 fprintf(fd
, " #define WITH_DEFAULT_IPV %c\n", WITH_DEFAULT_IPV
);
743 fprintf(fd
, " #define WITH_DEFAULT_IPV '\\0'\n");
746 fputs(" #undef WITH_DEFAULT_IPV\n", fd
);
751 xiofile_t
*sock1
, *sock2
;
752 int closing
= 0; /* 0..no eof yet, 1..first eof just occurred,
753 2..counting down closing timeout */
754 int sniffleft
= -1; /* -1 or an FD for teeing data arriving on xfd1 */
755 int sniffright
= -1; /* -1 or an FD for teeing data arriving on xfd2 */
757 /* call this function when the common command line options are parsed, and the
758 addresses are extracted (but not resolved). */
759 int socat(const char *address1
, const char *address2
) {
762 if (socat_opts
.lefttoright
) {
763 if ((sock1
= xioopen(address1
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
766 xiosetsigchild(sock1
, socat_sigchild
);
767 } else if (socat_opts
.righttoleft
) {
768 if ((sock1
= xioopen(address1
, XIO_WRONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
771 xiosetsigchild(sock1
, socat_sigchild
);
773 if ((sock1
= xioopen(address1
, XIO_RDWR
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
776 xiosetsigchild(sock1
, socat_sigchild
);
779 if (XIO_READABLE(sock1
) &&
780 (XIO_RDSTREAM(sock1
)->howtoend
== END_KILL
||
781 XIO_RDSTREAM(sock1
)->howtoend
== END_CLOSE_KILL
||
782 XIO_RDSTREAM(sock1
)->howtoend
== END_SHUTDOWN_KILL
)) {
784 for (i
= 0; i
< NUMUNKNOWN
; ++i
) {
785 if (XIO_RDSTREAM(sock1
)->para
.exec
.pid
== diedunknown
[i
]) {
786 /* child has alread died... but it might have put regular data into
787 the communication channel, so continue */
788 Info2("child "F_pid
" has already died with status %d",
789 XIO_RDSTREAM(sock1
)->para
.exec
.pid
, statunknown
[i
]);
790 ++num_child
; /* it was counted as anonymous child, undo */
791 if (statunknown
[i
] != 0) {
795 XIO_RDSTREAM(sock1
)->para
.exec
.pid
= 0;
796 /* return STAT_RETRYLATER; */
802 mayexec
= (sock1
->common
.flags
&XIO_DOESCONVERT
? 0 : XIO_MAYEXEC
);
803 if (XIO_WRITABLE(sock1
)) {
804 if (XIO_READABLE(sock1
)) {
805 if ((sock2
= xioopen(address2
, XIO_RDWR
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
808 xiosetsigchild(sock2
, socat_sigchild
);
810 if ((sock2
= xioopen(address2
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
813 xiosetsigchild(sock2
, socat_sigchild
);
815 } else { /* assuming sock1 is readable */
816 if ((sock2
= xioopen(address2
, XIO_WRONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
819 xiosetsigchild(sock2
, socat_sigchild
);
822 if (XIO_READABLE(sock2
) &&
823 (XIO_RDSTREAM(sock2
)->howtoend
== END_KILL
||
824 XIO_RDSTREAM(sock2
)->howtoend
== END_CLOSE_KILL
||
825 XIO_RDSTREAM(sock2
)->howtoend
== END_SHUTDOWN_KILL
)) {
827 for (i
= 0; i
< NUMUNKNOWN
; ++i
) {
828 if (XIO_RDSTREAM(sock2
)->para
.exec
.pid
== diedunknown
[i
]) {
829 /* child has alread died... but it might have put regular data into
830 the communication channel, so continue */
831 Info2("child "F_pid
" has already died with status %d",
832 XIO_RDSTREAM(sock2
)->para
.exec
.pid
, statunknown
[i
]);
833 if (statunknown
[i
] != 0) {
837 XIO_RDSTREAM(sock2
)->para
.exec
.pid
= 0;
838 /* return STAT_RETRYLATER; */
844 Info("resolved and opened all sock addresses");
845 return _socat(); /* nsocks, sockets are visible outside function */
848 /* checks if this is a connection to a child process, and if so, sees if the
849 child already died, leaving some data for us.
850 returns <0 if an error occurred;
851 returns 0 if no child or not yet died or died without data (sets eof);
852 returns >0 if child died and left data
854 int childleftdata(xiofile_t
*xfd
) {
858 /* have to check if a child process died before, but left read data */
859 if (XIO_READABLE(xfd
) &&
860 (XIO_RDSTREAM(xfd
)->howtoend
== END_KILL
||
861 XIO_RDSTREAM(xfd
)->howtoend
== END_CLOSE_KILL
||
862 XIO_RDSTREAM(xfd
)->howtoend
== END_SHUTDOWN_KILL
) &&
863 XIO_RDSTREAM(xfd
)->para
.exec
.pid
== 0) {
864 struct timeval timeout
= { 0, 0 };
866 if (XIO_READABLE(xfd
) && !(XIO_RDSTREAM(xfd
)->eof
>= 2 && !XIO_RDSTREAM(xfd
)->ignoreeof
)) {
867 in
.fd
= XIO_GETRDFD(xfd
);
868 in
.events
= POLLIN
/*|POLLRDBAND*/;
873 retval
= xiopoll(&in
, 1, &timeout
);
874 _errno
= errno
; diag_flush(); errno
= _errno
; /* just in case it's not debug level and Msg() not been called */
875 } while (retval
< 0 && errno
== EINTR
);
878 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec
"."F_tv_usec
"}): %s",
879 in
.fd
, in
.events
, timeout
.tv_sec
, timeout
.tv_usec
,
884 Info("terminated child did not leave data for us");
885 XIO_RDSTREAM(xfd
)->eof
= 2;
887 closing
= MAX(closing
, 1);
893 int xiotransfer(xiofile_t
*inpipe
, xiofile_t
*outpipe
,
894 unsigned char *buff
, size_t bufsiz
, bool righttoleft
);
896 bool mayrd1
; /* sock1 has read data or eof, according to poll() */
897 bool mayrd2
; /* sock2 has read data or eof, according to poll() */
898 bool maywr1
; /* sock1 can be written to, according to poll() */
899 bool maywr2
; /* sock2 can be written to, according to poll() */
901 /* here we come when the sockets are opened (in the meaning of C language),
902 and their options are set/applied
903 returns -1 on error or 0 on success */
905 char *transferwaitstring
;
906 struct pollfd fds
[4],
913 ssize_t bytes1
, bytes2
;
914 int polling
= 0; /* handling ignoreeof */
915 int wasaction
= 1; /* last poll was active, do NOT sleep before next */
916 struct timeval total_timeout
; /* the actual total timeout timer */
919 /* Open sniff file(s) */
921 struct timeval tv
= { 0 }; /* 'cache' to have same time in both */
923 if (xioinqopt('r', name
, sizeof(name
)) == 0) {
924 if (sniffleft
>= 0) Close(sniffleft
);
925 sniffleft
= xio_opensnifffile(name
, &tv
);
927 Error2("option -r \"%s\": %s", name
, strerror(errno
));
931 if (xioinqopt('R', name
, sizeof(name
)) == 0) {
932 if (sniffright
>= 0) Close(sniffright
);
933 sniffright
= xio_opensnifffile(name
, &tv
);
934 if (sniffright
< 0) {
935 Error2("option -R \"%s\": %s", name
, strerror(errno
));
941 if (socat_opts
.debug
) {
943 int msglevel
, exitlevel
;
945 msglevel
= diag_get_int('D'); /* save current message level */
946 diag_set_int('D', E_ERROR
); /* only print errors and fatals in filan */
947 exitlevel
= diag_get_int('e'); /* save current exit level */
948 diag_set_int('e', E_FATAL
); /* only exit on fatals */
950 fdi
= XIO_GETRDFD(sock1
);
951 fdo
= XIO_GETWRFD(sock1
);
952 filan_fd(fdi
, stderr
);
954 filan_fd(fdo
, stderr
);
957 fdi
= XIO_GETRDFD(sock2
);
958 fdo
= XIO_GETWRFD(sock2
);
959 filan_fd(fdi
, stderr
);
961 filan_fd(fdo
, stderr
);
964 diag_set_int('e', exitlevel
); /* restore old exit level */
965 diag_set_int('D', msglevel
); /* restore old message level */
967 #endif /* WITH_FILAN */
969 /* when converting nl to crnl, size might double */
970 if (xioparms
.bufsiz
> (SIZE_MAX
-1)/2) {
971 Error2("buffer size option (-b) to big - "F_Zu
" (max is "F_Zu
")", xioparms
.bufsiz
, (SIZE_MAX
-1)/2);
972 xioparms
.bufsiz
= (SIZE_MAX
-1)/2;
975 #if HAVE_PROTOTYPE_LIB_posix_memalign
976 /* Operations on files with flag O_DIRECT might need buffer alignment.
977 Without this, eg.read() fails with "Invalid argument" */
980 if ((_errno
= Posix_memalign((void **)&buff
, getpagesize(), 2*xioparms
.bufsiz
+1)) != 0) {
981 Error1("posix_memalign(): %s", strerror(_errno
));
985 #else /* !HAVE_PROTOTYPE_LIB_posix_memalign */
986 buff
= Malloc(2*xioparms
.bufsiz
+1);
987 if (buff
== NULL
) return -1;
988 #endif /* !HAVE_PROTOTYPE_LIB_posix_memalign */
990 if (socat_opts
.logopt
== 'm' && xioinqopt('l', NULL
, 0) == 'm') {
991 Info("switching to syslog");
992 diag_set('y', xioparms
.syslogfac
);
993 xiosetopt('l', "\0");
995 total_timeout
= socat_opts
.total_timeout
;
997 if (transferwaitstring
= getenv("SOCAT_TRANSFER_WAIT")) {
998 Info1("before starting data transfer loop: sleeping %ds (env:SOCAT_TRANSFER_WAIT)", atoi(transferwaitstring
));
999 sleep(atoi(transferwaitstring
));
1001 Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
1002 XIO_GETRDFD(sock1
), XIO_GETWRFD(sock1
),
1003 XIO_GETRDFD(sock2
), XIO_GETWRFD(sock2
));
1004 while (XIO_RDSTREAM(sock1
)->eof
<= 1 ||
1005 XIO_RDSTREAM(sock2
)->eof
<= 1) {
1006 struct timeval timeout
, *to
= NULL
;
1008 Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec
"."F_tv_usec
"}",
1009 XIO_RDSTREAM(sock1
)->eof
, XIO_RDSTREAM(sock2
)->eof
,
1011 total_timeout
.tv_sec
, total_timeout
.tv_usec
);
1016 if (socat_opts
.total_timeout
.tv_usec
<= 1000000) {
1017 if (total_timeout
.tv_usec
< socat_opts
.pollintv
.tv_usec
) {
1018 total_timeout
.tv_usec
+= 1000000;
1019 total_timeout
.tv_sec
-= 1;
1021 total_timeout
.tv_sec
-= socat_opts
.pollintv
.tv_sec
;
1022 total_timeout
.tv_usec
-= socat_opts
.pollintv
.tv_usec
;
1023 if (total_timeout
.tv_sec
< 0 ||
1024 total_timeout
.tv_sec
== 0 && total_timeout
.tv_usec
< 0) {
1025 Notice("inactivity timeout triggered");
1037 /* there is a ignoreeof poll timeout, use it */
1038 timeout
= socat_opts
.pollintv
;
1040 } else if (socat_opts
.total_timeout
.tv_usec
< 1000000) {
1041 /* there might occur a total inactivity timeout */
1042 timeout
= socat_opts
.total_timeout
;
1049 /* first eof already occurred, start end timer */
1050 timeout
= socat_opts
.pollintv
;
1055 /* frame 1: set the poll parameters and loop over poll() EINTR) */
1056 do { /* loop over poll() EINTR */
1059 childleftdata(sock1
);
1060 childleftdata(sock2
);
1063 /* first eof already occurred, start end timer */
1064 timeout
= socat_opts
.closwait
;
1069 /* use the ignoreeof timeout if appropriate */
1072 (socat_opts
.pollintv
.tv_sec
< timeout
.tv_sec
) ||
1073 ((socat_opts
.pollintv
.tv_sec
== timeout
.tv_sec
) &&
1074 socat_opts
.pollintv
.tv_usec
< timeout
.tv_usec
)) {
1075 timeout
= socat_opts
.pollintv
;
1079 /* now the fds will be assigned */
1080 if (XIO_READABLE(sock1
) &&
1081 !(XIO_RDSTREAM(sock1
)->eof
> 1 && !XIO_RDSTREAM(sock1
)->ignoreeof
) &&
1082 !socat_opts
.righttoleft
) {
1083 if (!mayrd1
&& !(XIO_RDSTREAM(sock1
)->eof
> 1)) {
1084 fd1in
->fd
= XIO_GETRDFD(sock1
);
1085 fd1in
->events
= POLLIN
;
1090 fd2out
->fd
= XIO_GETWRFD(sock2
);
1091 fd2out
->events
= POLLOUT
;
1099 if (XIO_READABLE(sock2
) &&
1100 !(XIO_RDSTREAM(sock2
)->eof
> 1 && !XIO_RDSTREAM(sock2
)->ignoreeof
) &&
1101 !socat_opts
.lefttoright
) {
1102 if (!mayrd2
&& !(XIO_RDSTREAM(sock2
)->eof
> 1)) {
1103 fd2in
->fd
= XIO_GETRDFD(sock2
);
1104 fd2in
->events
= POLLIN
;
1109 fd1out
->fd
= XIO_GETWRFD(sock1
);
1110 fd1out
->events
= POLLOUT
;
1118 /* frame 0: innermost part of the transfer loop: check FD status */
1119 retval
= xiopoll(fds
, 4, to
);
1120 if (retval
>= 0 || errno
!= EINTR
) {
1124 Info1("poll(): %s", strerror(errno
));
1129 when an exec'd process sends data and terminates, it is unpredictable
1130 whether the data or the sigchild arrives first.
1134 Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec
"."F_tv_usec
"}): %s",
1135 fds
[0].fd
, fds
[0].events
, fds
[1].fd
, fds
[1].events
,
1136 fds
[2].fd
, fds
[2].events
, fds
[3].fd
, fds
[3].events
,
1137 timeout
.tv_sec
, timeout
.tv_usec
, strerror(errno
));
1140 } else if (retval
== 0) {
1141 Info2("poll timed out (no data within %ld.%06ld seconds)",
1142 closing
>=1?socat_opts
.closwait
.tv_sec
:socat_opts
.total_timeout
.tv_sec
,
1143 closing
>=1?socat_opts
.closwait
.tv_usec
:socat_opts
.total_timeout
.tv_usec
);
1144 if (polling
&& !wasaction
) {
1145 /* there was a ignoreeof poll timeout, use it */
1146 polling
= 0; /*%%%*/
1147 if (XIO_RDSTREAM(sock1
)->ignoreeof
) {
1150 if (XIO_RDSTREAM(sock2
)->ignoreeof
) {
1153 } else if (polling
&& wasaction
) {
1156 } else if (socat_opts
.total_timeout
.tv_usec
< 1000000) {
1157 /* there was a total inactivity timeout */
1158 Notice("inactivity timeout triggered");
1166 /* one possibility to come here is ignoreeof on some fd, but no EOF
1167 and no data on any descriptor - this is no indication for end! */
1171 if (XIO_READABLE(sock1
) && XIO_GETRDFD(sock1
) >= 0 &&
1172 (fd1in
->revents
/*&(POLLIN|POLLHUP|POLLERR)*/)) {
1173 if (fd1in
->revents
& POLLNVAL
) {
1174 /* this is what we find on Mac OS X when poll()'ing on a device or
1175 named pipe. a read() might imm. return with 0 bytes, resulting
1177 Error1("poll(...[%d]: invalid request", fd1in
->fd
);
1183 if (XIO_READABLE(sock2
) && XIO_GETRDFD(sock2
) >= 0 &&
1185 if (fd2in
->revents
& POLLNVAL
) {
1186 Error1("poll(...[%d]: invalid request", fd2in
->fd
);
1192 if (XIO_GETWRFD(sock1
) >= 0 && fd1out
->fd
>= 0 && fd1out
->revents
) {
1193 if (fd1out
->revents
& POLLNVAL
) {
1194 Error1("poll(...[%d]: invalid request", fd1out
->fd
);
1200 if (XIO_GETWRFD(sock2
) >= 0 && fd2out
->fd
>= 0 && fd2out
->revents
) {
1201 if (fd2out
->revents
& POLLNVAL
) {
1202 Error1("poll(...[%d]: invalid request", fd2out
->fd
);
1209 if (mayrd1
&& maywr2
) {
1211 if ((bytes1
= xiotransfer(sock1
, sock2
, buff
, xioparms
.bufsiz
, false))
1213 if (errno
!= EAGAIN
) {
1214 closing
= MAX(closing
, 1);
1215 Notice("socket 1 to socket 2 is in error");
1216 if (socat_opts
.lefttoright
) {
1220 } else if (bytes1
> 0) {
1222 total_timeout
= socat_opts
.total_timeout
;
1224 /* is more data available that has already passed poll()? */
1225 mayrd1
= (xiopending(sock1
) > 0);
1226 if (XIO_RDSTREAM(sock1
)->readbytes
!= 0 &&
1227 XIO_RDSTREAM(sock1
)->actbytes
== 0) {
1228 /* avoid idle when all readbytes already there */
1231 /* escape char occurred? */
1232 if (XIO_RDSTREAM(sock1
)->actescape
) {
1233 bytes1
= 0; /* indicate EOF */
1236 /* (bytes1 == 0) handled later */
1241 if (mayrd2
&& maywr1
) {
1243 if ((bytes2
= xiotransfer(sock2
, sock1
, buff
, xioparms
.bufsiz
, true))
1245 if (errno
!= EAGAIN
) {
1246 closing
= MAX(closing
, 1);
1247 Notice("socket 2 to socket 1 is in error");
1248 if (socat_opts
.righttoleft
) {
1252 } else if (bytes2
> 0) {
1254 total_timeout
= socat_opts
.total_timeout
;
1256 /* is more data available that has already passed poll()? */
1257 mayrd2
= (xiopending(sock2
) > 0);
1258 if (XIO_RDSTREAM(sock2
)->readbytes
!= 0 &&
1259 XIO_RDSTREAM(sock2
)->actbytes
== 0) {
1260 /* avoid idle when all readbytes already there */
1263 /* escape char occurred? */
1264 if (XIO_RDSTREAM(sock2
)->actescape
) {
1265 bytes2
= 0; /* indicate EOF */
1268 /* (bytes2 == 0) handled later */
1273 /* NOW handle EOFs */
1275 /*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
1276 bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
1278 if (bytes1
== 0 || XIO_RDSTREAM(sock1
)->eof
>= 2) {
1279 if (XIO_RDSTREAM(sock1
)->ignoreeof
&&
1280 !XIO_RDSTREAM(sock1
)->actescape
&& !closing
) {
1281 Debug1("socket 1 (fd %d) is at EOF, ignoring",
1282 XIO_RDSTREAM(sock1
)->fd
); /*! */
1284 polling
= 1; /* do not hook this eof fd to poll for pollintv*/
1285 } else if (XIO_RDSTREAM(sock1
)->eof
<= 2) {
1286 Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1
));
1287 xioshutdown(sock2
, SHUT_WR
);
1288 XIO_RDSTREAM(sock1
)->eof
= 3;
1289 XIO_RDSTREAM(sock1
)->ignoreeof
= false;
1291 } else if (polling
&& XIO_RDSTREAM(sock1
)->ignoreeof
) {
1294 if (XIO_RDSTREAM(sock1
)->eof
>= 2) {
1295 if (socat_opts
.lefttoright
) {
1301 if (bytes2
== 0 || XIO_RDSTREAM(sock2
)->eof
>= 2) {
1302 if (XIO_RDSTREAM(sock2
)->ignoreeof
&&
1303 !XIO_RDSTREAM(sock2
)->actescape
&& !closing
) {
1304 Debug1("socket 2 (fd %d) is at EOF, ignoring",
1305 XIO_RDSTREAM(sock2
)->fd
);
1307 polling
= 1; /* do not hook this eof fd to poll for pollintv*/
1308 } else if (XIO_RDSTREAM(sock2
)->eof
<= 2) {
1309 Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2
));
1310 xioshutdown(sock1
, SHUT_WR
);
1311 XIO_RDSTREAM(sock2
)->eof
= 3;
1312 XIO_RDSTREAM(sock2
)->ignoreeof
= false;
1314 } else if (polling
&& XIO_RDSTREAM(sock2
)->ignoreeof
) {
1317 if (XIO_RDSTREAM(sock2
)->eof
>= 2) {
1318 if (socat_opts
.righttoleft
) {
1325 /* close everything that's still open */
1334 #define MAXTIMESTAMPLEN 128
1335 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
1336 should be at least MAXTIMESTAMPLEN bytes long.
1337 returns 0 on success or -1 if an error occurred */
1338 int gettimestamp(char *timestamp
) {
1340 #if HAVE_CLOCK_GETTIME
1341 struct timespec now
;
1342 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1344 #endif /* !HAVE_PROTOTYPE_LIB_gettimeofday */
1348 #if HAVE_CLOCK_GETTIME
1349 result
= clock_gettime(CLOCK_REALTIME
, &now
);
1354 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1355 result
= Gettimeofday(&now
, NULL
);
1362 if (nowt
== (time_t)-1) {
1367 bytes
= strftime(timestamp
, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt
));
1368 #if HAVE_CLOCK_GETTIME
1369 bytes
+= sprintf(timestamp
+19, "."F_tv_nsec
" ", now
.tv_nsec
/1000);
1370 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1371 bytes
+= sprintf(timestamp
+19, "."F_tv_usec
" ", now
.tv_usec
);
1373 strncpy(×tamp
[bytes
++], " ", 2);
1376 strcpy(timestamp
, ctime(&nowt
));
1377 bytes
= strlen(timestamp
);
1382 static const char *prefixltor
= "> ";
1383 static const char *prefixrtol
= "< ";
1384 static unsigned long numltor
;
1385 static unsigned long numrtol
;
1386 /* print block header (during verbose or hex dump)
1387 returns 0 on success or -1 if an error occurred */
1389 xioprintblockheader(FILE *file
, size_t bytes
, bool righttoleft
) {
1390 char timestamp
[MAXTIMESTAMPLEN
];
1391 char buff
[128+MAXTIMESTAMPLEN
];
1392 if (gettimestamp(timestamp
) < 0) {
1396 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1397 prefixrtol
, timestamp
, bytes
, numrtol
, numrtol
+bytes
-1);
1400 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1401 prefixltor
, timestamp
, bytes
, numltor
, numltor
+bytes
-1);
1409 /* inpipe is suspected to have read data available; read at most bufsiz bytes
1410 and transfer them to outpipe. Perform required data conversions.
1411 buff must be a malloc()'ed storage and might be realloc()'ed in this
1412 function if more space is required after conversions.
1413 Returns the number of bytes written, or 0 on EOF or <0 if an
1414 error occurred or when data was read but none written due to conversions
1415 (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
1416 the file has a mandatory lock.
1417 If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
1418 does NOT write a zero bytes block.
1420 /* inpipe, outpipe must be single descriptors (not dual!) */
1421 int xiotransfer(xiofile_t
*inpipe
, xiofile_t
*outpipe
,
1422 unsigned char *buff
, size_t bufsiz
, bool righttoleft
) {
1423 ssize_t bytes
, writt
= 0;
1426 bytes
= xioread(inpipe
, buff
, bufsiz
);
1428 if (errno
!= EAGAIN
)
1429 XIO_RDSTREAM(inpipe
)->eof
= 2;
1430 /*xioshutdown(inpipe, SHUT_RD);*/
1433 if (bytes
== 0 && XIO_RDSTREAM(inpipe
)->ignoreeof
&& !closing
) {
1435 } else if (bytes
== 0) {
1436 XIO_RDSTREAM(inpipe
)->eof
= 2;
1437 closing
= MAX(closing
, 1);
1442 ++XIO_RDSTREAM(inpipe
)->blocks_read
;
1443 XIO_RDSTREAM(inpipe
)->bytes_read
+= bytes
;
1445 /* handle escape char */
1446 if (XIO_RDSTREAM(inpipe
)->escape
!= -1) {
1447 /* check input data for escape char */
1448 unsigned char *ptr
= buff
;
1450 while (ctr
< bytes
) {
1451 if (*ptr
== XIO_RDSTREAM(inpipe
)->escape
) {
1452 /* found: set flag, truncate input data */
1453 XIO_RDSTREAM(inpipe
)->actescape
= true;
1455 Info("escape char found in input");
1461 XIO_RDSTREAM(inpipe
)->eof
= 2;
1468 if (XIO_RDSTREAM(inpipe
)->lineterm
!=
1469 XIO_WRSTREAM(outpipe
)->lineterm
) {
1470 cv_newline(buff
, &bytes
,
1471 XIO_RDSTREAM(inpipe
)->lineterm
,
1472 XIO_WRSTREAM(outpipe
)->lineterm
);
1475 errno
= EAGAIN
; return -1;
1478 if (!righttoleft
&& sniffleft
>= 0) {
1479 if ((sniffed
= Write(sniffleft
, buff
, bytes
)) < bytes
) {
1481 Warn3("-r: write(%d, buff, "F_Zu
"): %s",
1482 sniffleft
, bytes
, strerror(errno
));
1483 else if (sniffed
< bytes
)
1484 Warn3("-r: write(%d, buff, "F_Zu
") -> "F_Zd
,
1485 sniffleft
, bytes
, sniffed
);
1487 } else if (righttoleft
&& sniffright
>= 0) {
1488 if ((sniffed
= Write(sniffright
, buff
, bytes
)) < bytes
) {
1490 Warn3("-R: write(%d, buff, "F_Zu
"): %s",
1491 sniffright
, bytes
, strerror(errno
));
1492 else if (sniffed
< bytes
)
1493 Warn3("-R: write(%d, buff, "F_Zu
") -> "F_Zd
,
1494 sniffright
, bytes
, sniffed
);
1498 if (socat_opts
.verbose
&& socat_opts
.verbhex
) {
1503 const unsigned char *end
, *s
, *t
;
1506 xioprintblockheader(stderr
, bytes
, righttoleft
);
1509 j
= Min(N
, (size_t)(end
-s
));
1516 fprintf(stderr
, " %02x", c
);
1518 if (c
== '\n') break;
1521 /* fill hex column */
1543 fputc('\n', stderr
);
1546 fputs("--\n", stderr
);
1547 } else if (socat_opts
.verbose
) {
1549 xioprintblockheader(stderr
, bytes
, righttoleft
);
1550 while (i
< (size_t)bytes
) {
1552 if (i
> 0 && buff
[i
-1] == '\n')
1555 case '\a' : fputs("\\a", stderr
); break;
1556 case '\b' : fputs("\\b", stderr
); break;
1557 case '\t' : fputs("\t", stderr
); break;
1558 case '\n' : fputs("\n", stderr
); break;
1559 case '\v' : fputs("\\v", stderr
); break;
1560 case '\f' : fputs("\\f", stderr
); break;
1561 case '\r' : fputs("\\r", stderr
); break;
1562 case '\\' : fputs("\\\\", stderr
); break;
1571 } else if (socat_opts
.verbhex
) {
1574 xioprintblockheader(stderr
, bytes
, righttoleft
);
1575 for (i
= 0; i
< bytes
; ++i
) {
1576 fprintf(stderr
, " %02x", buff
[i
]);
1578 fputc('\n', stderr
);
1581 writt
= xiowrite(outpipe
, buff
, bytes
);
1583 /* EAGAIN when nonblocking but a mandatory lock is on file.
1584 the problem with EAGAIN is that the read cannot be repeated,
1585 so we need to buffer the data and try to write it later
1586 again. not yet implemented, sorry. */
1588 if (errno
== EPIPE
) {
1589 return 0; /* can no longer write; handle like EOF */
1594 Info3("transferred "F_Zu
" bytes from %d to %d",
1595 writt
, XIO_GETRDFD(inpipe
), XIO_GETWRFD(outpipe
));
1597 ++XIO_WRSTREAM(outpipe
)->blocks_written
;
1598 XIO_WRSTREAM(outpipe
)->bytes_written
+= writt
;
1609 /* converts the newline characters (or character sequences) from the one
1610 specified in lineterm1 to that of lineterm2. Possible values are
1611 LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
1612 bytes specifies the number of bytes input and output */
1613 int cv_newline(unsigned char *buff
, ssize_t
*bytes
,
1614 int lineterm1
, int lineterm2
) {
1615 /* must perform newline changes */
1616 if (lineterm1
<= LINETERM_CR
&& lineterm2
<= LINETERM_CR
) {
1617 /* no change in data length */
1618 unsigned char from
, to
, *p
, *z
;
1619 if (lineterm1
== LINETERM_RAW
) {
1620 from
= '\n'; to
= '\r';
1622 from
= '\r'; to
= '\n';
1627 if (*p
== from
) *p
= to
;
1631 } else if (lineterm1
== LINETERM_CRNL
) {
1632 /* buffer might become shorter */
1633 unsigned char to
, *s
, *t
, *z
;
1634 if (lineterm2
== LINETERM_RAW
) {
1654 /* buffer becomes longer (up to double length), must alloc another space */
1655 static unsigned char *buf2
; /*! not threadsafe */
1656 unsigned char from
; unsigned char *s
, *t
, *z
;
1658 if (lineterm1
== LINETERM_RAW
) {
1664 if ((buf2
= Malloc(xioparms
.bufsiz
)) == NULL
) {
1668 memcpy(buf2
, buff
, *bytes
);
1669 s
= buf2
; t
= buff
; z
= buf2
+ *bytes
;
1672 *t
++ = '\r'; *t
++ = '\n';
1684 void socat_signal(int signum
) {
1687 diag_in_handler
= 1;
1688 Notice1("socat_signal(): handling signal %d", signum
);
1691 diag_immediate_exit
= 1;
1694 diag_set_int('x', 128+signum
); /* in case Error exits for us */
1695 Error1("exiting on signal %d", signum
);
1696 diag_set_int('x', 0); /* in case Error did not exit */
1699 Warn1("exiting on signal %d", signum
); break;
1702 Notice1("exiting on signal %d", signum
); break;
1704 Notice1("socat_signal(): finishing signal %d", signum
);
1705 diag_exit(128+signum
); /* internal cleanup + _exit() */
1706 diag_in_handler
= 0;
1710 /* this is the callback when the child of an address died */
1711 static int socat_sigchild(struct single
*file
) {
1712 if (file
->ignoreeof
&& !closing
) {
1715 file
->eof
= MAX(file
->eof
, 1);
1721 static int socat_lock(void) {
1725 if ((lockrc
= xiolock(&socat_opts
.lock
)) < 0) {
1733 if (socat_opts
.lock
.lockfile
) {
1734 if ((lockrc
= xiolock(socat_opts
.lock
.lockfile
)) < 0) {
1735 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1742 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/
1745 if (socat_opts
.lock
.waitlock
) {
1746 if (xiowaitlock(socat_opts
.lock
.waitlock
, socat_opts
.lock
.intervall
)) {
1747 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1751 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1758 static void socat_unlock(void) {
1759 if (!havelock
) return;
1760 if (socat_opts
.lock
.lockfile
) {
1761 if (Unlink(socat_opts
.lock
.lockfile
) < 0) {
1762 if (!diag_in_handler
) {
1763 Warn2("unlink(\"%s\"): %s",
1764 socat_opts
.lock
.lockfile
, strerror(errno
));
1766 Warn1("unlink(\"%s\"): "F_strerror
,
1767 socat_opts
.lock
.lockfile
);
1770 Info1("released lock \"%s\"", socat_opts
.lock
.lockfile
);
1775 /* this is a callback function that may be called by the newchild hook of xio
1777 static int socat_newchild(void) {
1784 void socat_signal_logstats(int signum
) {
1785 diag_in_handler
= 1;
1786 Notice1("socat_signal_logstats(): handling signal %d", signum
);
1787 socat_print_stats();
1788 Notice1("socat_signal_logstats(): finishing signal %d", signum
);
1789 diag_in_handler
= 0;
1791 #endif /* WITH_STATS */
1794 static void socat_print_stats(void)
1796 const char ltorf0
[] = "STATISTICS: left to right: %%%ullu packets(s), %%%ullu byte(s)";
1797 const char rtolf0
[] = "STATISTICS: right to left: %%%ullu packets(s), %%%ullu byte(s)";
1798 char ltorf1
[sizeof(ltorf0
)]; /* final printf format with lengths of number */
1799 char rtolf1
[sizeof(rtolf0
)]; /* final printf format with lengths of number */
1800 unsigned int blocksd
= 1, bytesd
= 1; /* number of digits in output */
1801 struct single
*sock1w
, *sock2w
;
1804 if (sock1
== NULL
|| sock2
== NULL
) {
1805 Warn("transfer engine not yet started, statistics not available");
1808 if ((sock1
->tag
& ~XIO_TAG_CLOSED
) == XIO_TAG_DUAL
) {
1809 sock1w
= sock1
->dual
.stream
[1];
1811 sock1w
= &sock1
->stream
;
1813 if ((sock2
->tag
& ~XIO_TAG_CLOSED
) == XIO_TAG_DUAL
) {
1814 sock2w
= sock2
->dual
.stream
[1];
1816 sock2w
= &sock2
->stream
;
1818 if (!socat_opts
.righttoleft
&& !socat_opts
.righttoleft
) {
1819 /* Both directions - format output */
1820 unsigned long long int maxblocks
=
1821 Max(sock1w
->blocks_written
, sock2w
->blocks_written
);
1822 unsigned long long int maxbytes
=
1823 Max(sock1w
->bytes_written
, sock2w
->bytes_written
);
1824 /* Calculate number of digits */
1825 while (maxblocks
>= 10) { ++blocksd
; maxblocks
/= 10; }
1826 while (maxbytes
>= 10) { ++bytesd
; maxbytes
/= 10; }
1828 snprintf(ltorf1
, sizeof(ltorf1
), ltorf0
, blocksd
, bytesd
);
1829 snprintf(rtolf1
, sizeof(rtolf1
), rtolf0
, blocksd
, bytesd
);
1830 /* Statistics are E_INFO level; make sure they are printed anyway */
1831 savelevel
= diag_get_int('d');
1832 diag_set_int('d', E_INFO
);
1833 Warn("statistics are experimental");
1834 if (!socat_opts
.righttoleft
) {
1835 Info2(ltorf1
, sock2w
->blocks_written
, sock2w
->bytes_written
);
1837 if (!socat_opts
.lefttoright
) {
1838 Info2(rtolf1
, sock1w
->blocks_written
, sock1w
->bytes_written
);
1840 diag_set_int('d', savelevel
);
1843 #endif /* WITH_STATs */