Version 1.8.0.1
[socat.git] / socat.c
blobcf1685d446f6d4d6025a840a407f309c257dcb3b
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,1000000}, /* total_timeout (this invalid default means no 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 if (rto < 0) {
278 socat_opts.total_timeout.tv_sec = 0; /* infinite */
279 socat_opts.total_timeout.tv_usec = 1000000; /* by invalid */
280 } else {
281 socat_opts.total_timeout.tv_sec = rto;
282 socat_opts.total_timeout.tv_usec =
283 (rto-socat_opts.total_timeout.tv_sec) * 1000000;
285 break;
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");
294 if (arg1[0][2]) {
295 socat_opts.lock.lockfile = *arg1+2;
296 } else {
297 ++arg1, --argc;
298 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
299 Error("option -L requires an argument; use option \"-h\" for help");
300 Exit(1);
303 break;
304 case 'W': if (socat_opts.lock.lockfile) {
305 Error("only one -L and -W option allowed");
307 if (arg1[0][2]) {
308 socat_opts.lock.lockfile = *arg1+2;
309 } else {
310 ++arg1, --argc;
311 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
312 Error("option -W requires an argument; use option \"-h\" for help");
313 Exit(1);
316 socat_opts.lock.waitlock = true;
317 socat_opts.lock.intervall.tv_sec = 1;
318 socat_opts.lock.intervall.tv_nsec = 0;
319 break;
320 #if WITH_IP4 || WITH_IP6
321 case '0':
322 #if WITH_IP4
323 case '4':
324 #endif
325 #if WITH_IP6
326 case '6':
327 #endif
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];
331 break;
332 #endif /* WITH_IP4 || WITH_IP6 */
333 case '-':
334 if (!strcmp("experimental", &arg1[0][2])) {
335 xioparms.experimental = true;
336 } else if (!strcmp("statistics", &arg1[0][2])) {
337 socat_opts.statistics = true;
338 } else {
339 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
341 break;
342 case '\0':
343 case ',':
344 case ':':
345 isdash = true;
346 break; /* this "-" is a variation of STDIO */
347 default:
348 xioinqopt('p', buff, sizeof(buff)); /* fetch pipe separator char */
349 if (arg1[0][1] == buff[0]) {
350 isdash = true;
351 break;
353 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
354 Exit(1);
356 if (isdash) {
357 /* the leading "-" is a form of the first address */
358 break;
360 ++arg1; --argc;
362 if (argc != 2) {
363 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
364 Exit(1);
366 if (socat_opts.lefttoright && socat_opts.righttoleft) {
367 Error("-U and -u must not be combined");
370 xioinitialize2();
371 Info(copyright_socat);
372 #if WITH_OPENSSL
373 Info(copyright_openssl);
374 Info(copyright_ssleay);
375 #endif
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 */
389 #if HAVE_SIGACTION
390 struct sigaction act;
391 #endif
392 int i, m;
394 sigfillset(&act.sa_mask); /* while in sighandler block all signals */
395 act.sa_flags = 0;
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) {
400 #if HAVE_SIGACTION
401 Sigaction(i, &act, NULL);
402 #else
403 Signal(i, socat_signal);
404 #endif
408 #if WITH_STATS
409 #if HAVE_SIGACTION
410 act.sa_handler = socat_signal_logstats;
411 Sigaction(SIGUSR1, &act, NULL);
412 #else
413 Signal(SIGUSR1, socat_signal_logstats);
414 #endif
415 #endif /* WITH_STATS */
417 Signal(SIGPIPE, SIG_IGN);
419 /* set xio hooks */
420 xiohook_newchild = &socat_newchild;
422 if (lockrc = socat_lock()) {
423 /* =0: goon; >0: locked; <0: error, printed in sub */
424 if (lockrc > 0)
425 Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile);
426 Exit(1);
429 Atexit(socat_unlock);
430 #if WITH_STATS
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
439 options -0 -4 -6 */
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);
448 Exit(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);
459 #if WITH_HELP
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);
466 #if WITH_FILAN
467 fputs(" -D analyze file descriptors before loop\n", fd);
468 #endif
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);
494 #endif
495 #if WITH_IP4
496 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd);
497 #endif
498 #if WITH_IP6
499 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd);
500 #endif
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",
505 a, b, a, b);
509 void socat_version(FILE *fd) {
510 struct utsname ubuf;
512 fputs(copyright_socat, fd); fputc('\n', fd);
513 fprintf(fd, "socat version %s on %s\n", socatversion, timestamp);
514 Uname(&ubuf);
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);
518 #ifdef WITH_HELP
519 fprintf(fd, " #define WITH_HELP %d\n", WITH_HELP);
520 #else
521 fputs(" #undef WITH_HELP\n", fd);
522 #endif
523 #ifdef WITH_STATS
524 fprintf(fd, " #define WITH_STATS %d\n", WITH_STATS);
525 #else
526 fputs(" #undef WITH_STATS\n", fd);
527 #endif
528 #ifdef WITH_STDIO
529 fprintf(fd, " #define WITH_STDIO %d\n", WITH_STDIO);
530 #else
531 fputs(" #undef WITH_STDIO\n", fd);
532 #endif
533 #ifdef WITH_FDNUM
534 fprintf(fd, " #define WITH_FDNUM %d\n", WITH_FDNUM);
535 #else
536 fputs(" #undef WITH_FDNUM\n", fd);
537 #endif
538 #ifdef WITH_FILE
539 fprintf(fd, " #define WITH_FILE %d\n", WITH_FILE);
540 #else
541 fputs(" #undef WITH_FILE\n", fd);
542 #endif
543 #ifdef WITH_CREAT
544 fprintf(fd, " #define WITH_CREAT %d\n", WITH_CREAT);
545 #else
546 fputs(" #undef WITH_CREAT\n", fd);
547 #endif
548 #ifdef WITH_GOPEN
549 fprintf(fd, " #define WITH_GOPEN %d\n", WITH_GOPEN);
550 #else
551 fputs(" #undef WITH_GOPEN\n", fd);
552 #endif
553 #ifdef WITH_TERMIOS
554 fprintf(fd, " #define WITH_TERMIOS %d\n", WITH_TERMIOS);
555 #else
556 fputs(" #undef WITH_TERMIOS\n", fd);
557 #endif
558 #ifdef WITH_PIPE
559 fprintf(fd, " #define WITH_PIPE %d\n", WITH_PIPE);
560 #else
561 fputs(" #undef WITH_PIPE\n", fd);
562 #endif
563 #ifdef WITH_SOCKETPAIR
564 fprintf(fd, " #define WITH_SOCKETPAIR %d\n", WITH_SOCKETPAIR);
565 #else
566 fputs(" #undef WITH_SOCKETPAIR\n", fd);
567 #endif
568 #ifdef WITH_UNIX
569 fprintf(fd, " #define WITH_UNIX %d\n", WITH_UNIX);
570 #else
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);
575 #else
576 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd);
577 #endif /* WITH_ABSTRACT_UNIXSOCKET */
578 #ifdef WITH_IP4
579 fprintf(fd, " #define WITH_IP4 %d\n", WITH_IP4);
580 #else
581 fputs(" #undef WITH_IP4\n", fd);
582 #endif
583 #ifdef WITH_IP6
584 fprintf(fd, " #define WITH_IP6 %d\n", WITH_IP6);
585 #else
586 fputs(" #undef WITH_IP6\n", fd);
587 #endif
588 #ifdef WITH_RAWIP
589 fprintf(fd, " #define WITH_RAWIP %d\n", WITH_RAWIP);
590 #else
591 fputs(" #undef WITH_RAWIP\n", fd);
592 #endif
593 #ifdef WITH_GENERICSOCKET
594 fprintf(fd, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET);
595 #else
596 fputs(" #undef WITH_GENERICSOCKET\n", fd);
597 #endif
598 #ifdef WITH_INTERFACE
599 fprintf(fd, " #define WITH_INTERFACE %d\n", WITH_INTERFACE);
600 #else
601 fputs(" #undef WITH_INTERFACE\n", fd);
602 #endif
603 #ifdef WITH_TCP
604 fprintf(fd, " #define WITH_TCP %d\n", WITH_TCP);
605 #else
606 fputs(" #undef WITH_TCP\n", fd);
607 #endif
608 #ifdef WITH_UDP
609 fprintf(fd, " #define WITH_UDP %d\n", WITH_UDP);
610 #else
611 fputs(" #undef WITH_UDP\n", fd);
612 #endif
613 #ifdef WITH_SCTP
614 fprintf(fd, " #define WITH_SCTP %d\n", WITH_SCTP);
615 #else
616 fputs(" #undef WITH_SCTP\n", fd);
617 #endif
618 #ifdef WITH_DCCP
619 fprintf(fd, " #define WITH_DCCP %d\n", WITH_DCCP);
620 #else
621 fputs(" #undef WITH_DCCP\n", fd);
622 #endif
623 #ifdef WITH_UDPLITE
624 fprintf(fd, " #define WITH_UDPLITE %d\n", WITH_UDPLITE);
625 #else
626 fputs(" #undef WITH_UDPLITE\n", fd);
627 #endif
628 #ifdef WITH_LISTEN
629 fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN);
630 #else
631 fputs(" #undef WITH_LISTEN\n", fd);
632 #endif
633 #ifdef WITH_POSIXMQ
634 fprintf(fd, " #define WITH_POSIXMQ %d\n", WITH_POSIXMQ);
635 #else
636 fputs(" #undef WITH_POSIXMQ\n", fd);
637 #endif
638 #ifdef WITH_SOCKS4
639 fprintf(fd, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4);
640 #else
641 fputs(" #undef WITH_SOCKS4\n", fd);
642 #endif
643 #ifdef WITH_SOCKS4A
644 fprintf(fd, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A);
645 #else
646 fputs(" #undef WITH_SOCKS4A\n", fd);
647 #endif
648 #ifdef WITH_SOCKS5
649 fprintf(fd, " #define WITH_SOCKS5 %d\n", WITH_SOCKS5);
650 #else
651 fputs(" #undef WITH_SOCKS5\n", fd);
652 #endif
653 #ifdef WITH_VSOCK
654 fprintf(fd, " #define WITH_VSOCK %d\n", WITH_VSOCK);
655 #else
656 fputs(" #undef WITH_VSOCK\n", fd);
657 #endif
658 #ifdef WITH_NAMESPACES
659 fprintf(fd, " #define WITH_NAMESPACES %d\n", WITH_NAMESPACES);
660 #else
661 fputs(" #undef WITH_NAMESPACES\n", fd);
662 #endif
663 #ifdef WITH_PROXY
664 fprintf(fd, " #define WITH_PROXY %d\n", WITH_PROXY);
665 #else
666 fputs(" #undef WITH_PROXY\n", fd);
667 #endif
668 #ifdef WITH_SYSTEM
669 fprintf(fd, " #define WITH_SYSTEM %d\n", WITH_SYSTEM);
670 #else
671 fputs(" #undef WITH_SYSTEM\n", fd);
672 #endif
673 #ifdef WITH_SHELL
674 fprintf(fd, " #define WITH_SHELL %d\n", WITH_SHELL);
675 #else
676 fputs(" #undef WITH_SHELL\n", fd);
677 #endif
678 #ifdef WITH_EXEC
679 fprintf(fd, " #define WITH_EXEC %d\n", WITH_EXEC);
680 #else
681 fputs(" #undef WITH_EXEC\n", fd);
682 #endif
683 #ifdef WITH_READLINE
684 fprintf(fd, " #define WITH_READLINE %d\n", WITH_READLINE);
685 #else
686 fputs(" #undef WITH_READLINE\n", fd);
687 #endif
688 #ifdef WITH_TUN
689 fprintf(fd, " #define WITH_TUN %d\n", WITH_TUN);
690 #else
691 fputs(" #undef WITH_TUN\n", fd);
692 #endif
693 #ifdef WITH_PTY
694 fprintf(fd, " #define WITH_PTY %d\n", WITH_PTY);
695 #else
696 fputs(" #undef WITH_PTY\n", fd);
697 #endif
698 #ifdef WITH_OPENSSL
699 fprintf(fd, " #define WITH_OPENSSL %d\n", WITH_OPENSSL);
700 #else
701 fputs(" #undef WITH_OPENSSL\n", fd);
702 #endif
703 #ifdef WITH_FIPS
704 fprintf(fd, " #define WITH_FIPS %d\n", WITH_FIPS);
705 #else
706 fputs(" #undef WITH_FIPS\n", fd);
707 #endif
708 #ifdef WITH_LIBWRAP
709 fprintf(fd, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP);
710 #else
711 fputs(" #undef WITH_LIBWRAP\n", fd);
712 #endif
713 #ifdef WITH_SYCLS
714 fprintf(fd, " #define WITH_SYCLS %d\n", WITH_SYCLS);
715 #else
716 fputs(" #undef WITH_SYCLS\n", fd);
717 #endif
718 #ifdef WITH_FILAN
719 fprintf(fd, " #define WITH_FILAN %d\n", WITH_FILAN);
720 #else
721 fputs(" #undef WITH_FILAN\n", fd);
722 #endif
723 #ifdef WITH_RETRY
724 fprintf(fd, " #define WITH_RETRY %d\n", WITH_RETRY);
725 #else
726 fputs(" #undef WITH_RETRY\n", fd);
727 #endif
728 #ifdef WITH_DEVTESTS
729 fprintf(fd, " #define WITH_DEVTESTS %d\n", WITH_DEVTESTS);
730 #else
731 fputs(" #undef WITH_DEVTESTS\n", fd);
732 #endif
733 #ifdef WITH_MSGLEVEL
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]);
736 #else
737 fputs(" #undef WITH_MSGLEVEL\n", fd);
738 #endif
739 #ifdef WITH_DEFAULT_IPV
740 # if WITH_DEFAULT_IPV
741 fprintf(fd, " #define WITH_DEFAULT_IPV %c\n", WITH_DEFAULT_IPV);
742 # else
743 fprintf(fd, " #define WITH_DEFAULT_IPV '\\0'\n");
744 # endif
745 #else
746 fputs(" #undef WITH_DEFAULT_IPV\n", fd);
747 #endif
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) {
760 int mayexec;
762 if (socat_opts.lefttoright) {
763 if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
764 return -1;
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) {
769 return -1;
771 xiosetsigchild(sock1, socat_sigchild);
772 } else {
773 if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
774 return -1;
776 xiosetsigchild(sock1, socat_sigchild);
778 #if 1 /*! */
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)) {
783 int i;
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) {
792 return 1;
794 diedunknown[i] = 0;
795 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
796 /* return STAT_RETRYLATER; */
800 #endif
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) {
806 return -1;
808 xiosetsigchild(sock2, socat_sigchild);
809 } else {
810 if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
811 return -1;
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) {
817 return -1;
819 xiosetsigchild(sock2, socat_sigchild);
821 #if 1 /*! */
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)) {
826 int i;
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) {
834 return 1;
836 diedunknown[i] = 0;
837 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
838 /* return STAT_RETRYLATER; */
842 #endif
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) {
855 struct pollfd in;
856 int retval;
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*/;
869 in.revents = 0;
871 do {
872 int _errno;
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);
877 if (retval < 0) {
878 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
879 in.fd, in.events, timeout.tv_sec, timeout.tv_usec,
880 strerror(errno));
881 return -1;
883 if (retval == 0) {
884 Info("terminated child did not leave data for us");
885 XIO_RDSTREAM(xfd)->eof = 2;
886 xfd->stream.eof = 2;
887 closing = MAX(closing, 1);
890 return 0;
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 */
904 int _socat(void) {
905 char *transferwaitstring;
906 struct pollfd fds[4],
907 *fd1in = &fds[0],
908 *fd1out = &fds[1],
909 *fd2in = &fds[2],
910 *fd2out = &fds[3];
911 int retval;
912 unsigned char *buff;
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) */
920 char name[PATH_MAX];
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);
926 if (sniffleft < 0) {
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));
940 #if WITH_FILAN
941 if (socat_opts.debug) {
942 int fdi, fdo;
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);
953 if (fdo != fdi) {
954 filan_fd(fdo, stderr);
957 fdi = XIO_GETRDFD(sock2);
958 fdo = XIO_GETWRFD(sock2);
959 filan_fd(fdi, stderr);
960 if (fdo != fdi) {
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" */
979 int _errno;
980 if ((_errno = Posix_memalign((void **)&buff, getpagesize(), 2*xioparms.bufsiz+1)) != 0) {
981 Error1("posix_memalign(): %s", strerror(_errno));
982 return -1;
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,
1010 closing, wasaction,
1011 total_timeout.tv_sec, total_timeout.tv_usec);
1013 /* for ignoreeof */
1014 if (polling) {
1015 if (!wasaction) {
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");
1026 free(buff);
1027 return 0;
1031 } else {
1032 wasaction = 0;
1036 if (polling) {
1037 /* there is a ignoreeof poll timeout, use it */
1038 timeout = socat_opts.pollintv;
1039 to = &timeout;
1040 } else if (socat_opts.total_timeout.tv_usec < 1000000) {
1041 /* there might occur a total inactivity timeout */
1042 timeout = socat_opts.total_timeout;
1043 to = &timeout;
1044 } else {
1045 to = NULL;
1048 if (closing>=1) {
1049 /* first eof already occurred, start end timer */
1050 timeout = socat_opts.pollintv;
1051 to = &timeout;
1052 closing = 2;
1055 /* frame 1: set the poll parameters and loop over poll() EINTR) */
1056 do { /* loop over poll() EINTR */
1057 int _errno;
1059 childleftdata(sock1);
1060 childleftdata(sock2);
1062 if (closing>=1) {
1063 /* first eof already occurred, start end timer */
1064 timeout = socat_opts.closwait;
1065 to = &timeout;
1066 closing = 2;
1069 /* use the ignoreeof timeout if appropriate */
1070 if (polling) {
1071 if (closing == 0 ||
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;
1086 } else {
1087 fd1in->fd = -1;
1089 if (!maywr2) {
1090 fd2out->fd = XIO_GETWRFD(sock2);
1091 fd2out->events = POLLOUT;
1092 } else {
1093 fd2out->fd = -1;
1095 } else {
1096 fd1in->fd = -1;
1097 fd2out->fd = -1;
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;
1105 } else {
1106 fd2in->fd = -1;
1108 if (!maywr1) {
1109 fd1out->fd = XIO_GETWRFD(sock1);
1110 fd1out->events = POLLOUT;
1111 } else {
1112 fd1out->fd = -1;
1114 } else {
1115 fd1out->fd = -1;
1116 fd2in->fd = -1;
1118 /* frame 0: innermost part of the transfer loop: check FD status */
1119 retval = xiopoll(fds, 4, to);
1120 if (retval >= 0 || errno != EINTR) {
1121 break;
1123 _errno = errno;
1124 Info1("poll(): %s", strerror(errno));
1125 errno = _errno;
1126 } while (true);
1128 /* attention:
1129 when an exec'd process sends data and terminates, it is unpredictable
1130 whether the data or the sigchild arrives first.
1133 if (retval < 0) {
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));
1138 free(buff);
1139 return -1;
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) {
1148 mayrd1 = 0;
1150 if (XIO_RDSTREAM(sock2)->ignoreeof) {
1151 mayrd2 = 0;
1153 } else if (polling && wasaction) {
1154 wasaction = 0;
1156 } else if (socat_opts.total_timeout.tv_usec < 1000000) {
1157 /* there was a total inactivity timeout */
1158 Notice("inactivity timeout triggered");
1159 free(buff);
1160 return 0;
1163 if (closing) {
1164 break;
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! */
1168 continue;
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
1176 in a loop? */
1177 Error1("poll(...[%d]: invalid request", fd1in->fd);
1178 free(buff);
1179 return -1;
1181 mayrd1 = true;
1183 if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
1184 (fd2in->revents)) {
1185 if (fd2in->revents & POLLNVAL) {
1186 Error1("poll(...[%d]: invalid request", fd2in->fd);
1187 free(buff);
1188 return -1;
1190 mayrd2 = true;
1192 if (XIO_GETWRFD(sock1) >= 0 && fd1out->fd >= 0 && fd1out->revents) {
1193 if (fd1out->revents & POLLNVAL) {
1194 Error1("poll(...[%d]: invalid request", fd1out->fd);
1195 free(buff);
1196 return -1;
1198 maywr1 = true;
1200 if (XIO_GETWRFD(sock2) >= 0 && fd2out->fd >= 0 && fd2out->revents) {
1201 if (fd2out->revents & POLLNVAL) {
1202 Error1("poll(...[%d]: invalid request", fd2out->fd);
1203 free(buff);
1204 return -1;
1206 maywr2 = true;
1209 if (mayrd1 && maywr2) {
1210 mayrd1 = false;
1211 if ((bytes1 = xiotransfer(sock1, sock2, buff, xioparms.bufsiz, false))
1212 < 0) {
1213 if (errno != EAGAIN) {
1214 closing = MAX(closing, 1);
1215 Notice("socket 1 to socket 2 is in error");
1216 if (socat_opts.lefttoright) {
1217 break;
1220 } else if (bytes1 > 0) {
1221 maywr2 = false;
1222 total_timeout = socat_opts.total_timeout;
1223 wasaction = 1;
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 */
1229 mayrd1 = true;
1231 /* escape char occurred? */
1232 if (XIO_RDSTREAM(sock1)->actescape) {
1233 bytes1 = 0; /* indicate EOF */
1236 /* (bytes1 == 0) handled later */
1237 } else {
1238 bytes1 = -1;
1241 if (mayrd2 && maywr1) {
1242 mayrd2 = false;
1243 if ((bytes2 = xiotransfer(sock2, sock1, buff, xioparms.bufsiz, true))
1244 < 0) {
1245 if (errno != EAGAIN) {
1246 closing = MAX(closing, 1);
1247 Notice("socket 2 to socket 1 is in error");
1248 if (socat_opts.righttoleft) {
1249 break;
1252 } else if (bytes2 > 0) {
1253 maywr1 = false;
1254 total_timeout = socat_opts.total_timeout;
1255 wasaction = 1;
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 */
1261 mayrd2 = true;
1263 /* escape char occurred? */
1264 if (XIO_RDSTREAM(sock2)->actescape) {
1265 bytes2 = 0; /* indicate EOF */
1268 /* (bytes2 == 0) handled later */
1269 } else {
1270 bytes2 = -1;
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,
1277 closing);*/
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); /*! */
1283 mayrd1 = true;
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) {
1292 polling = 0;
1294 if (XIO_RDSTREAM(sock1)->eof >= 2) {
1295 if (socat_opts.lefttoright) {
1296 break;
1298 closing = 1;
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);
1306 mayrd2 = true;
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) {
1315 polling = 0;
1317 if (XIO_RDSTREAM(sock2)->eof >= 2) {
1318 if (socat_opts.righttoleft) {
1319 break;
1321 closing = 1;
1325 /* close everything that's still open */
1326 xioclose(sock1);
1327 xioclose(sock2);
1329 free(buff);
1330 return 0;
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) {
1339 size_t bytes;
1340 #if HAVE_CLOCK_GETTIME
1341 struct timespec now;
1342 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1343 struct timeval now;
1344 #endif /* !HAVE_PROTOTYPE_LIB_gettimeofday */
1345 time_t nowt;
1346 int result;
1348 #if HAVE_CLOCK_GETTIME
1349 result = clock_gettime(CLOCK_REALTIME, &now);
1350 if (result < 0) {
1351 return result;
1353 nowt = now.tv_sec;
1354 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1355 result = Gettimeofday(&now, NULL);
1356 if (result < 0) {
1357 return result;
1359 nowt = now.tv_sec;
1360 #else
1361 nowt = time(NULL);
1362 if (nowt == (time_t)-1) {
1363 return -1;
1365 #endif
1366 #if HAVE_STRFTIME
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);
1372 #else
1373 strncpy(&timestamp[bytes++], " ", 2);
1374 #endif
1375 #else
1376 strcpy(timestamp, ctime(&nowt));
1377 bytes = strlen(timestamp);
1378 #endif
1379 return 0;
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 */
1388 static int
1389 xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
1390 char timestamp[MAXTIMESTAMPLEN];
1391 char buff[128+MAXTIMESTAMPLEN];
1392 if (gettimestamp(timestamp) < 0) {
1393 return -1;
1395 if (righttoleft) {
1396 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1397 prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
1398 numrtol+=bytes;
1399 } else {
1400 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1401 prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
1402 numltor+=bytes;
1404 fputs(buff, file);
1405 return 0;
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;
1424 ssize_t sniffed;
1426 bytes = xioread(inpipe, buff, bufsiz);
1427 if (bytes < 0) {
1428 if (errno != EAGAIN)
1429 XIO_RDSTREAM(inpipe)->eof = 2;
1430 /*xioshutdown(inpipe, SHUT_RD);*/
1431 return -1;
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);
1440 if (bytes > 0) {
1441 #if WITH_STATS
1442 ++XIO_RDSTREAM(inpipe)->blocks_read;
1443 XIO_RDSTREAM(inpipe)->bytes_read += bytes;
1444 #endif
1445 /* handle escape char */
1446 if (XIO_RDSTREAM(inpipe)->escape != -1) {
1447 /* check input data for escape char */
1448 unsigned char *ptr = buff;
1449 size_t ctr = 0;
1450 while (ctr < bytes) {
1451 if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
1452 /* found: set flag, truncate input data */
1453 XIO_RDSTREAM(inpipe)->actescape = true;
1454 bytes = ctr;
1455 Info("escape char found in input");
1456 break;
1458 ++ptr; ++ctr;
1460 if (ctr != bytes) {
1461 XIO_RDSTREAM(inpipe)->eof = 2;
1466 if (bytes > 0) {
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);
1474 if (bytes == 0) {
1475 errno = EAGAIN; return -1;
1478 if (!righttoleft && sniffleft >= 0) {
1479 if ((sniffed = Write(sniffleft, buff, bytes)) < bytes) {
1480 if (sniffed < 0)
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) {
1489 if (sniffed < 0)
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) {
1499 /* Hack-o-rama */
1500 size_t i = 0;
1501 size_t j;
1502 size_t N = 16;
1503 const unsigned char *end, *s, *t;
1504 s = buff;
1505 end = buff+bytes;
1506 xioprintblockheader(stderr, bytes, righttoleft);
1507 while (s < end) {
1508 /*! prefix? */
1509 j = Min(N, (size_t)(end-s));
1511 /* print hex */
1512 t = s;
1513 i = 0;
1514 while (i < j) {
1515 int c = *t++;
1516 fprintf(stderr, " %02x", c);
1517 ++i;
1518 if (c == '\n') break;
1521 /* fill hex column */
1522 while (i < N) {
1523 fputs(" ", stderr);
1524 ++i;
1526 fputs(" ", stderr);
1528 /* print acsii */
1529 t = s;
1530 i = 0;
1531 while (i < j) {
1532 int c = *t++;
1533 if (c == '\n') {
1534 fputc('.', stderr);
1535 break;
1537 if (!isprint(c))
1538 c = '.';
1539 fputc(c, stderr);
1540 ++i;
1543 fputc('\n', stderr);
1544 s = t;
1546 fputs("--\n", stderr);
1547 } else if (socat_opts.verbose) {
1548 size_t i = 0;
1549 xioprintblockheader(stderr, bytes, righttoleft);
1550 while (i < (size_t)bytes) {
1551 int c = buff[i];
1552 if (i > 0 && buff[i-1] == '\n')
1553 /*! prefix? */;
1554 switch (c) {
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;
1563 default:
1564 if (!isprint(c))
1565 c = '.';
1566 fputc(c, stderr);
1567 break;
1569 ++i;
1571 } else if (socat_opts.verbhex) {
1572 int i;
1573 /* print prefix */
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);
1582 if (writt < 0) {
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. */
1587 #if 0
1588 if (errno == EPIPE) {
1589 return 0; /* can no longer write; handle like EOF */
1591 #endif
1592 return -1;
1593 } else {
1594 Info3("transferred "F_Zu" bytes from %d to %d",
1595 writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
1596 #if WITH_STATS
1597 ++XIO_WRSTREAM(outpipe)->blocks_written;
1598 XIO_WRSTREAM(outpipe)->bytes_written += writt;
1599 #endif
1602 return writt;
1605 #define CR '\r'
1606 #define LF '\n'
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';
1621 } else {
1622 from = '\r'; to = '\n';
1624 z = buff + *bytes;
1625 p = buff;
1626 while (p < z) {
1627 if (*p == from) *p = to;
1628 ++p;
1631 } else if (lineterm1 == LINETERM_CRNL) {
1632 /* buffer might become shorter */
1633 unsigned char to, *s, *t, *z;
1634 if (lineterm2 == LINETERM_RAW) {
1635 to = '\n';
1636 } else {
1637 to = '\r';
1639 z = buff + *bytes;
1640 s = t = buff;
1641 while (s < z) {
1642 if (*s == '\r') {
1643 ++s;
1644 continue;
1646 if (*s == '\n') {
1647 *t++ = to; ++s;
1648 } else {
1649 *t++ = *s++;
1652 *bytes = t - buff;
1653 } else {
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) {
1659 from = '\n';
1660 } else {
1661 from = '\r';
1663 if (buf2 == NULL) {
1664 if ((buf2 = Malloc(xioparms.bufsiz)) == NULL) {
1665 return -1;
1668 memcpy(buf2, buff, *bytes);
1669 s = buf2; t = buff; z = buf2 + *bytes;
1670 while (s < z) {
1671 if (*s == from) {
1672 *t++ = '\r'; *t++ = '\n';
1673 ++s;
1674 continue;
1675 } else {
1676 *t++ = *s++;
1679 *bytes = t - buff;;
1681 return 0;
1684 void socat_signal(int signum) {
1685 int _errno;
1686 _errno = errno;
1687 diag_in_handler = 1;
1688 Notice1("socat_signal(): handling signal %d", signum);
1689 switch (signum) {
1690 default:
1691 diag_immediate_exit = 1;
1692 case SIGQUIT:
1693 case SIGPIPE:
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 */
1697 break;
1698 case SIGTERM:
1699 Warn1("exiting on signal %d", signum); break;
1700 case SIGHUP:
1701 case SIGINT:
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;
1707 errno = _errno;
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) {
1714 } else {
1715 file->eof = MAX(file->eof, 1);
1716 closing = 1;
1718 return 0;
1721 static int socat_lock(void) {
1722 int lockrc;
1724 #if 1
1725 if ((lockrc = xiolock(&socat_opts.lock)) < 0) {
1726 return -1;
1728 if (lockrc == 0) {
1729 havelock = true;
1731 return lockrc;
1732 #else
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);*/
1736 return -1;
1738 if (lockrc) {
1739 return 1;
1741 havelock = true;
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);*/
1748 return -1;
1749 } else {
1750 havelock = true;
1751 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1754 return 0;
1755 #endif
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));
1765 } else {
1766 Warn1("unlink(\"%s\"): "F_strerror,
1767 socat_opts.lock.lockfile);
1769 } else {
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) {
1778 havelock = false;
1779 return 0;
1783 #if WITH_STATS
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 */
1793 #if 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;
1802 int savelevel;
1804 if (sock1 == NULL || sock2 == NULL) {
1805 Warn("transfer engine not yet started, statistics not available");
1806 return;
1808 if ((sock1->tag & ~XIO_TAG_CLOSED) == XIO_TAG_DUAL) {
1809 sock1w = sock1->dual.stream[1];
1810 } else {
1811 sock1w = &sock1->stream;
1813 if ((sock2->tag & ~XIO_TAG_CLOSED) == XIO_TAG_DUAL) {
1814 sock2w = sock2->dual.stream[1];
1815 } else {
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);
1841 return;
1843 #endif /* WITH_STATs */