Version 1.8.0.0
[socat.git] / socat.c
blobe98ecc25fca35b132abae967c9369d0cd1588b53
1 /* source: socat.c */
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 */
8 #include "config.h"
9 #include "xioconfig.h" /* what features are enabled */
11 #include "sysincludes.h"
13 #include "mytypes.h"
14 #include "compat.h"
15 #include "error.h"
17 #include "sycls.h"
18 #include "sysutils.h"
19 #include "dalan.h"
20 #include "filan.h"
21 #include "xio.h"
22 #include "xioopts.h"
23 #include "xiolockfile.h"
25 #include "xio-pipe.h"
28 /* command line options */
29 struct socat_opts {
30 bool verbose;
31 bool verbhex;
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 */
35 bool debug;
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 */
43 } socat_opts = {
44 false, /* verbose */
45 false, /* verbhex */
46 {1,0}, /* pollintv */
47 {0,500000}, /* closwait */
48 {0,0}, /* total_timeout */
49 0, /* debug */
50 0, /* strictopts */
51 's', /* logopt */
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);
63 int _socat(void);
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[] =
78 #include "./VERSION"
80 static const char timestamp[] = BUILD_DATE;
82 const char copyright_socat[] = "socat by Gerhard Rieger and contributors - see www.dest-unreach.org";
83 #if WITH_OPENSSL
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)";
86 #endif
88 bool havelock;
90 int main(int argc, const char *argv[]) {
91 const char **arg1, *a;
92 char *mainwaitstring;
93 char buff[10];
94 double rto;
95 int i, argc0, result;
96 bool isdash = false;
97 int msglevel = 0;
98 struct utsname ubuf;
99 int lockrc;
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) {
109 Exit(1);
112 xiosetopt('p', "!!");
113 xiosetopt('o', ":");
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);
121 #if WITH_HELP
122 case '?':
123 case 'h':
124 socat_usage(stdout);
125 xioopenhelp(stdout, (arg1[0][2]=='?'||arg1[0][2]=='h') ? (arg1[0][3]=='?'||arg1[0][3]=='h') ? 2 : 1 : 0);
126 Exit(0);
127 #endif /* WITH_HELP */
128 case 'd':
129 a = *arg1+2;
130 switch (*a) {
131 case 'd':
132 break;
133 case '-': case '0': case '1': case '2': case '3': case '4':
135 char *endptr;
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);
142 break;
143 case '\0':
144 ++msglevel;
145 diag_set_int('d', 4-msglevel);
146 break;
147 default: socat_usage(stderr);
149 if (*a != 'd') break;
150 ++msglevel;
151 while (*a) {
152 if (*a == 'd') {
153 ++msglevel;
154 diag_set_int('d', 4-msglevel);
155 } else {
156 socat_usage(stderr);
157 Exit(1);
159 ++a;
161 break;
162 #if WITH_FILAN
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;
165 #endif
166 case 'l':
167 switch (arg1[0][2]) {
168 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
169 diag_set('s', NULL);
170 xiosetopt('l', "m");
171 socat_opts.logopt = arg1[0][2];
172 xiosetopt('y', &arg1[0][3]);
173 break;
174 case 'y': /* syslog + facility */
175 diag_set(arg1[0][2], &arg1[0][3]);
176 break;
177 case 'f': /* to file, +filename */
178 case 'p': /* artificial program name */
179 if (arg1[0][3]) {
180 diag_set(arg1[0][2], &arg1[0][3]);
181 } else if (arg1[1]) {
182 diag_set(arg1[0][2], arg1[1]);
183 ++arg1, --argc;
184 } else {
185 Error1("option -l%c requires an argument; use option \"-h\" for help", arg1[0][2]);
187 break;
188 case 's': /* stderr */
189 diag_set(arg1[0][2], NULL);
190 break;
191 case 'u':
192 diag_set('u', NULL);
193 break;
194 case 'h':
195 diag_set_int('h', true);
196 break;
197 default:
198 Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1[0]);
199 break;
201 break;
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]) {
207 a = *arg1+2;
208 } else {
209 ++arg1, --argc;
210 if ((a = *arg1) == NULL) {
211 Error("option -r requires an argument; use option \"-h\" for help");
212 break;
215 xiosetopt('r', a);
216 break;
217 case 'R': if (arg1[0][2]) {
218 a = *arg1+2;
219 } else {
220 ++arg1, --argc;
221 if ((a = *arg1) == NULL) {
222 Error("option -R requires an argument; use option \"-h\" for help");
223 break;
226 xiosetopt('R', a);
227 break;
228 case 'b': if (arg1[0][2]) {
229 a = *arg1+2;
230 } else {
231 ++arg1, --argc;
232 if ((a = *arg1) == NULL) {
233 Error("option -b requires an argument; use option \"-h\" for help");
234 Exit(1);
237 xioparms.bufsiz = Strtoul(a, (char **)&a, 0, "-b");
238 break;
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 */
242 if (arg1[0][2]) {
243 a = *arg1+2;
244 } else {
245 ++arg1, --argc;
246 if ((a = *arg1) == NULL) {
247 Error("option -S requires an argument; use option \"-h\" for help");
248 Exit(1);
251 socat_opts.log_sigs = Strtoul(a, (char **)&a, 0, "-S");
252 break;
253 case 't': if (arg1[0][2]) {
254 a = *arg1+2;
255 } else {
256 ++arg1, --argc;
257 if ((a = *arg1) == NULL) {
258 Error("option -t requires an argument; use option \"-h\" for help");
259 Exit(1);
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;
266 break;
267 case 'T': if (arg1[0][2]) {
268 a = *arg1+2;
269 } else {
270 ++arg1, --argc;
271 if ((a = *arg1) == NULL) {
272 Error("option -T requires an argument; use option \"-h\" for help");
273 Exit(1);
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;
280 break;
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");
289 if (arg1[0][2]) {
290 socat_opts.lock.lockfile = *arg1+2;
291 } else {
292 ++arg1, --argc;
293 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
294 Error("option -L requires an argument; use option \"-h\" for help");
295 Exit(1);
298 break;
299 case 'W': if (socat_opts.lock.lockfile) {
300 Error("only one -L and -W option allowed");
302 if (arg1[0][2]) {
303 socat_opts.lock.lockfile = *arg1+2;
304 } else {
305 ++arg1, --argc;
306 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
307 Error("option -W requires an argument; use option \"-h\" for help");
308 Exit(1);
311 socat_opts.lock.waitlock = true;
312 socat_opts.lock.intervall.tv_sec = 1;
313 socat_opts.lock.intervall.tv_nsec = 0;
314 break;
315 #if WITH_IP4 || WITH_IP6
316 #if WITH_IP4
317 case '4':
318 #endif
319 #if WITH_IP6
320 case '6':
321 #endif
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];
325 break;
326 #endif /* WITH_IP4 || WITH_IP6 */
327 case '-':
328 if (!strcmp("experimental", &arg1[0][2])) {
329 xioparms.experimental = true;
330 } else if (!strcmp("statistics", &arg1[0][2])) {
331 socat_opts.statistics = true;
332 } else {
333 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
335 break;
336 case '\0':
337 case ',':
338 case ':':
339 isdash = true;
340 break; /* this "-" is a variation of STDIO */
341 default:
342 xioinqopt('p', buff, sizeof(buff)); /* fetch pipe separator char */
343 if (arg1[0][1] == buff[0]) {
344 isdash = true;
345 break;
347 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
348 Exit(1);
350 if (isdash) {
351 /* the leading "-" is a form of the first address */
352 break;
354 ++arg1; --argc;
356 if (argc != 2) {
357 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
358 Exit(1);
360 if (socat_opts.lefttoright && socat_opts.righttoleft) {
361 Error("-U and -u must not be combined");
364 xioinitialize2();
365 Info(copyright_socat);
366 #if WITH_OPENSSL
367 Info(copyright_openssl);
368 Info(copyright_ssleay);
369 #endif
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 */
383 #if HAVE_SIGACTION
384 struct sigaction act;
385 #endif
386 int i, m;
388 sigfillset(&act.sa_mask); /* while in sighandler block all signals */
389 act.sa_flags = 0;
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) {
394 #if HAVE_SIGACTION
395 Sigaction(i, &act, NULL);
396 #else
397 Signal(i, socat_signal);
398 #endif
402 #if WITH_STATS
403 #if HAVE_SIGACTION
404 act.sa_handler = socat_signal_logstats;
405 Sigaction(SIGUSR1, &act, NULL);
406 #else
407 Signal(SIGUSR1, socat_signal_logstats);
408 #endif
409 #endif /* WITH_STATS */
411 Signal(SIGPIPE, SIG_IGN);
413 /* set xio hooks */
414 xiohook_newchild = &socat_newchild;
416 if (lockrc = socat_lock()) {
417 /* =0: goon; >0: locked; <0: error, printed in sub */
418 if (lockrc > 0)
419 Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile);
420 Exit(1);
423 Atexit(socat_unlock);
424 #if WITH_STATS
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);
435 Exit(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);
446 #if WITH_HELP
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);
453 #if WITH_FILAN
454 fputs(" -D analyze file descriptors before loop\n", fd);
455 #endif
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);
479 #if WITH_IP4
480 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd);
481 #endif
482 #if WITH_IP6
483 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd);
484 #endif
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",
489 a, b, a, b);
493 void socat_version(FILE *fd) {
494 struct utsname ubuf;
496 fputs(copyright_socat, fd); fputc('\n', fd);
497 fprintf(fd, "socat version %s on %s\n", socatversion, timestamp);
498 Uname(&ubuf);
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);
502 #ifdef WITH_HELP
503 fprintf(fd, " #define WITH_HELP %d\n", WITH_HELP);
504 #else
505 fputs(" #undef WITH_HELP\n", fd);
506 #endif
507 #ifdef WITH_STATS
508 fprintf(fd, " #define WITH_STATS %d\n", WITH_STATS);
509 #else
510 fputs(" #undef WITH_STATS\n", fd);
511 #endif
512 #ifdef WITH_STDIO
513 fprintf(fd, " #define WITH_STDIO %d\n", WITH_STDIO);
514 #else
515 fputs(" #undef WITH_STDIO\n", fd);
516 #endif
517 #ifdef WITH_FDNUM
518 fprintf(fd, " #define WITH_FDNUM %d\n", WITH_FDNUM);
519 #else
520 fputs(" #undef WITH_FDNUM\n", fd);
521 #endif
522 #ifdef WITH_FILE
523 fprintf(fd, " #define WITH_FILE %d\n", WITH_FILE);
524 #else
525 fputs(" #undef WITH_FILE\n", fd);
526 #endif
527 #ifdef WITH_CREAT
528 fprintf(fd, " #define WITH_CREAT %d\n", WITH_CREAT);
529 #else
530 fputs(" #undef WITH_CREAT\n", fd);
531 #endif
532 #ifdef WITH_GOPEN
533 fprintf(fd, " #define WITH_GOPEN %d\n", WITH_GOPEN);
534 #else
535 fputs(" #undef WITH_GOPEN\n", fd);
536 #endif
537 #ifdef WITH_TERMIOS
538 fprintf(fd, " #define WITH_TERMIOS %d\n", WITH_TERMIOS);
539 #else
540 fputs(" #undef WITH_TERMIOS\n", fd);
541 #endif
542 #ifdef WITH_PIPE
543 fprintf(fd, " #define WITH_PIPE %d\n", WITH_PIPE);
544 #else
545 fputs(" #undef WITH_PIPE\n", fd);
546 #endif
547 #ifdef WITH_SOCKETPAIR
548 fprintf(fd, " #define WITH_SOCKETPAIR %d\n", WITH_SOCKETPAIR);
549 #else
550 fputs(" #undef WITH_SOCKETPAIR\n", fd);
551 #endif
552 #ifdef WITH_UNIX
553 fprintf(fd, " #define WITH_UNIX %d\n", WITH_UNIX);
554 #else
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);
559 #else
560 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd);
561 #endif /* WITH_ABSTRACT_UNIXSOCKET */
562 #ifdef WITH_IP4
563 fprintf(fd, " #define WITH_IP4 %d\n", WITH_IP4);
564 #else
565 fputs(" #undef WITH_IP4\n", fd);
566 #endif
567 #ifdef WITH_IP6
568 fprintf(fd, " #define WITH_IP6 %d\n", WITH_IP6);
569 #else
570 fputs(" #undef WITH_IP6\n", fd);
571 #endif
572 #ifdef WITH_RAWIP
573 fprintf(fd, " #define WITH_RAWIP %d\n", WITH_RAWIP);
574 #else
575 fputs(" #undef WITH_RAWIP\n", fd);
576 #endif
577 #ifdef WITH_GENERICSOCKET
578 fprintf(fd, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET);
579 #else
580 fputs(" #undef WITH_GENERICSOCKET\n", fd);
581 #endif
582 #ifdef WITH_INTERFACE
583 fprintf(fd, " #define WITH_INTERFACE %d\n", WITH_INTERFACE);
584 #else
585 fputs(" #undef WITH_INTERFACE\n", fd);
586 #endif
587 #ifdef WITH_TCP
588 fprintf(fd, " #define WITH_TCP %d\n", WITH_TCP);
589 #else
590 fputs(" #undef WITH_TCP\n", fd);
591 #endif
592 #ifdef WITH_UDP
593 fprintf(fd, " #define WITH_UDP %d\n", WITH_UDP);
594 #else
595 fputs(" #undef WITH_UDP\n", fd);
596 #endif
597 #ifdef WITH_SCTP
598 fprintf(fd, " #define WITH_SCTP %d\n", WITH_SCTP);
599 #else
600 fputs(" #undef WITH_SCTP\n", fd);
601 #endif
602 #ifdef WITH_DCCP
603 fprintf(fd, " #define WITH_DCCP %d\n", WITH_DCCP);
604 #else
605 fputs(" #undef WITH_DCCP\n", fd);
606 #endif
607 #ifdef WITH_UDPLITE
608 fprintf(fd, " #define WITH_UDPLITE %d\n", WITH_UDPLITE);
609 #else
610 fputs(" #undef WITH_UDPLITE\n", fd);
611 #endif
612 #ifdef WITH_LISTEN
613 fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN);
614 #else
615 fputs(" #undef WITH_LISTEN\n", fd);
616 #endif
617 #ifdef WITH_POSIXMQ
618 fprintf(fd, " #define WITH_POSIXMQ %d\n", WITH_POSIXMQ);
619 #else
620 fputs(" #undef WITH_POSIXMQ\n", fd);
621 #endif
622 #ifdef WITH_SOCKS4
623 fprintf(fd, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4);
624 #else
625 fputs(" #undef WITH_SOCKS4\n", fd);
626 #endif
627 #ifdef WITH_SOCKS4A
628 fprintf(fd, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A);
629 #else
630 fputs(" #undef WITH_SOCKS4A\n", fd);
631 #endif
632 #ifdef WITH_SOCKS5
633 fprintf(fd, " #define WITH_SOCKS5 %d\n", WITH_SOCKS5);
634 #else
635 fputs(" #undef WITH_SOCKS5\n", fd);
636 #endif
637 #ifdef WITH_VSOCK
638 fprintf(fd, " #define WITH_VSOCK %d\n", WITH_VSOCK);
639 #else
640 fputs(" #undef WITH_VSOCK\n", fd);
641 #endif
642 #ifdef WITH_NAMESPACES
643 fprintf(fd, " #define WITH_NAMESPACES %d\n", WITH_NAMESPACES);
644 #else
645 fputs(" #undef WITH_NAMESPACES\n", fd);
646 #endif
647 #ifdef WITH_PROXY
648 fprintf(fd, " #define WITH_PROXY %d\n", WITH_PROXY);
649 #else
650 fputs(" #undef WITH_PROXY\n", fd);
651 #endif
652 #ifdef WITH_SYSTEM
653 fprintf(fd, " #define WITH_SYSTEM %d\n", WITH_SYSTEM);
654 #else
655 fputs(" #undef WITH_SYSTEM\n", fd);
656 #endif
657 #ifdef WITH_SHELL
658 fprintf(fd, " #define WITH_SHELL %d\n", WITH_SHELL);
659 #else
660 fputs(" #undef WITH_SHELL\n", fd);
661 #endif
662 #ifdef WITH_EXEC
663 fprintf(fd, " #define WITH_EXEC %d\n", WITH_EXEC);
664 #else
665 fputs(" #undef WITH_EXEC\n", fd);
666 #endif
667 #ifdef WITH_READLINE
668 fprintf(fd, " #define WITH_READLINE %d\n", WITH_READLINE);
669 #else
670 fputs(" #undef WITH_READLINE\n", fd);
671 #endif
672 #ifdef WITH_TUN
673 fprintf(fd, " #define WITH_TUN %d\n", WITH_TUN);
674 #else
675 fputs(" #undef WITH_TUN\n", fd);
676 #endif
677 #ifdef WITH_PTY
678 fprintf(fd, " #define WITH_PTY %d\n", WITH_PTY);
679 #else
680 fputs(" #undef WITH_PTY\n", fd);
681 #endif
682 #ifdef WITH_OPENSSL
683 fprintf(fd, " #define WITH_OPENSSL %d\n", WITH_OPENSSL);
684 #else
685 fputs(" #undef WITH_OPENSSL\n", fd);
686 #endif
687 #ifdef WITH_FIPS
688 fprintf(fd, " #define WITH_FIPS %d\n", WITH_FIPS);
689 #else
690 fputs(" #undef WITH_FIPS\n", fd);
691 #endif
692 #ifdef WITH_LIBWRAP
693 fprintf(fd, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP);
694 #else
695 fputs(" #undef WITH_LIBWRAP\n", fd);
696 #endif
697 #ifdef WITH_SYCLS
698 fprintf(fd, " #define WITH_SYCLS %d\n", WITH_SYCLS);
699 #else
700 fputs(" #undef WITH_SYCLS\n", fd);
701 #endif
702 #ifdef WITH_FILAN
703 fprintf(fd, " #define WITH_FILAN %d\n", WITH_FILAN);
704 #else
705 fputs(" #undef WITH_FILAN\n", fd);
706 #endif
707 #ifdef WITH_RETRY
708 fprintf(fd, " #define WITH_RETRY %d\n", WITH_RETRY);
709 #else
710 fputs(" #undef WITH_RETRY\n", fd);
711 #endif
712 #ifdef WITH_MSGLEVEL
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]);
715 #else
716 fputs(" #undef WITH_MSGLEVEL\n", fd);
717 #endif
718 #ifdef WITH_DEFAULT_IPV
719 # if WITH_DEFAULT_IPV
720 fprintf(fd, " #define WITH_DEFAULT_IPV %c\n", WITH_DEFAULT_IPV);
721 # else
722 fprintf(fd, " #define WITH_DEFAULT_IPV '\\0'\n");
723 # endif
724 #else
725 fputs(" #undef WITH_DEFAULT_IPV\n", fd);
726 #endif
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) {
739 int mayexec;
741 if (socat_opts.lefttoright) {
742 if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
743 return -1;
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) {
748 return -1;
750 xiosetsigchild(sock1, socat_sigchild);
751 } else {
752 if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
753 return -1;
755 xiosetsigchild(sock1, socat_sigchild);
757 #if 1 /*! */
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)) {
762 int i;
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) {
771 return 1;
773 diedunknown[i] = 0;
774 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
775 /* return STAT_RETRYLATER; */
779 #endif
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) {
785 return -1;
787 xiosetsigchild(sock2, socat_sigchild);
788 } else {
789 if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
790 return -1;
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) {
796 return -1;
798 xiosetsigchild(sock2, socat_sigchild);
800 #if 1 /*! */
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)) {
805 int i;
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) {
813 return 1;
815 diedunknown[i] = 0;
816 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
817 /* return STAT_RETRYLATER; */
821 #endif
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) {
834 struct pollfd in;
835 int retval;
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*/;
848 in.revents = 0;
850 do {
851 int _errno;
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);
856 if (retval < 0) {
857 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
858 in.fd, in.events, timeout.tv_sec, timeout.tv_usec,
859 strerror(errno));
860 return -1;
862 if (retval == 0) {
863 Info("terminated child did not leave data for us");
864 XIO_RDSTREAM(xfd)->eof = 2;
865 xfd->stream.eof = 2;
866 closing = MAX(closing, 1);
869 return 0;
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 */
883 int _socat(void) {
884 char *transferwaitstring;
885 struct pollfd fds[4],
886 *fd1in = &fds[0],
887 *fd1out = &fds[1],
888 *fd2in = &fds[2],
889 *fd2out = &fds[3];
890 int retval;
891 unsigned char *buff;
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) */
899 char name[PATH_MAX];
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);
905 if (sniffleft < 0) {
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));
919 #if WITH_FILAN
920 if (socat_opts.debug) {
921 int fdi, fdo;
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);
932 if (fdo != fdi) {
933 filan_fd(fdo, stderr);
936 fdi = XIO_GETRDFD(sock2);
937 fdo = XIO_GETWRFD(sock2);
938 filan_fd(fdi, stderr);
939 if (fdo != fdi) {
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" */
958 int _errno;
959 if ((_errno = Posix_memalign((void **)&buff, getpagesize(), 2*xioparms.bufsiz+1)) != 0) {
960 Error1("posix_memalign(): %s", strerror(_errno));
961 return -1;
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,
989 closing, wasaction,
990 total_timeout.tv_sec, total_timeout.tv_usec);
992 /* for ignoreeof */
993 if (polling) {
994 if (!wasaction) {
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");
1006 free(buff);
1007 return 0;
1011 } else {
1012 wasaction = 0;
1016 if (polling) {
1017 /* there is a ignoreeof poll timeout, use it */
1018 timeout = socat_opts.pollintv;
1019 to = &timeout;
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;
1024 to = &timeout;
1025 } else {
1026 to = NULL;
1029 if (closing>=1) {
1030 /* first eof already occurred, start end timer */
1031 timeout = socat_opts.pollintv;
1032 to = &timeout;
1033 closing = 2;
1036 /* frame 1: set the poll parameters and loop over poll() EINTR) */
1037 do { /* loop over poll() EINTR */
1038 int _errno;
1040 childleftdata(sock1);
1041 childleftdata(sock2);
1043 if (closing>=1) {
1044 /* first eof already occurred, start end timer */
1045 timeout = socat_opts.closwait;
1046 to = &timeout;
1047 closing = 2;
1050 /* use the ignoreeof timeout if appropriate */
1051 if (polling) {
1052 if (closing == 0 ||
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;
1067 } else {
1068 fd1in->fd = -1;
1070 if (!maywr2) {
1071 fd2out->fd = XIO_GETWRFD(sock2);
1072 fd2out->events = POLLOUT;
1073 } else {
1074 fd2out->fd = -1;
1076 } else {
1077 fd1in->fd = -1;
1078 fd2out->fd = -1;
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;
1086 } else {
1087 fd2in->fd = -1;
1089 if (!maywr1) {
1090 fd1out->fd = XIO_GETWRFD(sock1);
1091 fd1out->events = POLLOUT;
1092 } else {
1093 fd1out->fd = -1;
1095 } else {
1096 fd1out->fd = -1;
1097 fd2in->fd = -1;
1099 /* frame 0: innermost part of the transfer loop: check FD status */
1100 retval = xiopoll(fds, 4, to);
1101 if (retval >= 0 || errno != EINTR) {
1102 break;
1104 _errno = errno;
1105 Info1("poll(): %s", strerror(errno));
1106 errno = _errno;
1107 } while (true);
1109 /* attention:
1110 when an exec'd process sends data and terminates, it is unpredictable
1111 whether the data or the sigchild arrives first.
1114 if (retval < 0) {
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));
1119 free(buff);
1120 return -1;
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) {
1129 mayrd1 = 0;
1131 if (XIO_RDSTREAM(sock2)->ignoreeof) {
1132 mayrd2 = 0;
1134 } else if (polling && wasaction) {
1135 wasaction = 0;
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");
1141 free(buff);
1142 return 0;
1145 if (closing) {
1146 break;
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! */
1150 continue;
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
1158 in a loop? */
1159 Error1("poll(...[%d]: invalid request", fd1in->fd);
1160 free(buff);
1161 return -1;
1163 mayrd1 = true;
1165 if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
1166 (fd2in->revents)) {
1167 if (fd2in->revents & POLLNVAL) {
1168 Error1("poll(...[%d]: invalid request", fd2in->fd);
1169 free(buff);
1170 return -1;
1172 mayrd2 = true;
1174 if (XIO_GETWRFD(sock1) >= 0 && fd1out->fd >= 0 && fd1out->revents) {
1175 if (fd1out->revents & POLLNVAL) {
1176 Error1("poll(...[%d]: invalid request", fd1out->fd);
1177 free(buff);
1178 return -1;
1180 maywr1 = true;
1182 if (XIO_GETWRFD(sock2) >= 0 && fd2out->fd >= 0 && fd2out->revents) {
1183 if (fd2out->revents & POLLNVAL) {
1184 Error1("poll(...[%d]: invalid request", fd2out->fd);
1185 free(buff);
1186 return -1;
1188 maywr2 = true;
1191 if (mayrd1 && maywr2) {
1192 mayrd1 = false;
1193 if ((bytes1 = xiotransfer(sock1, sock2, buff, xioparms.bufsiz, false))
1194 < 0) {
1195 if (errno != EAGAIN) {
1196 closing = MAX(closing, 1);
1197 Notice("socket 1 to socket 2 is in error");
1198 if (socat_opts.lefttoright) {
1199 break;
1202 } else if (bytes1 > 0) {
1203 maywr2 = false;
1204 total_timeout = socat_opts.total_timeout;
1205 wasaction = 1;
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 */
1211 mayrd1 = true;
1213 /* escape char occurred? */
1214 if (XIO_RDSTREAM(sock1)->actescape) {
1215 bytes1 = 0; /* indicate EOF */
1218 /* (bytes1 == 0) handled later */
1219 } else {
1220 bytes1 = -1;
1223 if (mayrd2 && maywr1) {
1224 mayrd2 = false;
1225 if ((bytes2 = xiotransfer(sock2, sock1, buff, xioparms.bufsiz, true))
1226 < 0) {
1227 if (errno != EAGAIN) {
1228 closing = MAX(closing, 1);
1229 Notice("socket 2 to socket 1 is in error");
1230 if (socat_opts.righttoleft) {
1231 break;
1234 } else if (bytes2 > 0) {
1235 maywr1 = false;
1236 total_timeout = socat_opts.total_timeout;
1237 wasaction = 1;
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 */
1243 mayrd2 = true;
1245 /* escape char occurred? */
1246 if (XIO_RDSTREAM(sock2)->actescape) {
1247 bytes2 = 0; /* indicate EOF */
1250 /* (bytes2 == 0) handled later */
1251 } else {
1252 bytes2 = -1;
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,
1259 closing);*/
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); /*! */
1265 mayrd1 = true;
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) {
1274 polling = 0;
1276 if (XIO_RDSTREAM(sock1)->eof >= 2) {
1277 if (socat_opts.lefttoright) {
1278 break;
1280 closing = 1;
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);
1288 mayrd2 = true;
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) {
1297 polling = 0;
1299 if (XIO_RDSTREAM(sock2)->eof >= 2) {
1300 if (socat_opts.righttoleft) {
1301 break;
1303 closing = 1;
1307 /* close everything that's still open */
1308 xioclose(sock1);
1309 xioclose(sock2);
1311 free(buff);
1312 return 0;
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) {
1321 size_t bytes;
1322 #if HAVE_CLOCK_GETTIME
1323 struct timespec now;
1324 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1325 struct timeval now;
1326 #endif /* !HAVE_PROTOTYPE_LIB_gettimeofday */
1327 time_t nowt;
1328 int result;
1330 #if HAVE_CLOCK_GETTIME
1331 result = clock_gettime(CLOCK_REALTIME, &now);
1332 if (result < 0) {
1333 return result;
1335 nowt = now.tv_sec;
1336 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1337 result = Gettimeofday(&now, NULL);
1338 if (result < 0) {
1339 return result;
1341 nowt = now.tv_sec;
1342 #else
1343 nowt = time(NULL);
1344 if (nowt == (time_t)-1) {
1345 return -1;
1347 #endif
1348 #if HAVE_STRFTIME
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);
1354 #else
1355 strncpy(&timestamp[bytes++], " ", 2);
1356 #endif
1357 #else
1358 strcpy(timestamp, ctime(&nowt));
1359 bytes = strlen(timestamp);
1360 #endif
1361 return 0;
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 */
1370 static int
1371 xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
1372 char timestamp[MAXTIMESTAMPLEN];
1373 char buff[128+MAXTIMESTAMPLEN];
1374 if (gettimestamp(timestamp) < 0) {
1375 return -1;
1377 if (righttoleft) {
1378 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1379 prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
1380 numrtol+=bytes;
1381 } else {
1382 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1383 prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
1384 numltor+=bytes;
1386 fputs(buff, file);
1387 return 0;
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;
1406 ssize_t sniffed;
1408 bytes = xioread(inpipe, buff, bufsiz);
1409 if (bytes < 0) {
1410 if (errno != EAGAIN)
1411 XIO_RDSTREAM(inpipe)->eof = 2;
1412 /*xioshutdown(inpipe, SHUT_RD);*/
1413 return -1;
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);
1422 if (bytes > 0) {
1423 #if WITH_STATS
1424 ++XIO_RDSTREAM(inpipe)->blocks_read;
1425 XIO_RDSTREAM(inpipe)->bytes_read += bytes;
1426 #endif
1427 /* handle escape char */
1428 if (XIO_RDSTREAM(inpipe)->escape != -1) {
1429 /* check input data for escape char */
1430 unsigned char *ptr = buff;
1431 size_t ctr = 0;
1432 while (ctr < bytes) {
1433 if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
1434 /* found: set flag, truncate input data */
1435 XIO_RDSTREAM(inpipe)->actescape = true;
1436 bytes = ctr;
1437 Info("escape char found in input");
1438 break;
1440 ++ptr; ++ctr;
1442 if (ctr != bytes) {
1443 XIO_RDSTREAM(inpipe)->eof = 2;
1448 if (bytes > 0) {
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);
1456 if (bytes == 0) {
1457 errno = EAGAIN; return -1;
1460 if (!righttoleft && sniffleft >= 0) {
1461 if ((sniffed = Write(sniffleft, buff, bytes)) < bytes) {
1462 if (sniffed < 0)
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) {
1471 if (sniffed < 0)
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) {
1481 /* Hack-o-rama */
1482 size_t i = 0;
1483 size_t j;
1484 size_t N = 16;
1485 const unsigned char *end, *s, *t;
1486 s = buff;
1487 end = buff+bytes;
1488 xioprintblockheader(stderr, bytes, righttoleft);
1489 while (s < end) {
1490 /*! prefix? */
1491 j = Min(N, (size_t)(end-s));
1493 /* print hex */
1494 t = s;
1495 i = 0;
1496 while (i < j) {
1497 int c = *t++;
1498 fprintf(stderr, " %02x", c);
1499 ++i;
1500 if (c == '\n') break;
1503 /* fill hex column */
1504 while (i < N) {
1505 fputs(" ", stderr);
1506 ++i;
1508 fputs(" ", stderr);
1510 /* print acsii */
1511 t = s;
1512 i = 0;
1513 while (i < j) {
1514 int c = *t++;
1515 if (c == '\n') {
1516 fputc('.', stderr);
1517 break;
1519 if (!isprint(c))
1520 c = '.';
1521 fputc(c, stderr);
1522 ++i;
1525 fputc('\n', stderr);
1526 s = t;
1528 fputs("--\n", stderr);
1529 } else if (socat_opts.verbose) {
1530 size_t i = 0;
1531 xioprintblockheader(stderr, bytes, righttoleft);
1532 while (i < (size_t)bytes) {
1533 int c = buff[i];
1534 if (i > 0 && buff[i-1] == '\n')
1535 /*! prefix? */;
1536 switch (c) {
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;
1545 default:
1546 if (!isprint(c))
1547 c = '.';
1548 fputc(c, stderr);
1549 break;
1551 ++i;
1553 } else if (socat_opts.verbhex) {
1554 int i;
1555 /* print prefix */
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);
1564 if (writt < 0) {
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. */
1569 #if 0
1570 if (errno == EPIPE) {
1571 return 0; /* can no longer write; handle like EOF */
1573 #endif
1574 return -1;
1575 } else {
1576 Info3("transferred "F_Zu" bytes from %d to %d",
1577 writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
1578 #if WITH_STATS
1579 ++XIO_WRSTREAM(outpipe)->blocks_written;
1580 XIO_WRSTREAM(outpipe)->bytes_written += writt;
1581 #endif
1584 return writt;
1587 #define CR '\r'
1588 #define LF '\n'
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';
1603 } else {
1604 from = '\r'; to = '\n';
1606 z = buff + *bytes;
1607 p = buff;
1608 while (p < z) {
1609 if (*p == from) *p = to;
1610 ++p;
1613 } else if (lineterm1 == LINETERM_CRNL) {
1614 /* buffer might become shorter */
1615 unsigned char to, *s, *t, *z;
1616 if (lineterm2 == LINETERM_RAW) {
1617 to = '\n';
1618 } else {
1619 to = '\r';
1621 z = buff + *bytes;
1622 s = t = buff;
1623 while (s < z) {
1624 if (*s == '\r') {
1625 ++s;
1626 continue;
1628 if (*s == '\n') {
1629 *t++ = to; ++s;
1630 } else {
1631 *t++ = *s++;
1634 *bytes = t - buff;
1635 } else {
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) {
1641 from = '\n';
1642 } else {
1643 from = '\r';
1645 if (buf2 == NULL) {
1646 if ((buf2 = Malloc(xioparms.bufsiz)) == NULL) {
1647 return -1;
1650 memcpy(buf2, buff, *bytes);
1651 s = buf2; t = buff; z = buf2 + *bytes;
1652 while (s < z) {
1653 if (*s == from) {
1654 *t++ = '\r'; *t++ = '\n';
1655 ++s;
1656 continue;
1657 } else {
1658 *t++ = *s++;
1661 *bytes = t - buff;;
1663 return 0;
1666 void socat_signal(int signum) {
1667 int _errno;
1668 _errno = errno;
1669 diag_in_handler = 1;
1670 Notice1("socat_signal(): handling signal %d", signum);
1671 switch (signum) {
1672 default:
1673 diag_immediate_exit = 1;
1674 case SIGQUIT:
1675 case SIGPIPE:
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 */
1679 break;
1680 case SIGTERM:
1681 Warn1("exiting on signal %d", signum); break;
1682 case SIGHUP:
1683 case SIGINT:
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;
1689 errno = _errno;
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) {
1696 } else {
1697 file->eof = MAX(file->eof, 1);
1698 closing = 1;
1700 return 0;
1703 static int socat_lock(void) {
1704 int lockrc;
1706 #if 1
1707 if ((lockrc = xiolock(&socat_opts.lock)) < 0) {
1708 return -1;
1710 if (lockrc == 0) {
1711 havelock = true;
1713 return lockrc;
1714 #else
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);*/
1718 return -1;
1720 if (lockrc) {
1721 return 1;
1723 havelock = true;
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);*/
1730 return -1;
1731 } else {
1732 havelock = true;
1733 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1736 return 0;
1737 #endif
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));
1747 } else {
1748 Warn1("unlink(\"%s\"): "F_strerror,
1749 socat_opts.lock.lockfile);
1751 } else {
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) {
1760 havelock = false;
1761 return 0;
1765 #if WITH_STATS
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 */
1775 #if 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;
1784 int savelevel;
1786 if (sock1 == NULL || sock2 == NULL) {
1787 Warn("transfer engine not yet started, statistics not available");
1788 return;
1790 if ((sock1->tag & ~XIO_TAG_CLOSED) == XIO_TAG_DUAL) {
1791 sock1w = sock1->dual.stream[1];
1792 } else {
1793 sock1w = &sock1->stream;
1795 if ((sock2->tag & ~XIO_TAG_CLOSED) == XIO_TAG_DUAL) {
1796 sock2w = sock2->dual.stream[1];
1797 } else {
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);
1823 return;
1825 #endif /* WITH_STATs */