GOPEN handles UNIX seqpacket sockets
[socat.git] / socat.c
blob3e94c78e96db3ea55c8ea80b732716b651927085
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 xiolock_t lock; /* a lock file */
40 } socat_opts = {
41 8192, /* bufsiz */
42 false, /* verbose */
43 false, /* verbhex */
44 {1,0}, /* pollintv */
45 {0,500000}, /* closwait */
46 {0,0}, /* total_timeout */
47 0, /* debug */
48 0, /* strictopts */
49 's', /* logopt */
50 false, /* lefttoright */
51 false, /* righttoleft */
52 { NULL, 0 }, /* lock */
55 void socat_usage(FILE *fd);
56 void socat_opt_hint(FILE *fd, char a, char b);
57 void socat_version(FILE *fd);
58 int socat(const char *address1, const char *address2);
59 int _socat(void);
60 int cv_newline(unsigned char *buff, ssize_t *bytes, int lineterm1, int lineterm2);
61 void socat_signal(int sig);
62 static int socat_sigchild(struct single *file);
64 void lftocrlf(char **in, ssize_t *len, size_t bufsiz);
65 void crlftolf(char **in, ssize_t *len, size_t bufsiz);
67 static int socat_lock(void);
68 static void socat_unlock(void);
69 static int socat_newchild(void);
71 static const char socatversion[] =
72 #include "./VERSION"
74 static const char timestamp[] = BUILD_DATE;
76 const char copyright_socat[] = "socat by Gerhard Rieger and contributors - see www.dest-unreach.org";
77 #if WITH_OPENSSL
78 const char copyright_openssl[] = "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)";
79 const char copyright_ssleay[] = "This product includes software written by Tim Hudson (tjh@cryptsoft.com)";
80 #endif
82 bool havelock;
85 int main(int argc, const char *argv[]) {
86 const char **arg1, *a;
87 char *mainwaitstring;
88 char buff[10];
89 double rto;
90 int i, argc0, result;
91 struct utsname ubuf;
92 int lockrc;
94 if (mainwaitstring = getenv("SOCAT_MAIN_WAIT")) {
95 sleep(atoi(mainwaitstring));
97 diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
99 /* we must init before applying options because env settings have lower
100 priority and are to be overridden by options */
101 if (xioinitialize() != 0) {
102 Exit(1);
105 xiosetopt('p', "!!");
106 xiosetopt('o', ":");
108 argc0 = argc; /* save for later use */
109 arg1 = argv+1; --argc;
110 while (arg1[0] && (arg1[0][0] == '-')) {
111 switch (arg1[0][1]) {
112 case 'V': if (arg1[0][2]) { socat_usage(stderr); Exit(1); }
113 socat_version(stdout); Exit(0);
114 #if WITH_HELP
115 case '?':
116 case 'h':
117 socat_usage(stdout);
118 xioopenhelp(stdout, (arg1[0][2]=='?'||arg1[0][2]=='h') ? (arg1[0][3]=='?'||arg1[0][3]=='h') ? 2 : 1 : 0);
119 Exit(0);
120 #endif /* WITH_HELP */
121 case 'd':
122 a = *arg1+1;
123 while (*a) {
124 if (*a == 'd') {
125 diag_set('d', NULL);
126 } else {
127 socat_usage(stderr);
128 Exit(1);
130 ++a;
132 break;
133 #if WITH_FILAN
134 case 'D': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
135 socat_opts.debug = true; break;
136 #endif
137 case 'l':
138 switch (arg1[0][2]) {
139 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
140 diag_set('s', NULL);
141 xiosetopt('l', "m");
142 socat_opts.logopt = arg1[0][2];
143 xiosetopt('y', &arg1[0][3]);
144 break;
145 case 'y': /* syslog + facility */
146 diag_set(arg1[0][2], &arg1[0][3]);
147 break;
148 case 'f': /* to file, +filename */
149 case 'p': /* artificial program name */
150 if (arg1[0][3]) {
151 diag_set(arg1[0][2], &arg1[0][3]);
152 } else if (arg1[1]) {
153 diag_set(arg1[0][2], arg1[1]);
154 ++arg1, --argc;
155 } else {
156 Error1("option -l%c requires an argument; use option \"-h\" for help", arg1[0][2]);
158 break;
159 case 's': /* stderr */
160 diag_set(arg1[0][2], NULL);
161 break;
162 case 'u':
163 diag_set('u', NULL);
164 break;
165 case 'h':
166 diag_set_int('h', true);
167 break;
168 default:
169 Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1[0]);
170 break;
172 break;
173 case 'v': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
174 socat_opts.verbose = true; break;
175 case 'x': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
176 socat_opts.verbhex = true; break;
177 case 'b': if (arg1[0][2]) {
178 a = *arg1+2;
179 } else {
180 ++arg1, --argc;
181 if ((a = *arg1) == NULL) {
182 Error("option -b requires an argument; use option \"-h\" for help");
183 Exit(1);
186 socat_opts.bufsiz = strtoul(a, (char **)&a, 0);
187 break;
188 case 's': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
189 diag_set_int('e', E_FATAL); break;
190 case 't': if (arg1[0][2]) {
191 a = *arg1+2;
192 } else {
193 ++arg1, --argc;
194 if ((a = *arg1) == NULL) {
195 Error("option -t requires an argument; use option \"-h\" for help");
196 Exit(1);
199 rto = strtod(a, (char **)&a);
200 socat_opts.closwait.tv_sec = rto;
201 socat_opts.closwait.tv_usec =
202 (rto-socat_opts.closwait.tv_sec) * 1000000;
203 break;
204 case 'T': if (arg1[0][2]) {
205 a = *arg1+2;
206 } else {
207 ++arg1, --argc;
208 if ((a = *arg1) == NULL) {
209 Error("option -T requires an argument; use option \"-h\" for help");
210 Exit(1);
213 rto = strtod(a, (char **)&a);
214 socat_opts.total_timeout.tv_sec = rto;
215 socat_opts.total_timeout.tv_usec =
216 (rto-socat_opts.total_timeout.tv_sec) * 1000000;
217 break;
218 case 'u': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
219 socat_opts.lefttoright = true; break;
220 case 'U': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
221 socat_opts.righttoleft = true; break;
222 case 'g': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
223 xioopts_ignoregroups = true; break;
224 case 'L': if (socat_opts.lock.lockfile)
225 Error("only one -L and -W option allowed");
226 if (arg1[0][2]) {
227 socat_opts.lock.lockfile = *arg1+2;
228 } else {
229 ++arg1, --argc;
230 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
231 Error("option -L requires an argument; use option \"-h\" for help");
232 Exit(1);
235 break;
236 case 'W': if (socat_opts.lock.lockfile)
237 Error("only one -L and -W option allowed");
238 if (arg1[0][2]) {
239 socat_opts.lock.lockfile = *arg1+2;
240 } else {
241 ++arg1, --argc;
242 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
243 Error("option -W requires an argument; use option \"-h\" for help");
244 Exit(1);
247 socat_opts.lock.waitlock = true;
248 socat_opts.lock.intervall.tv_sec = 1;
249 socat_opts.lock.intervall.tv_nsec = 0;
250 break;
251 #if WITH_IP4 || WITH_IP6
252 #if WITH_IP4
253 case '4':
254 #endif
255 #if WITH_IP6
256 case '6':
257 #endif
258 if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
259 xioopts.default_ip = arg1[0][1];
260 xioopts.preferred_ip = arg1[0][1];
261 break;
262 #endif /* WITH_IP4 || WITH_IP6 */
263 case '\0':
264 case ',':
265 case ':': break; /* this "-" is a variation of STDIO */
266 default:
267 xioinqopt('p', buff, sizeof(buff));
268 if (arg1[0][1] == buff[0]) {
269 break;
271 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
272 Exit(1);
274 /* the leading "-" might be a form of the first address */
275 xioinqopt('p', buff, sizeof(buff));
276 if (arg1[0][0] == '-' &&
277 (arg1[0][1] == '\0' || arg1[0][1] == ':' ||
278 arg1[0][1] == ',' || arg1[0][1] == buff[0]))
279 break;
280 ++arg1; --argc;
282 if (argc != 2) {
283 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
284 Exit(1);
286 if (socat_opts.lefttoright && socat_opts.righttoleft) {
287 Error("-U and -u must not be combined");
290 xioinitialize2();
291 Info(copyright_socat);
292 #if WITH_OPENSSL
293 Info(copyright_openssl);
294 Info(copyright_ssleay);
295 #endif
296 Debug2("socat version %s on %s", socatversion, timestamp);
297 xiosetenv("VERSION", socatversion, 1, NULL); /* SOCAT_VERSION */
298 uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */
299 Debug4("running on %s version %s, release %s, machine %s\n",
300 ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
302 #if WITH_MSGLEVEL <= E_DEBUG
303 for (i = 0; i < argc0; ++i) {
304 Debug2("argv[%d]: \"%s\"", i, argv[i]);
306 #endif /* WITH_MSGLEVEL <= E_DEBUG */
309 struct sigaction act;
310 sigfillset(&act.sa_mask);
311 act.sa_flags = 0;
312 act.sa_handler = socat_signal;
313 /* not sure which signals should be caught and print a message */
314 Sigaction(SIGHUP, &act, NULL);
315 Sigaction(SIGINT, &act, NULL);
316 Sigaction(SIGQUIT, &act, NULL);
317 Sigaction(SIGILL, &act, NULL);
318 Sigaction(SIGABRT, &act, NULL);
319 Sigaction(SIGBUS, &act, NULL);
320 Sigaction(SIGFPE, &act, NULL);
321 Sigaction(SIGSEGV, &act, NULL);
322 Sigaction(SIGTERM, &act, NULL);
324 Signal(SIGPIPE, SIG_IGN);
326 /* set xio hooks */
327 xiohook_newchild = &socat_newchild;
329 if (lockrc = socat_lock()) {
330 /* =0: goon; >0: locked; <0: error, printed in sub */
331 if (lockrc > 0)
332 Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile);
333 Exit(1);
336 Atexit(socat_unlock);
338 result = socat(arg1[0], arg1[1]);
339 Notice1("exiting with status %d", result);
340 Exit(result);
341 return 0; /* not reached, just for gcc -Wall */
345 void socat_usage(FILE *fd) {
346 fputs(copyright_socat, fd); fputc('\n', fd);
347 fputs("Usage:\n", fd);
348 fputs("socat [options] <bi-address> <bi-address>\n", fd);
349 fputs(" options:\n", fd);
350 fputs(" -V print version and feature information to stdout, and exit\n", fd);
351 #if WITH_HELP
352 fputs(" -h|-? print a help text describing command line options and addresses\n", fd);
353 fputs(" -hh like -h, plus a list of all common address option names\n", fd);
354 fputs(" -hhh like -hh, plus a list of all available address option names\n", fd);
355 #endif /* WITH_HELP */
356 fputs(" -d[ddd] increase verbosity (use up to 4 times; 2 are recommended)\n", fd);
357 #if WITH_FILAN
358 fputs(" -D analyze file descriptors before loop\n", fd);
359 #endif
360 fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd);
361 fputs(" -lf<logfile> log to file\n", fd);
362 fputs(" -ls log to stderr (default if no other log)\n", fd);
363 fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd);
364 fputs(" -lp<progname> set the program name used for logging\n", fd);
365 fputs(" -lu use microseconds for logging timestamps\n", fd);
366 fputs(" -lh add hostname to log messages\n", fd);
367 fputs(" -v verbose data traffic, text\n", fd);
368 fputs(" -x verbose data traffic, hexadecimal\n", fd);
369 fputs(" -b<size_t> set data buffer size (8192)\n", fd);
370 fputs(" -s sloppy (continue on error)\n", fd);
371 fputs(" -t<timeout> wait seconds before closing second channel\n", fd);
372 fputs(" -T<timeout> total inactivity timeout in seconds\n", fd);
373 fputs(" -u unidirectional mode (left to right)\n", fd);
374 fputs(" -U unidirectional mode (right to left)\n", fd);
375 fputs(" -g do not check option groups\n", fd);
376 fputs(" -L <lockfile> try to obtain lock, or fail\n", fd);
377 fputs(" -W <lockfile> try to obtain lock, or wait\n", fd);
378 #if WITH_IP4
379 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd);
380 #endif
381 #if WITH_IP6
382 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd);
383 #endif
386 void socat_opt_hint(FILE *fd, char a, char b) {
387 fprintf(fd, "Do not merge single character options, i.e. use \"-%c -%c\" instead of \"-%c%c\"\n",
388 a, b, a, b);
392 void socat_version(FILE *fd) {
393 struct utsname ubuf;
395 fputs(copyright_socat, fd); fputc('\n', fd);
396 fprintf(fd, "socat version %s on %s\n", socatversion, timestamp);
397 Uname(&ubuf);
398 fprintf(fd, " running on %s version %s, release %s, machine %s\n",
399 ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
400 fputs("features:\n", fd);
401 #ifdef WITH_STDIO
402 fprintf(fd, " #define WITH_STDIO %d\n", WITH_STDIO);
403 #else
404 fputs(" #undef WITH_STDIO\n", fd);
405 #endif
406 #ifdef WITH_FDNUM
407 fprintf(fd, " #define WITH_FDNUM %d\n", WITH_FDNUM);
408 #else
409 fputs(" #undef WITH_FDNUM\n", fd);
410 #endif
411 #ifdef WITH_FILE
412 fprintf(fd, " #define WITH_FILE %d\n", WITH_FILE);
413 #else
414 fputs(" #undef WITH_FILE\n", fd);
415 #endif
416 #ifdef WITH_CREAT
417 fprintf(fd, " #define WITH_CREAT %d\n", WITH_CREAT);
418 #else
419 fputs(" #undef WITH_CREAT\n", fd);
420 #endif
421 #ifdef WITH_GOPEN
422 fprintf(fd, " #define WITH_GOPEN %d\n", WITH_GOPEN);
423 #else
424 fputs(" #undef WITH_GOPEN\n", fd);
425 #endif
426 #ifdef WITH_TERMIOS
427 fprintf(fd, " #define WITH_TERMIOS %d\n", WITH_TERMIOS);
428 #else
429 fputs(" #undef WITH_TERMIOS\n", fd);
430 #endif
431 #ifdef WITH_PIPE
432 fprintf(fd, " #define WITH_PIPE %d\n", WITH_PIPE);
433 #else
434 fputs(" #undef WITH_PIPE\n", fd);
435 #endif
436 #ifdef WITH_UNIX
437 fprintf(fd, " #define WITH_UNIX %d\n", WITH_UNIX);
438 #else
439 fputs(" #undef WITH_UNIX\n", fd);
440 #endif /* WITH_UNIX */
441 #ifdef WITH_ABSTRACT_UNIXSOCKET
442 fprintf(fd, " #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET);
443 #else
444 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd);
445 #endif /* WITH_ABSTRACT_UNIXSOCKET */
446 #ifdef WITH_IP4
447 fprintf(fd, " #define WITH_IP4 %d\n", WITH_IP4);
448 #else
449 fputs(" #undef WITH_IP4\n", fd);
450 #endif
451 #ifdef WITH_IP6
452 fprintf(fd, " #define WITH_IP6 %d\n", WITH_IP6);
453 #else
454 fputs(" #undef WITH_IP6\n", fd);
455 #endif
456 #ifdef WITH_RAWIP
457 fprintf(fd, " #define WITH_RAWIP %d\n", WITH_RAWIP);
458 #else
459 fputs(" #undef WITH_RAWIP\n", fd);
460 #endif
461 #ifdef WITH_GENERICSOCKET
462 fprintf(fd, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET);
463 #else
464 fputs(" #undef WITH_GENERICSOCKET\n", fd);
465 #endif
466 #ifdef WITH_INTERFACE
467 fprintf(fd, " #define WITH_INTERFACE %d\n", WITH_INTERFACE);
468 #else
469 fputs(" #undef WITH_INTERFACE\n", fd);
470 #endif
471 #ifdef WITH_TCP
472 fprintf(fd, " #define WITH_TCP %d\n", WITH_TCP);
473 #else
474 fputs(" #undef WITH_TCP\n", fd);
475 #endif
476 #ifdef WITH_UDP
477 fprintf(fd, " #define WITH_UDP %d\n", WITH_UDP);
478 #else
479 fputs(" #undef WITH_UDP\n", fd);
480 #endif
481 #ifdef WITH_SCTP
482 fprintf(fd, " #define WITH_SCTP %d\n", WITH_SCTP);
483 #else
484 fputs(" #undef WITH_SCTP\n", fd);
485 #endif
486 #ifdef WITH_LISTEN
487 fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN);
488 #else
489 fputs(" #undef WITH_LISTEN\n", fd);
490 #endif
491 #ifdef WITH_SOCKS4
492 fprintf(fd, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4);
493 #else
494 fputs(" #undef WITH_SOCKS4\n", fd);
495 #endif
496 #ifdef WITH_SOCKS4A
497 fprintf(fd, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A);
498 #else
499 fputs(" #undef WITH_SOCKS4A\n", fd);
500 #endif
501 #ifdef WITH_PROXY
502 fprintf(fd, " #define WITH_PROXY %d\n", WITH_PROXY);
503 #else
504 fputs(" #undef WITH_PROXY\n", fd);
505 #endif
506 #ifdef WITH_SYSTEM
507 fprintf(fd, " #define WITH_SYSTEM %d\n", WITH_SYSTEM);
508 #else
509 fputs(" #undef WITH_SYSTEM\n", fd);
510 #endif
511 #ifdef WITH_EXEC
512 fprintf(fd, " #define WITH_EXEC %d\n", WITH_EXEC);
513 #else
514 fputs(" #undef WITH_EXEC\n", fd);
515 #endif
516 #ifdef WITH_READLINE
517 fprintf(fd, " #define WITH_READLINE %d\n", WITH_READLINE);
518 #else
519 fputs(" #undef WITH_READLINE\n", fd);
520 #endif
521 #ifdef WITH_TUN
522 fprintf(fd, " #define WITH_TUN %d\n", WITH_TUN);
523 #else
524 fputs(" #undef WITH_TUN\n", fd);
525 #endif
526 #ifdef WITH_PTY
527 fprintf(fd, " #define WITH_PTY %d\n", WITH_PTY);
528 #else
529 fputs(" #undef WITH_PTY\n", fd);
530 #endif
531 #ifdef WITH_OPENSSL
532 fprintf(fd, " #define WITH_OPENSSL %d\n", WITH_OPENSSL);
533 #else
534 fputs(" #undef WITH_OPENSSL\n", fd);
535 #endif
536 #ifdef WITH_FIPS
537 fprintf(fd, " #define WITH_FIPS %d\n", WITH_FIPS);
538 #else
539 fputs(" #undef WITH_FIPS\n", fd);
540 #endif
541 #ifdef WITH_LIBWRAP
542 fprintf(fd, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP);
543 #else
544 fputs(" #undef WITH_LIBWRAP\n", fd);
545 #endif
546 #ifdef WITH_SYCLS
547 fprintf(fd, " #define WITH_SYCLS %d\n", WITH_SYCLS);
548 #else
549 fputs(" #undef WITH_SYCLS\n", fd);
550 #endif
551 #ifdef WITH_FILAN
552 fprintf(fd, " #define WITH_FILAN %d\n", WITH_FILAN);
553 #else
554 fputs(" #undef WITH_FILAN\n", fd);
555 #endif
556 #ifdef WITH_RETRY
557 fprintf(fd, " #define WITH_RETRY %d\n", WITH_RETRY);
558 #else
559 fputs(" #undef WITH_RETRY\n", fd);
560 #endif
561 #ifdef WITH_MSGLEVEL
562 fprintf(fd, " #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL,
563 &"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL<<3]);
564 #else
565 fputs(" #undef WITH_MSGLEVEL\n", fd);
566 #endif
570 xiofile_t *sock1, *sock2;
571 int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
572 2..counting down closing timeout */
574 /* call this function when the common command line options are parsed, and the
575 addresses are extracted (but not resolved). */
576 int socat(const char *address1, const char *address2) {
577 int mayexec;
579 if (socat_opts.lefttoright) {
580 if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
581 return -1;
583 xiosetsigchild(sock1, socat_sigchild);
584 } else if (socat_opts.righttoleft) {
585 if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
586 return -1;
588 xiosetsigchild(sock1, socat_sigchild);
589 } else {
590 if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
591 return -1;
593 xiosetsigchild(sock1, socat_sigchild);
595 #if 1 /*! */
596 if (XIO_READABLE(sock1) &&
597 (XIO_RDSTREAM(sock1)->howtoend == END_KILL ||
598 XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL ||
599 XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) {
600 int i;
601 for (i = 0; i < NUMUNKNOWN; ++i) {
602 if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown[i]) {
603 /* child has alread died... but it might have put regular data into
604 the communication channel, so continue */
605 Info2("child "F_pid" has already died with status %d",
606 XIO_RDSTREAM(sock1)->para.exec.pid, statunknown[i]);
607 if (statunknown[i] != 0) {
608 return 1;
610 diedunknown[i] = 0;
611 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
612 /* return STAT_RETRYLATER; */
616 #endif
618 mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC);
619 if (XIO_WRITABLE(sock1)) {
620 if (XIO_READABLE(sock1)) {
621 if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
622 return -1;
624 xiosetsigchild(sock2, socat_sigchild);
625 } else {
626 if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
627 return -1;
629 xiosetsigchild(sock2, socat_sigchild);
631 } else { /* assuming sock1 is readable */
632 if ((sock2 = xioopen(address2, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
633 return -1;
635 xiosetsigchild(sock2, socat_sigchild);
637 #if 1 /*! */
638 if (XIO_READABLE(sock2) &&
639 (XIO_RDSTREAM(sock2)->howtoend == END_KILL ||
640 XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL ||
641 XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) {
642 int i;
643 for (i = 0; i < NUMUNKNOWN; ++i) {
644 if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown[i]) {
645 /* child has alread died... but it might have put regular data into
646 the communication channel, so continue */
647 Info2("child "F_pid" has already died with status %d",
648 XIO_RDSTREAM(sock2)->para.exec.pid, statunknown[i]);
649 if (statunknown[i] != 0) {
650 return 1;
652 diedunknown[i] = 0;
653 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
654 /* return STAT_RETRYLATER; */
658 #endif
660 Info("resolved and opened all sock addresses");
661 return
662 _socat(); /* nsocks, sockets are visible outside function */
665 /* checks if this is a connection to a child process, and if so, sees if the
666 child already died, leaving some data for us.
667 returns <0 if an error occurred;
668 returns 0 if no child or not yet died or died without data (sets eof);
669 returns >0 if child died and left data
671 int childleftdata(xiofile_t *xfd) {
672 struct pollfd in;
673 int retval;
675 /* have to check if a child process died before, but left read data */
676 if (XIO_READABLE(xfd) &&
677 (XIO_RDSTREAM(xfd)->howtoend == END_KILL ||
678 XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL ||
679 XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) &&
680 XIO_RDSTREAM(xfd)->para.exec.pid == 0) {
681 struct timeval timeout = { 0, 0 };
683 if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
684 in.fd = XIO_GETRDFD(xfd);
685 in.events = POLLIN/*|POLLRDBAND*/;
686 in.revents = 0;
688 do {
689 int _errno;
690 retval = xiopoll(&in, 1, &timeout);
691 _errno = errno; diag_flush(); errno = _errno; /* just in case it's not debug level and Msg() not been called */
692 } while (retval < 0 && errno == EINTR);
694 if (retval < 0) {
695 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
696 in.fd, in.events, timeout.tv_sec, timeout.tv_usec,
697 strerror(errno));
698 return -1;
700 if (retval == 0) {
701 Info("terminated child did not leave data for us");
702 XIO_RDSTREAM(xfd)->eof = 2;
703 xfd->stream.eof = 2;
704 closing = MAX(closing, 1);
707 return 0;
710 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
711 unsigned char *buff, size_t bufsiz, bool righttoleft);
713 bool mayrd1; /* sock1 has read data or eof, according to poll() */
714 bool mayrd2; /* sock2 has read data or eof, according to poll() */
715 bool maywr1; /* sock1 can be written to, according to poll() */
716 bool maywr2; /* sock2 can be written to, according to poll() */
718 /* here we come when the sockets are opened (in the meaning of C language),
719 and their options are set/applied
720 returns -1 on error or 0 on success */
721 int _socat(void) {
722 struct pollfd fds[4],
723 *fd1in = &fds[0],
724 *fd1out = &fds[1],
725 *fd2in = &fds[2],
726 *fd2out = &fds[3];
727 int retval;
728 unsigned char *buff;
729 ssize_t bytes1, bytes2;
730 int polling = 0; /* handling ignoreeof */
731 int wasaction = 1; /* last poll was active, do NOT sleep before next */
732 struct timeval total_timeout; /* the actual total timeout timer */
734 #if WITH_FILAN
735 if (socat_opts.debug) {
736 int fdi, fdo;
737 int msglevel, exitlevel;
739 msglevel = diag_get_int('D'); /* save current message level */
740 diag_set_int('D', E_ERROR); /* only print errors and fatals in filan */
741 exitlevel = diag_get_int('e'); /* save current exit level */
742 diag_set_int('e', E_FATAL); /* only exit on fatals */
744 fdi = XIO_GETRDFD(sock1);
745 fdo = XIO_GETWRFD(sock1);
746 filan_fd(fdi, stderr);
747 if (fdo != fdi) {
748 filan_fd(fdo, stderr);
751 fdi = XIO_GETRDFD(sock2);
752 fdo = XIO_GETWRFD(sock2);
753 filan_fd(fdi, stderr);
754 if (fdo != fdi) {
755 filan_fd(fdo, stderr);
758 diag_set_int('e', exitlevel); /* restore old exit level */
759 diag_set_int('D', msglevel); /* restore old message level */
761 #endif /* WITH_FILAN */
763 /* when converting nl to crnl, size might double */
764 if (socat_opts.bufsiz > (SIZE_MAX-1)/2) {
765 Error2("buffer size option (-b) to big - "F_Zu" (max is "F_Zu")", socat_opts.bufsiz, (SIZE_MAX-1)/2);
766 socat_opts.bufsiz = (SIZE_MAX-1)/2;
769 #if HAVE_PROTOTYPE_LIB_posix_memalign
770 /* Operations on files with flag O_DIRECT might need buffer alignment.
771 Without this, eg.read() fails with "Invalid argument" */
773 int _errno;
774 if ((_errno = Posix_memalign((void **)&buff, getpagesize(), 2*socat_opts.bufsiz+1)) != 0) {
775 Error1("posix_memalign(): %s", strerror(_errno));
776 return -1;
779 #else /* !HAVE_PROTOTYPE_LIB_posix_memalign */
780 buff = Malloc(2*socat_opts.bufsiz+1);
781 if (buff == NULL) return -1;
782 #endif /* !HAVE_PROTOTYPE_LIB_posix_memalign */
784 if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
785 Info("switching to syslog");
786 diag_set('y', xioopts.syslogfac);
787 xiosetopt('l', "\0");
789 total_timeout = socat_opts.total_timeout;
791 Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
792 XIO_GETRDFD(sock1), XIO_GETWRFD(sock1),
793 XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
794 while (XIO_RDSTREAM(sock1)->eof <= 1 ||
795 XIO_RDSTREAM(sock2)->eof <= 1) {
796 struct timeval timeout, *to = NULL;
798 Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}",
799 XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof,
800 closing, wasaction,
801 total_timeout.tv_sec, total_timeout.tv_usec);
803 /* for ignoreeof */
804 if (polling) {
805 if (!wasaction) {
806 if (socat_opts.total_timeout.tv_sec != 0 ||
807 socat_opts.total_timeout.tv_usec != 0) {
808 if (total_timeout.tv_usec < socat_opts.pollintv.tv_usec) {
809 total_timeout.tv_usec += 1000000;
810 total_timeout.tv_sec -= 1;
812 total_timeout.tv_sec -= socat_opts.pollintv.tv_sec;
813 total_timeout.tv_usec -= socat_opts.pollintv.tv_usec;
814 if (total_timeout.tv_sec < 0 ||
815 total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) {
816 Notice("inactivity timeout triggered");
817 free(buff);
818 return 0;
822 } else {
823 wasaction = 0;
827 if (polling) {
828 /* there is a ignoreeof poll timeout, use it */
829 timeout = socat_opts.pollintv;
830 to = &timeout;
831 } else if (socat_opts.total_timeout.tv_sec != 0 ||
832 socat_opts.total_timeout.tv_usec != 0) {
833 /* there might occur a total inactivity timeout */
834 timeout = socat_opts.total_timeout;
835 to = &timeout;
836 } else {
837 to = NULL;
840 if (closing>=1) {
841 /* first eof already occurred, start end timer */
842 timeout = socat_opts.pollintv;
843 to = &timeout;
844 closing = 2;
847 /* frame 1: set the poll parameters and loop over poll() EINTR) */
848 do { /* loop over poll() EINTR */
849 int _errno;
851 childleftdata(sock1);
852 childleftdata(sock2);
854 if (closing>=1) {
855 /* first eof already occurred, start end timer */
856 timeout = socat_opts.closwait;
857 to = &timeout;
858 closing = 2;
861 /* use the ignoreeof timeout if appropriate */
862 if (polling) {
863 if (closing == 0 ||
864 (socat_opts.pollintv.tv_sec < timeout.tv_sec) ||
865 ((socat_opts.pollintv.tv_sec == timeout.tv_sec) &&
866 socat_opts.pollintv.tv_usec < timeout.tv_usec)) {
867 timeout = socat_opts.pollintv;
871 /* now the fds will be assigned */
872 if (XIO_READABLE(sock1) &&
873 !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
874 !socat_opts.righttoleft) {
875 if (!mayrd1 && !(XIO_RDSTREAM(sock1)->eof > 1)) {
876 fd1in->fd = XIO_GETRDFD(sock1);
877 fd1in->events = POLLIN;
878 } else {
879 fd1in->fd = -1;
881 if (!maywr2) {
882 fd2out->fd = XIO_GETWRFD(sock2);
883 fd2out->events = POLLOUT;
884 } else {
885 fd2out->fd = -1;
887 } else {
888 fd1in->fd = -1;
889 fd2out->fd = -1;
891 if (XIO_READABLE(sock2) &&
892 !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
893 !socat_opts.lefttoright) {
894 if (!mayrd2 && !(XIO_RDSTREAM(sock2)->eof > 1)) {
895 fd2in->fd = XIO_GETRDFD(sock2);
896 fd2in->events = POLLIN;
897 } else {
898 fd2in->fd = -1;
900 if (!maywr1) {
901 fd1out->fd = XIO_GETWRFD(sock1);
902 fd1out->events = POLLOUT;
903 } else {
904 fd1out->fd = -1;
906 } else {
907 fd1out->fd = -1;
908 fd2in->fd = -1;
910 /* frame 0: innermost part of the transfer loop: check FD status */
911 retval = xiopoll(fds, 4, to);
912 if (retval >= 0 || errno != EINTR) {
913 break;
915 _errno = errno;
916 Info1("poll(): %s", strerror(errno));
917 errno = _errno;
918 } while (true);
920 /* attention:
921 when an exec'd process sends data and terminates, it is unpredictable
922 whether the data or the sigchild arrives first.
925 if (retval < 0) {
926 Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec"."F_tv_usec"}): %s",
927 fds[0].fd, fds[0].events, fds[1].fd, fds[1].events,
928 fds[2].fd, fds[2].events, fds[3].fd, fds[3].events,
929 timeout.tv_sec, timeout.tv_usec, strerror(errno));
930 free(buff);
931 return -1;
932 } else if (retval == 0) {
933 Info2("poll timed out (no data within %ld.%06ld seconds)",
934 closing>=1?socat_opts.closwait.tv_sec:socat_opts.total_timeout.tv_sec,
935 closing>=1?socat_opts.closwait.tv_usec:socat_opts.total_timeout.tv_usec);
936 if (polling && !wasaction) {
937 /* there was a ignoreeof poll timeout, use it */
938 polling = 0; /*%%%*/
939 if (XIO_RDSTREAM(sock1)->ignoreeof) {
940 mayrd1 = 0;
942 if (XIO_RDSTREAM(sock2)->ignoreeof) {
943 mayrd2 = 0;
945 } else if (polling && wasaction) {
946 wasaction = 0;
948 } else if (socat_opts.total_timeout.tv_sec != 0 ||
949 socat_opts.total_timeout.tv_usec != 0) {
950 /* there was a total inactivity timeout */
951 Notice("inactivity timeout triggered");
952 free(buff);
953 return 0;
956 if (closing) {
957 break;
959 /* one possibility to come here is ignoreeof on some fd, but no EOF
960 and no data on any descriptor - this is no indication for end! */
961 continue;
964 if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 &&
965 (fd1in->revents /*&(POLLIN|POLLHUP|POLLERR)*/)) {
966 if (fd1in->revents & POLLNVAL) {
967 /* this is what we find on Mac OS X when poll()'ing on a device or
968 named pipe. a read() might imm. return with 0 bytes, resulting
969 in a loop? */
970 Error1("poll(...[%d]: invalid request", fd1in->fd);
971 free(buff);
972 return -1;
974 mayrd1 = true;
976 if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
977 (fd2in->revents)) {
978 if (fd2in->revents & POLLNVAL) {
979 Error1("poll(...[%d]: invalid request", fd2in->fd);
980 free(buff);
981 return -1;
983 mayrd2 = true;
985 if (XIO_GETWRFD(sock1) >= 0 && fd1out->fd >= 0 && fd1out->revents) {
986 if (fd1out->revents & POLLNVAL) {
987 Error1("poll(...[%d]: invalid request", fd1out->fd);
988 free(buff);
989 return -1;
991 maywr1 = true;
993 if (XIO_GETWRFD(sock2) >= 0 && fd2out->fd >= 0 && fd2out->revents) {
994 if (fd2out->revents & POLLNVAL) {
995 Error1("poll(...[%d]: invalid request", fd2out->fd);
996 free(buff);
997 return -1;
999 maywr2 = true;
1002 if (mayrd1 && maywr2) {
1003 mayrd1 = false;
1004 if ((bytes1 = xiotransfer(sock1, sock2, buff, socat_opts.bufsiz, false))
1005 < 0) {
1006 if (errno != EAGAIN) {
1007 closing = MAX(closing, 1);
1008 Notice("socket 1 to socket 2 is in error");
1009 if (socat_opts.lefttoright) {
1010 break;
1013 } else if (bytes1 > 0) {
1014 maywr2 = false;
1015 total_timeout = socat_opts.total_timeout;
1016 wasaction = 1;
1017 /* is more data available that has already passed poll()? */
1018 mayrd1 = (xiopending(sock1) > 0);
1019 if (XIO_RDSTREAM(sock1)->readbytes != 0 &&
1020 XIO_RDSTREAM(sock1)->actbytes == 0) {
1021 /* avoid idle when all readbytes already there */
1022 mayrd1 = true;
1024 /* escape char occurred? */
1025 if (XIO_RDSTREAM(sock1)->actescape) {
1026 bytes1 = 0; /* indicate EOF */
1029 /* (bytes1 == 0) handled later */
1030 } else {
1031 bytes1 = -1;
1034 if (mayrd2 && maywr1) {
1035 mayrd2 = false;
1036 if ((bytes2 = xiotransfer(sock2, sock1, buff, socat_opts.bufsiz, true))
1037 < 0) {
1038 if (errno != EAGAIN) {
1039 closing = MAX(closing, 1);
1040 Notice("socket 2 to socket 1 is in error");
1041 if (socat_opts.righttoleft) {
1042 break;
1045 } else if (bytes2 > 0) {
1046 maywr1 = false;
1047 total_timeout = socat_opts.total_timeout;
1048 wasaction = 1;
1049 /* is more data available that has already passed poll()? */
1050 mayrd2 = (xiopending(sock2) > 0);
1051 if (XIO_RDSTREAM(sock2)->readbytes != 0 &&
1052 XIO_RDSTREAM(sock2)->actbytes == 0) {
1053 /* avoid idle when all readbytes already there */
1054 mayrd2 = true;
1056 /* escape char occurred? */
1057 if (XIO_RDSTREAM(sock2)->actescape) {
1058 bytes2 = 0; /* indicate EOF */
1061 /* (bytes2 == 0) handled later */
1062 } else {
1063 bytes2 = -1;
1066 /* NOW handle EOFs */
1068 /*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
1069 bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
1070 closing);*/
1071 if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
1072 if (XIO_RDSTREAM(sock1)->ignoreeof &&
1073 !XIO_RDSTREAM(sock1)->actescape && !closing) {
1074 Debug1("socket 1 (fd %d) is at EOF, ignoring",
1075 XIO_RDSTREAM(sock1)->fd); /*! */
1076 mayrd1 = true;
1077 polling = 1; /* do not hook this eof fd to poll for pollintv*/
1078 } else if (XIO_RDSTREAM(sock1)->eof <= 2) {
1079 Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
1080 xioshutdown(sock2, SHUT_WR);
1081 XIO_RDSTREAM(sock1)->eof = 3;
1082 XIO_RDSTREAM(sock1)->ignoreeof = false;
1084 } else if (polling && XIO_RDSTREAM(sock1)->ignoreeof) {
1085 polling = 0;
1087 if (XIO_RDSTREAM(sock1)->eof >= 2) {
1088 if (socat_opts.lefttoright) {
1089 break;
1091 closing = 1;
1094 if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
1095 if (XIO_RDSTREAM(sock2)->ignoreeof &&
1096 !XIO_RDSTREAM(sock2)->actescape && !closing) {
1097 Debug1("socket 2 (fd %d) is at EOF, ignoring",
1098 XIO_RDSTREAM(sock2)->fd);
1099 mayrd2 = true;
1100 polling = 1; /* do not hook this eof fd to poll for pollintv*/
1101 } else if (XIO_RDSTREAM(sock2)->eof <= 2) {
1102 Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
1103 xioshutdown(sock1, SHUT_WR);
1104 XIO_RDSTREAM(sock2)->eof = 3;
1105 XIO_RDSTREAM(sock2)->ignoreeof = false;
1107 } else if (polling && XIO_RDSTREAM(sock2)->ignoreeof) {
1108 polling = 0;
1110 if (XIO_RDSTREAM(sock2)->eof >= 2) {
1111 if (socat_opts.righttoleft) {
1112 break;
1114 closing = 1;
1118 /* close everything that's still open */
1119 xioclose(sock1);
1120 xioclose(sock2);
1122 free(buff);
1123 return 0;
1127 #define MAXTIMESTAMPLEN 128
1128 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
1129 should be at least MAXTIMESTAMPLEN bytes long.
1130 returns 0 on success or -1 if an error occurred */
1131 int gettimestamp(char *timestamp) {
1132 size_t bytes;
1133 #if HAVE_GETTIMEOFDAY || 1
1134 struct timeval now;
1135 int result;
1136 time_t nowt;
1137 #else /* !HAVE_GETTIMEOFDAY */
1138 time_t now;
1139 #endif /* !HAVE_GETTIMEOFDAY */
1141 #if HAVE_GETTIMEOFDAY || 1
1142 result = gettimeofday(&now, NULL);
1143 if (result < 0) {
1144 return result;
1145 } else {
1146 nowt = now.tv_sec;
1147 #if HAVE_STRFTIME
1148 bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
1149 bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
1150 #else
1151 strcpy(timestamp, ctime(&nowt));
1152 bytes = strlen(timestamp);
1153 #endif
1155 #else /* !HAVE_GETTIMEOFDAY */
1156 now = time(NULL); if (now == (time_t)-1) {
1157 return -1;
1158 } else {
1159 #if HAVE_STRFTIME
1160 bytes = strftime(timestamp, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now));
1161 #else
1162 strcpy(timestamp, ctime(&now));
1163 bytes = strlen(timestamp);
1164 #endif
1166 #endif /* !HAVE_GETTIMEOFDAY */
1167 return 0;
1170 static const char *prefixltor = "> ";
1171 static const char *prefixrtol = "< ";
1172 static unsigned long numltor;
1173 static unsigned long numrtol;
1174 /* print block header (during verbose or hex dump)
1175 returns 0 on success or -1 if an error occurred */
1176 static int
1177 xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
1178 char timestamp[MAXTIMESTAMPLEN];
1179 char buff[128+MAXTIMESTAMPLEN];
1180 if (gettimestamp(timestamp) < 0) {
1181 return -1;
1183 if (righttoleft) {
1184 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1185 prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
1186 numrtol+=bytes;
1187 } else {
1188 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1189 prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
1190 numltor+=bytes;
1192 fputs(buff, file);
1193 return 0;
1197 /* inpipe is suspected to have read data available; read at most bufsiz bytes
1198 and transfer them to outpipe. Perform required data conversions.
1199 buff must be a malloc()'ed storage and might be realloc()'ed in this
1200 function if more space is required after conversions.
1201 Returns the number of bytes written, or 0 on EOF or <0 if an
1202 error occurred or when data was read but none written due to conversions
1203 (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
1204 the file has a mandatory lock.
1205 If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
1206 does NOT write a zero bytes block.
1208 /* inpipe, outpipe must be single descriptors (not dual!) */
1209 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
1210 unsigned char *buff, size_t bufsiz, bool righttoleft) {
1211 ssize_t bytes, writt = 0;
1213 bytes = xioread(inpipe, buff, bufsiz);
1214 if (bytes < 0) {
1215 if (errno != EAGAIN)
1216 XIO_RDSTREAM(inpipe)->eof = 2;
1217 /*xioshutdown(inpipe, SHUT_RD);*/
1218 return -1;
1220 if (bytes == 0 && XIO_RDSTREAM(inpipe)->ignoreeof && !closing) {
1222 } else if (bytes == 0) {
1223 XIO_RDSTREAM(inpipe)->eof = 2;
1224 closing = MAX(closing, 1);
1227 if (bytes > 0) {
1228 /* handle escape char */
1229 if (XIO_RDSTREAM(inpipe)->escape != -1) {
1230 /* check input data for escape char */
1231 unsigned char *ptr = buff;
1232 size_t ctr = 0;
1233 while (ctr < bytes) {
1234 if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
1235 /* found: set flag, truncate input data */
1236 XIO_RDSTREAM(inpipe)->actescape = true;
1237 bytes = ctr;
1238 Info("escape char found in input");
1239 break;
1241 ++ptr; ++ctr;
1243 if (ctr != bytes) {
1244 XIO_RDSTREAM(inpipe)->eof = 2;
1249 if (bytes > 0) {
1251 if (XIO_RDSTREAM(inpipe)->lineterm !=
1252 XIO_WRSTREAM(outpipe)->lineterm) {
1253 cv_newline(buff, &bytes,
1254 XIO_RDSTREAM(inpipe)->lineterm,
1255 XIO_WRSTREAM(outpipe)->lineterm);
1257 if (bytes == 0) {
1258 errno = EAGAIN; return -1;
1261 if (socat_opts.verbose && socat_opts.verbhex) {
1262 /* Hack-o-rama */
1263 size_t i = 0;
1264 size_t j;
1265 size_t N = 16;
1266 const unsigned char *end, *s, *t;
1267 s = buff;
1268 end = buff+bytes;
1269 xioprintblockheader(stderr, bytes, righttoleft);
1270 while (s < end) {
1271 /*! prefix? */
1272 j = Min(N, (size_t)(end-s));
1274 /* print hex */
1275 t = s;
1276 i = 0;
1277 while (i < j) {
1278 int c = *t++;
1279 fprintf(stderr, " %02x", c);
1280 ++i;
1281 if (c == '\n') break;
1284 /* fill hex column */
1285 while (i < N) {
1286 fputs(" ", stderr);
1287 ++i;
1289 fputs(" ", stderr);
1291 /* print acsii */
1292 t = s;
1293 i = 0;
1294 while (i < j) {
1295 int c = *t++;
1296 if (c == '\n') {
1297 fputc('.', stderr);
1298 break;
1300 if (!isprint(c))
1301 c = '.';
1302 fputc(c, stderr);
1303 ++i;
1306 fputc('\n', stderr);
1307 s = t;
1309 fputs("--\n", stderr);
1310 } else if (socat_opts.verbose) {
1311 size_t i = 0;
1312 xioprintblockheader(stderr, bytes, righttoleft);
1313 while (i < (size_t)bytes) {
1314 int c = buff[i];
1315 if (i > 0 && buff[i-1] == '\n')
1316 /*! prefix? */;
1317 switch (c) {
1318 case '\a' : fputs("\\a", stderr); break;
1319 case '\b' : fputs("\\b", stderr); break;
1320 case '\t' : fputs("\t", stderr); break;
1321 case '\n' : fputs("\n", stderr); break;
1322 case '\v' : fputs("\\v", stderr); break;
1323 case '\f' : fputs("\\f", stderr); break;
1324 case '\r' : fputs("\\r", stderr); break;
1325 case '\\' : fputs("\\\\", stderr); break;
1326 default:
1327 if (!isprint(c))
1328 c = '.';
1329 fputc(c, stderr);
1330 break;
1332 ++i;
1334 } else if (socat_opts.verbhex) {
1335 int i;
1336 /* print prefix */
1337 xioprintblockheader(stderr, bytes, righttoleft);
1338 for (i = 0; i < bytes; ++i) {
1339 fprintf(stderr, " %02x", buff[i]);
1341 fputc('\n', stderr);
1344 writt = xiowrite(outpipe, buff, bytes);
1345 if (writt < 0) {
1346 /* EAGAIN when nonblocking but a mandatory lock is on file.
1347 the problem with EAGAIN is that the read cannot be repeated,
1348 so we need to buffer the data and try to write it later
1349 again. not yet implemented, sorry. */
1350 #if 0
1351 if (errno == EPIPE) {
1352 return 0; /* can no longer write; handle like EOF */
1354 #endif
1355 return -1;
1356 } else {
1357 Info3("transferred "F_Zu" bytes from %d to %d",
1358 writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
1361 return writt;
1364 #define CR '\r'
1365 #define LF '\n'
1368 /* converts the newline characters (or character sequences) from the one
1369 specified in lineterm1 to that of lineterm2. Possible values are
1370 LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
1371 bytes specifies the number of bytes input and output */
1372 int cv_newline(unsigned char *buff, ssize_t *bytes,
1373 int lineterm1, int lineterm2) {
1374 /* must perform newline changes */
1375 if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
1376 /* no change in data length */
1377 unsigned char from, to, *p, *z;
1378 if (lineterm1 == LINETERM_RAW) {
1379 from = '\n'; to = '\r';
1380 } else {
1381 from = '\r'; to = '\n';
1383 z = buff + *bytes;
1384 p = buff;
1385 while (p < z) {
1386 if (*p == from) *p = to;
1387 ++p;
1390 } else if (lineterm1 == LINETERM_CRNL) {
1391 /* buffer might become shorter */
1392 unsigned char to, *s, *t, *z;
1393 if (lineterm2 == LINETERM_RAW) {
1394 to = '\n';
1395 } else {
1396 to = '\r';
1398 z = buff + *bytes;
1399 s = t = buff;
1400 while (s < z) {
1401 if (*s == '\r') {
1402 ++s;
1403 continue;
1405 if (*s == '\n') {
1406 *t++ = to; ++s;
1407 } else {
1408 *t++ = *s++;
1411 *bytes = t - buff;
1412 } else {
1413 /* buffer becomes longer (up to double length), must alloc another space */
1414 static unsigned char *buf2; /*! not threadsafe */
1415 unsigned char from; unsigned char *s, *t, *z;
1417 if (lineterm1 == LINETERM_RAW) {
1418 from = '\n';
1419 } else {
1420 from = '\r';
1422 if (buf2 == NULL) {
1423 if ((buf2 = Malloc(socat_opts.bufsiz)) == NULL) {
1424 return -1;
1427 memcpy(buf2, buff, *bytes);
1428 s = buf2; t = buff; z = buf2 + *bytes;
1429 while (s < z) {
1430 if (*s == from) {
1431 *t++ = '\r'; *t++ = '\n';
1432 ++s;
1433 continue;
1434 } else {
1435 *t++ = *s++;
1438 *bytes = t - buff;;
1440 return 0;
1443 void socat_signal(int signum) {
1444 int _errno;
1445 _errno = errno;
1446 diag_in_handler = 1;
1447 Notice1("socat_signal(): handling signal %d", signum);
1448 switch (signum) {
1449 case SIGILL:
1450 case SIGABRT:
1451 case SIGBUS:
1452 case SIGFPE:
1453 case SIGSEGV:
1454 diag_immediate_exit = 1;
1455 case SIGQUIT:
1456 case SIGPIPE:
1457 diag_set_int('x', 128+signum); /* in case Error exits for us */
1458 Error1("exiting on signal %d", signum);
1459 diag_set_int('x', 0); /* in case Error did not exit */
1460 break;
1461 case SIGTERM:
1462 Warn1("exiting on signal %d", signum); break;
1463 case SIGHUP:
1464 case SIGINT:
1465 Notice1("exiting on signal %d", signum); break;
1467 //Exit(128+signum);
1468 Notice1("socat_signal(): finishing signal %d", signum);
1469 diag_exit(128+signum); /*!!! internal cleanup + _exit() */
1470 diag_in_handler = 0;
1471 errno = _errno;
1474 /* this is the callback when the child of an address died */
1475 static int socat_sigchild(struct single *file) {
1476 if (file->ignoreeof && !closing) {
1478 } else {
1479 file->eof = MAX(file->eof, 1);
1480 closing = 1;
1482 return 0;
1485 static int socat_lock(void) {
1486 int lockrc;
1488 #if 1
1489 if ((lockrc = xiolock(&socat_opts.lock)) < 0) {
1490 return -1;
1492 if (lockrc == 0) {
1493 havelock = true;
1495 return lockrc;
1496 #else
1497 if (socat_opts.lock.lockfile) {
1498 if ((lockrc = xiolock(socat_opts.lock.lockfile)) < 0) {
1499 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1500 return -1;
1502 if (lockrc) {
1503 return 1;
1505 havelock = true;
1506 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/
1509 if (socat_opts.lock.waitlock) {
1510 if (xiowaitlock(socat_opts.lock.waitlock, socat_opts.lock.intervall)) {
1511 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1512 return -1;
1513 } else {
1514 havelock = true;
1515 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1518 return 0;
1519 #endif
1522 static void socat_unlock(void) {
1523 if (!havelock) return;
1524 if (socat_opts.lock.lockfile) {
1525 if (Unlink(socat_opts.lock.lockfile) < 0) {
1526 if (!diag_in_handler) {
1527 Warn2("unlink(\"%s\"): %s",
1528 socat_opts.lock.lockfile, strerror(errno));
1529 } else {
1530 Warn1("unlink(\"%s\"): "F_strerror,
1531 socat_opts.lock.lockfile);
1533 } else {
1534 Info1("released lock \"%s\"", socat_opts.lock.lockfile);
1539 /* this is a callback function that may be called by the newchild hook of xio
1541 static int socat_newchild(void) {
1542 havelock = false;
1543 return 0;