version 1.7.3.0
[socat.git] / socat.c
blob8cb67677fa456e19227b1e5b4d5119dcf1f8449a
1 /* source: socat.c */
2 /* Copyright Gerhard Rieger */
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_version(FILE *fd);
57 int socat(const char *address1, const char *address2);
58 int _socat(void);
59 int cv_newline(unsigned char **buff, ssize_t *bytes, int lineterm1, int lineterm2);
60 void socat_signal(int sig);
61 static int socat_sigchild(struct single *file);
63 void lftocrlf(char **in, ssize_t *len, size_t bufsiz);
64 void crlftolf(char **in, ssize_t *len, size_t bufsiz);
66 static int socat_lock(void);
67 static void socat_unlock(void);
68 static int socat_newchild(void);
70 static const char socatversion[] =
71 #include "./VERSION"
73 static const char timestamp[] = BUILD_DATE;
75 const char copyright_socat[] = "socat by Gerhard Rieger - see www.dest-unreach.org";
76 #if WITH_OPENSSL
77 const char copyright_openssl[] = "This product includes software developed by the OpenSSL Project for use in the OpenSSL Toolkit. (http://www.openssl.org/)";
78 const char copyright_ssleay[] = "This product includes software written by Tim Hudson (tjh@cryptsoft.com)";
79 #endif
81 bool havelock;
84 int main(int argc, const char *argv[]) {
85 const char **arg1, *a;
86 char *mainwaitstring;
87 char buff[10];
88 double rto;
89 int i, argc0, result;
90 struct utsname ubuf;
91 int lockrc;
93 if (mainwaitstring = getenv("SOCAT_MAIN_WAIT")) {
94 sleep(atoi(mainwaitstring));
96 diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
98 /* we must init before applying options because env settings have lower
99 priority and are to be overridden by options */
100 if (xioinitialize() != 0) {
101 Exit(1);
104 xiosetopt('p', "!!");
105 xiosetopt('o', ":");
107 argc0 = argc; /* save for later use */
108 arg1 = argv+1; --argc;
109 while (arg1[0] && (arg1[0][0] == '-')) {
110 switch (arg1[0][1]) {
111 case 'V': socat_version(stdout); Exit(0);
112 #if WITH_HELP
113 case '?':
114 case 'h':
115 socat_usage(stdout);
116 xioopenhelp(stdout, (arg1[0][2]=='?'||arg1[0][2]=='h') ? (arg1[0][3]=='?'||arg1[0][3]=='h') ? 2 : 1 : 0);
117 Exit(0);
118 #endif /* WITH_HELP */
119 case 'd': diag_set('d', NULL); break;
120 #if WITH_FILAN
121 case 'D': socat_opts.debug = true; break;
122 #endif
123 case 'l':
124 switch (arg1[0][2]) {
125 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
126 diag_set('s', NULL);
127 xiosetopt('l', "m");
128 socat_opts.logopt = arg1[0][2];
129 xiosetopt('y', &arg1[0][3]);
130 break;
131 case 'y': /* syslog + facility */
132 diag_set(arg1[0][2], &arg1[0][3]);
133 break;
134 case 'f': /* to file, +filename */
135 case 'p': /* artificial program name */
136 if (arg1[0][3]) {
137 diag_set(arg1[0][2], &arg1[0][3]);
138 } else if (arg1[1]) {
139 diag_set(arg1[0][2], arg1[1]);
140 ++arg1, --argc;
141 } else {
142 Error1("option -l%c requires an argument; use option \"-h\" for help", arg1[0][2]);
144 break;
145 case 's': /* stderr */
146 diag_set(arg1[0][2], NULL);
147 break;
148 case 'u':
149 diag_set('u', NULL);
150 break;
151 case 'h':
152 diag_set_int('h', true);
153 break;
154 default:
155 Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1[0]);
156 break;
158 break;
159 case 'v': socat_opts.verbose = true; break;
160 case 'x': socat_opts.verbhex = true; break;
161 case 'b': if (arg1[0][2]) {
162 a = *arg1+2;
163 } else {
164 ++arg1, --argc;
165 if ((a = *arg1) == NULL) {
166 Error("option -b requires an argument; use option \"-h\" for help");
167 Exit(1);
170 socat_opts.bufsiz = strtoul(a, (char **)&a, 0);
171 break;
172 case 's':
173 diag_set_int('e', E_FATAL); break;
174 case 't': if (arg1[0][2]) {
175 a = *arg1+2;
176 } else {
177 ++arg1, --argc;
178 if ((a = *arg1) == NULL) {
179 Error("option -t requires an argument; use option \"-h\" for help");
180 Exit(1);
183 rto = strtod(a, (char **)&a);
184 socat_opts.closwait.tv_sec = rto;
185 socat_opts.closwait.tv_usec =
186 (rto-socat_opts.closwait.tv_sec) * 1000000;
187 break;
188 case 'T': if (arg1[0][2]) {
189 a = *arg1+2;
190 } else {
191 ++arg1, --argc;
192 if ((a = *arg1) == NULL) {
193 Error("option -T requires an argument; use option \"-h\" for help");
194 Exit(1);
197 rto = strtod(a, (char **)&a);
198 socat_opts.total_timeout.tv_sec = rto;
199 socat_opts.total_timeout.tv_usec =
200 (rto-socat_opts.total_timeout.tv_sec) * 1000000;
201 break;
202 case 'u': socat_opts.lefttoright = true; break;
203 case 'U': socat_opts.righttoleft = true; break;
204 case 'g': xioopts_ignoregroups = true; break;
205 case 'L': if (socat_opts.lock.lockfile)
206 Error("only one -L and -W option allowed");
207 if (arg1[0][2]) {
208 socat_opts.lock.lockfile = *arg1+2;
209 } else {
210 ++arg1, --argc;
211 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
212 Error("option -L requires an argument; use option \"-h\" for help");
213 Exit(1);
216 break;
217 case 'W': if (socat_opts.lock.lockfile)
218 Error("only one -L and -W option allowed");
219 if (arg1[0][2]) {
220 socat_opts.lock.lockfile = *arg1+2;
221 } else {
222 ++arg1, --argc;
223 if ((socat_opts.lock.lockfile = *arg1) == NULL) {
224 Error("option -W requires an argument; use option \"-h\" for help");
225 Exit(1);
228 socat_opts.lock.waitlock = true;
229 socat_opts.lock.intervall.tv_sec = 1;
230 socat_opts.lock.intervall.tv_nsec = 0;
231 break;
232 #if WITH_IP4 || WITH_IP6
233 #if WITH_IP4
234 case '4':
235 #endif
236 #if WITH_IP6
237 case '6':
238 #endif
239 xioopts.default_ip = arg1[0][1];
240 xioopts.preferred_ip = arg1[0][1];
241 break;
242 #endif /* WITH_IP4 || WITH_IP6 */
243 case '\0':
244 case ',':
245 case ':': break; /* this "-" is a variation of STDIO */
246 default:
247 xioinqopt('p', buff, sizeof(buff));
248 if (arg1[0][1] == buff[0]) {
249 break;
251 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1[0]);
252 Exit(1);
254 /* the leading "-" might be a form of the first address */
255 xioinqopt('p', buff, sizeof(buff));
256 if (arg1[0][0] == '-' &&
257 (arg1[0][1] == '\0' || arg1[0][1] == ':' ||
258 arg1[0][1] == ',' || arg1[0][1] == buff[0]))
259 break;
260 ++arg1; --argc;
262 if (argc != 2) {
263 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc);
264 Exit(1);
266 if (socat_opts.lefttoright && socat_opts.righttoleft) {
267 Error("-U and -u must not be combined");
270 xioinitialize2();
271 Info(copyright_socat);
272 #if WITH_OPENSSL
273 Info(copyright_openssl);
274 Info(copyright_ssleay);
275 #endif
276 Debug2("socat version %s on %s", socatversion, timestamp);
277 xiosetenv("VERSION", socatversion, 1, NULL); /* SOCAT_VERSION */
278 uname(&ubuf); /* ! here we circumvent internal tracing (Uname) */
279 Debug4("running on %s version %s, release %s, machine %s\n",
280 ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
282 #if WITH_MSGLEVEL <= E_DEBUG
283 for (i = 0; i < argc0; ++i) {
284 Debug2("argv[%d]: \"%s\"", i, argv[i]);
286 #endif /* WITH_MSGLEVEL <= E_DEBUG */
289 struct sigaction act;
290 sigfillset(&act.sa_mask);
291 act.sa_flags = 0;
292 act.sa_handler = socat_signal;
293 /* not sure which signals should be cauhgt and print a message */
294 Sigaction(SIGHUP, &act, NULL);
295 Sigaction(SIGINT, &act, NULL);
296 Sigaction(SIGQUIT, &act, NULL);
297 Sigaction(SIGILL, &act, NULL);
298 Sigaction(SIGABRT, &act, NULL);
299 Sigaction(SIGBUS, &act, NULL);
300 Sigaction(SIGFPE, &act, NULL);
301 Sigaction(SIGSEGV, &act, NULL);
302 Sigaction(SIGTERM, &act, NULL);
304 Signal(SIGPIPE, SIG_IGN);
306 /* set xio hooks */
307 xiohook_newchild = &socat_newchild;
309 if (lockrc = socat_lock()) {
310 /* =0: goon; >0: locked; <0: error, printed in sub */
311 if (lockrc > 0)
312 Error1("could not obtain lock \"%s\"", socat_opts.lock.lockfile);
313 Exit(1);
316 Atexit(socat_unlock);
318 result = socat(arg1[0], arg1[1]);
319 Notice1("exiting with status %d", result);
320 Exit(result);
321 return 0; /* not reached, just for gcc -Wall */
325 void socat_usage(FILE *fd) {
326 fputs(copyright_socat, fd); fputc('\n', fd);
327 fputs("Usage:\n", fd);
328 fputs("socat [options] <bi-address> <bi-address>\n", fd);
329 fputs(" options:\n", fd);
330 fputs(" -V print version and feature information to stdout, and exit\n", fd);
331 #if WITH_HELP
332 fputs(" -h|-? print a help text describing command line options and addresses\n", fd);
333 fputs(" -hh like -h, plus a list of all common address option names\n", fd);
334 fputs(" -hhh like -hh, plus a list of all available address option names\n", fd);
335 #endif /* WITH_HELP */
336 fputs(" -d increase verbosity (use up to 4 times; 2 are recommended)\n", fd);
337 #if WITH_FILAN
338 fputs(" -D analyze file descriptors before loop\n", fd);
339 #endif
340 fputs(" -ly[facility] log to syslog, using facility (default is daemon)\n", fd);
341 fputs(" -lf<logfile> log to file\n", fd);
342 fputs(" -ls log to stderr (default if no other log)\n", fd);
343 fputs(" -lm[facility] mixed log mode (stderr during initialization, then syslog)\n", fd);
344 fputs(" -lp<progname> set the program name used for logging\n", fd);
345 fputs(" -lu use microseconds for logging timestamps\n", fd);
346 fputs(" -lh add hostname to log messages\n", fd);
347 fputs(" -v verbose data traffic, text\n", fd);
348 fputs(" -x verbose data traffic, hexadecimal\n", fd);
349 fputs(" -b<size_t> set data buffer size (8192)\n", fd);
350 fputs(" -s sloppy (continue on error)\n", fd);
351 fputs(" -t<timeout> wait seconds before closing second channel\n", fd);
352 fputs(" -T<timeout> total inactivity timeout in seconds\n", fd);
353 fputs(" -u unidirectional mode (left to right)\n", fd);
354 fputs(" -U unidirectional mode (right to left)\n", fd);
355 fputs(" -g do not check option groups\n", fd);
356 fputs(" -L <lockfile> try to obtain lock, or fail\n", fd);
357 fputs(" -W <lockfile> try to obtain lock, or wait\n", fd);
358 #if WITH_IP4
359 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd);
360 #endif
361 #if WITH_IP6
362 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd);
363 #endif
367 void socat_version(FILE *fd) {
368 struct utsname ubuf;
370 fputs(copyright_socat, fd); fputc('\n', fd);
371 fprintf(fd, "socat version %s on %s\n", socatversion, timestamp);
372 Uname(&ubuf);
373 fprintf(fd, " running on %s version %s, release %s, machine %s\n",
374 ubuf.sysname, ubuf.version, ubuf.release, ubuf.machine);
375 fputs("features:\n", fd);
376 #ifdef WITH_STDIO
377 fprintf(fd, " #define WITH_STDIO %d\n", WITH_STDIO);
378 #else
379 fputs(" #undef WITH_STDIO\n", fd);
380 #endif
381 #ifdef WITH_FDNUM
382 fprintf(fd, " #define WITH_FDNUM %d\n", WITH_FDNUM);
383 #else
384 fputs(" #undef WITH_FDNUM\n", fd);
385 #endif
386 #ifdef WITH_FILE
387 fprintf(fd, " #define WITH_FILE %d\n", WITH_FILE);
388 #else
389 fputs(" #undef WITH_FILE\n", fd);
390 #endif
391 #ifdef WITH_CREAT
392 fprintf(fd, " #define WITH_CREAT %d\n", WITH_CREAT);
393 #else
394 fputs(" #undef WITH_CREAT\n", fd);
395 #endif
396 #ifdef WITH_GOPEN
397 fprintf(fd, " #define WITH_GOPEN %d\n", WITH_GOPEN);
398 #else
399 fputs(" #undef WITH_GOPEN\n", fd);
400 #endif
401 #ifdef WITH_TERMIOS
402 fprintf(fd, " #define WITH_TERMIOS %d\n", WITH_TERMIOS);
403 #else
404 fputs(" #undef WITH_TERMIOS\n", fd);
405 #endif
406 #ifdef WITH_PIPE
407 fprintf(fd, " #define WITH_PIPE %d\n", WITH_PIPE);
408 #else
409 fputs(" #undef WITH_PIPE\n", fd);
410 #endif
411 #ifdef WITH_UNIX
412 fprintf(fd, " #define WITH_UNIX %d\n", WITH_UNIX);
413 #else
414 fputs(" #undef WITH_UNIX\n", fd);
415 #endif /* WITH_UNIX */
416 #ifdef WITH_ABSTRACT_UNIXSOCKET
417 fprintf(fd, " #define WITH_ABSTRACT_UNIXSOCKET %d\n", WITH_ABSTRACT_UNIXSOCKET);
418 #else
419 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd);
420 #endif /* WITH_ABSTRACT_UNIXSOCKET */
421 #ifdef WITH_IP4
422 fprintf(fd, " #define WITH_IP4 %d\n", WITH_IP4);
423 #else
424 fputs(" #undef WITH_IP4\n", fd);
425 #endif
426 #ifdef WITH_IP6
427 fprintf(fd, " #define WITH_IP6 %d\n", WITH_IP6);
428 #else
429 fputs(" #undef WITH_IP6\n", fd);
430 #endif
431 #ifdef WITH_RAWIP
432 fprintf(fd, " #define WITH_RAWIP %d\n", WITH_RAWIP);
433 #else
434 fputs(" #undef WITH_RAWIP\n", fd);
435 #endif
436 #ifdef WITH_GENERICSOCKET
437 fprintf(fd, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET);
438 #else
439 fputs(" #undef WITH_GENERICSOCKET\n", fd);
440 #endif
441 #ifdef WITH_INTERFACE
442 fprintf(fd, " #define WITH_INTERFACE %d\n", WITH_INTERFACE);
443 #else
444 fputs(" #undef WITH_INTERFACE\n", fd);
445 #endif
446 #ifdef WITH_TCP
447 fprintf(fd, " #define WITH_TCP %d\n", WITH_TCP);
448 #else
449 fputs(" #undef WITH_TCP\n", fd);
450 #endif
451 #ifdef WITH_UDP
452 fprintf(fd, " #define WITH_UDP %d\n", WITH_UDP);
453 #else
454 fputs(" #undef WITH_UDP\n", fd);
455 #endif
456 #ifdef WITH_SCTP
457 fprintf(fd, " #define WITH_SCTP %d\n", WITH_SCTP);
458 #else
459 fputs(" #undef WITH_SCTP\n", fd);
460 #endif
461 #ifdef WITH_LISTEN
462 fprintf(fd, " #define WITH_LISTEN %d\n", WITH_LISTEN);
463 #else
464 fputs(" #undef WITH_LISTEN\n", fd);
465 #endif
466 #ifdef WITH_SOCKS4
467 fprintf(fd, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4);
468 #else
469 fputs(" #undef WITH_SOCKS4\n", fd);
470 #endif
471 #ifdef WITH_SOCKS4A
472 fprintf(fd, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A);
473 #else
474 fputs(" #undef WITH_SOCKS4A\n", fd);
475 #endif
476 #ifdef WITH_PROXY
477 fprintf(fd, " #define WITH_PROXY %d\n", WITH_PROXY);
478 #else
479 fputs(" #undef WITH_PROXY\n", fd);
480 #endif
481 #ifdef WITH_SYSTEM
482 fprintf(fd, " #define WITH_SYSTEM %d\n", WITH_SYSTEM);
483 #else
484 fputs(" #undef WITH_SYSTEM\n", fd);
485 #endif
486 #ifdef WITH_EXEC
487 fprintf(fd, " #define WITH_EXEC %d\n", WITH_EXEC);
488 #else
489 fputs(" #undef WITH_EXEC\n", fd);
490 #endif
491 #ifdef WITH_READLINE
492 fprintf(fd, " #define WITH_READLINE %d\n", WITH_READLINE);
493 #else
494 fputs(" #undef WITH_READLINE\n", fd);
495 #endif
496 #ifdef WITH_TUN
497 fprintf(fd, " #define WITH_TUN %d\n", WITH_TUN);
498 #else
499 fputs(" #undef WITH_TUN\n", fd);
500 #endif
501 #ifdef WITH_PTY
502 fprintf(fd, " #define WITH_PTY %d\n", WITH_PTY);
503 #else
504 fputs(" #undef WITH_PTY\n", fd);
505 #endif
506 #ifdef WITH_OPENSSL
507 fprintf(fd, " #define WITH_OPENSSL %d\n", WITH_OPENSSL);
508 #else
509 fputs(" #undef WITH_OPENSSL\n", fd);
510 #endif
511 #ifdef WITH_FIPS
512 fprintf(fd, " #define WITH_FIPS %d\n", WITH_FIPS);
513 #else
514 fputs(" #undef WITH_FIPS\n", fd);
515 #endif
516 #ifdef WITH_LIBWRAP
517 fprintf(fd, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP);
518 #else
519 fputs(" #undef WITH_LIBWRAP\n", fd);
520 #endif
521 #ifdef WITH_SYCLS
522 fprintf(fd, " #define WITH_SYCLS %d\n", WITH_SYCLS);
523 #else
524 fputs(" #undef WITH_SYCLS\n", fd);
525 #endif
526 #ifdef WITH_FILAN
527 fprintf(fd, " #define WITH_FILAN %d\n", WITH_FILAN);
528 #else
529 fputs(" #undef WITH_FILAN\n", fd);
530 #endif
531 #ifdef WITH_RETRY
532 fprintf(fd, " #define WITH_RETRY %d\n", WITH_RETRY);
533 #else
534 fputs(" #undef WITH_RETRY\n", fd);
535 #endif
536 #ifdef WITH_MSGLEVEL
537 fprintf(fd, " #define WITH_MSGLEVEL %d /*%s*/\n", WITH_MSGLEVEL,
538 &"debug\0\0\0info\0\0\0\0notice\0\0warn\0\0\0\0error\0\0\0fatal\0\0\0"[WITH_MSGLEVEL<<3]);
539 #else
540 fputs(" #undef WITH_MSGLEVEL\n", fd);
541 #endif
545 xiofile_t *sock1, *sock2;
546 int closing = 0; /* 0..no eof yet, 1..first eof just occurred,
547 2..counting down closing timeout */
549 /* call this function when the common command line options are parsed, and the
550 addresses are extracted (but not resolved). */
551 int socat(const char *address1, const char *address2) {
552 int mayexec;
554 if (socat_opts.lefttoright) {
555 if ((sock1 = xioopen(address1, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
556 return -1;
558 xiosetsigchild(sock1, socat_sigchild);
559 } else if (socat_opts.righttoleft) {
560 if ((sock1 = xioopen(address1, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
561 return -1;
563 xiosetsigchild(sock1, socat_sigchild);
564 } else {
565 if ((sock1 = xioopen(address1, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|XIO_MAYCONVERT)) == NULL) {
566 return -1;
568 xiosetsigchild(sock1, socat_sigchild);
570 #if 1 /*! */
571 if (XIO_READABLE(sock1) &&
572 (XIO_RDSTREAM(sock1)->howtoend == END_KILL ||
573 XIO_RDSTREAM(sock1)->howtoend == END_CLOSE_KILL ||
574 XIO_RDSTREAM(sock1)->howtoend == END_SHUTDOWN_KILL)) {
575 if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown1) {
576 /* child has alread died... but it might have put regular data into
577 the communication channel, so continue */
578 Info1("child "F_pid" has already died (diedunknown1)",
579 XIO_RDSTREAM(sock1)->para.exec.pid);
580 diedunknown1 = 0;
581 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
582 /* return STAT_RETRYLATER; */
583 } else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown2) {
584 Info1("child "F_pid" has already died (diedunknown2)",
585 XIO_RDSTREAM(sock1)->para.exec.pid);
586 diedunknown2 = 0;
587 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
588 } else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown3) {
589 Info1("child "F_pid" has already died (diedunknown3)",
590 XIO_RDSTREAM(sock1)->para.exec.pid);
591 diedunknown3 = 0;
592 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
593 } else if (XIO_RDSTREAM(sock1)->para.exec.pid == diedunknown4) {
594 Info1("child "F_pid" has already died (diedunknown4)",
595 XIO_RDSTREAM(sock1)->para.exec.pid);
596 diedunknown4 = 0;
597 XIO_RDSTREAM(sock1)->para.exec.pid = 0;
600 #endif
602 mayexec = (sock1->common.flags&XIO_DOESCONVERT ? 0 : XIO_MAYEXEC);
603 if (XIO_WRITABLE(sock1)) {
604 if (XIO_READABLE(sock1)) {
605 if ((sock2 = xioopen(address2, XIO_RDWR|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
606 return -1;
608 xiosetsigchild(sock2, socat_sigchild);
609 } else {
610 if ((sock2 = xioopen(address2, XIO_RDONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
611 return -1;
613 xiosetsigchild(sock2, socat_sigchild);
615 } else { /* assuming sock1 is readable */
616 if ((sock2 = xioopen(address2, XIO_WRONLY|XIO_MAYFORK|XIO_MAYCHILD|mayexec|XIO_MAYCONVERT)) == NULL) {
617 return -1;
619 xiosetsigchild(sock2, socat_sigchild);
621 #if 1 /*! */
622 if (XIO_READABLE(sock2) &&
623 (XIO_RDSTREAM(sock2)->howtoend == END_KILL ||
624 XIO_RDSTREAM(sock2)->howtoend == END_CLOSE_KILL ||
625 XIO_RDSTREAM(sock2)->howtoend == END_SHUTDOWN_KILL)) {
626 if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown1) {
627 /* child has alread died... but it might have put regular data into
628 the communication channel, so continue */
629 Info1("child "F_pid" has already died (diedunknown1)",
630 XIO_RDSTREAM(sock2)->para.exec.pid);
631 diedunknown1 = 0;
632 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
633 /* return STAT_RETRYLATER; */
634 } else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown2) {
635 Info1("child "F_pid" has already died (diedunknown2)",
636 XIO_RDSTREAM(sock2)->para.exec.pid);
637 diedunknown2 = 0;
638 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
639 } else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown3) {
640 Info1("child "F_pid" has already died (diedunknown3)",
641 XIO_RDSTREAM(sock2)->para.exec.pid);
642 diedunknown3 = 0;
643 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
644 } else if (XIO_RDSTREAM(sock2)->para.exec.pid == diedunknown4) {
645 Info1("child "F_pid" has already died (diedunknown4)",
646 XIO_RDSTREAM(sock2)->para.exec.pid);
647 diedunknown4 = 0;
648 XIO_RDSTREAM(sock2)->para.exec.pid = 0;
651 #endif
653 Info("resolved and opened all sock addresses");
654 return
655 _socat(); /* nsocks, sockets are visible outside function */
658 /* checks if this is a connection to a child process, and if so, sees if the
659 child already died, leaving some data for us.
660 returns <0 if an error occurred;
661 returns 0 if no child or not yet died or died without data (sets eof);
662 returns >0 if child died and left data
664 int childleftdata(xiofile_t *xfd) {
665 struct pollfd in;
666 int retval;
668 /* have to check if a child process died before, but left read data */
669 if (XIO_READABLE(xfd) &&
670 (XIO_RDSTREAM(xfd)->howtoend == END_KILL ||
671 XIO_RDSTREAM(xfd)->howtoend == END_CLOSE_KILL ||
672 XIO_RDSTREAM(xfd)->howtoend == END_SHUTDOWN_KILL) &&
673 XIO_RDSTREAM(xfd)->para.exec.pid == 0) {
674 struct timeval timeout = { 0, 0 };
676 if (XIO_READABLE(xfd) && !(XIO_RDSTREAM(xfd)->eof >= 2 && !XIO_RDSTREAM(xfd)->ignoreeof)) {
677 in.fd = XIO_GETRDFD(xfd);
678 in.events = POLLIN/*|POLLRDBAND*/;
679 in.revents = 0;
681 do {
682 int _errno;
683 retval = xiopoll(&in, 1, &timeout);
684 _errno = errno; diag_flush(); errno = _errno; /* just in case it's not debug level and Msg() not been called */
685 } while (retval < 0 && errno == EINTR);
687 if (retval < 0) {
688 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec"."F_tv_usec"}): %s",
689 in.fd, in.events, timeout.tv_sec, timeout.tv_usec,
690 strerror(errno));
691 return -1;
693 if (retval == 0) {
694 Info("terminated child did not leave data for us");
695 XIO_RDSTREAM(xfd)->eof = 2;
696 xfd->stream.eof = 2;
697 closing = MAX(closing, 1);
700 return 0;
703 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
704 unsigned char **buff, size_t bufsiz, bool righttoleft);
706 bool mayrd1; /* sock1 has read data or eof, according to poll() */
707 bool mayrd2; /* sock2 has read data or eof, according to poll() */
708 bool maywr1; /* sock1 can be written to, according to poll() */
709 bool maywr2; /* sock2 can be written to, according to poll() */
711 /* here we come when the sockets are opened (in the meaning of C language),
712 and their options are set/applied
713 returns -1 on error or 0 on success */
714 int _socat(void) {
715 struct pollfd fds[4],
716 *fd1in = &fds[0],
717 *fd1out = &fds[1],
718 *fd2in = &fds[2],
719 *fd2out = &fds[3];
720 int retval;
721 unsigned char *buff;
722 ssize_t bytes1, bytes2;
723 int polling = 0; /* handling ignoreeof */
724 int wasaction = 1; /* last poll was active, do NOT sleep before next */
725 struct timeval total_timeout; /* the actual total timeout timer */
727 #if WITH_FILAN
728 if (socat_opts.debug) {
729 int fdi, fdo;
730 int msglevel, exitlevel;
732 msglevel = diag_get_int('D'); /* save current message level */
733 diag_set_int('D', E_ERROR); /* only print errors and fatals in filan */
734 exitlevel = diag_get_int('e'); /* save current exit level */
735 diag_set_int('e', E_FATAL); /* only exit on fatals */
737 fdi = XIO_GETRDFD(sock1);
738 fdo = XIO_GETWRFD(sock1);
739 filan_fd(fdi, stderr);
740 if (fdo != fdi) {
741 filan_fd(fdo, stderr);
744 fdi = XIO_GETRDFD(sock2);
745 fdo = XIO_GETWRFD(sock2);
746 filan_fd(fdi, stderr);
747 if (fdo != fdi) {
748 filan_fd(fdo, stderr);
751 diag_set_int('e', exitlevel); /* restore old exit level */
752 diag_set_int('D', msglevel); /* restore old message level */
754 #endif /* WITH_FILAN */
756 /* when converting nl to crnl, size might double */
757 buff = Malloc(2*socat_opts.bufsiz+1);
758 if (buff == NULL) return -1;
760 if (socat_opts.logopt == 'm' && xioinqopt('l', NULL, 0) == 'm') {
761 Info("switching to syslog");
762 diag_set('y', xioopts.syslogfac);
763 xiosetopt('l', "\0");
765 total_timeout = socat_opts.total_timeout;
767 Notice4("starting data transfer loop with FDs [%d,%d] and [%d,%d]",
768 XIO_GETRDFD(sock1), XIO_GETWRFD(sock1),
769 XIO_GETRDFD(sock2), XIO_GETWRFD(sock2));
770 while (XIO_RDSTREAM(sock1)->eof <= 1 ||
771 XIO_RDSTREAM(sock2)->eof <= 1) {
772 struct timeval timeout, *to = NULL;
774 Debug6("data loop: sock1->eof=%d, sock2->eof=%d, closing=%d, wasaction=%d, total_to={"F_tv_sec"."F_tv_usec"}",
775 XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock2)->eof,
776 closing, wasaction,
777 total_timeout.tv_sec, total_timeout.tv_usec);
779 /* for ignoreeof */
780 if (polling) {
781 if (!wasaction) {
782 if (socat_opts.total_timeout.tv_sec != 0 ||
783 socat_opts.total_timeout.tv_usec != 0) {
784 if (total_timeout.tv_usec < socat_opts.pollintv.tv_usec) {
785 total_timeout.tv_usec += 1000000;
786 total_timeout.tv_sec -= 1;
788 total_timeout.tv_sec -= socat_opts.pollintv.tv_sec;
789 total_timeout.tv_usec -= socat_opts.pollintv.tv_usec;
790 if (total_timeout.tv_sec < 0 ||
791 total_timeout.tv_sec == 0 && total_timeout.tv_usec < 0) {
792 Notice("inactivity timeout triggered");
793 free(buff);
794 return 0;
798 } else {
799 wasaction = 0;
803 if (polling) {
804 /* there is a ignoreeof poll timeout, use it */
805 timeout = socat_opts.pollintv;
806 to = &timeout;
807 } else if (socat_opts.total_timeout.tv_sec != 0 ||
808 socat_opts.total_timeout.tv_usec != 0) {
809 /* there might occur a total inactivity timeout */
810 timeout = socat_opts.total_timeout;
811 to = &timeout;
812 } else {
813 to = NULL;
816 if (closing>=1) {
817 /* first eof already occurred, start end timer */
818 timeout = socat_opts.pollintv;
819 to = &timeout;
820 closing = 2;
823 /* frame 1: set the poll parameters and loop over poll() EINTR) */
824 do { /* loop over poll() EINTR */
825 int _errno;
827 childleftdata(sock1);
828 childleftdata(sock2);
830 if (closing>=1) {
831 /* first eof already occurred, start end timer */
832 timeout = socat_opts.closwait;
833 to = &timeout;
834 closing = 2;
837 /* use the ignoreeof timeout if appropriate */
838 if (polling) {
839 if (closing == 0 ||
840 (socat_opts.pollintv.tv_sec < timeout.tv_sec) ||
841 ((socat_opts.pollintv.tv_sec == timeout.tv_sec) &&
842 socat_opts.pollintv.tv_usec < timeout.tv_usec)) {
843 timeout = socat_opts.pollintv;
847 /* now the fds will be assigned */
848 if (XIO_READABLE(sock1) &&
849 !(XIO_RDSTREAM(sock1)->eof > 1 && !XIO_RDSTREAM(sock1)->ignoreeof) &&
850 !socat_opts.righttoleft) {
851 if (!mayrd1 && !(XIO_RDSTREAM(sock1)->eof > 1)) {
852 fd1in->fd = XIO_GETRDFD(sock1);
853 fd1in->events = POLLIN;
854 } else {
855 fd1in->fd = -1;
857 if (!maywr2) {
858 fd2out->fd = XIO_GETWRFD(sock2);
859 fd2out->events = POLLOUT;
860 } else {
861 fd2out->fd = -1;
863 } else {
864 fd1in->fd = -1;
865 fd2out->fd = -1;
867 if (XIO_READABLE(sock2) &&
868 !(XIO_RDSTREAM(sock2)->eof > 1 && !XIO_RDSTREAM(sock2)->ignoreeof) &&
869 !socat_opts.lefttoright) {
870 if (!mayrd2 && !(XIO_RDSTREAM(sock2)->eof > 1)) {
871 fd2in->fd = XIO_GETRDFD(sock2);
872 fd2in->events = POLLIN;
873 } else {
874 fd2in->fd = -1;
876 if (!maywr1) {
877 fd1out->fd = XIO_GETWRFD(sock1);
878 fd1out->events = POLLOUT;
879 } else {
880 fd1out->fd = -1;
882 } else {
883 fd1out->fd = -1;
884 fd2in->fd = -1;
886 /* frame 0: innermost part of the transfer loop: check FD status */
887 retval = xiopoll(fds, 4, to);
888 if (retval >= 0 || errno != EINTR) {
889 break;
891 _errno = errno;
892 Info1("poll(): %s", strerror(errno));
893 errno = _errno;
894 } while (true);
896 /* attention:
897 when an exec'd process sends data and terminates, it is unpredictable
898 whether the data or the sigchild arrives first.
901 if (retval < 0) {
902 Error11("xiopoll({%d,%0o}{%d,%0o}{%d,%0o}{%d,%0o}, 4, {"F_tv_sec"."F_tv_usec"}): %s",
903 fds[0].fd, fds[0].events, fds[1].fd, fds[1].events,
904 fds[2].fd, fds[2].events, fds[3].fd, fds[3].events,
905 timeout.tv_sec, timeout.tv_usec, strerror(errno));
906 free(buff);
907 return -1;
908 } else if (retval == 0) {
909 Info2("poll timed out (no data within %ld.%06ld seconds)",
910 closing>=1?socat_opts.closwait.tv_sec:socat_opts.total_timeout.tv_sec,
911 closing>=1?socat_opts.closwait.tv_usec:socat_opts.total_timeout.tv_usec);
912 if (polling && !wasaction) {
913 /* there was a ignoreeof poll timeout, use it */
914 polling = 0; /*%%%*/
915 if (XIO_RDSTREAM(sock1)->ignoreeof) {
916 mayrd1 = 0;
918 if (XIO_RDSTREAM(sock2)->ignoreeof) {
919 mayrd2 = 0;
921 } else if (polling && wasaction) {
922 wasaction = 0;
924 } else if (socat_opts.total_timeout.tv_sec != 0 ||
925 socat_opts.total_timeout.tv_usec != 0) {
926 /* there was a total inactivity timeout */
927 Notice("inactivity timeout triggered");
928 free(buff);
929 return 0;
932 if (closing) {
933 break;
935 /* one possibility to come here is ignoreeof on some fd, but no EOF
936 and no data on any descriptor - this is no indication for end! */
937 continue;
940 if (XIO_READABLE(sock1) && XIO_GETRDFD(sock1) >= 0 &&
941 (fd1in->revents /*&(POLLIN|POLLHUP|POLLERR)*/)) {
942 if (fd1in->revents & POLLNVAL) {
943 /* this is what we find on Mac OS X when poll()'ing on a device or
944 named pipe. a read() might imm. return with 0 bytes, resulting
945 in a loop? */
946 Error1("poll(...[%d]: invalid request", fd1in->fd);
947 free(buff);
948 return -1;
950 mayrd1 = true;
952 if (XIO_READABLE(sock2) && XIO_GETRDFD(sock2) >= 0 &&
953 (fd2in->revents)) {
954 if (fd2in->revents & POLLNVAL) {
955 Error1("poll(...[%d]: invalid request", fd2in->fd);
956 free(buff);
957 return -1;
959 mayrd2 = true;
961 if (XIO_GETWRFD(sock1) >= 0 && fd1out->fd >= 0 && fd1out->revents) {
962 if (fd1out->revents & POLLNVAL) {
963 Error1("poll(...[%d]: invalid request", fd1out->fd);
964 free(buff);
965 return -1;
967 maywr1 = true;
969 if (XIO_GETWRFD(sock2) >= 0 && fd2out->fd >= 0 && fd2out->revents) {
970 if (fd2out->revents & POLLNVAL) {
971 Error1("poll(...[%d]: invalid request", fd2out->fd);
972 free(buff);
973 return -1;
975 maywr2 = true;
978 if (mayrd1 && maywr2) {
979 mayrd1 = false;
980 if ((bytes1 = xiotransfer(sock1, sock2, &buff, socat_opts.bufsiz, false))
981 < 0) {
982 if (errno != EAGAIN) {
983 closing = MAX(closing, 1);
984 Notice("socket 1 to socket 2 is in error");
985 if (socat_opts.lefttoright) {
986 break;
989 } else if (bytes1 > 0) {
990 maywr2 = false;
991 total_timeout = socat_opts.total_timeout;
992 wasaction = 1;
993 /* is more data available that has already passed poll()? */
994 mayrd1 = (xiopending(sock1) > 0);
995 if (XIO_RDSTREAM(sock1)->readbytes != 0 &&
996 XIO_RDSTREAM(sock1)->actbytes == 0) {
997 /* avoid idle when all readbytes already there */
998 mayrd1 = true;
1000 /* escape char occurred? */
1001 if (XIO_RDSTREAM(sock1)->actescape) {
1002 bytes1 = 0; /* indicate EOF */
1005 /* (bytes1 == 0) handled later */
1006 } else {
1007 bytes1 = -1;
1010 if (mayrd2 && maywr1) {
1011 mayrd2 = false;
1012 if ((bytes2 = xiotransfer(sock2, sock1, &buff, socat_opts.bufsiz, true))
1013 < 0) {
1014 if (errno != EAGAIN) {
1015 closing = MAX(closing, 1);
1016 Notice("socket 2 to socket 1 is in error");
1017 if (socat_opts.righttoleft) {
1018 break;
1021 } else if (bytes2 > 0) {
1022 maywr1 = false;
1023 total_timeout = socat_opts.total_timeout;
1024 wasaction = 1;
1025 /* is more data available that has already passed poll()? */
1026 mayrd2 = (xiopending(sock2) > 0);
1027 if (XIO_RDSTREAM(sock2)->readbytes != 0 &&
1028 XIO_RDSTREAM(sock2)->actbytes == 0) {
1029 /* avoid idle when all readbytes already there */
1030 mayrd2 = true;
1032 /* escape char occurred? */
1033 if (XIO_RDSTREAM(sock2)->actescape) {
1034 bytes2 = 0; /* indicate EOF */
1037 /* (bytes2 == 0) handled later */
1038 } else {
1039 bytes2 = -1;
1042 /* NOW handle EOFs */
1044 /*0 Debug4("bytes1=F_Zd, XIO_RDSTREAM(sock1)->eof=%d, XIO_RDSTREAM(sock1)->ignoreeof=%d, closing=%d",
1045 bytes1, XIO_RDSTREAM(sock1)->eof, XIO_RDSTREAM(sock1)->ignoreeof,
1046 closing);*/
1047 if (bytes1 == 0 || XIO_RDSTREAM(sock1)->eof >= 2) {
1048 if (XIO_RDSTREAM(sock1)->ignoreeof &&
1049 !XIO_RDSTREAM(sock1)->actescape && !closing) {
1050 Debug1("socket 1 (fd %d) is at EOF, ignoring",
1051 XIO_RDSTREAM(sock1)->fd); /*! */
1052 mayrd1 = true;
1053 polling = 1; /* do not hook this eof fd to poll for pollintv*/
1054 } else {
1055 Notice1("socket 1 (fd %d) is at EOF", XIO_GETRDFD(sock1));
1056 xioshutdown(sock2, SHUT_WR);
1057 XIO_RDSTREAM(sock1)->eof = 2;
1058 XIO_RDSTREAM(sock1)->ignoreeof = false;
1060 } else if (polling && XIO_RDSTREAM(sock1)->ignoreeof) {
1061 polling = 0;
1063 if (XIO_RDSTREAM(sock1)->eof >= 2) {
1064 if (socat_opts.lefttoright) {
1065 break;
1067 closing = 1;
1070 if (bytes2 == 0 || XIO_RDSTREAM(sock2)->eof >= 2) {
1071 if (XIO_RDSTREAM(sock2)->ignoreeof &&
1072 !XIO_RDSTREAM(sock2)->actescape && !closing) {
1073 Debug1("socket 2 (fd %d) is at EOF, ignoring",
1074 XIO_RDSTREAM(sock2)->fd);
1075 mayrd2 = true;
1076 polling = 1; /* do not hook this eof fd to poll for pollintv*/
1077 } else {
1078 Notice1("socket 2 (fd %d) is at EOF", XIO_GETRDFD(sock2));
1079 xioshutdown(sock1, SHUT_WR);
1080 XIO_RDSTREAM(sock2)->eof = 2;
1081 XIO_RDSTREAM(sock2)->ignoreeof = false;
1083 } else if (polling && XIO_RDSTREAM(sock2)->ignoreeof) {
1084 polling = 0;
1086 if (XIO_RDSTREAM(sock2)->eof >= 2) {
1087 if (socat_opts.righttoleft) {
1088 break;
1090 closing = 1;
1094 /* close everything that's still open */
1095 xioclose(sock1);
1096 xioclose(sock2);
1098 free(buff);
1099 return 0;
1103 #define MAXTIMESTAMPLEN 128
1104 /* prints the timestamp to the buffer and terminates it with '\0'. This buffer
1105 should be at least MAXTIMESTAMPLEN bytes long.
1106 returns 0 on success or -1 if an error occurred */
1107 int gettimestamp(char *timestamp) {
1108 size_t bytes;
1109 #if HAVE_GETTIMEOFDAY || 1
1110 struct timeval now;
1111 int result;
1112 time_t nowt;
1113 #else /* !HAVE_GETTIMEOFDAY */
1114 time_t now;
1115 #endif /* !HAVE_GETTIMEOFDAY */
1117 #if HAVE_GETTIMEOFDAY || 1
1118 result = gettimeofday(&now, NULL);
1119 if (result < 0) {
1120 return result;
1121 } else {
1122 nowt = now.tv_sec;
1123 #if HAVE_STRFTIME
1124 bytes = strftime(timestamp, 20, "%Y/%m/%d %H:%M:%S", localtime(&nowt));
1125 bytes += sprintf(timestamp+19, "."F_tv_usec" ", now.tv_usec);
1126 #else
1127 strcpy(timestamp, ctime(&nowt));
1128 bytes = strlen(timestamp);
1129 #endif
1131 #else /* !HAVE_GETTIMEOFDAY */
1132 now = time(NULL); if (now == (time_t)-1) {
1133 return -1;
1134 } else {
1135 #if HAVE_STRFTIME
1136 bytes = strftime(timestamp, 21, "%Y/%m/%d %H:%M:%S ", localtime(&now));
1137 #else
1138 strcpy(timestamp, ctime(&now));
1139 bytes = strlen(timestamp);
1140 #endif
1142 #endif /* !HAVE_GETTIMEOFDAY */
1143 return 0;
1146 static const char *prefixltor = "> ";
1147 static const char *prefixrtol = "< ";
1148 static unsigned long numltor;
1149 static unsigned long numrtol;
1150 /* print block header (during verbose or hex dump)
1151 returns 0 on success or -1 if an error occurred */
1152 static int
1153 xioprintblockheader(FILE *file, size_t bytes, bool righttoleft) {
1154 char timestamp[MAXTIMESTAMPLEN];
1155 char buff[128+MAXTIMESTAMPLEN];
1156 if (gettimestamp(timestamp) < 0) {
1157 return -1;
1159 if (righttoleft) {
1160 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1161 prefixrtol, timestamp, bytes, numrtol, numrtol+bytes-1);
1162 numrtol+=bytes;
1163 } else {
1164 sprintf(buff, "%s%s length="F_Zu" from=%lu to=%lu\n",
1165 prefixltor, timestamp, bytes, numltor, numltor+bytes-1);
1166 numltor+=bytes;
1168 fputs(buff, file);
1169 return 0;
1173 /* inpipe is suspected to have read data available; read at most bufsiz bytes
1174 and transfer them to outpipe. Perform required data conversions.
1175 buff must be a malloc()'ed storage and might be realloc()'ed in this
1176 function if more space is required after conversions.
1177 Returns the number of bytes written, or 0 on EOF or <0 if an
1178 error occurred or when data was read but none written due to conversions
1179 (with EAGAIN). EAGAIN also occurs when reading from a nonblocking FD where
1180 the file has a mandatory lock.
1181 If 0 bytes were read (EOF), it does NOT shutdown or close a channel, and it
1182 does NOT write a zero bytes block.
1184 /* inpipe, outpipe must be single descriptors (not dual!) */
1185 int xiotransfer(xiofile_t *inpipe, xiofile_t *outpipe,
1186 unsigned char **buff, size_t bufsiz, bool righttoleft) {
1187 ssize_t bytes, writt = 0;
1189 bytes = xioread(inpipe, *buff, bufsiz);
1190 if (bytes < 0) {
1191 if (errno != EAGAIN)
1192 XIO_RDSTREAM(inpipe)->eof = 2;
1193 /*xioshutdown(inpipe, SHUT_RD);*/
1194 return -1;
1196 if (bytes == 0 && XIO_RDSTREAM(inpipe)->ignoreeof && !closing) {
1198 } else if (bytes == 0) {
1199 XIO_RDSTREAM(inpipe)->eof = 2;
1200 closing = MAX(closing, 1);
1203 if (bytes > 0) {
1204 /* handle escape char */
1205 if (XIO_RDSTREAM(inpipe)->escape != -1) {
1206 /* check input data for escape char */
1207 unsigned char *ptr = *buff;
1208 size_t ctr = 0;
1209 while (ctr < bytes) {
1210 if (*ptr == XIO_RDSTREAM(inpipe)->escape) {
1211 /* found: set flag, truncate input data */
1212 XIO_RDSTREAM(inpipe)->actescape = true;
1213 bytes = ctr;
1214 Info("escape char found in input");
1215 break;
1217 ++ptr; ++ctr;
1219 if (ctr != bytes) {
1220 XIO_RDSTREAM(inpipe)->eof = 2;
1225 if (bytes > 0) {
1227 if (XIO_RDSTREAM(inpipe)->lineterm !=
1228 XIO_WRSTREAM(outpipe)->lineterm) {
1229 cv_newline(buff, &bytes,
1230 XIO_RDSTREAM(inpipe)->lineterm,
1231 XIO_WRSTREAM(outpipe)->lineterm);
1233 if (bytes == 0) {
1234 errno = EAGAIN; return -1;
1237 if (socat_opts.verbose && socat_opts.verbhex) {
1238 /* Hack-o-rama */
1239 size_t i = 0;
1240 size_t j;
1241 size_t N = 16;
1242 const unsigned char *end, *s, *t;
1243 s = *buff;
1244 end = (*buff)+bytes;
1245 xioprintblockheader(stderr, bytes, righttoleft);
1246 while (s < end) {
1247 /*! prefix? */
1248 j = Min(N, (size_t)(end-s));
1250 /* print hex */
1251 t = s;
1252 i = 0;
1253 while (i < j) {
1254 int c = *t++;
1255 fprintf(stderr, " %02x", c);
1256 ++i;
1257 if (c == '\n') break;
1260 /* fill hex column */
1261 while (i < N) {
1262 fputs(" ", stderr);
1263 ++i;
1265 fputs(" ", stderr);
1267 /* print acsii */
1268 t = s;
1269 i = 0;
1270 while (i < j) {
1271 int c = *t++;
1272 if (c == '\n') {
1273 fputc('.', stderr);
1274 break;
1276 if (!isprint(c))
1277 c = '.';
1278 fputc(c, stderr);
1279 ++i;
1282 fputc('\n', stderr);
1283 s = t;
1285 fputs("--\n", stderr);
1286 } else if (socat_opts.verbose) {
1287 size_t i = 0;
1288 xioprintblockheader(stderr, bytes, righttoleft);
1289 while (i < (size_t)bytes) {
1290 int c = (*buff)[i];
1291 if (i > 0 && (*buff)[i-1] == '\n')
1292 /*! prefix? */;
1293 switch (c) {
1294 case '\a' : fputs("\\a", stderr); break;
1295 case '\b' : fputs("\\b", stderr); break;
1296 case '\t' : fputs("\t", stderr); break;
1297 case '\n' : fputs("\n", stderr); break;
1298 case '\v' : fputs("\\v", stderr); break;
1299 case '\f' : fputs("\\f", stderr); break;
1300 case '\r' : fputs("\\r", stderr); break;
1301 case '\\' : fputs("\\\\", stderr); break;
1302 default:
1303 if (!isprint(c))
1304 c = '.';
1305 fputc(c, stderr);
1306 break;
1308 ++i;
1310 } else if (socat_opts.verbhex) {
1311 int i;
1312 /* print prefix */
1313 xioprintblockheader(stderr, bytes, righttoleft);
1314 for (i = 0; i < bytes; ++i) {
1315 fprintf(stderr, " %02x", (*buff)[i]);
1317 fputc('\n', stderr);
1320 writt = xiowrite(outpipe, *buff, bytes);
1321 if (writt < 0) {
1322 /* EAGAIN when nonblocking but a mandatory lock is on file.
1323 the problem with EAGAIN is that the read cannot be repeated,
1324 so we need to buffer the data and try to write it later
1325 again. not yet implemented, sorry. */
1326 #if 0
1327 if (errno == EPIPE) {
1328 return 0; /* can no longer write; handle like EOF */
1330 #endif
1331 return -1;
1332 } else {
1333 Info3("transferred "F_Zu" bytes from %d to %d",
1334 writt, XIO_GETRDFD(inpipe), XIO_GETWRFD(outpipe));
1337 return writt;
1340 #define CR '\r'
1341 #define LF '\n'
1344 /* converts the newline characters (or character sequences) from the one
1345 specified in lineterm1 to that of lineterm2. Possible values are
1346 LINETERM_CR, LINETERM_CRNL, LINETERM_RAW.
1347 buff points to the malloc()'ed data, input and output. It may be subject to
1348 realloc(). bytes specifies the number of bytes input and output */
1349 int cv_newline(unsigned char **buff, ssize_t *bufsiz,
1350 int lineterm1, int lineterm2) {
1351 ssize_t *bytes = bufsiz;
1352 /* must perform newline changes */
1353 if (lineterm1 <= LINETERM_CR && lineterm2 <= LINETERM_CR) {
1354 /* no change in data length */
1355 unsigned char from, to, *p, *z;
1356 if (lineterm1 == LINETERM_RAW) {
1357 from = '\n'; to = '\r';
1358 } else {
1359 from = '\r'; to = '\n';
1361 z = *buff + *bytes;
1362 p = *buff;
1363 while (p < z) {
1364 if (*p == from) *p = to;
1365 ++p;
1368 } else if (lineterm1 == LINETERM_CRNL) {
1369 /* buffer becomes shorter */
1370 unsigned char to, *s, *t, *z;
1371 if (lineterm2 == LINETERM_RAW) {
1372 to = '\n';
1373 } else {
1374 to = '\r';
1376 z = *buff + *bytes;
1377 s = t = *buff;
1378 while (s < z) {
1379 if (*s == '\r') {
1380 ++s;
1381 continue;
1383 if (*s == '\n') {
1384 *t++ = to; ++s;
1385 } else {
1386 *t++ = *s++;
1389 *bufsiz = t - *buff;
1390 } else {
1391 /* buffer becomes longer, must alloc another space */
1392 unsigned char *buf2;
1393 unsigned char from; unsigned char *s, *t, *z;
1394 if (lineterm1 == LINETERM_RAW) {
1395 from = '\n';
1396 } else {
1397 from = '\r';
1399 if ((buf2 = Malloc(2*socat_opts.bufsiz/*sic!*/+1)) == NULL) {
1400 return -1;
1402 s = *buff; t = buf2; z = *buff + *bytes;
1403 while (s < z) {
1404 if (*s == from) {
1405 *t++ = '\r'; *t++ = '\n';
1406 ++s;
1407 continue;
1408 } else {
1409 *t++ = *s++;
1412 free(*buff);
1413 *buff = buf2;
1414 *bufsiz = t - buf2;;
1416 return 0;
1419 void socat_signal(int signum) {
1420 int _errno;
1421 _errno = errno;
1422 diag_in_handler = 1;
1423 Notice1("socat_signal(): handling signal %d", signum);
1424 switch (signum) {
1425 case SIGQUIT:
1426 case SIGILL:
1427 case SIGABRT:
1428 case SIGBUS:
1429 case SIGFPE:
1430 case SIGSEGV:
1431 case SIGPIPE:
1432 diag_set_int('x', 128+signum); /* in case Error exits for us */
1433 Error1("exiting on signal %d", signum);
1434 diag_set_int('x', 0); /* in case Error did not exit */
1435 break;
1436 case SIGTERM:
1437 Warn1("exiting on signal %d", signum); break;
1438 case SIGHUP:
1439 case SIGINT:
1440 Notice1("exiting on signal %d", signum); break;
1442 //Exit(128+signum);
1443 Notice1("socat_signal(): finishing signal %d", signum);
1444 diag_exit(128+signum); /*!!! internal cleanup + _exit() */
1445 diag_in_handler = 0;
1446 errno = _errno;
1449 /* this is the callback when the child of an address died */
1450 static int socat_sigchild(struct single *file) {
1451 if (file->ignoreeof && !closing) {
1453 } else {
1454 file->eof = MAX(file->eof, 1);
1455 closing = 1;
1457 return 0;
1460 static int socat_lock(void) {
1461 int lockrc;
1463 #if 1
1464 if ((lockrc = xiolock(&socat_opts.lock)) < 0) {
1465 return -1;
1467 if (lockrc == 0) {
1468 havelock = true;
1470 return lockrc;
1471 #else
1472 if (socat_opts.lock.lockfile) {
1473 if ((lockrc = xiolock(socat_opts.lock.lockfile)) < 0) {
1474 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1475 return -1;
1477 if (lockrc) {
1478 return 1;
1480 havelock = true;
1481 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.lockfile);*/
1484 if (socat_opts.lock.waitlock) {
1485 if (xiowaitlock(socat_opts.lock.waitlock, socat_opts.lock.intervall)) {
1486 /*Error1("error with lockfile \"%s\"", socat_opts.lock.lockfile);*/
1487 return -1;
1488 } else {
1489 havelock = true;
1490 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
1493 return 0;
1494 #endif
1497 static void socat_unlock(void) {
1498 if (!havelock) return;
1499 if (socat_opts.lock.lockfile) {
1500 if (Unlink(socat_opts.lock.lockfile) < 0) {
1501 if (!diag_in_handler) {
1502 Warn2("unlink(\"%s\"): %s",
1503 socat_opts.lock.lockfile, strerror(errno));
1504 } else {
1505 Warn1("unlink(\"%s\"): "F_strerror,
1506 socat_opts.lock.lockfile);
1508 } else {
1509 Info1("released lock \"%s\"", socat_opts.lock.lockfile);
1514 /* this is a callback function that may be called by the newchild hook of xio
1516 static int socat_newchild(void) {
1517 havelock = false;
1518 return 0;