AIX: Fixed configure and compile issues
[socat.git] / socat.c
blob728fa88e1425e159eb06fe3e3d8576687cfc85fe
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"
26 /* command line options */
27 struct {
28 size_t bufsiz;
29 bool verbose;
30 bool verbhex;
31 struct timeval pollintv; /* with ignoreeof, reread after seconds */
32 struct timeval closwait; /* after close of x, die after seconds */
33 struct timeval total_timeout;/* when nothing happens, die after seconds */
34 bool debug;
35 bool strictopts; /* stop on errors in address options */
36 char logopt; /* y..syslog; s..stderr; f..file; m..mixed */
37 bool lefttoright; /* first addr ro, second addr wo */
38 bool righttoleft; /* first addr wo, second addr ro */
39 int sniffleft; /* -1 or an FD for teeing data arriving on xfd1 */
40 int sniffright; /* -1 or an FD for teeing data arriving on xfd2 */
41 xiolock_t lock; /* a lock file */
42 } socat_opts = {
43 8192, /* bufsiz */
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 -1, /* sniffleft */
55 -1, /* sniffright */
56 { NULL, 0 }, /* lock */
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 static int socat_sigchild(struct single *file);
68 void lftocrlf(char **in, ssize_t *len, size_t bufsiz);
69 void crlftolf(char **in, ssize_t *len, size_t bufsiz);
71 static int socat_lock(void);
72 static void socat_unlock(void);
73 static int socat_newchild(void);
75 static const char socatversion[] =
76 #include "./VERSION"
78 static const char timestamp[] = BUILD_DATE;
80 const char copyright_socat[] = "socat by Gerhard Rieger and contributors - see www.dest-unreach.org";
81 #if WITH_OPENSSL
82 const char copyright_openssl[] = "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)";
83 const char copyright_ssleay[] = "This product includes software written by Tim Hudson (tjh@cryptsoft.com)";
84 #endif
86 bool havelock;
89 int main(int argc, const char *argv[]) {
90 const char **arg1, *a;
91 char *mainwaitstring;
92 char buff[10];
93 double rto;
94 int i, argc0, result;
95 bool isdash = false;
96 struct utsname ubuf;
97 int lockrc;
99 if (mainwaitstring = getenv("SOCAT_MAIN_WAIT")) {
100 sleep(atoi(mainwaitstring));
102 diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
104 /* we must init before applying options because env settings have lower
105 priority and are to be overridden by options */
106 if (xioinitialize() != 0) {
107 Exit(1);
110 xiosetopt('p', "!!");
111 xiosetopt('o', ":");
113 argc0 = argc; /* save for later use */
114 arg1 = argv+1; --argc;
115 while (arg1[0] && (arg1[0][0] == '-')) {
116 switch (arg1[0][1]) {
117 case 'V': if (arg1[0][2]) { socat_usage(stderr); Exit(1); }
118 socat_version(stdout); Exit(0);
119 #if WITH_HELP
120 case '?':
121 case 'h':
122 socat_usage(stdout);
123 xioopenhelp(stdout, (arg1[0][2]=='?'||arg1[0][2]=='h') ? (arg1[0][3]=='?'||arg1[0][3]=='h') ? 2 : 1 : 0);
124 Exit(0);
125 #endif /* WITH_HELP */
126 case 'd':
127 a = *arg1+1;
128 while (*a) {
129 if (*a == 'd') {
130 diag_set('d', NULL);
131 } else {
132 socat_usage(stderr);
133 Exit(1);
135 ++a;
137 break;
138 #if WITH_FILAN
139 case 'D': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
140 socat_opts.debug = true; break;
141 #endif
142 case 'l':
143 switch (arg1[0][2]) {
144 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
145 diag_set('s', NULL);
146 xiosetopt('l', "m");
147 socat_opts.logopt = arg1[0][2];
148 xiosetopt('y', &arg1[0][3]);
149 break;
150 case 'y': /* syslog + facility */
151 diag_set(arg1[0][2], &arg1[0][3]);
152 break;
153 case 'f': /* to file, +filename */
154 case 'p': /* artificial program name */
155 if (arg1[0][3]) {
156 diag_set(arg1[0][2], &arg1[0][3]);
157 } else if (arg1[1]) {
158 diag_set(arg1[0][2], arg1[1]);
159 ++arg1, --argc;
160 } else {
161 Error1("option -l%c requires an argument; use option \"-h\" for help", arg1[0][2]);
163 break;
164 case 's': /* stderr */
165 diag_set(arg1[0][2], NULL);
166 break;
167 case 'u':
168 diag_set('u', NULL);
169 break;
170 case 'h':
171 diag_set_int('h', true);
172 break;
173 default:
174 Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1[0]);
175 break;
177 break;
178 case 'v': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
179 socat_opts.verbose = true; break;
180 case 'x': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
181 socat_opts.verbhex = true; break;
182 case 'r': if (arg1[0][2]) {
183 a = *arg1+2;
184 } else {
185 ++arg1, --argc;
186 if ((a = *arg1) == NULL) {
187 Error("option -r requires an argument; use option \"-h\" for help");
188 break;
191 if ((socat_opts.sniffleft = Open(a, O_CREAT|O_WRONLY|O_APPEND|
192 #ifdef O_LARGEFILE
193 O_LARGEFILE|
194 #endif
195 O_NONBLOCK, 0664)) < 0) {
196 if (errno == ENXIO) {
197 if ((socat_opts.sniffleft = Open(a, O_CREAT|O_RDWR|O_APPEND|
198 #ifdef O_LARGEFILE
199 O_LARGEFILE|
200 #endif
201 O_NONBLOCK, 0664)) > 0)
202 break; /* try to open pipe rdwr */
204 Error2("option -r \"%s\": %s", a, strerror(errno));
206 break;
207 case 'R': if (arg1[0][2]) {
208 a = *arg1+2;
209 } else {
210 ++arg1, --argc;
211 if ((a = *arg1) == NULL) {
212 Error("option -R requires an argument; use option \"-h\" for help");
213 break;
216 if ((socat_opts.sniffright = Open(a, O_CREAT|O_WRONLY|O_APPEND|
217 #ifdef O_LARGEFILE
218 O_LARGEFILE|
219 #endif
220 O_NONBLOCK, 0664)) < 0) {
221 if (errno == ENXIO) {
222 if ((socat_opts.sniffright = Open(a, O_CREAT|O_RDWR|O_APPEND|
223 #ifdef O_LARGEFILE
224 O_LARGEFILE|
225 #endif
226 O_NONBLOCK, 0664)) > 0)
227 break; /* try to open pipe rdwr */
229 Error2("option -R \"%s\": %s", a, strerror(errno));
231 break;
232 case 'b': if (arg1[0][2]) {
233 a = *arg1+2;
234 } else {
235 ++arg1, --argc;
236 if ((a = *arg1) == NULL) {
237 Error("option -b requires an argument; use option \"-h\" for help");
238 Exit(1);
241 socat_opts.bufsiz = strtoul(a, (char **)&a, 0);
242 break;
243 case 's': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
244 diag_set_int('e', E_FATAL); break;
245 case 't': if (arg1[0][2]) {
246 a = *arg1+2;
247 } else {
248 ++arg1, --argc;
249 if ((a = *arg1) == NULL) {
250 Error("option -t requires an argument; use option \"-h\" for help");
251 Exit(1);
254 rto = strtod(a, (char **)&a);
255 socat_opts.closwait.tv_sec = rto;
256 socat_opts.closwait.tv_usec =
257 (rto-socat_opts.closwait.tv_sec) * 1000000;
258 break;
259 case 'T': if (arg1[0][2]) {
260 a = *arg1+2;
261 } else {
262 ++arg1, --argc;
263 if ((a = *arg1) == NULL) {
264 Error("option -T requires an argument; use option \"-h\" for help");
265 Exit(1);
268 rto = strtod(a, (char **)&a);
269 socat_opts.total_timeout.tv_sec = rto;
270 socat_opts.total_timeout.tv_usec =
271 (rto-socat_opts.total_timeout.tv_sec) * 1000000;
272 break;
273 case 'u': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
274 socat_opts.lefttoright = true; break;
275 case 'U': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
276 socat_opts.righttoleft = true; break;
277 case 'g': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
278 xioopts_ignoregroups = true; break;
279 case 'L': if (socat_opts.lock.lockfile)
280 Error("only one -L and -W option allowed");
281 if (arg1[0][2]) {
282 socat_opts.lock.lockfile = *arg1+2;
283 } else {
284 ++arg1, --argc;
285 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
286 Error("option -L requires an argument; use option \"-h\" for help");
287 Exit(1);
290 break;
291 case 'W': if (socat_opts.lock.lockfile)
292 Error("only one -L and -W option allowed");
293 if (arg1[0][2]) {
294 socat_opts.lock.lockfile = *arg1+2;
295 } else {
296 ++arg1, --argc;
297 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
298 Error("option -W requires an argument; use option \"-h\" for help");
299 Exit(1);
302 socat_opts.lock.waitlock = true;
303 socat_opts.lock.intervall.tv_sec = 1;
304 socat_opts.lock.intervall.tv_nsec = 0;
305 break;
306 #if WITH_IP4 || WITH_IP6
307 #if WITH_IP4
308 case '4':
309 #endif
310 #if WITH_IP6
311 case '6':
312 #endif
313 if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
314 xioopts.default_ip = arg1[0][1];
315 xioopts.preferred_ip = arg1[0][1];
316 break;
317 #endif /* WITH_IP4 || WITH_IP6 */
318 case '\0':
319 case ',':
320 case ':':
321 isdash = true;
322 break; /* this "-" is a variation of STDIO */
323 default:
324 xioinqopt('p', buff, sizeof(buff)); /* fetch pipe separator char */
325 if (arg1[0][1] == buff[0]) {
326 isdash = true;
327 break;
329 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
330 Exit(1);
332 if (isdash) {
333 /* the leading "-" is a form of the first address */
334 break;
336 ++arg1; --argc;
338 if (argc != 2) {
339 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
340 Exit(1);
342 if (socat_opts.lefttoright && socat_opts.righttoleft) {
343 Error("-U and -u must not be combined");
346 xioinitialize2();
347 Info(copyright_socat);
348 #if WITH_OPENSSL
349 Info(copyright_openssl);
350 Info(copyright_ssleay);
351 #endif
352 Debug2("socat version %s on %s", socatversion, timestamp);
353 xiosetenv("VERSION", socatversion, 1, NULL); /* SOCAT_VERSION */
354 uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */
355 Debug4("running on %s version %s, release %s, machine %s\n",
356 ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
358 #if WITH_MSGLEVEL <= E_DEBUG
359 for (i = 0; i < argc0; ++i) {
360 Debug2("argv[%d]: \"%s\"", i, argv[i]);
362 #endif /* WITH_MSGLEVEL <= E_DEBUG */
365 struct sigaction act;
366 sigfillset(&act.sa_mask);
367 act.sa_flags = 0;
368 act.sa_handler = socat_signal;
369 /* not sure which signals should be caught and print a message */
370 Sigaction(SIGHUP, &act, NULL);
371 Sigaction(SIGINT, &act, NULL);
372 Sigaction(SIGQUIT, &act, NULL);
373 Sigaction(SIGILL, &act, NULL);
374 Sigaction(SIGABRT, &act, NULL);
375 Sigaction(SIGBUS, &act, NULL);
376 Sigaction(SIGFPE, &act, NULL);
377 Sigaction(SIGSEGV, &act, NULL);
378 Sigaction(SIGTERM, &act, NULL);
380 Signal(SIGPIPE, SIG_IGN);
382 /* set xio hooks */
383 xiohook_newchild = &socat_newchild;
385 if (lockrc = socat_lock()) {
386 /* =0: goon; >0: locked; <0: error, printed in sub */
387 if (lockrc > 0)
388 Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile);
389 Exit(1);
392 Atexit(socat_unlock);
394 result = socat(arg1[0], arg1[1]);
395 Notice1("exiting with status %d", result);
396 Exit(result);
397 return 0; /* not reached, just for gcc -Wall */
401 void socat_usage(FILE *fd) {
402 fputs(copyright_socat, fd); fputc('\n', fd);
403 fputs("Usage:\n", fd);
404 fputs("socat [options] <bi-address> <bi-address>\n", fd);
405 fputs(" options:\n", fd);
406 fputs(" -V print version and feature information to stdout, and exit\n", fd);
407 #if WITH_HELP
408 fputs(" -h|-? print a help text describing command line options and addresses\n", fd);
409 fputs(" -hh like -h, plus a list of all common address option names\n", fd);
410 fputs(" -hhh like -hh, plus a list of all available address option names\n", fd);
411 #endif /* WITH_HELP */
412 fputs(" -d[ddd] increase verbosity (use up to 4 times; 2 are recommended)\n", fd);
413 #if WITH_FILAN
414 fputs(" -D analyze file descriptors before loop\n", fd);
415 #endif
416 fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd);
417 fputs(" -lf<logfile> log to file\n", fd);
418 fputs(" -ls log to stderr (default if no other log)\n", fd);
419 fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd);
420 fputs(" -lp<progname> set the program name used for logging\n", fd);
421 fputs(" -lu use microseconds for logging timestamps\n", fd);
422 fputs(" -lh add hostname to log messages\n", fd);
423 fputs(" -v verbose text dump of data traffic\n", fd);
424 fputs(" -x verbose hexadecimal dump of data traffic\n", fd);
425 fputs(" -r <file> raw dump of data flowing from left to right\n", fd);
426 fputs(" -R <file> raw dump of data flowing from right to left\n", fd);
427 fputs(" -b<size_t> set data buffer size (8192)\n", fd);
428 fputs(" -s sloppy (continue on error)\n", fd);
429 fputs(" -t<timeout> wait seconds before closing second channel\n", fd);
430 fputs(" -T<timeout> total inactivity timeout in seconds\n", fd);
431 fputs(" -u unidirectional mode (left to right)\n", fd);
432 fputs(" -U unidirectional mode (right to left)\n", fd);
433 fputs(" -g do not check option groups\n", fd);
434 fputs(" -L <lockfile> try to obtain lock, or fail\n", fd);
435 fputs(" -W <lockfile> try to obtain lock, or wait\n", fd);
436 #if WITH_IP4
437 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd);
438 #endif
439 #if WITH_IP6
440 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd);
441 #endif
444 void socat_opt_hint(FILE *fd, char a, char b) {
445 fprintf(fd, "Do not merge single character options, i.e. use \"-%c -%c\" instead of \"-%c%c\"\n",
446 a, b, a, b);
450 void socat_version(FILE *fd) {
451 struct utsname ubuf;
453 fputs(copyright_socat, fd); fputc('\n', fd);
454 fprintf(fd, "socat version %s on %s\n", socatversion, timestamp);
455 Uname(&ubuf);
456 fprintf(fd, " running on %s version %s, release %s, machine %s\n",
457 ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
458 fputs("features:\n", fd);
459 #ifdef WITH_STDIO
460 fprintf(fd, " #define WITH_STDIO %d\n", WITH_STDIO);
461 #else
462 fputs(" #undef WITH_STDIO\n", fd);
463 #endif
464 #ifdef WITH_FDNUM
465 fprintf(fd, " #define WITH_FDNUM %d\n", WITH_FDNUM);
466 #else
467 fputs(" #undef WITH_FDNUM\n", fd);
468 #endif
469 #ifdef WITH_FILE
470 fprintf(fd, " #define WITH_FILE %d\n", WITH_FILE);
471 #else
472 fputs(" #undef WITH_FILE\n", fd);
473 #endif
474 #ifdef WITH_CREAT
475 fprintf(fd, " #define WITH_CREAT %d\n", WITH_CREAT);
476 #else
477 fputs(" #undef WITH_CREAT\n", fd);
478 #endif
479 #ifdef WITH_GOPEN
480 fprintf(fd, " #define WITH_GOPEN %d\n", WITH_GOPEN);
481 #else
482 fputs(" #undef WITH_GOPEN\n", fd);
483 #endif
484 #ifdef WITH_TERMIOS
485 fprintf(fd, " #define WITH_TERMIOS %d\n", WITH_TERMIOS);
486 #else
487 fputs(" #undef WITH_TERMIOS\n", fd);
488 #endif
489 #ifdef WITH_PIPE
490 fprintf(fd, " #define WITH_PIPE %d\n", WITH_PIPE);
491 #else
492 fputs(" #undef WITH_PIPE\n", fd);
493 #endif
494 #ifdef WITH_UNIX
495 fprintf(fd, " #define WITH_UNIX %d\n", WITH_UNIX);
496 #else
497 fputs(" #undef WITH_UNIX\n", fd);
498 #endif /* WITH_UNIX */
499 #ifdef WITH_ABSTRACT_UNIXSOCKET
500 fprintf(fd, " #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET);
501 #else
502 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd);
503 #endif /* WITH_ABSTRACT_UNIXSOCKET */
504 #ifdef WITH_IP4
505 fprintf(fd, " #define WITH_IP4 %d\n", WITH_IP4);
506 #else
507 fputs(" #undef WITH_IP4\n", fd);
508 #endif
509 #ifdef WITH_IP6
510 fprintf(fd, " #define WITH_IP6 %d\n", WITH_IP6);
511 #else
512 fputs(" #undef WITH_IP6\n", fd);
513 #endif
514 #ifdef WITH_RAWIP
515 fprintf(fd, " #define WITH_RAWIP %d\n", WITH_RAWIP);
516 #else
517 fputs(" #undef WITH_RAWIP\n", fd);
518 #endif
519 #ifdef WITH_GENERICSOCKET
520 fprintf(fd, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET);
521 #else
522 fputs(" #undef WITH_GENERICSOCKET\n", fd);
523 #endif
524 #ifdef WITH_INTERFACE
525 fprintf(fd, " #define WITH_INTERFACE %d\n", WITH_INTERFACE);
526 #else
527 fputs(" #undef WITH_INTERFACE\n", fd);
528 #endif
529 #ifdef WITH_TCP
530 fprintf(fd, " #define WITH_TCP %d\n", WITH_TCP);
531 #else
532 fputs(" #undef WITH_TCP\n", fd);
533 #endif
534 #ifdef WITH_UDP
535 fprintf(fd, " #define WITH_UDP %d\n", WITH_UDP);
536 #else
537 fputs(" #undef WITH_UDP\n", fd);
538 #endif
539 #ifdef WITH_SCTP
540 fprintf(fd, " #define WITH_SCTP %d\n", WITH_SCTP);
541 #else
542 fputs(" #undef WITH_SCTP\n", fd);
543 #endif
544 #ifdef WITH_LISTEN
545 fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN);
546 #else
547 fputs(" #undef WITH_LISTEN\n", fd);
548 #endif
549 #ifdef WITH_SOCKS4
550 fprintf(fd, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4);
551 #else
552 fputs(" #undef WITH_SOCKS4\n", fd);
553 #endif
554 #ifdef WITH_SOCKS4A
555 fprintf(fd, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A);
556 #else
557 fputs(" #undef WITH_SOCKS4A\n", fd);
558 #endif
559 #ifdef WITH_VSOCK
560 fprintf(fd, " #define WITH_VSOCK %d\n", WITH_VSOCK);
561 #else
562 fputs(" #undef WITH_VSOCK\n", fd);
563 #endif
564 #ifdef WITH_PROXY
565 fprintf(fd, " #define WITH_PROXY %d\n", WITH_PROXY);
566 #else
567 fputs(" #undef WITH_PROXY\n", fd);
568 #endif
569 #ifdef WITH_SYSTEM
570 fprintf(fd, " #define WITH_SYSTEM %d\n", WITH_SYSTEM);
571 #else
572 fputs(" #undef WITH_SYSTEM\n", fd);
573 #endif
574 #ifdef WITH_EXEC
575 fprintf(fd, " #define WITH_EXEC %d\n", WITH_EXEC);
576 #else
577 fputs(" #undef WITH_EXEC\n", fd);
578 #endif
579 #ifdef WITH_READLINE
580 fprintf(fd, " #define WITH_READLINE %d\n", WITH_READLINE);
581 #else
582 fputs(" #undef WITH_READLINE\n", fd);
583 #endif
584 #ifdef WITH_TUN
585 fprintf(fd, " #define WITH_TUN %d\n", WITH_TUN);
586 #else
587 fputs(" #undef WITH_TUN\n", fd);
588 #endif
589 #ifdef WITH_PTY
590 fprintf(fd, " #define WITH_PTY %d\n", WITH_PTY);
591 #else
592 fputs(" #undef WITH_PTY\n", fd);
593 #endif
594 #ifdef WITH_OPENSSL
595 fprintf(fd, " #define WITH_OPENSSL %d\n", WITH_OPENSSL);
596 #else
597 fputs(" #undef WITH_OPENSSL\n", fd);
598 #endif
599 #ifdef WITH_FIPS
600 fprintf(fd, " #define WITH_FIPS %d\n", WITH_FIPS);
601 #else
602 fputs(" #undef WITH_FIPS\n", fd);
603 #endif
604 #ifdef WITH_LIBWRAP
605 fprintf(fd, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP);
606 #else
607 fputs(" #undef WITH_LIBWRAP\n", fd);
608 #endif
609 #ifdef WITH_SYCLS
610 fprintf(fd, " #define WITH_SYCLS %d\n", WITH_SYCLS);
611 #else
612 fputs(" #undef WITH_SYCLS\n", fd);
613 #endif
614 #ifdef WITH_FILAN
615 fprintf(fd, " #define WITH_FILAN %d\n", WITH_FILAN);
616 #else
617 fputs(" #undef WITH_FILAN\n", fd);
618 #endif
619 #ifdef WITH_RETRY
620 fprintf(fd, " #define WITH_RETRY %d\n", WITH_RETRY);
621 #else
622 fputs(" #undef WITH_RETRY\n", fd);
623 #endif
624 #ifdef WITH_MSGLEVEL
625 fprintf(fd, " #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL,
626 &"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL<<3]);
627 #else
628 fputs(" #undef WITH_MSGLEVEL\n", fd);
629 #endif
633 xiofile_t *sock1, *sock2;
634 int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
635 2..counting down closing timeout */
637 /* call this function when the common command line options are parsed, and the
638 addresses are extracted (but not resolved). */
639 int socat(const char *address1, const char *address2) {
640 int mayexec;
642 if (socat_opts.lefttoright) {
643 if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
644 return -1;
646 xiosetsigchild(sock1, socat_sigchild);
647 } else if (socat_opts.righttoleft) {
648 if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
649 return -1;
651 xiosetsigchild(sock1, socat_sigchild);
652 } else {
653 if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
654 return -1;
656 xiosetsigchild(sock1, socat_sigchild);
658 #if 1 /*! */
659 if (XIO_READABLE(sock1) &&
660 (XIO_RDSTREAM(sock1)->howtoend == END_KILL ||
661 XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL ||
662 XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) {
663 int i;
664 for (i = 0; i < NUMUNKNOWN; ++i) {
665 if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown[i]) {
666 /* child has alread died... but it might have put regular data into
667 the communication channel, so continue */
668 Info2("child "F_pid" has already died with status %d",
669 XIO_RDSTREAM(sock1)->para.exec.pid, statunknown[i]);
670 if (statunknown[i] != 0) {
671 return 1;
673 diedunknown[i] = 0;
674 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
675 /* return STAT_RETRYLATER; */
679 #endif
681 mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC);
682 if (XIO_WRITABLE(sock1)) {
683 if (XIO_READABLE(sock1)) {
684 if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
685 return -1;
687 xiosetsigchild(sock2, socat_sigchild);
688 } else {
689 if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
690 return -1;
692 xiosetsigchild(sock2, socat_sigchild);
694 } else { /* assuming sock1 is readable */
695 if ((sock2 = xioopen(address2, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
696 return -1;
698 xiosetsigchild(sock2, socat_sigchild);
700 #if 1 /*! */
701 if (XIO_READABLE(sock2) &&
702 (XIO_RDSTREAM(sock2)->howtoend == END_KILL ||
703 XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL ||
704 XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) {
705 int i;
706 for (i = 0; i < NUMUNKNOWN; ++i) {
707 if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown[i]) {
708 /* child has alread died... but it might have put regular data into
709 the communication channel, so continue */
710 Info2("child "F_pid" has already died with status %d",
711 XIO_RDSTREAM(sock2)->para.exec.pid, statunknown[i]);
712 if (statunknown[i] != 0) {
713 return 1;
715 diedunknown[i] = 0;
716 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
717 /* return STAT_RETRYLATER; */
721 #endif
723 Info("resolved and opened all sock addresses");
724 return
725 _socat(); /* nsocks, sockets are visible outside function */
728 /* checks if this is a connection to a child process, and if so, sees if the
729 child already died, leaving some data for us.
730 returns <0 if an error occurred;
731 returns 0 if no child or not yet died or died without data (sets eof);
732 returns >0 if child died and left data
734 int childleftdata(xiofile_t *xfd) {
735 struct pollfd in;
736 int retval;
738 /* have to check if a child process died before, but left read data */
739 if (XIO_READABLE(xfd) &&
740 (XIO_RDSTREAM(xfd)->howtoend == END_KILL ||
741 XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL ||
742 XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) &&
743 XIO_RDSTREAM(xfd)->para.exec.pid == 0) {
744 struct timeval timeout = { 0, 0 };
746 if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
747 in.fd = XIO_GETRDFD(xfd);
748 in.events = POLLIN/*|POLLRDBAND*/;
749 in.revents = 0;
751 do {
752 int _errno;
753 retval = xiopoll(&in, 1, &timeout);
754 _errno = errno; diag_flush(); errno = _errno; /* just in case it's not debug level and Msg() not been called */
755 } while (retval < 0 && errno == EINTR);
757 if (retval < 0) {
758 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
759 in.fd, in.events, timeout.tv_sec, timeout.tv_usec,
760 strerror(errno));
761 return -1;
763 if (retval == 0) {
764 Info("terminated child did not leave data for us");
765 XIO_RDSTREAM(xfd)->eof = 2;
766 xfd->stream.eof = 2;
767 closing = MAX(closing, 1);
770 return 0;
773 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
774 unsigned char *buff, size_t bufsiz, bool righttoleft);
776 bool mayrd1; /* sock1 has read data or eof, according to poll() */
777 bool mayrd2; /* sock2 has read data or eof, according to poll() */
778 bool maywr1; /* sock1 can be written to, according to poll() */
779 bool maywr2; /* sock2 can be written to, according to poll() */
781 /* here we come when the sockets are opened (in the meaning of C language),
782 and their options are set/applied
783 returns -1 on error or 0 on success */
784 int _socat(void) {
785 struct pollfd fds[4],
786 *fd1in = &fds[0],
787 *fd1out = &fds[1],
788 *fd2in = &fds[2],
789 *fd2out = &fds[3];
790 int retval;
791 unsigned char *buff;
792 ssize_t bytes1, bytes2;
793 int polling = 0; /* handling ignoreeof */
794 int wasaction = 1; /* last poll was active, do NOT sleep before next */
795 struct timeval total_timeout; /* the actual total timeout timer */
797 #if WITH_FILAN
798 if (socat_opts.debug) {
799 int fdi, fdo;
800 int msglevel, exitlevel;
802 msglevel = diag_get_int('D'); /* save current message level */
803 diag_set_int('D', E_ERROR); /* only print errors and fatals in filan */
804 exitlevel = diag_get_int('e'); /* save current exit level */
805 diag_set_int('e', E_FATAL); /* only exit on fatals */
807 fdi = XIO_GETRDFD(sock1);
808 fdo = XIO_GETWRFD(sock1);
809 filan_fd(fdi, stderr);
810 if (fdo != fdi) {
811 filan_fd(fdo, stderr);
814 fdi = XIO_GETRDFD(sock2);
815 fdo = XIO_GETWRFD(sock2);
816 filan_fd(fdi, stderr);
817 if (fdo != fdi) {
818 filan_fd(fdo, stderr);
821 diag_set_int('e', exitlevel); /* restore old exit level */
822 diag_set_int('D', msglevel); /* restore old message level */
824 #endif /* WITH_FILAN */
826 /* when converting nl to crnl, size might double */
827 if (socat_opts.bufsiz > (SIZE_MAX-1)/2) {
828 Error2("buffer size option (-b) to big - "F_Zu" (max is "F_Zu")", socat_opts.bufsiz, (SIZE_MAX-1)/2);
829 socat_opts.bufsiz = (SIZE_MAX-1)/2;
832 #if HAVE_PROTOTYPE_LIB_posix_memalign
833 /* Operations on files with flag O_DIRECT might need buffer alignment.
834 Without this, eg.read() fails with "Invalid argument" */
836 int _errno;
837 if ((_errno = Posix_memalign((void **)&buff, getpagesize(), 2*socat_opts.bufsiz+1)) != 0) {
838 Error1("posix_memalign(): %s", strerror(_errno));
839 return -1;
842 #else /* !HAVE_PROTOTYPE_LIB_posix_memalign */
843 buff = Malloc(2*socat_opts.bufsiz+1);
844 if (buff == NULL) return -1;
845 #endif /* !HAVE_PROTOTYPE_LIB_posix_memalign */
847 if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
848 Info("switching to syslog");
849 diag_set('y', xioopts.syslogfac);
850 xiosetopt('l', "\0");
852 total_timeout = socat_opts.total_timeout;
854 Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
855 XIO_GETRDFD(sock1), XIO_GETWRFD(sock1),
856 XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
857 while (XIO_RDSTREAM(sock1)->eof <= 1 ||
858 XIO_RDSTREAM(sock2)->eof <= 1) {
859 struct timeval timeout, *to = NULL;
861 Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}",
862 XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof,
863 closing, wasaction,
864 total_timeout.tv_sec, total_timeout.tv_usec);
866 /* for ignoreeof */
867 if (polling) {
868 if (!wasaction) {
869 if (socat_opts.total_timeout.tv_sec != 0 ||
870 socat_opts.total_timeout.tv_usec != 0) {
871 if (total_timeout.tv_usec < socat_opts.pollintv.tv_usec) {
872 total_timeout.tv_usec += 1000000;
873 total_timeout.tv_sec -= 1;
875 total_timeout.tv_sec -= socat_opts.pollintv.tv_sec;
876 total_timeout.tv_usec -= socat_opts.pollintv.tv_usec;
877 if (total_timeout.tv_sec < 0 ||
878 total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) {
879 Notice("inactivity timeout triggered");
880 free(buff);
881 return 0;
885 } else {
886 wasaction = 0;
890 if (polling) {
891 /* there is a ignoreeof poll timeout, use it */
892 timeout = socat_opts.pollintv;
893 to = &timeout;
894 } else if (socat_opts.total_timeout.tv_sec != 0 ||
895 socat_opts.total_timeout.tv_usec != 0) {
896 /* there might occur a total inactivity timeout */
897 timeout = socat_opts.total_timeout;
898 to = &timeout;
899 } else {
900 to = NULL;
903 if (closing>=1) {
904 /* first eof already occurred, start end timer */
905 timeout = socat_opts.pollintv;
906 to = &timeout;
907 closing = 2;
910 /* frame 1: set the poll parameters and loop over poll() EINTR) */
911 do { /* loop over poll() EINTR */
912 int _errno;
914 childleftdata(sock1);
915 childleftdata(sock2);
917 if (closing>=1) {
918 /* first eof already occurred, start end timer */
919 timeout = socat_opts.closwait;
920 to = &timeout;
921 closing = 2;
924 /* use the ignoreeof timeout if appropriate */
925 if (polling) {
926 if (closing == 0 ||
927 (socat_opts.pollintv.tv_sec < timeout.tv_sec) ||
928 ((socat_opts.pollintv.tv_sec == timeout.tv_sec) &&
929 socat_opts.pollintv.tv_usec < timeout.tv_usec)) {
930 timeout = socat_opts.pollintv;
934 /* now the fds will be assigned */
935 if (XIO_READABLE(sock1) &&
936 !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
937 !socat_opts.righttoleft) {
938 if (!mayrd1 && !(XIO_RDSTREAM(sock1)->eof > 1)) {
939 fd1in->fd = XIO_GETRDFD(sock1);
940 fd1in->events = POLLIN;
941 } else {
942 fd1in->fd = -1;
944 if (!maywr2) {
945 fd2out->fd = XIO_GETWRFD(sock2);
946 fd2out->events = POLLOUT;
947 } else {
948 fd2out->fd = -1;
950 } else {
951 fd1in->fd = -1;
952 fd2out->fd = -1;
954 if (XIO_READABLE(sock2) &&
955 !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
956 !socat_opts.lefttoright) {
957 if (!mayrd2 && !(XIO_RDSTREAM(sock2)->eof > 1)) {
958 fd2in->fd = XIO_GETRDFD(sock2);
959 fd2in->events = POLLIN;
960 } else {
961 fd2in->fd = -1;
963 if (!maywr1) {
964 fd1out->fd = XIO_GETWRFD(sock1);
965 fd1out->events = POLLOUT;
966 } else {
967 fd1out->fd = -1;
969 } else {
970 fd1out->fd = -1;
971 fd2in->fd = -1;
973 /* frame 0: innermost part of the transfer loop: check FD status */
974 retval = xiopoll(fds, 4, to);
975 if (retval >= 0 || errno != EINTR) {
976 break;
978 _errno = errno;
979 Info1("poll(): %s", strerror(errno));
980 errno = _errno;
981 } while (true);
983 /* attention:
984 when an exec'd process sends data and terminates, it is unpredictable
985 whether the data or the sigchild arrives first.
988 if (retval < 0) {
989 Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec"."F_tv_usec"}): %s",
990 fds[0].fd, fds[0].events, fds[1].fd, fds[1].events,
991 fds[2].fd, fds[2].events, fds[3].fd, fds[3].events,
992 timeout.tv_sec, timeout.tv_usec, strerror(errno));
993 free(buff);
994 return -1;
995 } else if (retval == 0) {
996 Info2("poll timed out (no data within %ld.%06ld seconds)",
997 closing>=1?socat_opts.closwait.tv_sec:socat_opts.total_timeout.tv_sec,
998 closing>=1?socat_opts.closwait.tv_usec:socat_opts.total_timeout.tv_usec);
999 if (polling && !wasaction) {
1000 /* there was a ignoreeof poll timeout, use it */
1001 polling = 0; /*%%%*/
1002 if (XIO_RDSTREAM(sock1)->ignoreeof) {
1003 mayrd1 = 0;
1005 if (XIO_RDSTREAM(sock2)->ignoreeof) {
1006 mayrd2 = 0;
1008 } else if (polling && wasaction) {
1009 wasaction = 0;
1011 } else if (socat_opts.total_timeout.tv_sec != 0 ||
1012 socat_opts.total_timeout.tv_usec != 0) {
1013 /* there was a total inactivity timeout */
1014 Notice("inactivity timeout triggered");
1015 free(buff);
1016 return 0;
1019 if (closing) {
1020 break;
1022 /* one possibility to come here is ignoreeof on some fd, but no EOF
1023 and no data on any descriptor - this is no indication for end! */
1024 continue;
1027 if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 &&
1028 (fd1in->revents /*&(POLLIN|POLLHUP|POLLERR)*/)) {
1029 if (fd1in->revents & POLLNVAL) {
1030 /* this is what we find on Mac OS X when poll()'ing on a device or
1031 named pipe. a read() might imm. return with 0 bytes, resulting
1032 in a loop? */
1033 Error1("poll(...[%d]: invalid request", fd1in->fd);
1034 free(buff);
1035 return -1;
1037 mayrd1 = true;
1039 if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
1040 (fd2in->revents)) {
1041 if (fd2in->revents & POLLNVAL) {
1042 Error1("poll(...[%d]: invalid request", fd2in->fd);
1043 free(buff);
1044 return -1;
1046 mayrd2 = true;
1048 if (XIO_GETWRFD(sock1) >= 0 && fd1out->fd >= 0 && fd1out->revents) {
1049 if (fd1out->revents & POLLNVAL) {
1050 Error1("poll(...[%d]: invalid request", fd1out->fd);
1051 free(buff);
1052 return -1;
1054 maywr1 = true;
1056 if (XIO_GETWRFD(sock2) >= 0 && fd2out->fd >= 0 && fd2out->revents) {
1057 if (fd2out->revents & POLLNVAL) {
1058 Error1("poll(...[%d]: invalid request", fd2out->fd);
1059 free(buff);
1060 return -1;
1062 maywr2 = true;
1065 if (mayrd1 && maywr2) {
1066 mayrd1 = false;
1067 if ((bytes1 = xiotransfer(sock1, sock2, buff, socat_opts.bufsiz, false))
1068 < 0) {
1069 if (errno != EAGAIN) {
1070 closing = MAX(closing, 1);
1071 Notice("socket 1 to socket 2 is in error");
1072 if (socat_opts.lefttoright) {
1073 break;
1076 } else if (bytes1 > 0) {
1077 maywr2 = false;
1078 total_timeout = socat_opts.total_timeout;
1079 wasaction = 1;
1080 /* is more data available that has already passed poll()? */
1081 mayrd1 = (xiopending(sock1) > 0);
1082 if (XIO_RDSTREAM(sock1)->readbytes != 0 &&
1083 XIO_RDSTREAM(sock1)->actbytes == 0) {
1084 /* avoid idle when all readbytes already there */
1085 mayrd1 = true;
1087 /* escape char occurred? */
1088 if (XIO_RDSTREAM(sock1)->actescape) {
1089 bytes1 = 0; /* indicate EOF */
1092 /* (bytes1 == 0) handled later */
1093 } else {
1094 bytes1 = -1;
1097 if (mayrd2 && maywr1) {
1098 mayrd2 = false;
1099 if ((bytes2 = xiotransfer(sock2, sock1, buff, socat_opts.bufsiz, true))
1100 < 0) {
1101 if (errno != EAGAIN) {
1102 closing = MAX(closing, 1);
1103 Notice("socket 2 to socket 1 is in error");
1104 if (socat_opts.righttoleft) {
1105 break;
1108 } else if (bytes2 > 0) {
1109 maywr1 = false;
1110 total_timeout = socat_opts.total_timeout;
1111 wasaction = 1;
1112 /* is more data available that has already passed poll()? */
1113 mayrd2 = (xiopending(sock2) > 0);
1114 if (XIO_RDSTREAM(sock2)->readbytes != 0 &&
1115 XIO_RDSTREAM(sock2)->actbytes == 0) {
1116 /* avoid idle when all readbytes already there */
1117 mayrd2 = true;
1119 /* escape char occurred? */
1120 if (XIO_RDSTREAM(sock2)->actescape) {
1121 bytes2 = 0; /* indicate EOF */
1124 /* (bytes2 == 0) handled later */
1125 } else {
1126 bytes2 = -1;
1129 /* NOW handle EOFs */
1131 /*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
1132 bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
1133 closing);*/
1134 if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
1135 if (XIO_RDSTREAM(sock1)->ignoreeof &&
1136 !XIO_RDSTREAM(sock1)->actescape && !closing) {
1137 Debug1("socket 1 (fd %d) is at EOF, ignoring",
1138 XIO_RDSTREAM(sock1)->fd); /*! */
1139 mayrd1 = true;
1140 polling = 1; /* do not hook this eof fd to poll for pollintv*/
1141 } else if (XIO_RDSTREAM(sock1)->eof <= 2) {
1142 Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
1143 xioshutdown(sock2, SHUT_WR);
1144 XIO_RDSTREAM(sock1)->eof = 3;
1145 XIO_RDSTREAM(sock1)->ignoreeof = false;
1147 } else if (polling && XIO_RDSTREAM(sock1)->ignoreeof) {
1148 polling = 0;
1150 if (XIO_RDSTREAM(sock1)->eof >= 2) {
1151 if (socat_opts.lefttoright) {
1152 break;
1154 closing = 1;
1157 if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
1158 if (XIO_RDSTREAM(sock2)->ignoreeof &&
1159 !XIO_RDSTREAM(sock2)->actescape && !closing) {
1160 Debug1("socket 2 (fd %d) is at EOF, ignoring",
1161 XIO_RDSTREAM(sock2)->fd);
1162 mayrd2 = true;
1163 polling = 1; /* do not hook this eof fd to poll for pollintv*/
1164 } else if (XIO_RDSTREAM(sock2)->eof <= 2) {
1165 Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
1166 xioshutdown(sock1, SHUT_WR);
1167 XIO_RDSTREAM(sock2)->eof = 3;
1168 XIO_RDSTREAM(sock2)->ignoreeof = false;
1170 } else if (polling && XIO_RDSTREAM(sock2)->ignoreeof) {
1171 polling = 0;
1173 if (XIO_RDSTREAM(sock2)->eof >= 2) {
1174 if (socat_opts.righttoleft) {
1175 break;
1177 closing = 1;
1181 /* close everything that's still open */
1182 xioclose(sock1);
1183 xioclose(sock2);
1185 free(buff);
1186 return 0;
1190 #define MAXTIMESTAMPLEN 128
1191 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
1192 should be at least MAXTIMESTAMPLEN bytes long.
1193 returns 0 on success or -1 if an error occurred */
1194 int gettimestamp(char *timestamp) {
1195 size_t bytes;
1196 #if HAVE_CLOCK_GETTIME
1197 struct timespec now;
1198 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1199 struct timeval now;
1200 #endif /* !HAVE_PROTOTYPE_LIB_gettimeofday */
1201 time_t nowt;
1202 int result;
1204 #if HAVE_CLOCK_GETTIME
1205 result = clock_gettime(CLOCK_REALTIME, &now);
1206 if (result < 0) {
1207 return result;
1209 nowt = now.tv_sec;
1210 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1211 result = Gettimeofday(&now, NULL);
1212 if (result < 0) {
1213 return result;
1215 nowt = now.tv_sec;
1216 #else
1217 nowt = time(NULL);
1218 if (nowt == (time_t)-1) {
1219 return -1;
1221 #endif
1222 #if HAVE_STRFTIME
1223 bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
1224 #if HAVE_CLOCK_GETTIME
1225 bytes += sprintf(timestamp+19, "."F_tv_nsec" ", now.tv_nsec/1000);
1226 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1227 bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
1228 #else
1229 strncpy(&timestamp[bytes++], " ", 2);
1230 #endif
1231 #else
1232 strcpy(timestamp, ctime(&nowt));
1233 bytes = strlen(timestamp);
1234 #endif
1235 return 0;
1238 static const char *prefixltor = "> ";
1239 static const char *prefixrtol = "< ";
1240 static unsigned long numltor;
1241 static unsigned long numrtol;
1242 /* print block header (during verbose or hex dump)
1243 returns 0 on success or -1 if an error occurred */
1244 static int
1245 xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
1246 char timestamp[MAXTIMESTAMPLEN];
1247 char buff[128+MAXTIMESTAMPLEN];
1248 if (gettimestamp(timestamp) < 0) {
1249 return -1;
1251 if (righttoleft) {
1252 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1253 prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
1254 numrtol+=bytes;
1255 } else {
1256 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1257 prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
1258 numltor+=bytes;
1260 fputs(buff, file);
1261 return 0;
1265 /* inpipe is suspected to have read data available; read at most bufsiz bytes
1266 and transfer them to outpipe. Perform required data conversions.
1267 buff must be a malloc()'ed storage and might be realloc()'ed in this
1268 function if more space is required after conversions.
1269 Returns the number of bytes written, or 0 on EOF or <0 if an
1270 error occurred or when data was read but none written due to conversions
1271 (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
1272 the file has a mandatory lock.
1273 If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
1274 does NOT write a zero bytes block.
1276 /* inpipe, outpipe must be single descriptors (not dual!) */
1277 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
1278 unsigned char *buff, size_t bufsiz, bool righttoleft) {
1279 ssize_t bytes, writt = 0;
1281 bytes = xioread(inpipe, buff, bufsiz);
1282 if (bytes < 0) {
1283 if (errno != EAGAIN)
1284 XIO_RDSTREAM(inpipe)->eof = 2;
1285 /*xioshutdown(inpipe, SHUT_RD);*/
1286 return -1;
1288 if (bytes == 0 && XIO_RDSTREAM(inpipe)->ignoreeof && !closing) {
1290 } else if (bytes == 0) {
1291 XIO_RDSTREAM(inpipe)->eof = 2;
1292 closing = MAX(closing, 1);
1295 if (bytes > 0) {
1296 /* handle escape char */
1297 if (XIO_RDSTREAM(inpipe)->escape != -1) {
1298 /* check input data for escape char */
1299 unsigned char *ptr = buff;
1300 size_t ctr = 0;
1301 while (ctr < bytes) {
1302 if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
1303 /* found: set flag, truncate input data */
1304 XIO_RDSTREAM(inpipe)->actescape = true;
1305 bytes = ctr;
1306 Info("escape char found in input");
1307 break;
1309 ++ptr; ++ctr;
1311 if (ctr != bytes) {
1312 XIO_RDSTREAM(inpipe)->eof = 2;
1317 if (bytes > 0) {
1319 if (XIO_RDSTREAM(inpipe)->lineterm !=
1320 XIO_WRSTREAM(outpipe)->lineterm) {
1321 cv_newline(buff, &bytes,
1322 XIO_RDSTREAM(inpipe)->lineterm,
1323 XIO_WRSTREAM(outpipe)->lineterm);
1325 if (bytes == 0) {
1326 errno = EAGAIN; return -1;
1329 if (!righttoleft && socat_opts.sniffleft >= 0) {
1330 Write(socat_opts.sniffleft, buff, bytes);
1331 } else if (righttoleft && socat_opts.sniffright >= 0) {
1332 Write(socat_opts.sniffright, buff, bytes);
1335 if (socat_opts.verbose && socat_opts.verbhex) {
1336 /* Hack-o-rama */
1337 size_t i = 0;
1338 size_t j;
1339 size_t N = 16;
1340 const unsigned char *end, *s, *t;
1341 s = buff;
1342 end = buff+bytes;
1343 xioprintblockheader(stderr, bytes, righttoleft);
1344 while (s < end) {
1345 /*! prefix? */
1346 j = Min(N, (size_t)(end-s));
1348 /* print hex */
1349 t = s;
1350 i = 0;
1351 while (i < j) {
1352 int c = *t++;
1353 fprintf(stderr, " %02x", c);
1354 ++i;
1355 if (c == '\n') break;
1358 /* fill hex column */
1359 while (i < N) {
1360 fputs(" ", stderr);
1361 ++i;
1363 fputs(" ", stderr);
1365 /* print acsii */
1366 t = s;
1367 i = 0;
1368 while (i < j) {
1369 int c = *t++;
1370 if (c == '\n') {
1371 fputc('.', stderr);
1372 break;
1374 if (!isprint(c))
1375 c = '.';
1376 fputc(c, stderr);
1377 ++i;
1380 fputc('\n', stderr);
1381 s = t;
1383 fputs("--\n", stderr);
1384 } else if (socat_opts.verbose) {
1385 size_t i = 0;
1386 xioprintblockheader(stderr, bytes, righttoleft);
1387 while (i < (size_t)bytes) {
1388 int c = buff[i];
1389 if (i > 0 && buff[i-1] == '\n')
1390 /*! prefix? */;
1391 switch (c) {
1392 case '\a' : fputs("\\a", stderr); break;
1393 case '\b' : fputs("\\b", stderr); break;
1394 case '\t' : fputs("\t", stderr); break;
1395 case '\n' : fputs("\n", stderr); break;
1396 case '\v' : fputs("\\v", stderr); break;
1397 case '\f' : fputs("\\f", stderr); break;
1398 case '\r' : fputs("\\r", stderr); break;
1399 case '\\' : fputs("\\\\", stderr); break;
1400 default:
1401 if (!isprint(c))
1402 c = '.';
1403 fputc(c, stderr);
1404 break;
1406 ++i;
1408 } else if (socat_opts.verbhex) {
1409 int i;
1410 /* print prefix */
1411 xioprintblockheader(stderr, bytes, righttoleft);
1412 for (i = 0; i < bytes; ++i) {
1413 fprintf(stderr, " %02x", buff[i]);
1415 fputc('\n', stderr);
1418 writt = xiowrite(outpipe, buff, bytes);
1419 if (writt < 0) {
1420 /* EAGAIN when nonblocking but a mandatory lock is on file.
1421 the problem with EAGAIN is that the read cannot be repeated,
1422 so we need to buffer the data and try to write it later
1423 again. not yet implemented, sorry. */
1424 #if 0
1425 if (errno == EPIPE) {
1426 return 0; /* can no longer write; handle like EOF */
1428 #endif
1429 return -1;
1430 } else {
1431 Info3("transferred "F_Zu" bytes from %d to %d",
1432 writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
1435 return writt;
1438 #define CR '\r'
1439 #define LF '\n'
1442 /* converts the newline characters (or character sequences) from the one
1443 specified in lineterm1 to that of lineterm2. Possible values are
1444 LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
1445 bytes specifies the number of bytes input and output */
1446 int cv_newline(unsigned char *buff, ssize_t *bytes,
1447 int lineterm1, int lineterm2) {
1448 /* must perform newline changes */
1449 if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
1450 /* no change in data length */
1451 unsigned char from, to, *p, *z;
1452 if (lineterm1 == LINETERM_RAW) {
1453 from = '\n'; to = '\r';
1454 } else {
1455 from = '\r'; to = '\n';
1457 z = buff + *bytes;
1458 p = buff;
1459 while (p < z) {
1460 if (*p == from) *p = to;
1461 ++p;
1464 } else if (lineterm1 == LINETERM_CRNL) {
1465 /* buffer might become shorter */
1466 unsigned char to, *s, *t, *z;
1467 if (lineterm2 == LINETERM_RAW) {
1468 to = '\n';
1469 } else {
1470 to = '\r';
1472 z = buff + *bytes;
1473 s = t = buff;
1474 while (s < z) {
1475 if (*s == '\r') {
1476 ++s;
1477 continue;
1479 if (*s == '\n') {
1480 *t++ = to; ++s;
1481 } else {
1482 *t++ = *s++;
1485 *bytes = t - buff;
1486 } else {
1487 /* buffer becomes longer (up to double length), must alloc another space */
1488 static unsigned char *buf2; /*! not threadsafe */
1489 unsigned char from; unsigned char *s, *t, *z;
1491 if (lineterm1 == LINETERM_RAW) {
1492 from = '\n';
1493 } else {
1494 from = '\r';
1496 if (buf2 == NULL) {
1497 if ((buf2 = Malloc(socat_opts.bufsiz)) == NULL) {
1498 return -1;
1501 memcpy(buf2, buff, *bytes);
1502 s = buf2; t = buff; z = buf2 + *bytes;
1503 while (s < z) {
1504 if (*s == from) {
1505 *t++ = '\r'; *t++ = '\n';
1506 ++s;
1507 continue;
1508 } else {
1509 *t++ = *s++;
1512 *bytes = t - buff;;
1514 return 0;
1517 void socat_signal(int signum) {
1518 int _errno;
1519 _errno = errno;
1520 diag_in_handler = 1;
1521 Notice1("socat_signal(): handling signal %d", signum);
1522 switch (signum) {
1523 case SIGILL:
1524 case SIGABRT:
1525 case SIGBUS:
1526 case SIGFPE:
1527 case SIGSEGV:
1528 diag_immediate_exit = 1;
1529 case SIGQUIT:
1530 case SIGPIPE:
1531 diag_set_int('x', 128+signum); /* in case Error exits for us */
1532 Error1("exiting on signal %d", signum);
1533 diag_set_int('x', 0); /* in case Error did not exit */
1534 break;
1535 case SIGTERM:
1536 Warn1("exiting on signal %d", signum); break;
1537 case SIGHUP:
1538 case SIGINT:
1539 Notice1("exiting on signal %d", signum); break;
1541 //Exit(128+signum);
1542 Notice1("socat_signal(): finishing signal %d", signum);
1543 diag_exit(128+signum); /*!!! internal cleanup + _exit() */
1544 diag_in_handler = 0;
1545 errno = _errno;
1548 /* this is the callback when the child of an address died */
1549 static int socat_sigchild(struct single *file) {
1550 if (file->ignoreeof && !closing) {
1552 } else {
1553 file->eof = MAX(file->eof, 1);
1554 closing = 1;
1556 return 0;
1559 static int socat_lock(void) {
1560 int lockrc;
1562 #if 1
1563 if ((lockrc = xiolock(&socat_opts.lock)) < 0) {
1564 return -1;
1566 if (lockrc == 0) {
1567 havelock = true;
1569 return lockrc;
1570 #else
1571 if (socat_opts.lock.lockfile) {
1572 if ((lockrc = xiolock(socat_opts.lock.lockfile)) < 0) {
1573 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1574 return -1;
1576 if (lockrc) {
1577 return 1;
1579 havelock = true;
1580 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/
1583 if (socat_opts.lock.waitlock) {
1584 if (xiowaitlock(socat_opts.lock.waitlock, socat_opts.lock.intervall)) {
1585 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1586 return -1;
1587 } else {
1588 havelock = true;
1589 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1592 return 0;
1593 #endif
1596 static void socat_unlock(void) {
1597 if (!havelock) return;
1598 if (socat_opts.lock.lockfile) {
1599 if (Unlink(socat_opts.lock.lockfile) < 0) {
1600 if (!diag_in_handler) {
1601 Warn2("unlink(\"%s\"): %s",
1602 socat_opts.lock.lockfile, strerror(errno));
1603 } else {
1604 Warn1("unlink(\"%s\"): "F_strerror,
1605 socat_opts.lock.lockfile);
1607 } else {
1608 Info1("released lock \"%s\"", socat_opts.lock.lockfile);
1613 /* this is a callback function that may be called by the newchild hook of xio
1615 static int socat_newchild(void) {
1616 havelock = false;
1617 return 0;