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 */
9 #include "xioconfig.h" /* what features are enabled */
11 #include "sysincludes.h"
23 #include "xiolockfile.h"
26 /* command line options */
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 */
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 */
47 {0,500000}, /* closwait */
48 {0,0}, /* total_timeout */
52 false, /* lefttoright */
53 false, /* righttoleft */
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
);
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
[] =
78 static const char timestamp
[] = BUILD_DATE
;
80 const char copyright_socat
[] = "socat by Gerhard Rieger and contributors - see www.dest-unreach.org";
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)";
89 int main(int argc
, const char *argv
[]) {
90 const char **arg1
, *a
;
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) {
110 xiosetopt('p', "!!");
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);
123 xioopenhelp(stdout
, (arg1
[0][2]=='?'||arg1
[0][2]=='h') ? (arg1
[0][3]=='?'||arg1
[0][3]=='h') ? 2 : 1 : 0);
125 #endif /* WITH_HELP */
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;
143 switch (arg1
[0][2]) {
144 case 'm': /* mixed mode: stderr, then switch to syslog; + facility */
147 socat_opts
.logopt
= arg1
[0][2];
148 xiosetopt('y', &arg1
[0][3]);
150 case 'y': /* syslog + facility */
151 diag_set(arg1
[0][2], &arg1
[0][3]);
153 case 'f': /* to file, +filename */
154 case 'p': /* artificial program name */
156 diag_set(arg1
[0][2], &arg1
[0][3]);
157 } else if (arg1
[1]) {
158 diag_set(arg1
[0][2], arg1
[1]);
161 Error1("option -l%c requires an argument; use option \"-h\" for help", arg1
[0][2]);
164 case 's': /* stderr */
165 diag_set(arg1
[0][2], NULL
);
171 diag_set_int('h', true);
174 Error1("unknown log option \"%s\"; use option \"-h\" for help", arg1
[0]);
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]) {
186 if ((a
= *arg1
) == NULL
) {
187 Error("option -r requires an argument; use option \"-h\" for help");
191 if ((socat_opts
.sniffleft
= Open(a
, O_CREAT
|O_WRONLY
|O_APPEND
|
195 O_NONBLOCK
, 0664)) < 0) {
196 if (errno
== ENXIO
) {
197 if ((socat_opts
.sniffleft
= Open(a
, O_CREAT
|O_RDWR
|O_APPEND
|
201 O_NONBLOCK
, 0664)) > 0)
202 break; /* try to open pipe rdwr */
204 Error2("option -r \"%s\": %s", a
, strerror(errno
));
207 case 'R': if (arg1
[0][2]) {
211 if ((a
= *arg1
) == NULL
) {
212 Error("option -R requires an argument; use option \"-h\" for help");
216 if ((socat_opts
.sniffright
= Open(a
, O_CREAT
|O_WRONLY
|O_APPEND
|
220 O_NONBLOCK
, 0664)) < 0) {
221 if (errno
== ENXIO
) {
222 if ((socat_opts
.sniffright
= Open(a
, O_CREAT
|O_RDWR
|O_APPEND
|
226 O_NONBLOCK
, 0664)) > 0)
227 break; /* try to open pipe rdwr */
229 Error2("option -R \"%s\": %s", a
, strerror(errno
));
232 case 'b': if (arg1
[0][2]) {
236 if ((a
= *arg1
) == NULL
) {
237 Error("option -b requires an argument; use option \"-h\" for help");
241 socat_opts
.bufsiz
= strtoul(a
, (char **)&a
, 0);
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]) {
249 if ((a
= *arg1
) == NULL
) {
250 Error("option -t requires an argument; use option \"-h\" for help");
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;
259 case 'T': if (arg1
[0][2]) {
263 if ((a
= *arg1
) == NULL
) {
264 Error("option -T requires an argument; use option \"-h\" for help");
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;
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");
282 socat_opts
.lock
.lockfile
= *arg1
+2;
285 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
286 Error("option -L requires an argument; use option \"-h\" for help");
291 case 'W': if (socat_opts
.lock
.lockfile
)
292 Error("only one -L and -W option allowed");
294 socat_opts
.lock
.lockfile
= *arg1
+2;
297 if ((socat_opts
.lock
.lockfile
= *arg1
) == NULL
) {
298 Error("option -W requires an argument; use option \"-h\" for help");
302 socat_opts
.lock
.waitlock
= true;
303 socat_opts
.lock
.intervall
.tv_sec
= 1;
304 socat_opts
.lock
.intervall
.tv_nsec
= 0;
306 #if WITH_IP4 || WITH_IP6
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];
317 #endif /* WITH_IP4 || WITH_IP6 */
322 break; /* this "-" is a variation of STDIO */
324 xioinqopt('p', buff
, sizeof(buff
)); /* fetch pipe separator char */
325 if (arg1
[0][1] == buff
[0]) {
329 Error1("unknown option \"%s\"; use option \"-h\" for help", arg1
[0]);
333 /* the leading "-" is a form of the first address */
339 Error1("exactly 2 addresses required (there are %d); use option \"-h\" for help", argc
);
342 if (socat_opts
.lefttoright
&& socat_opts
.righttoleft
) {
343 Error("-U and -u must not be combined");
347 Info(copyright_socat
);
349 Info(copyright_openssl
);
350 Info(copyright_ssleay
);
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
);
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
);
383 xiohook_newchild
= &socat_newchild
;
385 if (lockrc
= socat_lock()) {
386 /* =0: goon; >0: locked; <0: error, printed in sub */
388 Error1("could not obtain lock \"%s\"", socat_opts
.lock
.lockfile
);
392 Atexit(socat_unlock
);
394 result
= socat(arg1
[0], arg1
[1]);
395 Notice1("exiting with status %d", 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
);
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
);
414 fputs(" -D analyze file descriptors before loop\n", fd
);
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
);
437 fputs(" -4 prefer IPv4 if version is not explicitly specified\n", fd
);
440 fputs(" -6 prefer IPv6 if version is not explicitly specified\n", fd
);
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",
450 void socat_version(FILE *fd
) {
453 fputs(copyright_socat
, fd
); fputc('\n', fd
);
454 fprintf(fd
, "socat version %s on %s\n", socatversion
, timestamp
);
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
);
460 fprintf(fd
, " #define WITH_STDIO %d\n", WITH_STDIO
);
462 fputs(" #undef WITH_STDIO\n", fd
);
465 fprintf(fd
, " #define WITH_FDNUM %d\n", WITH_FDNUM
);
467 fputs(" #undef WITH_FDNUM\n", fd
);
470 fprintf(fd
, " #define WITH_FILE %d\n", WITH_FILE
);
472 fputs(" #undef WITH_FILE\n", fd
);
475 fprintf(fd
, " #define WITH_CREAT %d\n", WITH_CREAT
);
477 fputs(" #undef WITH_CREAT\n", fd
);
480 fprintf(fd
, " #define WITH_GOPEN %d\n", WITH_GOPEN
);
482 fputs(" #undef WITH_GOPEN\n", fd
);
485 fprintf(fd
, " #define WITH_TERMIOS %d\n", WITH_TERMIOS
);
487 fputs(" #undef WITH_TERMIOS\n", fd
);
490 fprintf(fd
, " #define WITH_PIPE %d\n", WITH_PIPE
);
492 fputs(" #undef WITH_PIPE\n", fd
);
495 fprintf(fd
, " #define WITH_UNIX %d\n", WITH_UNIX
);
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
);
502 fputs(" #undef WITH_ABSTRACT_UNIXSOCKET\n", fd
);
503 #endif /* WITH_ABSTRACT_UNIXSOCKET */
505 fprintf(fd
, " #define WITH_IP4 %d\n", WITH_IP4
);
507 fputs(" #undef WITH_IP4\n", fd
);
510 fprintf(fd
, " #define WITH_IP6 %d\n", WITH_IP6
);
512 fputs(" #undef WITH_IP6\n", fd
);
515 fprintf(fd
, " #define WITH_RAWIP %d\n", WITH_RAWIP
);
517 fputs(" #undef WITH_RAWIP\n", fd
);
519 #ifdef WITH_GENERICSOCKET
520 fprintf(fd
, " #define WITH_GENERICSOCKET %d\n", WITH_GENERICSOCKET
);
522 fputs(" #undef WITH_GENERICSOCKET\n", fd
);
524 #ifdef WITH_INTERFACE
525 fprintf(fd
, " #define WITH_INTERFACE %d\n", WITH_INTERFACE
);
527 fputs(" #undef WITH_INTERFACE\n", fd
);
530 fprintf(fd
, " #define WITH_TCP %d\n", WITH_TCP
);
532 fputs(" #undef WITH_TCP\n", fd
);
535 fprintf(fd
, " #define WITH_UDP %d\n", WITH_UDP
);
537 fputs(" #undef WITH_UDP\n", fd
);
540 fprintf(fd
, " #define WITH_SCTP %d\n", WITH_SCTP
);
542 fputs(" #undef WITH_SCTP\n", fd
);
545 fprintf(fd
, " #define WITH_LISTEN %d\n", WITH_LISTEN
);
547 fputs(" #undef WITH_LISTEN\n", fd
);
550 fprintf(fd
, " #define WITH_SOCKS4 %d\n", WITH_SOCKS4
);
552 fputs(" #undef WITH_SOCKS4\n", fd
);
555 fprintf(fd
, " #define WITH_SOCKS4A %d\n", WITH_SOCKS4A
);
557 fputs(" #undef WITH_SOCKS4A\n", fd
);
560 fprintf(fd
, " #define WITH_VSOCK %d\n", WITH_VSOCK
);
562 fputs(" #undef WITH_VSOCK\n", fd
);
565 fprintf(fd
, " #define WITH_PROXY %d\n", WITH_PROXY
);
567 fputs(" #undef WITH_PROXY\n", fd
);
570 fprintf(fd
, " #define WITH_SYSTEM %d\n", WITH_SYSTEM
);
572 fputs(" #undef WITH_SYSTEM\n", fd
);
575 fprintf(fd
, " #define WITH_EXEC %d\n", WITH_EXEC
);
577 fputs(" #undef WITH_EXEC\n", fd
);
580 fprintf(fd
, " #define WITH_READLINE %d\n", WITH_READLINE
);
582 fputs(" #undef WITH_READLINE\n", fd
);
585 fprintf(fd
, " #define WITH_TUN %d\n", WITH_TUN
);
587 fputs(" #undef WITH_TUN\n", fd
);
590 fprintf(fd
, " #define WITH_PTY %d\n", WITH_PTY
);
592 fputs(" #undef WITH_PTY\n", fd
);
595 fprintf(fd
, " #define WITH_OPENSSL %d\n", WITH_OPENSSL
);
597 fputs(" #undef WITH_OPENSSL\n", fd
);
600 fprintf(fd
, " #define WITH_FIPS %d\n", WITH_FIPS
);
602 fputs(" #undef WITH_FIPS\n", fd
);
605 fprintf(fd
, " #define WITH_LIBWRAP %d\n", WITH_LIBWRAP
);
607 fputs(" #undef WITH_LIBWRAP\n", fd
);
610 fprintf(fd
, " #define WITH_SYCLS %d\n", WITH_SYCLS
);
612 fputs(" #undef WITH_SYCLS\n", fd
);
615 fprintf(fd
, " #define WITH_FILAN %d\n", WITH_FILAN
);
617 fputs(" #undef WITH_FILAN\n", fd
);
620 fprintf(fd
, " #define WITH_RETRY %d\n", WITH_RETRY
);
622 fputs(" #undef WITH_RETRY\n", fd
);
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]);
628 fputs(" #undef WITH_MSGLEVEL\n", fd
);
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
) {
642 if (socat_opts
.lefttoright
) {
643 if ((sock1
= xioopen(address1
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
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
) {
651 xiosetsigchild(sock1
, socat_sigchild
);
653 if ((sock1
= xioopen(address1
, XIO_RDWR
|XIO_MAYFORK
|XIO_MAYCHILD
|XIO_MAYCONVERT
)) == NULL
) {
656 xiosetsigchild(sock1
, socat_sigchild
);
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
)) {
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) {
674 XIO_RDSTREAM(sock1
)->para
.exec
.pid
= 0;
675 /* return STAT_RETRYLATER; */
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
) {
687 xiosetsigchild(sock2
, socat_sigchild
);
689 if ((sock2
= xioopen(address2
, XIO_RDONLY
|XIO_MAYFORK
|XIO_MAYCHILD
|mayexec
|XIO_MAYCONVERT
)) == NULL
) {
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
) {
698 xiosetsigchild(sock2
, socat_sigchild
);
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
)) {
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) {
716 XIO_RDSTREAM(sock2
)->para
.exec
.pid
= 0;
717 /* return STAT_RETRYLATER; */
723 Info("resolved and opened all sock addresses");
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
) {
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*/;
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
);
758 Error5("xiopoll({%d,%0o}, 1, {"F_tv_sec
"."F_tv_usec
"}): %s",
759 in
.fd
, in
.events
, timeout
.tv_sec
, timeout
.tv_usec
,
764 Info("terminated child did not leave data for us");
765 XIO_RDSTREAM(xfd
)->eof
= 2;
767 closing
= MAX(closing
, 1);
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 */
785 struct pollfd fds
[4],
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 */
798 if (socat_opts
.debug
) {
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
);
811 filan_fd(fdo
, stderr
);
814 fdi
= XIO_GETRDFD(sock2
);
815 fdo
= XIO_GETWRFD(sock2
);
816 filan_fd(fdi
, stderr
);
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" */
837 if ((_errno
= Posix_memalign((void **)&buff
, getpagesize(), 2*socat_opts
.bufsiz
+1)) != 0) {
838 Error1("posix_memalign(): %s", strerror(_errno
));
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
,
864 total_timeout
.tv_sec
, total_timeout
.tv_usec
);
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");
891 /* there is a ignoreeof poll timeout, use it */
892 timeout
= socat_opts
.pollintv
;
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
;
904 /* first eof already occurred, start end timer */
905 timeout
= socat_opts
.pollintv
;
910 /* frame 1: set the poll parameters and loop over poll() EINTR) */
911 do { /* loop over poll() EINTR */
914 childleftdata(sock1
);
915 childleftdata(sock2
);
918 /* first eof already occurred, start end timer */
919 timeout
= socat_opts
.closwait
;
924 /* use the ignoreeof timeout if appropriate */
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
;
945 fd2out
->fd
= XIO_GETWRFD(sock2
);
946 fd2out
->events
= POLLOUT
;
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
;
964 fd1out
->fd
= XIO_GETWRFD(sock1
);
965 fd1out
->events
= POLLOUT
;
973 /* frame 0: innermost part of the transfer loop: check FD status */
974 retval
= xiopoll(fds
, 4, to
);
975 if (retval
>= 0 || errno
!= EINTR
) {
979 Info1("poll(): %s", strerror(errno
));
984 when an exec'd process sends data and terminates, it is unpredictable
985 whether the data or the sigchild arrives first.
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
));
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
) {
1005 if (XIO_RDSTREAM(sock2
)->ignoreeof
) {
1008 } else if (polling
&& wasaction
) {
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");
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! */
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
1033 Error1("poll(...[%d]: invalid request", fd1in
->fd
);
1039 if (XIO_READABLE(sock2
) && XIO_GETRDFD(sock2
) >= 0 &&
1041 if (fd2in
->revents
& POLLNVAL
) {
1042 Error1("poll(...[%d]: invalid request", fd2in
->fd
);
1048 if (XIO_GETWRFD(sock1
) >= 0 && fd1out
->fd
>= 0 && fd1out
->revents
) {
1049 if (fd1out
->revents
& POLLNVAL
) {
1050 Error1("poll(...[%d]: invalid request", fd1out
->fd
);
1056 if (XIO_GETWRFD(sock2
) >= 0 && fd2out
->fd
>= 0 && fd2out
->revents
) {
1057 if (fd2out
->revents
& POLLNVAL
) {
1058 Error1("poll(...[%d]: invalid request", fd2out
->fd
);
1065 if (mayrd1
&& maywr2
) {
1067 if ((bytes1
= xiotransfer(sock1
, sock2
, buff
, socat_opts
.bufsiz
, false))
1069 if (errno
!= EAGAIN
) {
1070 closing
= MAX(closing
, 1);
1071 Notice("socket 1 to socket 2 is in error");
1072 if (socat_opts
.lefttoright
) {
1076 } else if (bytes1
> 0) {
1078 total_timeout
= socat_opts
.total_timeout
;
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 */
1087 /* escape char occurred? */
1088 if (XIO_RDSTREAM(sock1
)->actescape
) {
1089 bytes1
= 0; /* indicate EOF */
1092 /* (bytes1 == 0) handled later */
1097 if (mayrd2
&& maywr1
) {
1099 if ((bytes2
= xiotransfer(sock2
, sock1
, buff
, socat_opts
.bufsiz
, true))
1101 if (errno
!= EAGAIN
) {
1102 closing
= MAX(closing
, 1);
1103 Notice("socket 2 to socket 1 is in error");
1104 if (socat_opts
.righttoleft
) {
1108 } else if (bytes2
> 0) {
1110 total_timeout
= socat_opts
.total_timeout
;
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 */
1119 /* escape char occurred? */
1120 if (XIO_RDSTREAM(sock2
)->actescape
) {
1121 bytes2
= 0; /* indicate EOF */
1124 /* (bytes2 == 0) handled later */
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,
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
); /*! */
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
) {
1150 if (XIO_RDSTREAM(sock1
)->eof
>= 2) {
1151 if (socat_opts
.lefttoright
) {
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
);
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
) {
1173 if (XIO_RDSTREAM(sock2
)->eof
>= 2) {
1174 if (socat_opts
.righttoleft
) {
1181 /* close everything that's still open */
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
) {
1196 #if HAVE_CLOCK_GETTIME
1197 struct timespec now
;
1198 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1200 #endif /* !HAVE_PROTOTYPE_LIB_gettimeofday */
1204 #if HAVE_CLOCK_GETTIME
1205 result
= clock_gettime(CLOCK_REALTIME
, &now
);
1210 #elif HAVE_PROTOTYPE_LIB_gettimeofday
1211 result
= Gettimeofday(&now
, NULL
);
1218 if (nowt
== (time_t)-1) {
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
);
1229 strncpy(×tamp
[bytes
++], " ", 2);
1232 strcpy(timestamp
, ctime(&nowt
));
1233 bytes
= strlen(timestamp
);
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 */
1245 xioprintblockheader(FILE *file
, size_t bytes
, bool righttoleft
) {
1246 char timestamp
[MAXTIMESTAMPLEN
];
1247 char buff
[128+MAXTIMESTAMPLEN
];
1248 if (gettimestamp(timestamp
) < 0) {
1252 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1253 prefixrtol
, timestamp
, bytes
, numrtol
, numrtol
+bytes
-1);
1256 sprintf(buff
, "%s%s length="F_Zu
" from=%lu to=%lu\n",
1257 prefixltor
, timestamp
, bytes
, numltor
, numltor
+bytes
-1);
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
);
1283 if (errno
!= EAGAIN
)
1284 XIO_RDSTREAM(inpipe
)->eof
= 2;
1285 /*xioshutdown(inpipe, SHUT_RD);*/
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);
1296 /* handle escape char */
1297 if (XIO_RDSTREAM(inpipe
)->escape
!= -1) {
1298 /* check input data for escape char */
1299 unsigned char *ptr
= buff
;
1301 while (ctr
< bytes
) {
1302 if (*ptr
== XIO_RDSTREAM(inpipe
)->escape
) {
1303 /* found: set flag, truncate input data */
1304 XIO_RDSTREAM(inpipe
)->actescape
= true;
1306 Info("escape char found in input");
1312 XIO_RDSTREAM(inpipe
)->eof
= 2;
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
);
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
) {
1340 const unsigned char *end
, *s
, *t
;
1343 xioprintblockheader(stderr
, bytes
, righttoleft
);
1346 j
= Min(N
, (size_t)(end
-s
));
1353 fprintf(stderr
, " %02x", c
);
1355 if (c
== '\n') break;
1358 /* fill hex column */
1380 fputc('\n', stderr
);
1383 fputs("--\n", stderr
);
1384 } else if (socat_opts
.verbose
) {
1386 xioprintblockheader(stderr
, bytes
, righttoleft
);
1387 while (i
< (size_t)bytes
) {
1389 if (i
> 0 && buff
[i
-1] == '\n')
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;
1408 } else if (socat_opts
.verbhex
) {
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
);
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. */
1425 if (errno
== EPIPE
) {
1426 return 0; /* can no longer write; handle like EOF */
1431 Info3("transferred "F_Zu
" bytes from %d to %d",
1432 writt
, XIO_GETRDFD(inpipe
), XIO_GETWRFD(outpipe
));
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';
1455 from
= '\r'; to
= '\n';
1460 if (*p
== from
) *p
= to
;
1464 } else if (lineterm1
== LINETERM_CRNL
) {
1465 /* buffer might become shorter */
1466 unsigned char to
, *s
, *t
, *z
;
1467 if (lineterm2
== LINETERM_RAW
) {
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
) {
1497 if ((buf2
= Malloc(socat_opts
.bufsiz
)) == NULL
) {
1501 memcpy(buf2
, buff
, *bytes
);
1502 s
= buf2
; t
= buff
; z
= buf2
+ *bytes
;
1505 *t
++ = '\r'; *t
++ = '\n';
1517 void socat_signal(int signum
) {
1520 diag_in_handler
= 1;
1521 Notice1("socat_signal(): handling signal %d", signum
);
1528 diag_immediate_exit
= 1;
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 */
1536 Warn1("exiting on signal %d", signum
); break;
1539 Notice1("exiting on signal %d", signum
); break;
1542 Notice1("socat_signal(): finishing signal %d", signum
);
1543 diag_exit(128+signum
); /*!!! internal cleanup + _exit() */
1544 diag_in_handler
= 0;
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
) {
1553 file
->eof
= MAX(file
->eof
, 1);
1559 static int socat_lock(void) {
1563 if ((lockrc
= xiolock(&socat_opts
.lock
)) < 0) {
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);*/
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);*/
1589 /*0 Info1("obtained lock \"%s\"", socat_opts.lock.waitlock);*/
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
));
1604 Warn1("unlink(\"%s\"): "F_strerror
,
1605 socat_opts
.lock
.lockfile
);
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) {