diff --git a/socat-1.7.4.3.tar.gz b/socat-1.7.4.3.tar.gz
deleted file mode 100644
index abc58429aa01adf8d11da96f454193ebf8da0370..0000000000000000000000000000000000000000
Binary files a/socat-1.7.4.3.tar.gz and /dev/null differ
diff --git a/socat-1.7.4.4.patch b/socat-1.7.4.4.patch
new file mode 100644
index 0000000000000000000000000000000000000000..3e371d4ac44e4279b0b27aa536495b5cf752caed
--- /dev/null
+++ b/socat-1.7.4.4.patch
@@ -0,0 +1,3586 @@
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/CHANGES socat-1.7.4.4/CHANGES
+--- socat-1.7.4.3/CHANGES 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/CHANGES 2022-10-30 16:21:47.880473970 +0100
+@@ -1,4 +1,144 @@
+
++####################### V 1.7.4.4:
++
++Corrections:
++ In error.c msg2() there was a stack overflow on long messages: The
++ terminating \0 Byte was written behind the last position.
++ Thanks to Martin Liška for sending the address sanitizer report.
++
++ UDP-RECVFROM with fork sometimes terminated when multiple packets
++ arrived. This issue was introduced with a bug fix in version 1.7.4.0.
++ Reason was not handling EAGAIN on recvmsg().
++ Thanks to Jamie McQuillan for reporting this issue.
++
++ Address TCP with options connect-timeout and retry terminated
++ immediately when a connection attempt failed on network error or
++ connection refused.
++ Test: TCP_TIMEOUT_RETRY
++ Thanks to Kamil Holubicki for reporting this issue.
++
++ There were a couple of weaknesses and errors when accessing invalid or
++ incompatible file system entries with UNIX domain, file, and generic
++ addresses.
++ For example, UNIX-CONNECT, when using a non matching socktype, failed
++ with -1 and did not print an error message, instead of printing an
++ error message and exiting with rc=1.
++ Thanks to Paul Wise for reporting and analyzing the case of accessing
++ a left over socket entry with GOPEN.
++
++ The rawer option failed because it tried to clear CREAD.
++ Test: RAWER
++
++ UDP-SEND and UPD-SENDTO with option lowport always bound to port 1
++ instead of a free port in range 640..1023
++ Test: UDP_LOWPORT
++
++ Fixed bad parser error message on "socat /tmp/x\"x/x -"
++
++ Tightened syntax checks to detect numerical arguments that are missing
++ or have trailing garbage.
++ Test: INTEGER_GARBAGE
++
++ ctype(3) functions need there arguments to be unsigned char.
++ Thanks to Taylor R Campbell for sending a patch.
++
++ Filan library uses Socats diag/error message system and therefore had
++ always the signal handler messages socket pair open. This fix avoids
++ this socketpair in standalone Filan.
++
++ Corrected printf format for type socklen_t in two places.
++
++Porting:
++ OpenSSL, at least 1.1 on Ubuntu, crashed with SIGSEGV under certain
++ conditions: client connection to server with certificate with empty
++ subject, and pressing ^C after successful connect.
++ This crash is now prevented by setting OPENSSL_INIT_NO_ATEXIT.
++ Thanks to Martin Dorey for reporting and analyzing this issue, and for
++ providing an environment for reproduction.
++
++ Socat failed to compile on platforms that have
++ IP_ADD_SOURCE_MEMBERSHIP but not struct ip_mreq_source
++ Thanks to Justin Yackoski for sending a patch.
++
++ configure.ac's detection of getprotobynumber_r() variant did not
++ recognize if this function does not exist, e.g. on Musl libc.
++ Thanks to Alexander Kanavin and Baruch Siach for sending patches.
++
++ Corrected message format when no strftime() is available; improved
++ handling of very long host or program names
++
++ Solaris requires that termios options are always applied to the slave
++ side of PTY.
++
++ Fixed ancillary messages on Solaris.
++
++ Filan: Solaris has the open file path infos in /proc//path/
++ Thanks to Andy Fiddaman to directing me to the patch.
++
++ Filan now recognizes and prints Solaris doors and event ports.
++
++ Solaris derivatives no longer need librt for clock_gettime()
++ Thanks to Andy Fiddaman to directing me to the patch.
++
++Building:
++ Failure during building documentation, e.g. due to missing Yodl
++ packages, now does not let the build process fail.
++ Feature requested by Seyhun.
++
++Features:
++ Filan prints target of symlink when appropriate
++ Test: FILANSYMLINK
++
++ VSOCK-LISTEN now generates environment variables SOCAT_PEERADDR,
++ SOCAT_PEERPORT, SOCAT_SOCKADDR, SOCAT_SOCKPORT
++ New address aliases VSOCK, VSOCK-L
++
++Documentation:
++ Fixed typo in doc/socat-tun.html and link in README.
++ Thanks to William Suthers for reporting.
++
++ Fixed hard coded path in docu examples.
++ Thanks to Jakub Wilk for sending a patch.
++
++ Updated doc/socat-openssltunnel.html: 2048 bits, commonname
++
++Testing:
++ Unset SOCAT_MAIN_WAIT on informational Socat calls
++
++ SOCAT=socat used ./socat instead of the version derived by $PATH
++
++ Do not try VSOCK_ECHO test when feature is not compiled in.
++
++ Fixed logging of test 220 TUNINTERFACE
++
++ Musl libc refuses to execve() shell scripts, 2 tests needed to be
++ adapted.
++
++ Musl libc has FOPEN_MAX=1000 which made bash dumping core on test
++ EXCEED_FOPEN_MAX.
++
++ Added tests for failures of UNIX socket and GOPEN accesses to non
++ matching file system entries.
++ Tests:
++ CONNECT_TO_MISSING CONNECT_TO_DENIED CONNECT_TO_DIRECTORY
++ CONNECT_TO_ORPHANED CONNECT_TO_FILE CONNECT_TO_DGRAM
++ CONNECT_TO_SEQPACKET SEND_TO_MISSING SEND_TO_DENIED SEND_TO_DIRECTORY
++ SEND_TO_ORPHANED SEND_TO_FILE SEND_TO_STREAM SEND_TO_SEQPACKET
++ SENDTO_TO_MISSING SENDTO_TO_DENIED SENDTO_TO_DIRECTORY
++ SENDTO_TO_ORPHANED SENDTO_TO_FILE SENDTO_TO_STREAM SENDTO_TO_SEQPACKET
++ SEQPACKET_TO_MISSING SEQPACKET_TO_DENIED SEQPACKET_TO_DIRECTORY
++ SEQPACKET_TO_ORPHANED SEQPACKET_TO_FILE SEQPACKET_TO_STREAM
++ SEQPACKET_TO_DGRAM UNIX_TO_MISSING UNIX_TO_DENIED UNIX_TO_DIRECTORY
++ UNIX_TO_FILE UNIX_TO_ORPHANED GOPEN_TO_DENIED GOPEN_TO_DIRECTORY
++ GOPEN_TO_ORPHANED
++
++ On RHEL-9 SCTP support requires installation of package
++ kernel-modules-extra. test.sh now detects when SCTP is missing in
++ kernel and reacts with warnings instead of errors.
++
++ VSOCK loopback still does not seem to work even in kernel 5.13, so just
++ issue warning on "No such device".
++
+ ####################### V 1.7.4.3:
+
+ Corrections:
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/Makefile.in socat-1.7.4.4/Makefile.in
+--- socat-1.7.4.3/Makefile.in 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/Makefile.in 2022-10-30 16:21:47.880473970 +0100
+@@ -100,11 +100,11 @@
+ rm -f doc/socat.1 doc/socat.html
+
+ doc/socat.1: doc/socat.yo
+- mkdir -p $(@D); yodl2man -o $@ $+
++ -mkdir -p $(@D); yodl2man -o $@ $+
+
+ doc/socat.html: doc/socat.yo
+ # care for refs in html
+- mkdir -p $(@D); cd $(@D); yodl2html -o socat.html ../$+; cd ..
++ -mkdir -p $(@D); cd $(@D); yodl2html -o socat.html ../$+; cd ..
+
+ progs: $(PROGS)
+
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/README socat-1.7.4.4/README
+--- socat-1.7.4.3/README 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/README 2022-10-30 16:21:47.880473970 +0100
+@@ -75,7 +75,7 @@
+
+ Get the tarball and extract it:
+ tar xzf socat.tar.gz
+- cd socat-1.7.4.3
++ cd socat-1.7.4.4
+ ./configure
+ make
+ su
+@@ -306,4 +306,4 @@
+
+ public git repository:
+ git://repo.or.cz/socat.git
+- http://repo.or.cz/r/socat.git
++ http://repo.or.cz/socat.git
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/VERSION socat-1.7.4.4/VERSION
+--- socat-1.7.4.3/VERSION 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/VERSION 2022-10-30 16:21:47.880473970 +0100
+@@ -1 +1 @@
+-"1.7.4.3"
++"1.7.4.4"
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/compat.h socat-1.7.4.4/compat.h
+--- socat-1.7.4.3/compat.h 2021-01-10 13:57:35.000000000 +0100
++++ socat-1.7.4.4/compat.h 2022-10-30 16:21:47.880473970 +0100
+@@ -31,6 +31,10 @@
+ # undef PIPE_STATES_SOCKET
+ #endif
+
++#if defined(__sun) || defined(__sun__) || defined(__SunOS)
++# define XIO_ANCILLARY_TYPE_SOLARIS 1
++#endif
++
+ /*****************************************************************************/
+
+ /* substitute some features that might be missing on some platforms */
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/config.h.in socat-1.7.4.4/config.h.in
+--- socat-1.7.4.3/config.h.in 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/config.h.in 2022-10-30 16:21:47.880473970 +0100
+@@ -652,6 +652,7 @@
+
+ /* Define if you have the /proc/$$/fd directories */
+ #undef HAVE_PROC_DIR_FD
++#undef HAVE_PROC_DIR_PATH
+
+ #undef HAVE_SETGRENT
+ #undef HAVE_GETGRENT
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/configure socat-1.7.4.4/configure
+--- socat-1.7.4.3/configure 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/configure 2022-10-30 16:21:47.884473989 +0100
+@@ -4358,7 +4358,7 @@
+ return 0;
+ }
+ _ACEOF
+-if ac_fn_c_try_compile "$LINENO"; then :
++if ac_fn_c_try_link "$LINENO"; then :
+ sc_cv_getprotobynumber_r=1; tmp_bynum_variant=Linux
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+@@ -4373,7 +4373,7 @@
+ return 0;
+ }
+ _ACEOF
+-if ac_fn_c_try_compile "$LINENO"; then :
++if ac_fn_c_try_link "$LINENO"; then :
+ sc_cv_getprotobynumber_r=2; tmp_bynum_variant=Solaris
+ else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+@@ -4388,17 +4388,20 @@
+ return 0;
+ }
+ _ACEOF
+-if ac_fn_c_try_compile "$LINENO"; then :
++if ac_fn_c_try_link "$LINENO"; then :
+ sc_cv_getprotobynumber_r=3; tmp_bynum_variant=AIX
+ else
+ sc_cv_getprotobynumber_r=
+
+ fi
+-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
+ fi
+-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
+ fi
+-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
++rm -f core conftest.err conftest.$ac_objext \
++ conftest$ac_exeext conftest.$ac_ext
+ fi
+
+ if test "$sc_cv_getprotobynumber_r"; then
+@@ -8377,7 +8380,12 @@
+ $as_echo "$sc_cv_have_prototype_lib_gettimeofday" >&6; }
+
+
+-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
++ac_fn_c_check_func "$LINENO" "clock_gettime" "ac_cv_func_clock_gettime"
++if test "x$ac_cv_func_clock_gettime" = xyes; then :
++ $as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
++
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+ $as_echo_n "checking for clock_gettime in -lrt... " >&6; }
+ if ${ac_cv_lib_rt_clock_gettime+:} false; then :
+ $as_echo_n "(cached) " >&6
+@@ -8418,6 +8426,8 @@
+
+ fi
+
++fi
++
+
+ # with Linux it's in libc, with AIX in libbsd
+ ac_fn_c_check_func "$LINENO" "flock" "ac_cv_func_flock"
+@@ -21101,6 +21111,20 @@
+ $as_echo "no" >&6; }
+ fi
+
++# On Solaris family, we have to use /proc/$$/path/N
++{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for /proc/*/path" >&5
++$as_echo_n "checking for /proc/*/path... " >&6; }
++if test -d /proc/$$/path; then
++ $as_echo "#define HAVE_PROC_DIR_PATH 1" >>confdefs.h
++
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
++$as_echo "yes" >&6; }
++else
++ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
++$as_echo "no" >&6; }
++fi
++
++
+ # on some platforms, raw linking with libwrap fails because allow_severity and
+ # deny_severity are not explicitely defined. Thus we put the libwrap part to
+ # the end
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/configure.ac socat-1.7.4.4/configure.ac
+--- socat-1.7.4.3/configure.ac 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/configure.ac 2022-10-30 16:21:47.884473989 +0100
+@@ -137,13 +137,13 @@
+ # getprotobynumber_r() is not standardized
+ AC_MSG_CHECKING(for getprotobynumber_r() variant)
+ AC_CACHE_VAL(sc_cv_getprotobynumber_r,
+-[AC_TRY_COMPILE([#include
++[AC_TRY_LINK([#include
+ #include ],[getprotobynumber_r(1,NULL,NULL,1024,NULL);],
+ [sc_cv_getprotobynumber_r=1; tmp_bynum_variant=Linux],
+- [AC_TRY_COMPILE([#include
++ [AC_TRY_LINK([#include
+ #include ],[getprotobynumber_r(1,NULL,NULL,1024);],
+ [sc_cv_getprotobynumber_r=2; tmp_bynum_variant=Solaris],
+- [AC_TRY_COMPILE([#include
++ [AC_TRY_LINK([#include
+ #include ],[getprotobynumber_r(1,NULL,NULL);],
+ [sc_cv_getprotobynumber_r=3; tmp_bynum_variant=AIX],
+
+@@ -1516,8 +1516,7 @@
+
+ AC_CHECK_PROTOTYPE_LIB(gettimeofday)
+
+-AC_CHECK_LIB(rt, clock_gettime,
+- [LIBS="-lrt $LIBS"; AC_DEFINE(HAVE_CLOCK_GETTIME)])
++AC_CHECK_FUNC(clock_gettime, AC_DEFINE(HAVE_CLOCK_GETTIME), AC_CHECK_LIB(rt, clock_gettime, [LIBS="-lrt $LIBS"; AC_DEFINE(HAVE_CLOCK_GETTIME)]))
+
+ dnl Search for flock()
+ # with Linux it's in libc, with AIX in libbsd
+@@ -1985,6 +1984,16 @@
+ AC_MSG_RESULT(no)
+ fi
+
++# On Solaris family, we have to use /proc/$$/path/N
++AC_MSG_CHECKING(for /proc/*/path)
++if test -d /proc/$$/path; then
++ AC_DEFINE(HAVE_PROC_DIR_PATH, 1)
++ AC_MSG_RESULT(yes)
++else
++ AC_MSG_RESULT(no)
++fi
++
++
+ dnl "tcpd" "tcpwrappers"
+ # on some platforms, raw linking with libwrap fails because allow_severity and
+ # deny_severity are not explicitely defined. Thus we put the libwrap part to
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat-openssltunnel.html socat-1.7.4.4/doc/socat-openssltunnel.html
+--- socat-1.7.4.3/doc/socat-openssltunnel.html 2016-07-21 23:28:19.000000000 +0200
++++ socat-1.7.4.4/doc/socat-openssltunnel.html 2022-10-30 16:21:47.896474048 +0100
+@@ -42,13 +42,13 @@
+ FILENAME=server
+
+ Generate a public/private key pair:
+-openssl genrsa -out $FILENAME.key 1024
++openssl genrsa -out $FILENAME.key 2048
+
+ Generate a self signed certificate:
+
+ openssl req -new -key $FILENAME.key -x509 -days 3653 -out $FILENAME.crt
+ You will be prompted for your country code, name etc.; you may quit all prompts
+-with the enter key.
++with the ENTER key, except for the Common Name which must be exactly the name or IP address of the server that the client will use.
+ First prepare a different basename for the files related to the client certificate:
+ Repeat the procedure for certificate generation described above. A special common name is not required.
+ Copy client.pem to the SSL client, and client.crt to the
+ server.
+
+@@ -81,7 +81,7 @@
+ ceritificate and private key, and After starting this command, socat should be listening on port 4433, but
+ will require client authentication.
+
+@@ -89,7 +89,7 @@
+ This command should establish a secured connection to the server
+ process.
+
+@@ -100,10 +100,10 @@
+ address of the server:
+
++ Socat 1.7.3.0 introduces check of servers commonname by the client, and optionally check of clients commonname by the server.
++
+
+-This document was last modified in March 2007.
++This document was last modified in Oct. 2023.
+
+
+ After successful connection both TUN interfaces should be active and transfer
+-date between each other using the TCP connection. Try this by pinging
++data between each other using the TCP connection. Try this by pinging
+ 192.168.255.1 from the client and 192.168.255.2 from the server.
+
+
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat.1 socat-1.7.4.4/doc/socat.1
+--- socat-1.7.4.3/doc/socat.1 2022-01-08 22:10:29.000000000 +0100
++++ socat-1.7.4.4/doc/socat.1 2022-10-30 16:21:47.900474067 +0100
+@@ -3792,7 +3792,7 @@
+ SOCAT_IP_DSTADDR: it contains the target address of the packet which may be a
+ unicast, multicast, or broadcast address\&.
+ .IP
+-.IP "\fB\f(CWecho \-e \(dq\&M\-SEARCH * HTTP/1\&.1\enHOST: 239\&.255\&.255\&.250:1900\enMAN: \e\(dq\&ssdp:discover\e\(dq\&\enMX: 4\enST: \e\(dq\&ssdp:all\e\(dq\&\en\(dq\& |\&./socat \- UDP\-DATAGRAM:239\&.255\&.255\&.250:1900,crlf\fP\fP"
++.IP "\fB\f(CWecho \-e \(dq\&M\-SEARCH * HTTP/1\&.1\enHOST: 239\&.255\&.255\&.250:1900\enMAN: \e\(dq\&ssdp:discover\e\(dq\&\enMX: 4\enST: \e\(dq\&ssdp:all\e\(dq\&\en\(dq\& |socat \- UDP\-DATAGRAM:239\&.255\&.255\&.250:1900,crlf\fP\fP"
+
+ .IP
+ sends an SSDP (Simple Service Discovery Protocol) query to the local network
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat.html socat-1.7.4.4/doc/socat.html
+--- socat-1.7.4.3/doc/socat.html 2022-01-08 22:10:29.000000000 +0100
++++ socat-1.7.4.4/doc/socat.html 2022-10-30 16:21:47.900474067 +0100
+@@ -1,26 +1,10 @@
+
+-
+
+ sends an SSDP (Simple Service Discovery Protocol) query to the local network
+ and collects and outputs the answers received.
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/doc/socat.yo socat-1.7.4.4/doc/socat.yo
+--- socat-1.7.4.3/doc/socat.yo 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/doc/socat.yo 2022-10-30 16:21:47.900474067 +0100
+@@ -3578,7 +3578,7 @@
+
+
+ label(EXAMPLE_SSD)
+-dit(bf(tt(echo -e "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 4\nST: \"ssdp:all\"\n" |./socat - UDP-DATAGRAM:239.255.255.250:1900,crlf)))
++dit(bf(tt(echo -e "M-SEARCH * HTTP/1.1\nHOST: 239.255.255.250:1900\nMAN: \"ssdp:discover\"\nMX: 4\nST: \"ssdp:all\"\n" |socat - UDP-DATAGRAM:239.255.255.250:1900,crlf)))
+
+ sends an SSDP (Simple Service Discovery Protocol) query to the local network
+ and collects and outputs the answers received.
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/error.c socat-1.7.4.4/error.c
+--- socat-1.7.4.3/error.c 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/error.c 2022-10-30 16:21:47.884473989 +0100
+@@ -37,6 +37,7 @@
+ int exitstatus; /* pass signal number to error exit */
+ bool withhostname; /* in custom logs add hostname */
+ char *hostname;
++ bool signalsafe;
+ } ;
+
+
+@@ -44,7 +45,7 @@
+
+
+ struct diag_opts diagopts =
+- { NULL, E_ERROR, E_ERROR, 0, NULL, LOG_DAEMON, false, 0 } ;
++ { NULL, E_ERROR, E_ERROR, 0, NULL, LOG_DAEMON, false, 0, false, NULL, true } ;
+
+ static void msg2(
+ #if HAVE_CLOCK_GETTIME
+@@ -134,8 +135,10 @@
+ diaginitialized = 1;
+ /* gcc with GNU libc refuses to set this in the initializer */
+ diagopts.logfile = stderr;
+- if (diag_sock_pair() < 0) {
+- return -1;
++ if (diagopts.signalsafe) {
++ if (diag_sock_pair() < 0) {
++ return -1;
++ }
+ }
+ return 0;
+ }
+@@ -143,6 +146,16 @@
+
+
+ void diag_set(char what, const char *arg) {
++ switch (what) {
++ case 'I':
++ if (diagopts.signalsafe) {
++ if (diag_sock_send >= 0) { Close(diag_sock_send); diag_sock_send = -1; }
++ if (diag_sock_recv >= 0) { Close(diag_sock_recv); diag_sock_recv = -1; }
++ }
++ diagopts.signalsafe = false;
++ return;
++ }
++
+ DIAG_INIT;
+ switch (what) {
+ const struct wordent *keywd;
+@@ -240,7 +253,10 @@
+ int diag_fork() {
+ Close(diag_sock_send);
+ Close(diag_sock_recv);
+- return diag_sock_pair();
++ if (diagopts.signalsafe) {
++ return diag_sock_pair();
++ }
++ return 0;
+ }
+
+ /* Linux and AIX syslog format:
+@@ -281,7 +297,7 @@
+ diag_dgram.level = level;
+ diag_dgram.exitcode = diagopts.exitstatus;
+ vsnprintf_r(diag_dgram.text, sizeof(diag_dgram.text), format, ap);
+- if (diag_in_handler && !diag_immediate_msg) {
++ if (diagopts.signalsafe && diag_in_handler && !diag_immediate_msg) {
+ send(diag_sock_send, &diag_dgram, sizeof(diag_dgram)-TEXTLEN + strlen(diag_dgram.text)+1,
+ 0 /* for canonical reasons */
+ #ifdef MSG_DONTWAIT
+@@ -317,8 +333,8 @@
+ #if HAVE_STRFTIME
+ struct tm struct_tm;
+ #endif
+-#define BUFLEN 512
+- char buff[BUFLEN], *bufp, *syslp;
++#define MSGLEN 512
++ char buff[MSGLEN+2], *bufp = buff, *syslp;
+ size_t bytes;
+
+ #if HAVE_CLOCK_GETTIME
+@@ -328,12 +344,14 @@
+ #else
+ epoch = *now;
+ #endif
++ /*! consider caching instead of recalculating many times per second */
+ #if HAVE_STRFTIME
+- bytes = strftime(buff, 20, "%Y/%m/%d %H:%M:%S", localtime_r(&epoch, &struct_tm));
+- buff[bytes] = '\0';
++ bytes = strftime(bufp, 20, "%Y/%m/%d %H:%M:%S", localtime_r(&epoch, &struct_tm));
+ #else
+- bytes = snprintf(buff, 11, F_time, epoch);
++ bytes = snprintf(bufp, 11, F_time, epoch);
+ #endif
++ bufp += bytes;
++ *bufp = '\0';
+ if (diagopts.micros) {
+ #if HAVE_CLOCK_GETTIME
+ micros = now->tv_nsec/1000;
+@@ -342,29 +360,38 @@
+ #else
+ micros = 0;
+ #endif
+- bytes += sprintf(buff+19, ".%06lu ", micros);
++ bufp += sprintf(bufp, ".%06lu ", micros);
+ } else {
+- buff[19] = ' '; buff[20] = '\0';
++ *bufp++ = ' ';
++ *bufp = '\0';
+ }
+- bytes = strlen(buff);
+
+- bufp = buff + bytes;
+ if (diagopts.withhostname) {
+- bytes = sprintf(bufp, "%s ", diagopts.hostname), bufp+=bytes;
+- }
+- bytes = sprintf(bufp, "%s["F_pid"] ", diagopts.progname, getpid());
++ bytes = snprintf(bufp, MSGLEN-(bufp-buff), "%s ", diagopts.hostname);
++ if (bytes >= MSGLEN-(bufp-buff))
++ bytes = MSGLEN-(bufp-buff)-1;
++ bufp += bytes;
++ }
++ bytes = snprintf(bufp, MSGLEN-(bufp-buff), "%s["F_pid"] ", diagopts.progname, getpid());
++ if (bytes >= MSGLEN-(bufp-buff))
++ bytes = MSGLEN-(bufp-buff)-1;
+ bufp += bytes;
+- syslp = bufp;
+- *bufp++ = "DINWEF"[level];
++ syslp = bufp; /* syslog prefixes with time etc.itself */
++ if (bufp < buff+MSGLEN)
++ *bufp++ = "DINWEF"[level];
+ #if 0 /* only for debugging socat */
+- if (handler) bufp[-1] = tolower(bufp[-1]); /* for debugging, low chars indicate messages from signal handlers */
++ if (handler) bufp[-1] = tolower((unsigned char)bufp[-1]); /* for debugging, low chars indicate messages from signal handlers */
+ #endif
+- *bufp++ = ' ';
+- strncpy(bufp, text, BUFLEN-(bufp-buff)-1);
+- strcat(bufp, "\n");
++ if (bufp < buff+MSGLEN)
++ *bufp++ = ' ';
++ strncpy(bufp, text, MSGLEN-(bufp-buff));
++ bufp = strchr(bufp, '\0');
++ strcpy(bufp, "\n");
+ _msg(level, buff, syslp);
+ if (level >= diagopts.exitlevel) {
+ if (E_NOTICE >= diagopts.msglevel) {
++ if ((syslp - buff) + 16 > MSGLEN+1)
++ syslp = buff + MSGLEN - 15;
+ snprintf_r(syslp, 16, "N exit(%d)\n", exitcode?exitcode:(diagopts.exitstatus?diagopts.exitstatus:1));
+ _msg(E_NOTICE, buff, syslp);
+ }
+@@ -388,6 +415,11 @@
+ void diag_flush(void) {
+ struct diag_dgram recv_dgram;
+ char exitmsg[20];
++
++ if (!diagopts.signalsafe) {
++ return;
++ }
++
+ while (recv(diag_sock_recv, &recv_dgram, sizeof(recv_dgram)-1,
+ 0 /* for canonical reasons */
+ #ifdef MSG_DONTWAIT
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/fdname.c socat-1.7.4.4/fdname.c
+--- socat-1.7.4.3/fdname.c 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/fdname.c 2022-10-30 16:21:47.884473989 +0100
+@@ -60,7 +60,7 @@
+ }
+ }
+
+-#if HAVE_PROC_DIR_FD
++#if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH
+ static int procgetfdname(int fd, char *filepath, size_t pathsize) {
+ static pid_t pid = -1;
+ char procpath[PATH_MAX];
+@@ -91,30 +91,36 @@
+ #endif /* !HAVE_STAT64 */
+
+ if (pid < 0) pid = Getpid();
+- snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/fd/%d", pid, fd);
++ snprintf(procpath, sizeof(procpath), "/proc/"F_pid"/"
++#if HAVE_PROC_DIR_PATH
++ "path"
++#else
++ "fd"
++#endif
++ "/%d", pid, fd);
+ if ((len = Readlink(procpath, filepath, pathsize-1)) < 0) {
+- Error4("readlink(\"%s\", %p, "F_Zu"): %s",
++ Warn4("readlink(\"%s\", %p, "F_Zu"): %s",
+ procpath, filepath, pathsize, strerror(errno));
+- return -1;
++ len = 0;
+ }
+ filepath[len] = '\0';
+ return 0;
+ }
+-#endif /* HAVE_PROC_DIR_FD */
++#endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */
+
+ int statname(const char *file, int fd, int filetype, FILE *outfile,
+ char style) {
+ char filepath[PATH_MAX];
+
+ filepath[0] = '\0';
+-#if HAVE_PROC_DIR_FD
++#if HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH
+ if (fd >= 0) {
+ procgetfdname(fd, filepath, sizeof(filepath));
+ if (filepath[0] == '/') {
+ file = filepath;
+ }
+ }
+-#endif /* HAVE_PROC_DIR_FD */
++#endif /* HAVE_PROC_DIR_FD || HAVE_PROC_DIR_PATH */
+ /* now see for type specific infos */
+ switch (filetype) {
+ case (S_IFIFO>>12): /* 1, FIFO */
+@@ -156,6 +162,18 @@
+ return -1;
+ #endif /* !_WITH_SOCKET */
+ break;
++#ifdef S_IFDOOR
++ case (S_IFDOOR>>12): /* 13, door (Solaris) */
++ fputs("door", outfile);
++ if (file) fprintf(outfile, " %s", file);
++ break;
++#endif /* HAVE_MACRO_S_IFDOOR */
++#ifdef S_IFPORT
++ case (S_IFPORT>>12): /* 14, event port (Solaris) */
++ fputs("event_port", outfile);
++ if (file) fprintf(outfile, " %s", file);
++ break;
++#endif /* HAVE_MACRO_S_IFPORT */
+ }
+ /* ioctl() */
+ fputc('\n', outfile);
+@@ -237,12 +255,21 @@
+ #if defined(SO_PROTOCOL) || defined(SO_PROTOTYPE)
+ optlen = sizeof(proto);
+ #ifdef SO_PROTOCOL
+- Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen);
++ rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOCOL, &proto, &optlen);
+ #elif defined(SO_PROTOTYPE)
+- Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen);
++ rc = Getsockopt(fd, SOL_SOCKET, SO_PROTOTYPE, &proto, &optlen);
+ #endif
++ if (rc < 0) {
++ Warn5("getsocktop(%d, SOL_SOCKET, "
++#ifdef SO_PROTOCOL
++ "SO_PROTOCOL"
++#else
++ "SO_PROTOTYPE"
++#endif
++ ", &%p, {"F_socklen"}): errno=%d (%s)", fd, &proto, optlen, errno, strerror(errno));
++ }
++ proto = 0;
+ #endif /* defined(SO_PROTOCOL) || defined(SO_PROTOTYPE) */
+-
+ optlen = sizeof(opttype);
+ Getsockopt(fd, SOL_SOCKET, SO_TYPE, &opttype, &optlen);
+ sockettype(opttype, typename, sizeof(typename));
+@@ -261,8 +288,12 @@
+ }
+ strncpy(protoname, protoentp->p_name, sizeof(protoname));
+ #elif HAVE_GETPROTOBYNUMBER_R==2 /* Solaris */
+- protoentp = getprotobynumber(proto);
+- strncpy(protoname, protoentp->p_name, sizeof(protoname));
++ {
++# define FILAN_GETPROTOBYNUMBER_R_BUFLEN 1024
++ char buffer[FILAN_GETPROTOBYNUMBER_R_BUFLEN];
++ protoentp = getprotobynumber_r(proto, &protoent, buffer, FILAN_GETPROTOBYNUMBER_R_BUFLEN);
++ strncpy(protoname, protoentp->p_name, sizeof(protoname));
++ }
+ #elif HAVE_GETPROTOBYNUMBER_R==3 /* AIX */
+ {
+ struct protoent_data proto_data;
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/filan.c socat-1.7.4.4/filan.c
+--- socat-1.7.4.3/filan.c 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/filan.c 2022-10-30 16:21:47.884473989 +0100
+@@ -79,17 +79,20 @@
+ default:
+ if ((fd =
+ Open(filename, O_RDONLY|O_NOCTTY|O_NONBLOCK
++#ifdef O_NOFOLLOW
++ |(filan_followsymlinks?0:O_NOFOLLOW)
++#endif
+ #ifdef O_LARGEFILE
+ |O_LARGEFILE
+ #endif
+ , 0700))
+ < 0) {
+- Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_LARGEFILE, 0700): %s",
++ Warn2("open(\"%s\", O_RDONLY|O_NOCTTY|O_NONBLOCK|O_NOFOLLOW|O_LARGEFILE, 0700): %s",
+ filename, strerror(errno));
+ }
+ }
+
+- result = filan_stat(&buf, fd, -1, outfile);
++ result = filan_stat(&buf, fd, -1, outfile, filename);
+ fputc('\n', outfile);
+ return result;
+ }
+@@ -119,7 +122,7 @@
+ }
+ Debug2("fd %d is a %s", fd, getfiletypestring(buf.st_mode));
+
+- result = filan_stat(&buf, fd, fd, outfile);
++ result = filan_stat(&buf, fd, fd, outfile, NULL);
+
+ if (result >= 0) {
+ /* even more dynamic info */
+@@ -212,7 +215,12 @@
+ #else
+ struct stat *buf
+ #endif /* !HAVE_STAT64 */
+- , int statfd, int dynfd, FILE *outfile) {
++ , int statfd, int dynfd, FILE *outfile,
++ const char *filename /* Linux does not (yet) provide an
++ freadlink system call, so we need
++ the original name for readlink in
++ case it is a symlink */
++ ) {
+ char stdevstr[8];
+
+ /* print header */
+@@ -380,7 +388,11 @@
+ break;
+ case (S_IFREG): /* 8, regular file */
+ break;
++#ifdef S_IFLNK
+ case (S_IFLNK): /* 10, symbolic link */
++ /* we wait for freadlink() sytem call */
++ break;
++#endif /* S_IFLNK */
+ break;
+ #ifdef S_IFSOCK
+ case (S_IFSOCK): /* 12, socket */
+@@ -393,6 +405,19 @@
+ break;
+ #endif /* S_IFSOCK */
+ }
++ } else {
++ switch (buf->st_mode&S_IFMT) {
++#ifdef S_IFLNK
++ case (S_IFLNK): /* 10, symbolic link */
++ {
++ char linktarget[PATH_MAX+1];
++ memset(linktarget, 0, PATH_MAX+1);
++ Readlink(filename, linktarget, PATH_MAX);
++ fprintf(outfile, "LINKTARGET=%s", linktarget);
++ }
++ break;
++#endif /* S_IFLNK */
++ }
+ }
+ /* ioctl() */
+ return 0;
+@@ -917,7 +942,7 @@
+ fd, &tcpinfo, sizeof(tcpinfo), strerror(errno));
+ return -1;
+ }
+- fprintf(outfile, "%s={%u}\t", "TCPI_STATE", tcpinfo.tcpi_state);
++ fprintf(outfile, "%s={%u}\t", "TCPI_STATE", tcpinfo.tcpi_state);
+ #if 0 /* on BSD these components are prefixed with __ - I get tired... */
+ fprintf(outfile, "%s={%u}\t", "TCPI_CA_STATE", tcpinfo.tcpi_ca_state);
+ fprintf(outfile, "%s={%u}\t", "TCPI_RETRANSMITS", tcpinfo.tcpi_retransmits);
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/filan.h socat-1.7.4.4/filan.h
+--- socat-1.7.4.3/filan.h 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/filan.h 2022-10-30 16:21:47.888474009 +0100
+@@ -22,7 +22,8 @@
+ #else
+ struct stat *buf
+ #endif /* !HAVE_STAT64 */
+- , int statfd, int dynfd, FILE *outfile);
++ , int statfd, int dynfd, FILE *outfile,
++ const char *filename);
+
+ extern int cdevan(int fd, FILE *outfile);
+
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/filan_main.c socat-1.7.4.4/filan_main.c
+--- socat-1.7.4.3/filan_main.c 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/filan_main.c 2022-10-30 16:21:47.888474009 +0100
+@@ -21,7 +21,7 @@
+
+
+ int main(int argc, const char *argv[]) {
+- const char **arg1, *a;
++ const char **arg1, *a0, *a;
+ const char *filename = NULL, *waittimetxt;
+ unsigned int m = 0; /* first FD (default) */
+ unsigned int n = FD_SETSIZE; /* last excl. */
+@@ -32,6 +32,7 @@
+ const char *outfname = NULL;
+ unsigned long fildes;
+
++ diag_set('I', false);
+ diag_set('p', strchr(argv[0], '/') ? strrchr(argv[0], '/')+1 : argv[0]);
+
+ arg1 = argv+1; --argc;
+@@ -50,27 +51,39 @@
+ case 'S': style = arg1[0][1]; break;
+ case 'r': filan_rawoutput = true; break;
+ case 'i': if (arg1[0][2]) {
+- a = *arg1+2;
++ a = a0 = *arg1+2;
+ } else {
+ ++arg1, --argc;
+- if ((a = *arg1) == NULL) {
++ if ((a = a0 = *arg1) == NULL) {
+ Error("option -i requires an argument");
+ filan_usage(stderr); exit(1);
+ }
+ }
+ m = strtoul(a, (char **)&a, 0);
++ if (a == a0) {
++ Error1("not a numerical arg in \"-b %s\"", a0);
++ }
++ if (*a != '\0') {
++ Error1("trailing garbage in \"-b %s\"", a0);
++ }
+ n = m;
+ break;
+ case 'n': if (arg1[0][2]) {
+- a = *arg1+2;
++ a = a0 = *arg1+2;
+ } else {
+ ++arg1, --argc;
+- if ((a = *arg1) == NULL) {
++ if ((a = a0 = *arg1) == NULL) {
+ Error("option -n requires an argument");
+ filan_usage(stderr); exit(1);
+ }
+ }
+ n = strtoul(a, (char **)&a, 0);
++ if (a == a0) {
++ Error1("not a numerical arg in \"-b %s\"", a0);
++ }
++ if (*a != '\0') {
++ Error1("trailing garbage in \"-b %s\"", a0);
++ }
+ break;
+ case 'f': if (arg1[0][2]) {
+ filename = *arg1+2;
+@@ -135,7 +148,7 @@
+ else if (!strcmp(outfname,"stderr")) { fdout=stderr; }
+ /* file descriptor */
+ else if (*outfname == '+') {
+- a = outfname+1;
++ a = outfname+1;
+ fildes = strtoul(a, (char **)&a, 0);
+ if ((fdout = fdopen(fildes, "w")) == NULL) {
+ Error2("can't fdopen file descriptor %lu: %s\n", fildes, strerror(errno));
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/socat.c socat-1.7.4.4/socat.c
+--- socat-1.7.4.3/socat.c 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/socat.c 2022-10-30 16:21:47.888474009 +0100
+@@ -238,7 +238,7 @@
+ Exit(1);
+ }
+ }
+- socat_opts.bufsiz = strtoul(a, (char **)&a, 0);
++ socat_opts.bufsiz = Strtoul(a, (char **)&a, 0, "-b");
+ break;
+ case 's': if (arg1[0][2]) { socat_opt_hint(stderr, arg1[0][1], arg1[0][2]); Exit(1); }
+ diag_set_int('e', E_FATAL); break;
+@@ -251,7 +251,7 @@
+ Exit(1);
+ }
+ }
+- rto = strtod(a, (char **)&a);
++ rto = Strtod(a, (char **)&a, "-t");
+ socat_opts.closwait.tv_sec = rto;
+ socat_opts.closwait.tv_usec =
+ (rto-socat_opts.closwait.tv_sec) * 1000000;
+@@ -265,7 +265,7 @@
+ Exit(1);
+ }
+ }
+- rto = strtod(a, (char **)&a);
++ rto = Strtod(a, (char **)&a, "-T");
+ socat_opts.total_timeout.tv_sec = rto;
+ socat_opts.total_timeout.tv_usec =
+ (rto-socat_opts.total_timeout.tv_sec) * 1000000;
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/socat.spec socat-1.7.4.4/socat.spec
+--- socat-1.7.4.3/socat.spec 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/socat.spec 2022-10-30 16:21:47.888474009 +0100
+@@ -1,6 +1,6 @@
+
+ %define majorver 1.7
+-%define minorver 4.3
++%define minorver 4.4
+
+ Summary: socat - multipurpose relay
+ Name: socat
+Binary files socat-1.7.4.3/socat.tar and socat-1.7.4.4/socat.tar differ
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/sslcls.c socat-1.7.4.4/sslcls.c
+--- socat-1.7.4.3/sslcls.c 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/sslcls.c 2022-10-30 16:21:47.888474009 +0100
+@@ -21,7 +21,7 @@
+ #include "sysutils.h"
+ #include "sycls.h"
+
+-#if HAVE_OPENSSL_init_ssl
++#if HAVE_OPENSSL_INIT_SSL
+ int sycOPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings) {
+ int result;
+ Debug2("OPENSSL_init_ssl("F_uint64_t", %p)", opts, settings);
+@@ -31,7 +31,7 @@
+ }
+ #endif
+
+-#if !HAVE_OPENSSL_init_ssl
++#if !HAVE_OPENSSL_INIT_SSL
+ void sycSSL_load_error_strings(void) {
+ Debug("SSL_load_error_strings()");
+ SSL_load_error_strings();
+@@ -39,7 +39,7 @@
+ }
+ #endif
+
+-#if !HAVE_OPENSSL_init_ssl
++#if !HAVE_OPENSSL_INIT_SSL
+ int sycSSL_library_init(void) {
+ int result;
+ Debug("SSL_library_init()");
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/sslcls.h socat-1.7.4.4/sslcls.h
+--- socat-1.7.4.3/sslcls.h 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/sslcls.h 2022-10-30 16:21:47.888474009 +0100
+@@ -8,7 +8,7 @@
+ #if WITH_SYCLS
+ #if WITH_OPENSSL
+
+-#if HAVE_OPENSSL_init_ssl
++#if HAVE_OPENSSL_INIT_SSL
+ int sycOPENSSL_init_ssl(uint64_t opts, const OPENSSL_INIT_SETTINGS *settings);
+ #endif
+ void sycSSL_load_error_strings(void);
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/sycls.c socat-1.7.4.4/sycls.c
+--- socat-1.7.4.3/sycls.c 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/sycls.c 2022-10-30 16:21:47.888474009 +0100
+@@ -677,7 +677,10 @@
+ _errno = errno;
+ if (!diag_in_handler) diag_flush();
+ #if WITH_SYCLS
+- Debug1("ioctl() -> %d", retval);
++ if (retval < 0)
++ Debug2("ioctl() -> %d, errno=%d", retval, _errno);
++ else
++ Debug1("ioctl() -> %d", retval);
+ #endif /* WITH_SYCLS */
+ errno = _errno;
+ return retval;
+@@ -1736,6 +1739,7 @@
+ }
+ #endif
+
++
+ #if WITH_READLINE
+
+ char *Readline(const char *prompt) {
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/sycls.h socat-1.7.4.4/sycls.h
+--- socat-1.7.4.3/sycls.h 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/sycls.h 2022-10-30 16:21:47.888474009 +0100
+@@ -167,6 +167,8 @@
+ int Mkstemp(char *template);
+ int Setenv(const char *name, const char *value, int overwrite);
+ void Unsetenv(const char *name);
++#endif /* WITH_SYCLS */
++#if WITH_SYCLS
+
+ char *Readline(const char *prompt);
+ void Using_history(void);
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/sysutils.c socat-1.7.4.4/sysutils.c
+--- socat-1.7.4.3/sysutils.c 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/sysutils.c 2022-10-30 16:21:47.888474009 +0100
+@@ -745,7 +745,7 @@
+ progname = diag_get_string('p');
+ envname[0] = '\0'; strncat(envname, progname, XIO_ENVNAMELEN-1);
+ l = strlen(envname);
+- for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
++ for (i = 0; i < l; ++i) envname[i] = toupper((unsigned char)envname[i]);
+ strncat(envname+l, "_", XIO_ENVNAMELEN-l-1);
+ l += 1;
+ strncat(envname+l, varname, XIO_ENVNAMELEN-l-1);
+@@ -771,7 +771,7 @@
+ l += 1;
+ strncat(envname+l, varname2, XIO_ENVNAMELEN-l-1);
+ l += strlen(envname+l);
+- for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
++ for (i = 0; i < l; ++i) envname[i] = toupper((unsigned char)envname[i]);
+ return _xiosetenv(envname, value, overwrite, sep);
+ # undef XIO_ENVNAMELEN
+ }
+@@ -799,7 +799,7 @@
+ l += 1;
+ strncat(envname+l, varname3, XIO_ENVNAMELEN-l-1);
+ l += strlen(envname+l);
+- for (i = 0; i < l; ++i) envname[i] = toupper(envname[i]);
++ for (i = 0; i < l; ++i) envname[i] = toupper((unsigned char)envname[i]);
+ return _xiosetenv(envname, value, overwrite, sep);
+ # undef XIO_ENVNAMELEN
+ }
+@@ -824,3 +824,45 @@
+ return xiosetenv(varname, envbuff, overwrite, NULL);
+ # undef XIO_SHORTLEN
+ }
++
++
++unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt) {
++ unsigned long res;
++
++ res = strtoul(nptr, endptr, base);
++ if (nptr == *endptr) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", txt);
++ }
++ if (**endptr != '\0') {
++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt);
++ }
++ return res;
++}
++
++#if HAVE_STRTOLL
++long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt) {
++ long long int res;
++
++ res = strtoul(nptr, endptr, base);
++ if (nptr == *endptr) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", txt);
++ }
++ if (**endptr != '\0') {
++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt);
++ }
++ return res;
++}
++#endif /* HAVE_STRTOLL */
++
++double Strtod(const char *nptr, char **endptr, const char *txt) {
++ double res;
++
++ res = strtod(nptr, endptr);
++ if (nptr == *endptr) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", txt);
++ }
++ if (**endptr != '\0') {
++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", txt);
++ }
++ return res;
++}
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/sysutils.h socat-1.7.4.4/sysutils.h
+--- socat-1.7.4.3/sysutils.h 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/sysutils.h 2022-10-30 16:21:47.888474009 +0100
+@@ -107,5 +107,8 @@
+ int overwrite);
+ extern int xiosetenvushort(const char *varname, unsigned short value,
+ int overwrite);
++extern unsigned long int Strtoul(const char *nptr, char **endptr, int base, const char *txt);
++extern long long int Strtoll(const char *nptr, char **endptr, int base, const char *txt);
++extern double Strtod(const char *nptr, char **endptr, const char *txt);
+
+ #endif /* !defined(__sysutils_h_included) */
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/test.sh socat-1.7.4.4/test.sh
+--- socat-1.7.4.3/test.sh 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/test.sh 2022-10-30 16:21:47.892474028 +0100
+@@ -51,6 +51,18 @@
+ [ -z "$SECONDs" ] && SECONDs=0
+
+ withroot=0 # perform privileged tests even if not run by root
++
++[ -z "$SOCAT" ] && SOCAT="./socat"
++if ! [ -x "$SOCAT" ] && ! type $SOCAT >/dev/null 2>&1; then
++ echo "$SOCAT does not exist" >&2; exit 1;
++fi
++if [ "$SOCAT" = socat ]; then
++ SOCAT=$(type -p socat) || SOCAT=$(which socat)
++fi
++#echo $SOCAT
++if [ -z "$PROCAN" ]; then if test -x ./procan; then PROCAN="./procan"; elif type procan >/dev/null 2>&1; then PROCAN=procan; elif test -x ${SOCAT%/*}/procan; then PROCAN=${SOCAT%/*}/procan; else PROCAN=false; fi; fi
++if [ -z "$FILAN" ]; then if test -x ./filan; then FILAN="./filan"; elif ! type filan >/dev/null 2>&1; then FILAN=filan; elif test -x ${SOCAT%/*}/filan; then FILAN=${SOCAT%/*}/filan; else FILAN=false; fi; fi
++
+ #PATH=$PATH:/opt/freeware/bin
+ #PATH=$PATH:/usr/local/ssl/bin
+ PATH=$PATH:/sbin # RHEL6:ip
+@@ -60,23 +72,18 @@
+ #OPENSSL_RAND="-rand /dev/egd-pool"
+ #SOCAT_EGD="egd=/dev/egd-pool"
+ MISCDELAY=1
+-[ -z "$SOCAT" ] && SOCAT="./socat"
+-if ! [ -x "$SOCAT" ] && ! type $SOCAT >/dev/null 2>&1; then
+- echo "$SOCAT does not exist" >&2; exit 1;
+-fi
+-if [ -z "$PROCAN" ]; then if test -x ./procan; then PROCAN="./procan"; elif type procan >/dev/null 2>&1; then PROCAN=procan; elif test -x ${SOCAT%/*}/procan; then PROCAN=${SOCAT%/*}/procan; else PROCAN=false; fi; fi
+-if [ -z "$FILAN" ]; then if test -x ./filan; then FILAN="./filan"; elif ! type filan >/dev/null 2>&1; then FILAN=filan; elif test -x ${SOCAT%/*}/filan; then FILAN=${SOCAT%/*}/filan; else FILAN=false; fi; fi
++
+ opts="$opt_t $OPTS"
+ export SOCAT_OPTS="$opts"
+ #debug="1"
+ debug=
+ TESTS="$*"; export TESTS
+-if ! $SOCAT -V >/dev/null 2>&1; then
++if ! SOCAT_MAIN_WAIT= $SOCAT -V >/dev/null 2>&1; then
+ echo "Failed to execute $SOCAT, exiting" >&2
+ exit 1
+ fi
+
+-SOCAT_VERSION=$($SOCAT -V |head -n 2 |tail -n 1 |sed 's/.* \([0-9][1-9]*\.[0-9][0-9]*\.[0-9][^[:space:]]*\).*/\1/')
++SOCAT_VERSION=$(SOCAT_MAIN_WAIT= $SOCAT -V |head -n 2 |tail -n 1 |sed 's/.* \([0-9][1-9]*\.[0-9][0-9]*\.[0-9][^[:space:]]*\).*/\1/')
+ if [ -z "$SOCAT_VERSION" ]; then
+ echo "Warning: failed to retrieve Socat version" >&2
+ fi
+@@ -263,8 +270,8 @@
+ # PTYOPTS2=
+ # ;;
+ SunOS)
+- PTYOPTS="echo=0,opost=0,perm=600"
+- PTYOPTS2="cfmakeraw"
++ PTYOPTS="perm=600"
++ PTYOPTS2="echo=0,opost=0"
+ ;;
+ *)
+ PTYOPTS="echo=0,opost=0"
+@@ -1842,7 +1849,7 @@
+ local a A;
+ for a in $@; do
+ A=$(echo "$a" |tr 'a-z-' 'A-Z_')
+- if $SOCAT -V |grep "#define WITH_$A 1\$" >/dev/null; then
++ if SOCAT_MAIN_WAIT= $SOCAT -V |grep "#define WITH_$A 1\$" >/dev/null; then
+ if [[ "$A" =~ OPENSSL.* ]]; then
+ gentestcert testsrv
+ gentestcert testcli
+@@ -2063,6 +2070,7 @@
+ runssctp4 () {
+ runsip4 >/dev/null || { echo SCTP4; return 1; }
+ $SOCAT -h |grep ' sctp4-' >/dev/null || return 1
++ $SOCAT /dev/null SCTP4-L:0,accept-timeout=0.001 2>/dev/null || return 1;
+ return 0;
+ }
+
+@@ -2070,6 +2078,7 @@
+ runssctp6 () {
+ runsip6 >/dev/null || { echo SCTP6; return 1; }
+ $SOCAT -h |grep ' sctp6-' >/dev/null || return 1
++ $SOCAT /dev/null SCTP6-L:0,accept-timeout=0.001 2>/dev/null || return 1;
+ return 0;
+ }
+
+@@ -2479,6 +2488,12 @@
+ return 1
+ }
+
++# system dependent values
++case "$UNAME" in
++ SunOS) SOCK_SEQPACKET=6 ;;
++ *) SOCK_SEQPACKET=5 ;;
++esac
++
+ # generate a test certificate and key
+ gentestcert () {
+ local name="$1"
+@@ -2535,6 +2550,8 @@
+ cat $name.key $name.crt testcert.dh >$name.pem
+ }
+
++#------------------------------------------------------------------------------
++# Begin of functional tests
+
+ NAME=UNISTDIO
+ case "$TESTS " in
+@@ -2668,7 +2685,7 @@
+ numCANT=$((numCANT+1))
+ listCANT="$listCANT $N"
+ else
+-testecho "$N" "$TEST" "" "exec:$CAT,pty,$PTYOPTS" "$opts"
++testecho "$N" "$TEST" "" "exec:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts"
+ fi
+ esac
+ N=$((N+1))
+@@ -2684,7 +2701,7 @@
+ numCANT=$((numCANT+1))
+ listCANT="$listCANT $N"
+ else
+-testecho "$N" "$TEST" "" "system:$CAT,pty,$PTYOPTS" "$opts"
++testecho "$N" "$TEST" "" "system:$CAT,pty,$PTYOPTS,$PTYOPTS2" "$opts"
+ fi
+ esac
+ N=$((N+1))
+@@ -2996,15 +3013,19 @@
+ if [ "$rc2" -ne 0 ]; then
+ $PRINTF "$FAILED: $TRACE $SOCAT:\n"
+ echo "$CMD1 &"
++ cat "${te}1"
+ echo "$CMD2"
+ echo "rc=$rc2"
+- cat "${te}1"
+ cat "${te}2"
+ numFAIL=$((numFAIL+1))
+ listFAIL="$listFAIL $N"
+ elif ! echo "$da" |diff - "$tf" >"$tdiff"; then
+ $PRINTF "$FAILED: diff:\n"
+ cat "$tdiff"
++ echo "$CMD1 &"
++ cat "${te}1"
++ echo "$CMD2"
++ cat "${te}2"
+ numFAIL=$((numFAIL+1))
+ listFAIL="$listFAIL $N"
+ else
+@@ -3875,10 +3896,6 @@
+ *%$N%*|*%functions%*|*%gopen%*|*%unix%*|*%listen%*|*%seqpacket%*|*%$NAME%*)
+ TEST="$NAME: GOPEN on UNIX seqpacket socket"
+ if ! eval $NUMCOND; then :; else
+- case "$UNAME" in
+- SunOS) SOCK_SEQPACKET=6 ;;
+- *) SOCK_SEQPACKET=5 ;;
+- esac
+ ts="$td/test$N.socket"
+ tf="$td/test$N.stdout"
+ te="$td/test$N.stderr"
+@@ -6485,10 +6502,13 @@
+ N=$((N+1))
+
+
++# Test if Filan can determine UNIX domain socket in file system
+ NAME=FILANSOCKET
+ case "$TESTS" in
+ *%$N%*|*%filan%*|*%$NAME%*)
+ TEST="$NAME: capability to analyze named unix socket"
++# Run Filan on a listening UNIX domain socket.
++# When its output gives "socket" as type (2nd column), the test succeeded
+ if ! eval $NUMCOND; then :; else
+ ts="$td/test$N.socket"
+ te1="$td/test$N.stderr1" # socat
+@@ -6500,10 +6520,16 @@
+ type=$($FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print($2);}')
+ if [ "$type" = "socket" ]; then
+ $PRINTF "$OK\n"
+- numOK=$((numOK+1))
++ if [ "$VERBOSE" ]; then
++ echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\""
++ echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'"
++ fi
++ numOK=$((numOK+1))
+ else
+ $PRINTF "$FAILED\n"
++ echo "$SOCAT $opts UNIX-LISTEN:\"$ts\" /dev/null \"$te1\"" >&2
+ cat "$te1"
++ echo "$FILAN -f "$ts" 2>$te2 |tail -n 1 |awk '{print(\$2);}'" >&2
+ cat "$te2"
+ numFAIL=$((numFAIL+1))
+ listFAIL="$listFAIL $N"
+@@ -8534,7 +8560,9 @@
+ kill $bg 2>/dev/null; wait
+ if [ $rc -ne 0 ]; then
+ $PRINTF "$FAILED: $TRACE $SOCAT:\n"
+- echo "$CMD &"
++ echo "$CMD1 &"
++ cat "${te}1"
++ echo "$CMD"
+ cat "$te"
+ numFAIL=$((numFAIL+1))
+ listFAIL="$listFAIL $N"
+@@ -8981,7 +9009,8 @@
+ sh="$td/test$N-sed.sh"
+ echo 'sed s/XXXX/YYYY/' >"$sh"
+ chmod a+x "$sh"
+-CMD1="$TRACE $SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,broadcast exec:$sh"
++# EXEC need not work with script (musl libc), so use SYSTEM
++CMD1="$TRACE $SOCAT $opts IP4-RECVFROM:$ts1p,reuseaddr,broadcast SYSTEM:$sh"
+ #CMD2="$TRACE $SOCAT $opts - IP4-BROADCAST:$ts1"
+ CMD2="$TRACE $SOCAT $opts - IP4-DATAGRAM:$ts1,broadcast"
+ printf "test $F_n $TEST... " $N
+@@ -9390,7 +9419,6 @@
+ tdiff="$td/test$N.diff"
+ tl="$td/test$N.lock"
+ da="$(date) $RANDOM"
+-dalen=$((${#da}+1))
+ TUNNET=10.255.255
+ TUNNAME=tun9
+ CMD1="$TRACE $SOCAT $opts -L $tl TUN:$TUNNET.1/24,iff-up=1,tun-type=tun,tun-name=$TUNNAME echo"
+@@ -9400,7 +9428,7 @@
+ pid1="$!"
+ #waitinterface "$TUNNAME"
+ sleep 1
+-echo "$da" |$CMD 2>"${te}1" >"$tf" 2>"${te}"
++echo "$da" |$CMD >"$tf" 2>"${te}"
+ kill $pid1 2>/dev/null
+ wait
+ if [ $? -ne 0 ]; then
+@@ -9857,6 +9885,7 @@
+ # Cygwin: 20 unlimit 256 64
+ # AIX: 32767 65534 65534
+ # SunOS 8: 20 1024
++# musl libc: 1024
+ NAME=EXCEED_FOPEN_MAX
+ case "$TESTS" in
+ *%$N%*|*%functions%*|*%maxfds%*|*%$NAME%*)
+@@ -9877,7 +9906,12 @@
+ numCANT=$((numCANT+1))
+ listCANT="$listCANT $N"
+ else
+-OPEN_FILES=$FOPEN_MAX # more than the highest FOPEN_MAX
++ if [ $FOPEN_MAX -lt 270 ]; then
++ OPEN_FILES=$FOPEN_MAX # more than the highest FOPEN_MAX
++ else
++ OPEN_FILES=269 # bash tends to SIGSEGV on higher value
++ # btw, the test is obsolete anyway
++ fi
+ i=3; while [ "$i" -lt "$OPEN_FILES" ]; do
+ REDIR="$REDIR $i>&2"
+ i=$((i+1))
+@@ -10541,7 +10575,7 @@
+ eval "$CMD0 2>\"${te}0\" >\"$tf\" &"
+ pid0=$!
+ wait${protov}port $tsa1 1
+-echo |$CMD1 2>"${te}1"
++{ echo; sleep 0.1; } |$CMD1 2>"${te}1"
+ rc1=$?
+ waitfile "$tf" 2
+ kill $pid0 2>/dev/null; wait
+@@ -10655,7 +10689,7 @@
+ eval "$CMD0 >\"$tf\" 2>\"${te}0\" &"
+ pid0="$!"
+ wait${proto}port $tra 1
+-echo "XYZ" |$CMD1 2>"${te}1"
++{ echo "XYZ"; sleep 0.1; } |$CMD1 2>"${te}1"
+ rc1="$?"
+ waitfile "$tf" 2
+ #i=0; while [ ! -s "${te}0" -a "$i" -lt 10 ]; do usleep 100000; i=$((i+1)); done
+@@ -11865,7 +11899,7 @@
+ N=$((N+1))
+
+
+-# PTY address allowed to sepcify address parameters but ignored them
++# PTY address allowed to specify address parameters but ignored them
+ NAME=PTY_VOIDARG
+ case "$TESTS" in
+ *%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%$NAME%*)
+@@ -13714,11 +13748,13 @@
+ te="$td/test$N.stderr"
+ tdiff="$td/test$N.diff"
+ da="test$N $(date) $RANDOM"
+-CMD0="$TRACE $SOCAT $opts -T 1 STDIO,echo=0 EXEC:cat"
++CMD0="$TRACE $SOCAT $opts -T 1 STDIO,echo=0 EXEC:cat 2>${te}0"
+ echo "$CMD0" >$td/test$N.sh
+ chmod a+x $td/test$N.sh
++# EXEC need not work with script (musl libc), so use SYSTEM
++CMD1="$TRACE $SOCAT $opts /dev/null SYSTEM:$td/test$N.sh,pty,$PTYOPTS"
+ printf "test $F_n $TEST... " $N
+-$SOCAT /dev/null EXEC:$td/test$N.sh,pty 2>"${te}0"
++$CMD1 2>"${te}1"
+ rc0=$?
+ if [ $rc0 -eq 0 ]; then
+ $PRINTF "$OK\n"
+@@ -13727,6 +13763,8 @@
+ $PRINTF "$FAILED\n"
+ echo "$CMD0"
+ cat "${te}0"
++ echo "$CMD1"
++ cat "${te}1"
+ numFAIL=$((numFAIL+1))
+ listFAIL="$listFAIL $N"
+ fi
+@@ -13860,7 +13898,7 @@
+ # Test if unbalanced quoting in Socat addresses is detected
+ NAME=UNBALANCED_QUOTE
+ case "$TESTS" in
+-*%$N%*|*%functions%*|*%bugs%*|*%$NAME%*)
++*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*)
+ TEST="$NAME: Test fix of unbalanced quoting"
+ # Invoke Socat with an address containing unbalanced quoting. If Socat prints
+ # a "syntax error" message, the test succeeds
+@@ -13872,8 +13910,10 @@
+ CMD0="$TRACE $SOCAT $opts -u FILE:$td/ab\"cd FILE:/dev/null"
+ printf "test $F_n $TEST... " $N
+ $CMD0 >/dev/null 2>"${te}0"
+-if grep -q "syntax error" "${te}0"; then
++if grep -q -i -e "syntax error" -e "unexpected end" "${te}0"; then
+ $PRINTF "$OK\n"
++ if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi
++ if [ "$debug" ]; then cat ${te} >&2; fi
+ numOK=$((numOK+1))
+ else
+ $PRINTF "$FAILED\n"
+@@ -14525,8 +14565,8 @@
+ listCANT="$listCANT $N"
+ else
+ # Second, set accept-timeout and see if socat exits before kill
+-CMD2="$TRACE $SOCAT $opts TCP-LISTEN:$PORT,reuseaddr,accept-timeout=1 PIPE" >"$te1" &
+-$CMD2 >"$te1" 2>&1 "$te2" 2>&1 "$tk2"; then
+@@ -14666,10 +14706,15 @@
+ NAME=VSOCK_ECHO
+ case "$TESTS" in
+ *%$N%*|*%functions%*|*%vsock%*|*%socket%*|*%$NAME%*)
+-TEST="$NAME: test communication via vsock loopback socket"
++TEST="$NAME: test communication via VSOCK loopback socket"
+ # Start a listening echo server
+ # Connect with a client, send data and compare reply with original data
+-if ! eval $NUMCOND; then :; else
++if ! eval $NUMCOND; then :;
++elif ! fea=$(testfeats VSOCK); then
++ $PRINTF "test $F_n $TEST... ${YELLOW}$fea not available${NORMAL}\n" $N
++ numCANT=$((numCANT+1))
++ listCANT="$listCANT $N"
++else
+ tf="$td/test$N.stdout"
+ te="$td/test$N.stderr"
+ tdiff="$td/test$N.diff"
+@@ -14691,6 +14736,10 @@
+ $PRINTF "${YELLOW}works only on Linux from 5.6${NORMAL}\n" $N
+ numCANT=$((numCANT+1))
+ listCANT="$listCANT $N"
++elif grep -q "No such device" "${te}1"; then
++ $PRINTF "${YELLOW}Loopback does not work${NORMAL}\n" $N
++ numCANT=$((numCANT+1))
++ listCANT="$listCANT $N"
+ elif [ $rc1 -ne 0 ]; then
+ $PRINTF "$FAILED\n"
+ echo "$CMD0 &" >&2
+@@ -15245,6 +15294,368 @@
+ PORT=$((PORT+1))
+ N=$((N+1))
+
++# Socats access to different types of file system entries using various kinds
++# of addresses fails in a couple of useless combinations. These failures have
++# to print an error message and exit with return code 1.
++# Up to version 1.7.4.2 this desired behaviour was found for most combinations,
++# however some fix in 1.7.4.3 degraded the overall result.
++# This group of tests checks all known compinations.
++while read entry method; do
++if [ -z "$entry" ] || [[ "$entry" == \#* ]]; then continue; fi
++NAME=$(toupper $method)_TO_$(toupper $entry)
++case "$TESTS" in
++*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%unix%*|*%$NAME%*)
++#set -vx
++TEST="$NAME: Failure handling on $method access to $entry"
++# Create some kind of system entry and try to access it with some improper
++# address. Check if Socat returns with rc 1 and prints an error message
++if ! eval $NUMCOND; then :; else
++ts="$td/test$N.socket"
++tf="$td/test$N.stdout"
++te="$td/test$N.stderr"
++tdiff="$td/test$N.diff"
++da="test$N $(date) $RANDOM"
++
++printf "test $F_n $TEST... " $N
++# create an invalid or non-matching UNIX socket
++case "$entry" in
++ missing) pid0=; rm -f $ts ;;
++ denied) pid0=; rm -f $ts; touch $ts; chmod 000 $ts ;;
++ directory) pid0=; mkdir -p $ts ;;
++ orphaned) pid0= # the remainder of a UNIX socket in FS
++ SOCAT_MAIN_WAIT= $SOCAT $opts UNIX-LISTEN:$ts,unlink-close=0 /dev/null >${tf}0 2>${te}0 &
++ waitunixport $ts 1
++ SOCAT_MAIN_WAIT= $SOCAT $opts /dev/null UNIX-CONNECT:$ts >>${tf}0 2>>${te}0
++ ;;
++ file) pid0=; rm -f $ts; touch $ts ;;
++ stream) CMD0="$SOCAT $opts UNIX-LISTEN:$ts /dev/null"
++ SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 &
++ pid0=$! ;;
++ dgram) CMD0="$SOCAT $opts -u UNIX-RECV:$ts /dev/null"
++ SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 &
++ pid0=$! ;;
++ seqpacket) CMD0="$SOCAT $opts UNIX-LISTEN:$ts,socktype=$SOCK_SEQPACKET /dev/null"
++ SOCAT_MAIN_WAIT= $CMD0 >${tf}0 2>${te}0 &
++ pid0=$! ;;
++esac
++[ "$pid0" ] && waitunixport $ts 1
++# try to access this socket
++case "$method" in
++ connect) CMD1="$TRACE $SOCAT $opts -u - UNIX-CONNECT:$ts" ;;
++ send) CMD1="$TRACE $SOCAT $opts -u - UNIX-SEND:$ts" ;;
++ sendto) CMD1="$TRACE $SOCAT $opts -u - UNIX-SENDTO:$ts" ;;
++ seqpacket) CMD1="$TRACE $SOCAT $opts -u - UNIX-CONNECT:$ts,socktype=$SOCK_SEQPACKET" ;;
++ unix) CMD1="$TRACE $SOCAT $opts -u - UNIX-CLIENT:$ts" ;;
++ gopen) CMD1="$TRACE $SOCAT $opts -u - GOPEN:$ts" ;;
++esac
++echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
++rc1=$?
++[ "$pid0" ] && { kill $pid0 2>/dev/null; wait; }
++if [ $rc1 != 1 ]; then
++ $PRINTF "$FAILED (bad return code $rc1)\n"
++ if [ "$pid0" ]; then
++ echo "$CMD0 &" >&2
++ cat "${te}0" >&2
++ fi
++ echo "$CMD1" >&2
++ cat "${te}1" >&2
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++elif nerr=$(grep ' E ' "${te}1" |wc -l); test "$nerr" -ne 1; then
++ $PRINTF "$FAILED ($nerr error message(s) instead of 1)\n"
++ if [ "$pid0" ]; then
++ echo "$CMD0 &" >&2
++ cat "${te}0" >&2
++ fi
++ echo "$CMD1" >&2
++ cat "${te}1" >&2
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++else
++ $PRINTF "$OK\n"
++ if [ "$VERBOSE" ]; then
++ if [ "$pid0" ]; then echo "$CMD0 &" >&2; fi
++ echo "$CMD1" >&2
++ fi
++ numOK=$((numOK+1))
++fi
++set +vx
++fi # NUMCOND
++ ;;
++esac
++N=$((N+1))
++done <<<"
++missing connect
++denied connect
++directory connect
++orphaned connect
++file connect
++dgram connect
++seqpacket connect
++missing send
++denied send
++directory send
++orphaned send
++file send
++stream send
++seqpacket send
++missing sendto
++denied sendto
++directory sendto
++orphaned sendto
++file sendto
++stream sendto
++seqpacket sendto
++missing seqpacket
++denied seqpacket
++directory seqpacket
++orphaned seqpacket
++file seqpacket
++stream seqpacket
++dgram seqpacket
++missing unix
++denied unix
++directory unix
++file unix
++orphaned unix
++denied gopen
++directory gopen
++orphaned gopen
++"
++
++
++# Test TCP with options connect-timeout and retry.
++# Up to 1.7.4.3 this terminated immediately on connection refused
++NAME=TCP_TIMEOUT_RETRY
++case "$TESTS" in
++*%$N%*|*%functions%*|*%bugs%*|*%tcp%*|*%socket%*|*%$NAME%*)
++TEST="$NAME: TCP with options connect-timeout and retry"
++# In background run a delayed echo server
++# In foreground start TCP with connect-timeout and retry. On first attempt the
++# server is not listening; when socat makes a second attempt that succeeds, the
++# bug is absent and the test succeeded.
++if ! eval $NUMCOND; then :; else
++tf="$td/test$N.stdout"
++te="$td/test$N.stderr"
++tdiff="$td/test$N.diff"
++da="test$N $(date) $RANDOM"
++CMD0="sleep 1 && $TRACE $SOCAT $opts TCP-L:$PORT,reuseaddr PIPE"
++CMD1="$TRACE $SOCAT $opts - TCP:$LOCALHOST:$PORT,connect-timeout=2,retry=1,interval=2"
++printf "test $F_n $TEST... " $N
++eval "$CMD0" >/dev/null 2>"${te}0" &
++pid0=$!
++echo "$da" |$CMD1 >"${tf}1" 2>"${te}1"
++rc1=$?
++kill $pid0 2>/dev/null; wait
++if [ $rc1 -ne 0 ]; then
++ $PRINTF "$FAILED\n"
++ echo "$CMD0 &" >&2
++ cat "${te}0" >&2
++ echo "$CMD1" >&2
++ cat "${te}1" >&2
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++elif echo "$da" |diff - "${tf}1" >$tdiff; then
++ $PRINTF "$OK\n"
++ if [ "$VERBOSE" ]; then
++ echo "$CMD0 &" >&2
++ echo "$CMD1" >&2
++ fi
++ numOK=$((numOK+1))
++else
++ $PRINTF "$FAILED\n"
++ echo "$CMD0 &" >&2
++ cat "${te}0" >&2
++ echo "$CMD1" >&2
++ cat "${te}1" >&2
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++fi
++fi # NUMCOND
++ ;;
++esac
++PORT=$((PORT+1))
++N=$((N+1))
++
++
++# Test if the rawer option works. Up to Socat 1.7.4.3, it failed because it
++# cleared the CREAD flag.
++NAME=RAWER
++case "$TESTS" in
++*%$N%*|*%functions%*|*%bugs%*|*%pty%*|*%$NAME%*)
++TEST="$NAME: Test if the rawer option fails"
++# Invoke Socat with a terminal address with option rawer. When it has no error
++# the test succeeded.
++if ! eval $NUMCOND; then :; else
++tf="$td/test$N.stdout"
++te="$td/test$N.stderr"
++tdiff="$td/test$N.diff"
++da="test$N $(date) $RANDOM"
++CMD0="$SOCAT -lp outer /dev/null EXEC:\"$SOCAT\\ -lp\\ inner\\ -\\,rawer\\ PIPE\",pty"
++printf "test $F_n $TEST... " $N
++eval "$CMD0" >/dev/null 2>"${te}0"
++rc0=$?
++if [ $rc0 -eq 0 ]; then
++ $PRINTF "$OK\n"
++ if [ "$VERBOSE" ]; then
++ echo "$CMD0" >&2
++ fi
++ numOK=$((numOK+1))
++else
++ $PRINTF "$FAILED\n"
++ echo "$CMD0" >&2
++ cat "${te}0" >&2
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++fi
++fi # NUMCOND
++ ;;
++esac
++PORT=$((PORT+1))
++N=$((N+1))
++
++# Up to 1.7.4.3 there was a bug with the lowport option:
++# Active addresses UDP-SEND, UDP-SENDTO always bound to port 1 instead of
++# 640..1023
++NAME=UDP_LOWPORT
++case "$TESTS" in
++*%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*)
++TEST="$NAME: UDP4-SEND with lowport"
++# Run Socat with UDP4-SEND:...,lowport and full logging and check the
++# parameters of bind() call. It port is in the range 640..1023 the test
++# succeeded.
++if ! eval $NUMCOND; then :; else
++tf="$td/test$N.stdout"
++te="$td/test$N.stderr"
++tdiff="$td/test$N.diff"
++da="test$N $(date) $RANDOM"
++CMD="$TRACE $SOCAT $opts -d -d -d -d /dev/null UDP4-SENDTO:$LOCALHOST:$PORT,lowport"
++printf "test $F_n $TEST... " $N
++$CMD >/dev/null 2>"${te}"
++rc1=$?
++LOWPORT=$(grep 'D bind(.*:' $te |sed 's/.*:\([0-9][0-9]*\),.*/\1/')
++#echo "LOWPORT=\"$LOWPORT\"" >&2
++#type socat >&2
++if [[ $LOWPORT =~ [0-9][0-9]* ]] && [ "$LOWPORT" -ge 640 -a "$LOWPORT" -le 1023 ]; then
++ $PRINTF "$OK\n"
++ if [ "$VERBOSE" ]; then
++ echo "$CMD" >&2
++ fi
++ numOK=$((numOK+1))
++else
++ $PRINTF "$FAILED\n"
++ echo "$CMD" >&2
++ cat "${te}" >&2
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++fi
++fi # NUMCOND
++ ;;
++esac
++PORT=$((PORT+1))
++N=$((N+1))
++
++# Test if trailing garbage in integer type options gives error
++NAME=MISSING_INTEGER
++case "$TESTS" in
++*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*)
++TEST="$NAME: Error on option that's missing integer value"
++# Invoke Socat with pty and option ispeed=b19200.
++# When socat terminates with error the test succeeded
++if ! eval $NUMCOND; then :; else
++tf="$td/test$N.stdout"
++te="$td/test$N.stderr"
++tdiff="$td/test$N.diff"
++da="test$N $(date) $RANDOM"
++CMD0="$TRACE $SOCAT $opts - PTY,ispeed=b19200"
++printf "test $F_n $TEST... " $N
++$CMD0 /dev/null 2>"${te}0"
++if grep -q "missing numerical value" "${te}0"; then
++ $PRINTF "$OK\n"
++ numOK=$((numOK+1))
++else
++ $PRINTF "$FAILED\n"
++ echo "$CMD0"
++ cat "${te}0"
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++fi
++fi # NUMCOND
++ ;;
++esac
++N=$((N+1))
++
++# Test if trailing garbage in integer type options gives error
++NAME=INTEGER_GARBAGE
++case "$TESTS" in
++*%$N%*|*%functions%*|*%syntax%*|*%bugs%*|*%$NAME%*)
++TEST="$NAME: Error on trailing garbabe"
++# Invoke Socat with pty and option ispeed=b19200.
++# When socat terminates with error the test succeeded
++if ! eval $NUMCOND; then :; else
++tf="$td/test$N.stdout"
++te="$td/test$N.stderr"
++tdiff="$td/test$N.diff"
++da="test$N $(date) $RANDOM"
++CMD0="$TRACE $SOCAT $opts - PTY,ispeed=19200B"
++printf "test $F_n $TEST... " $N
++$CMD0 /dev/null 2>"${te}0"
++if grep -q "trailing garbage" "${te}0"; then
++ $PRINTF "$OK\n"
++ if [ "$VERBOSE" ]; then echo "$CMD0" >&2; fi
++ if [ "$debug" ]; then cat ${te} >&2; fi
++ numOK=$((numOK+1))
++else
++ $PRINTF "$FAILED\n"
++ echo "$CMD0"
++ cat "${te}0"
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++fi
++fi # NUMCOND
++ ;;
++esac
++N=$((N+1))
++
++
++# Test if Filan can print the target of symbolic links
++NAME=FILANSYMLINK
++case "$TESTS" in
++*%$N%*|*%filan%*|*%$NAME%*)
++TEST="$NAME: capability to display symlink target"
++# Run Filan on a symbolic link
++# When its output contains "LINKTARGET=" the test succeeded
++if ! eval $NUMCOND; then :; else
++tf="$td/test$N.file"
++tl="$td/test$N.symlink"
++te="$td/test$N.stderr"
++printf "test $F_n $TEST... " $N
++touch "$tf"
++ln -s "$tf" "$tl"
++target=$($FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/')
++if [ "$target" = "$tf" ]; then
++ $PRINTF "$OK\n"
++ if [ "$VERBOSE" ]; then
++ echo "touch \"$tf\""
++ echo "ln -s \"$tf\" \"$tl\""
++ echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'"
++ fi
++ numOK=$((numOK+1))
++else
++ $PRINTF "$FAILED\n"
++ echo "touch \"$tf\"" >&2
++ echo "ln -s \"$tf\" \"$tl\"" >&2
++ echo "$FILAN -f "$tl" 2>$te |tail -n 1 |sed 's/.*LINKTARGET=\([^ ]*\)/\1/'" >&2
++ cat "$te"
++ numFAIL=$((numFAIL+1))
++ listFAIL="$listFAIL $N"
++fi
++kill $spid 2>/dev/null
++wait
++fi ;; # NUMCOND
++esac
++N=$((N+1))
++
+
+ # end of common tests
+
+@@ -15347,12 +15758,12 @@
+ #==============================================================================
+ # test template
+
+-# give a description of what is tested (a bugfix, a new feature...)
++# Give a description of what is tested (a bugfix, a new feature...)
+ NAME=SHORT_UNIQUE_TESTNAME
+ case "$TESTS" in
+ *%$N%*|*%functions%*|*%bugs%*|*%socket%*|*%$NAME%*)
+ TEST="$NAME: give a one line description of test"
+-# describe how the test is performed, and what's the success criteria
++# Describe how the test is performed, and what's the success criteria
+ if ! eval $NUMCOND; then :; else
+ tf="$td/test$N.stdout"
+ te="$td/test$N.stderr"
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/utils.c socat-1.7.4.4/utils.c
+--- socat-1.7.4.3/utils.c 2017-01-06 21:58:40.000000000 +0100
++++ socat-1.7.4.4/utils.c 2022-10-30 16:21:47.892474028 +0100
+@@ -97,7 +97,7 @@
+ int hn; /* high nibble */
+ int ln; /* low nibble */
+ int n; /* written chars */
+- if (isprint(c)) {
++ if (isprint((unsigned char)c)) {
+ *o = c;
+ return 1;
+ }
+@@ -160,7 +160,7 @@
+ *scratch = '\0';
+ return scratch0;
+ }
+-
++
+
+ /* since version 1.7.2.4 socat supports C-99 behaviour of snprintf but still
+ can handle the old glibc case with -1 return on truncation.
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/vsnprintf_r.c socat-1.7.4.4/vsnprintf_r.c
+--- socat-1.7.4.3/vsnprintf_r.c 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/vsnprintf_r.c 2022-10-30 16:21:47.892474028 +0100
+@@ -404,7 +404,7 @@
+ do {
+ fsize = 10*fsize+(c-'0');
+ c = *format++;
+- } while (c && isdigit(c));
++ } while (c && isdigit((unsigned char)c));
+ break;
+ }
+ if (c == '\0') { break; }
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-interface.c socat-1.7.4.4/xio-interface.c
+--- socat-1.7.4.3/xio-interface.c 2017-01-06 21:58:40.000000000 +0100
++++ socat-1.7.4.4/xio-interface.c 2022-10-30 16:21:47.892474028 +0100
+@@ -69,7 +69,7 @@
+
+ return
+ _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
+- opts, xioflags, xfd, groups, pf, socktype, 0);
++ opts, xioflags, xfd, groups, pf, socktype, 0, 0);
+ }
+
+ static
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-ip.c socat-1.7.4.4/xio-ip.c
+--- socat-1.7.4.3/xio-ip.c 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/xio-ip.c 2022-10-30 16:21:47.892474028 +0100
+@@ -71,7 +71,7 @@
+ #ifdef IP_ADD_MEMBERSHIP
+ const struct optdesc opt_ip_add_membership = { "ip-add-membership", "membership",OPT_IP_ADD_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQN, OFUNC_SOCKOPT, SOL_IP, IP_ADD_MEMBERSHIP };
+ #endif
+-#ifdef IP_ADD_SOURCE_MEMBERSHIP
++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
+ const struct optdesc opt_ip_add_source_membership = { "ip-add-source-membership", "source-membership",OPT_IP_ADD_SOURCE_MEMBERSHIP, GROUP_SOCK_IP, PH_PASTSOCKET, TYPE_IP_MREQ_SOURCE, OFUNC_SOCKOPT, SOL_IP, IP_ADD_SOURCE_MEMBERSHIP };
+ #endif
+ #ifdef IP_RECVDSTADDR
+@@ -618,7 +618,11 @@
+ cmsgtype = "IP_OPTIONS"; cmsgname = "options"; cmsgctr = -1;
+ /*!!!*/
+ break;
++#if XIO_ANCILLARY_TYPE_SOLARIS
++ case IP_RECVTOS:
++#else
+ case IP_TOS:
++#endif
+ cmsgtype = "IP_TOS"; cmsgname = "tos"; cmsgctr = msglen;
+ break;
+ case IP_TTL: /* Linux */
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-openssl.c socat-1.7.4.4/xio-openssl.c
+--- socat-1.7.4.3/xio-openssl.c 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/xio-openssl.c 2022-10-30 16:21:47.892474028 +0100
+@@ -959,11 +959,15 @@
+ openssl_delete_cert_info();
+
+ /* OpenSSL preparation */
+-#if HAVE_OPENSSL_init_ssl
++#if HAVE_OPENSSL_INIT_SSL
+ {
++ uint64_t opts = 0;
+ OPENSSL_INIT_SETTINGS *settings;
+ settings = OPENSSL_INIT_new();
+- sycOPENSSL_init_ssl(0, settings);
++#ifdef OPENSSL_INIT_NO_ATEXIT
++ opts |= OPENSSL_INIT_NO_ATEXIT;
++#endif
++ sycOPENSSL_init_ssl(opts, settings);
+ }
+ #else
+ sycSSL_library_init();
+@@ -1503,7 +1507,7 @@
+ progname = diag_get_string('p');
+ envprefix[0] = '\0'; strncat(envprefix, progname, XIO_ENVNAMELEN-1);
+ l = strlen(envprefix);
+- for (i = 0; i < l; ++i) envprefix[i] = toupper(envprefix[i]);
++ for (i = 0; i < l; ++i) envprefix[i] = toupper((unsigned char)envprefix[i]);
+ strncat(envprefix+l, "_OPENSSL_", XIO_ENVNAMELEN-l-1);
+
+ #if HAVE_VAR_ENVIRON
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-progcall.c socat-1.7.4.4/xio-progcall.c
+--- socat-1.7.4.3/xio-progcall.c 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/xio-progcall.c 2022-10-30 16:21:47.892474028 +0100
+@@ -8,6 +8,7 @@
+ #include "xioopen.h"
+
+ #include "xio-process.h"
++#include "xio-named.h"
+ #include "xio-progcall.h"
+
+ #include "xio-socket.h"
+@@ -73,6 +74,8 @@
+ bool withstderr = false;
+ bool nofork = false;
+ bool withfork;
++ char *tn = NULL;
++ int trigger[2];
+
+ popts = moveopts(*copts, GROUP_ALL);
+ if (applyopts_single(fd, popts, PH_INIT) < 0) return -1;
+@@ -223,19 +226,9 @@
+ /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", PTMX, ptyfd);*/
+ }
+ if (ptyfd >= 0 && ttyfd < 0) {
+- char *tn = NULL;
+ /* we used PTMX before forking */
+ extern char *ptsname(int);
+-#if HAVE_GRANTPT /* AIX, not Linux */
+- if (Grantpt(ptyfd)/*!*/ < 0) {
+- Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
+- }
+-#endif /* HAVE_GRANTPT */
+-#if HAVE_UNLOCKPT
+- if (Unlockpt(ptyfd)/*!*/ < 0) {
+- Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
+- }
+-#endif /* HAVE_UNLOCKPT */
++
+ #if HAVE_PROTOTYPE_LIB_ptsname /* AIX, not Linux */
+ if ((tn = Ptsname(ptyfd)) == NULL) {
+ Warn2("ptsname(%d): %s", ptyfd, strerror(errno));
+@@ -247,35 +240,16 @@
+ }
+ }
+ ptyname[0] = '\0'; strncat(ptyname, tn, MAXPTYNAMELEN-1);
+- if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
+- Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
+- } else {
+- /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
+- }
+-
+-#ifdef I_PUSH
+- /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
+- /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
+- /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
+- /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
+- if (Ioctl(ttyfd, I_FIND, "ldterm\0") == 0) {
+- Ioctl(ttyfd, I_PUSH, "ptem\0\0\0"); /* 0 */ /* padding for AdressSanitizer */
+- Ioctl(ttyfd, I_PUSH, "ldterm\0"); /* 0 */
+- Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
+- }
+-#endif
+-
+-#if 0 /* the following block need not work */
+-
+- if (ttyfd >= 0 && ((tn = Ttyname(ttyfd)) == NULL)) {
+- Warn2("ttyname(%d): %s", ttyfd, strerror(errno));
++#if HAVE_GRANTPT /* AIX, not Linux */
++ if (Grantpt(ptyfd)/*!*/ < 0) {
++ Warn2("grantpt(%d): %s", ptyfd, strerror(errno));
+ }
+- if (tn == NULL) {
+- Error("could not open pty");
+- return -1;
++#endif /* HAVE_GRANTPT */
++#if HAVE_UNLOCKPT
++ if (Unlockpt(ptyfd)/*!*/ < 0) {
++ Warn2("unlockpt(%d): %s", ptyfd, strerror(errno));
+ }
+-#endif
+- Info1("opened pseudo terminal %s", tn);
++#endif /* HAVE_UNLOCKPT */
+ }
+ }
+ #endif /* HAVE_DEV_PTMX || HAVE_DEV_PTC */
+@@ -290,7 +264,7 @@
+ }
+ #endif /* HAVE_OPENPTY */
+ free(*copts);
+- if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS)) == NULL) {
++ if ((*copts = moveopts(popts, GROUP_TERMIOS|GROUP_FORK|GROUP_EXEC|GROUP_PROCESS|GROUP_NAMED)) == NULL) {
+ return -1;
+ }
+ applyopts_cloexec(ptyfd, popts);/*!*/
+@@ -306,8 +280,6 @@
+
+ fd->fd = ptyfd;
+
+- /* this for child, was after fork */
+- applyopts(ttyfd, *copts, PH_FD);
+ } else
+ #endif /* HAVE_PTY */
+ if (usepipes) {
+@@ -411,6 +383,7 @@
+ xiosetchilddied(); /* set SIGCHLD handler */
+
+ if (withfork) {
++ Socketpair(PF_UNIX, SOCK_STREAM, 0, trigger);
+ pid = xio_fork(true, E_ERROR);
+ if (pid < 0) {
+ return -1;
+@@ -422,10 +395,43 @@
+ /* In particular, it's not defined whether ignoring SIGCHLD is inheritable. */
+ if (Signal(SIGCHLD, SIG_DFL) == SIG_ERR) {
+ Warn1("signal(SIGCHLD, SIG_DFL): %s", strerror(errno));
++ Close(trigger[0]);
+ }
+
+ #if HAVE_PTY
+ if (usepty) {
++ applyopts_named(tn, *copts, PH_PREOPEN);
++ applyopts_named(tn, *copts, PH_EARLY);
++ applyopts_named(tn, *copts, PH_FD);
++
++ if (ttyfd < 0) {
++ if ((ttyfd = Open(tn, O_RDWR|O_NOCTTY, 0620)) < 0) {
++ Warn2("open(\"%s\", O_RDWR|O_NOCTTY, 0620): %s", tn, strerror(errno));
++ } else {
++ /*0 Info2("open(\"%s\", O_RDWR|O_NOCTTY, 0620) -> %d", tn, ttyfd);*/
++ }
++ } else {
++ if ((tn = Ttyname(ttyfd)) == NULL) {
++ Warn2("ttyname(%d): %s", ttyfd, strerror(errno));
++ }
++ }
++
++#ifdef I_PUSH
++ /* Linux: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> -1 EINVAL */
++ /* AIX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 1 */
++ /* SunOS: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
++ /* HP-UX: I_PUSH def'd; pty: ioctl(, I_FIND, ...) -> 0 */
++ if (Ioctl(ttyfd, I_FIND, "ldterm\0") == 0) {
++ Ioctl(ttyfd, I_PUSH, "ptem\0\0\0"); /* 0 */ /* padding for AdressSanitizer */
++ Ioctl(ttyfd, I_PUSH, "ldterm\0"); /* 0 */
++ Ioctl(ttyfd, I_PUSH, "ttcompat"); /* HP-UX: -1 */
++ }
++#endif
++
++ /* this for child, was after fork */
++ applyopts(ttyfd, *copts, PH_FD);
++
++ Info1("opened pseudo terminal %s", tn);
+ Close(ptyfd);
+ if (rw != XIO_RDONLY && fdi != ttyfd) {
+ /* make sure that the internal diagnostic socket pair fds do not conflict
+@@ -451,7 +457,6 @@
+ }
+
+ applyopts(ttyfd, *copts, PH_LATE);
+-
+ applyopts(ttyfd, *copts, PH_LATE2);
+ } else
+ #endif /* HAVE_PTY */
+@@ -539,6 +544,10 @@
+ applyopts(fdi, *copts, PH_LATE);
+ applyopts(fdi, *copts, PH_LATE2);
+ }
++ if (withfork) {
++ Info("Signalling parent ready");
++ Close(trigger[1]);
++ }
+ } /* withfork */
+ else {
+ applyopts(-1, *copts, PH_LATE);
+@@ -556,6 +565,7 @@
+
+ /* for parent (this is our socat process) */
+ Notice1("forked off child process "F_pid, pid);
++ Close(trigger[1]);
+
+ #if 0
+ if ((popts = copyopts(*copts,
+@@ -565,9 +575,11 @@
+
+ #if HAVE_PTY
+ if (usepty) {
++# if 0
+ if (Close(ttyfd) < 0) {
+ Info2("close(%d): %s", ttyfd, strerror(errno));
+ }
++# endif
+ } else
+ #endif /* HAVE_PTY */
+ if (usepipes) {
+@@ -586,6 +598,14 @@
+ return STAT_NORETRY;
+ }
+
++ {
++ struct pollfd fds[1];
++ fds[0].fd = trigger[0];
++ fds[0].events = POLLIN|POLLHUP;
++ Poll(fds, 1, -1);
++ Info("Child process signalled ready");
++ }
++
+ return pid; /* indicate parent (main) process */
+ }
+ #endif /* WITH_EXEC || WITH_SYSTEM */
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-rawip.c socat-1.7.4.4/xio-rawip.c
+--- socat-1.7.4.3/xio-rawip.c 2017-01-06 21:58:40.000000000 +0100
++++ socat-1.7.4.4/xio-rawip.c 2022-10-30 16:21:47.892474028 +0100
+@@ -143,7 +143,7 @@
+ }
+ return
+ _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
+- opts, xioflags, xfd, groups, *pf, socktype, ipproto);
++ opts, xioflags, xfd, groups, *pf, socktype, ipproto, 0);
+ }
+
+
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-socket.c socat-1.7.4.4/xio-socket.c
+--- socat-1.7.4.3/xio-socket.c 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/xio-socket.c 2022-10-30 16:21:47.896474048 +0100
+@@ -14,6 +14,9 @@
+ #include "xio-socket.h"
+ #include "xio-named.h"
+ #include "xio-unix.h"
++#if WITH_VSOCK
++#include "xio-vsock.h"
++#endif
+ #if WITH_IP4
+ #include "xio-ip4.h"
+ #endif /* WITH_IP4 */
+@@ -63,6 +66,14 @@
+ char *nambuff, int namlen,
+ char *envbuff, int envlen,
+ char *valbuff, int vallen);
++static int xiobind(
++ struct single *xfd,
++ union sockaddr_union *us,
++ size_t uslen,
++ struct opt *opts,
++ int pf,
++ bool alt,
++ int level);
+
+
+ #if WITH_GENERICSOCKET
+@@ -457,7 +468,7 @@
+
+ return
+ _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
+- opts, xioflags, xfd, groups, pf, socktype, proto);
++ opts, xioflags, xfd, groups, pf, socktype, proto, 0);
+ }
+
+
+@@ -693,6 +704,7 @@
+
+ #endif /* WITH_GENERICSOCKET */
+
++/* EINTR not handled specially */
+ int xiogetpacketinfo(int fd)
+ {
+ #if defined(MSG_ERRQUEUE)
+@@ -737,14 +749,14 @@
+
+
+
+-/* a subroutine that is common to all socket addresses that want to connect
+- to a peer address.
+- might fork.
+- applies and consumes the following options:
++/* A subroutine that is common to all socket addresses that want to connect()
++ a socket to a peer.
++ Applies and consumes the following options:
+ PH_PASTSOCKET, PH_FD, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_CONNECT,
+ PH_CONNECTED, PH_LATE,
+ OFUNC_OFFSET,
+ OPT_SO_TYPE, OPT_SO_PROTOTYPE, OPT_USER, OPT_GROUP, OPT_CLOEXEC
++ Does not fork, does not retry.
+ returns 0 on success.
+ */
+ int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
+@@ -774,111 +786,9 @@
+
+ applyopts_cloexec(xfd->fd, opts);
+
+-#if WITH_UNIX
+- if (pf == PF_UNIX && us != NULL) {
+- applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
+- }
+-#endif
+- applyopts(xfd->fd, opts, PH_PREBIND);
+- applyopts(xfd->fd, opts, PH_BIND);
+-#if WITH_TCP || WITH_UDP
+- if (alt) {
+- union sockaddr_union sin, *sinp;
+- unsigned short *port, i, N;
+- div_t dv;
+-
+- /* prepare sockaddr for bind probing */
+- if (us) {
+- sinp = us;
+- } else {
+- if (them->sa_family == AF_INET) {
+- socket_in_init(&sin.ip4);
+-#if WITH_IP6
+- } else {
+- socket_in6_init(&sin.ip6);
+-#endif
+- }
+- sinp = &sin;
+- }
+- if (them->sa_family == AF_INET) {
+- port = &sin.ip4.sin_port;
+-#if WITH_IP6
+- } else if (them->sa_family == AF_INET6) {
+- port = &sin.ip6.sin6_port;
+-#endif
+- } else {
+- port = 0; /* just to make compiler happy */
+- }
+- /* combine random+step variant to quickly find a free port when only
+- few are in use, and certainly find a free port in defined time even
+- if there are almost all in use */
+- /* dirt 1: having tcp/udp code in socket function */
+- /* dirt 2: using a time related system call for init of random */
+- {
+- /* generate a random port, with millisecond random init */
+-#if 0
+- struct timeb tb;
+- ftime(&tb);
+- srandom(tb.time*1000+tb.millitm);
+-#else
+- struct timeval tv;
+- struct timezone tz;
+- tz.tz_minuteswest = 0;
+- tz.tz_dsttime = 0;
+- if ((result = Gettimeofday(&tv, &tz)) < 0) {
+- Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
+- }
+- srandom(tv.tv_sec*1000000+tv.tv_usec);
+-#endif
+- }
+- dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER);
+- i = N = XIO_IPPORT_LOWER + dv.rem;
+- do { /* loop over lowport bind() attempts */
+- *port = htons(i);
+- if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
+- Msg4(errno==EADDRINUSE?E_INFO:level,
+- "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
+- sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
+- sizeof(*sinp), strerror(errno));
+- if (errno != EADDRINUSE) {
+- Close(xfd->fd);
+- return STAT_RETRYLATER;
+- }
+- } else {
+- break; /* could bind to port, good, continue past loop */
+- }
+- --i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
+- if (i == N) {
+- Msg(level, "no low port available");
+- /*errno = EADDRINUSE; still assigned */
+- Close(xfd->fd);
+- return STAT_RETRYLATER;
+- }
+- } while (i != N);
+- } else
+-#endif /* WITH_TCP || WITH_UDP */
+-
+- if (us) {
+-#if WITH_UNIX
+- if (pf == PF_UNIX && us != NULL) {
+- applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
+- }
+-#endif
+- if (Bind(xfd->fd, &us->soa, uslen) < 0) {
+- Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
+- xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
+- uslen, strerror(errno));
+- Close(xfd->fd);
+- return STAT_RETRYLATER;
+- }
+- }
+-#if WITH_UNIX
+- if (pf == PF_UNIX && us != NULL) {
+- applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
++ if (xiobind(xfd, us, uslen, opts, pf, alt, level) < 0) {
++ return -1;
+ }
+-#endif
+-
+- applyopts(xfd->fd, opts, PH_PASTBIND);
+
+ applyopts(xfd->fd, opts, PH_CONNECT);
+
+@@ -902,6 +812,8 @@
+ xfd->para.socket.connect_timeout.tv_usec != 0) {
+ struct timeval timeout;
+ struct pollfd writefd;
++ int err;
++ socklen_t errlen = sizeof(err);
+ int result;
+
+ Info4("connect(%d, %s, "F_Zd"): %s",
+@@ -937,30 +849,40 @@
+ #endif
+ return STAT_RETRYLATER;
+ }
+- /* otherwise OK */
++ /* otherwise OK or network error */
++ result = Getsockopt(xfd->fd, SOL_SOCKET, SO_ERROR, &err, &errlen);
++ if (result != 0) {
++ Msg2(level, "getsockopt(%d, SOL_SOCKET, SO_ERROR, ...): %s",
++ xfd->fd, strerror(err));
++ return STAT_RETRYLATER;
++ }
++ Debug2("getsockopt(%d, SOL_SOCKET, SO_ERROR, { %d }) -> 0",
++ xfd->fd, err);
++ if (err != 0) {
++ Msg4(level, "connect(%d, %s, "F_Zd"): %s",
++ xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
++ themlen, strerror(err));
++ return STAT_RETRYLATER;
++ }
+ Fcntl_l(xfd->fd, F_SETFL, fcntl_flags);
+ } else {
+ Warn4("connect(%d, %s, "F_Zd"): %s",
+ xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
+ themlen, strerror(errno));
+ }
+- } else if (pf == PF_UNIX && errno == EPROTOTYPE) {
++ } else if (pf == PF_UNIX) {
+ /* this is for UNIX domain sockets: a connect attempt seems to be
+- the only way to distinguish stream and datagram sockets */
++ the only way to distinguish stream and datagram sockets.
++ And no ancillary message expected
++ */
+ int _errno = errno;
+ Info4("connect(%d, %s, "F_Zd"): %s",
+ xfd->fd, sockaddr_info(them, themlen, infobuff, sizeof(infobuff)),
+ themlen, strerror(errno));
+-#if 0
+- Info("assuming datagram socket");
+- xfd->dtype = DATA_RECVFROM;
+- xfd->salen = themlen;
+- memcpy(&xfd->peersa.soa, them, xfd->salen);
+-#endif
+- /*!!! and remove bind socket */
++ /* caller must handle this condition */
+ Close(xfd->fd); xfd->fd = -1;
+ errno = _errno;
+- return -1;
++ return STAT_RETRYLATER;
+ } else {
+ /* try to find details about error, especially from ICMP */
+ xiogetpacketinfo(xfd->fd);
+@@ -1103,7 +1025,7 @@
+ union sockaddr_union *us, socklen_t uslen,
+ struct opt *opts,
+ int xioflags, xiosingle_t *xfd, unsigned groups,
+- int pf, int socktype, int ipproto) {
++ int pf, int socktype, int ipproto, bool alt) {
+ int level = E_ERROR;
+ union sockaddr_union la; socklen_t lalen = sizeof(la);
+ char infobuff[256];
+@@ -1125,30 +1047,9 @@
+
+ applyopts_cloexec(xfd->fd, opts);
+
+-#if WITH_UNIX
+- if (pf == PF_UNIX && us != NULL) {
+- applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
+- }
+-#endif
+- applyopts(xfd->fd, opts, PH_PREBIND);
+- applyopts(xfd->fd, opts, PH_BIND);
+-
+- if (us) {
+- if (Bind(xfd->fd, &us->soa, uslen) < 0) {
+- Msg4(level, "bind(%d, {%s}, "F_socklen"): %s",
+- xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
+- uslen, strerror(errno));
+- Close(xfd->fd);
+- return STAT_RETRYLATER;
+- }
+- }
+-#if WITH_UNIX
+- if (pf == PF_UNIX && us != NULL) {
+- applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
++ if (xiobind(xfd, us, uslen, opts, pf, alt, level) < 0) {
++ return -1;
+ }
+-#endif
+-
+- applyopts(xfd->fd, opts, PH_PASTBIND);
+
+ /*applyopts(xfd->fd, opts, PH_CONNECT);*/
+
+@@ -1245,6 +1146,7 @@
+ return;
+ }
+ if (pid == xio_waitingfor) {
++ xio_waitingfor = 0; /* so this child will not set hashappened again */
+ xio_hashappened = true;
+ xio_childstatus = WEXITSTATUS(status);
+ Debug("xiosigaction_hasread() ->");
+@@ -1284,6 +1186,7 @@
+ PH_INIT, PH_PREBIND, PH_BIND, PH_PASTBIND, PH_EARLY, PH_PREOPEN, PH_FD,
+ PH_CONNECTED, PH_LATE, PH_LATE2
+ OPT_FORK, OPT_SO_TYPE, OPT_SO_PROTOTYPE, cloexec, OPT_RANGE, tcpwrap
++ EINTR is not handled specially.
+ */
+ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
+ struct sockaddr *us, socklen_t uslen,
+@@ -1318,25 +1221,16 @@
+
+ applyopts_cloexec(xfd->fd, opts);
+
+- applyopts(xfd->fd, opts, PH_PREBIND);
+- applyopts(xfd->fd, opts, PH_BIND);
+- if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
+- Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
+- sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
+- strerror(errno));
+- Close(xfd->fd);
+- return STAT_RETRYLATER;
+- }
+-
+-#if WITH_UNIX
+- if (pf == AF_UNIX && us != NULL) {
+- applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
++ if (xiobind(xfd, (union sockaddr_union *)us, uslen,
++ opts, pf, 0, level) < 0) {
++ return -1;
+ }
+-#endif
+
+ applyopts(xfd->fd, opts, PH_PASTBIND);
++
+ #if WITH_UNIX
+ if (pf == AF_UNIX && us != NULL) {
++ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
+ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
+ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
+ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
+@@ -1413,6 +1307,7 @@
+ socklen_t palen = sizeof(_peername); /* peer address size */
+ char ctrlbuff[1024]; /* ancillary messages */
+ struct msghdr msgh = {0};
++ int rc;
+
+ socket_init(pf, pa);
+
+@@ -1423,6 +1318,7 @@
+ drop = true;
+ }
+
++ Info("Recvfrom: Checking/waiting for next packet");
+ /* loop until select()/poll() returns valid */
+ do {
+ struct pollfd readfd;
+@@ -1455,15 +1351,15 @@
+ #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
+ msgh.msg_controllen = sizeof(ctrlbuff);
+ #endif
+- if (xiogetpacketsrc(xfd->fd,
++ while ((rc = xiogetpacketsrc(xfd->fd,
+ &msgh,
+ MSG_PEEK
+ #ifdef MSG_TRUNC
+ |MSG_TRUNC
+ #endif
+- ) < 0) {
+- return STAT_RETRYLATER;
+- }
++ )) < 0 &&
++ errno == EINTR) ;
++ if (rc < 0) return STAT_RETRYLATER;
+ palen = msgh.msg_namelen;
+
+ Notice1("receiving packet from %s"/*"src"*/,
+@@ -1534,24 +1430,21 @@
+ break;
+ }
+
+- /* server: continue loop with listen */
+ xio_waitingfor = pid;
+
++ do {
+ #if HAVE_PSELECT
+- {
++ {
+ struct timespec timeout = { LONG_MAX, 0 };
+ Pselect(0, NULL, NULL, NULL, &timeout, &oldset);
+ Sigprocmask(SIG_SETMASK, &oldset, NULL);
+- }
++ }
+ #else /* ! HAVE_PSELECT */
+- /* now we are ready to handle signals */
+- Sigprocmask(SIG_SETMASK, &oldset, NULL);
+-
+- while (!xio_hashappened) {
+- Sleep(1); /* any signal speeds up return */
+- }
++ /* now we are ready to handle signals */
++ Sigprocmask(SIG_SETMASK, &oldset, NULL);
++ Sleep(1); /* any signal speeds up return */
+ #endif /* ! HAVE_PSELECT */
+- xio_waitingfor = 0; /* so this child will not set hashappened again */
++ } while (!xio_hashappened) ;
+ xio_hashappened = false;
+
+ if (xio_childstatus != 0) {
+@@ -1578,7 +1471,6 @@
+ struct opt *opts, int pf, int socktype, int proto,
+ int level) {
+ char *rangename;
+- char infobuff[256];
+
+ if (applyopts_single(xfd, opts, PH_INIT) < 0) return STAT_NORETRY;
+
+@@ -1591,26 +1483,13 @@
+
+ applyopts_cloexec(xfd->fd, opts);
+
+- applyopts(xfd->fd, opts, PH_PREBIND);
+- applyopts(xfd->fd, opts, PH_BIND);
+- if ((us != NULL) && Bind(xfd->fd, us, uslen) < 0) {
+- Msg4(level, "bind(%d, {%s}, "F_socklen"): %s", xfd->fd,
+- sockaddr_info(us, uslen, infobuff, sizeof(infobuff)), uslen,
+- strerror(errno));
+- Close(xfd->fd);
+- return STAT_RETRYLATER;
++ if (xiobind(xfd, (union sockaddr_union *)us, uslen, opts, pf, 0, level) < 0) {
++ return -1;
+ }
+
+ #if WITH_UNIX
+ if (pf == AF_UNIX && us != NULL) {
+ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_FD);
+- }
+-#endif
+-
+- applyopts_single(xfd, opts, PH_PASTBIND);
+- applyopts(xfd->fd, opts, PH_PASTBIND);
+-#if WITH_UNIX
+- if (pf == AF_UNIX && us != NULL) {
+ /*applyopts_early(((struct sockaddr_un *)us)->sun_path, opts);*/
+ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_EARLY);
+ applyopts_named(((struct sockaddr_un *)us)->sun_path, opts, PH_PREOPEN);
+@@ -1648,7 +1527,7 @@
+ char *pfname;
+
+ if (retropt_string(opts, OPT_PROTOCOL_FAMILY, &pfname) >= 0) {
+- if (isdigit(pfname[0])) {
++ if (isdigit((unsigned char)pfname[0])) {
+ *pf = strtoul(pfname, NULL /*!*/, 0);
+ #if WITH_IP4
+ } else if (!strcasecmp("inet", pfname) ||
+@@ -1676,9 +1555,12 @@
+ }
+
+
+-/* this function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
+- the arriving packet. in msgh the msg_name pointer must refer to an (empty)
+- sockaddr storage. */
++/* This function calls recvmsg(..., MSG_PEEK, ...) to obtain information about
++ the arriving packet, thus it does not "consume" the packet.
++ In msgh the msg_name pointer must refer to an (empty) sockaddr storage.
++ Returns STAT_OK on success, or STAT_RETRYLATER when an error occurred,
++ including EINTR.
++ */
+ int xiogetpacketsrc(int fd, struct msghdr *msgh, int flags) {
+ char peekbuff[1];
+ #if HAVE_STRUCT_IOVEC
+@@ -2190,8 +2072,21 @@
+ xiosetenv(namebuff, valuebuff, 1, NULL);
+ namebuff[strlen(lr)] = '\0'; ++idx;
+ } while (result > 0);
+- break;
++ break;
+ #endif /* WITH_IP6 */
++#if WITH_VSOCK
++ case PF_VSOCK:
++ strcpy(namebuff, lr);
++ do {
++ result =
++ xiosetsockaddrenv_vsock(idx, strchr(namebuff, '\0'), XIOSOCKADDRENVLEN-strlen(lr),
++ valuebuff, XIOSOCKADDRENVLEN,
++ &sau->vm, proto);
++ xiosetenv(namebuff, valuebuff, 1, NULL);
++ namebuff[strlen(lr)] = '\0'; ++idx;
++ } while (result > 0);
++ break;
++#endif /* WITH_VSOCK */
+ #if LATER
+ case PF_PACKET:
+ result = xiosetsockaddrenv_packet(lr, (void *)sau, proto); break;
+@@ -2245,3 +2140,124 @@
+ }
+ return result;
+ }
++
++int xiobind(
++ struct single *xfd,
++ union sockaddr_union *us,
++ size_t uslen,
++ struct opt *opts,
++ int pf,
++ bool alt,
++ int level)
++{
++ char infobuff[256];
++ int result;
++
++#if WITH_UNIX
++ if (pf == PF_UNIX && us != NULL) {
++ applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
++ }
++#endif
++ applyopts(xfd->fd, opts, PH_PREBIND);
++ applyopts(xfd->fd, opts, PH_BIND);
++#if WITH_TCP || WITH_UDP
++ if (alt) {
++ union sockaddr_union sin, *sinp;
++ unsigned short *port, i, N;
++ div_t dv;
++
++ /* prepare sockaddr for bind probing */
++ if (us) {
++ sinp = us;
++ } else {
++ if (pf == AF_INET) {
++ socket_in_init(&sin.ip4);
++#if WITH_IP6
++ } else {
++ socket_in6_init(&sin.ip6);
++#endif
++ }
++ sinp = &sin;
++ }
++ if (pf == AF_INET) {
++ port = &sin.ip4.sin_port;
++#if WITH_IP6
++ } else if (pf == AF_INET6) {
++ port = &sin.ip6.sin6_port;
++#endif
++ } else {
++ port = 0; /* just to make compiler happy */
++ }
++ /* combine random+step variant to quickly find a free port when only
++ few are in use, and certainly find a free port in defined time even
++ if there are almost all in use */
++ /* dirt 1: having tcp/udp code in socket function */
++ /* dirt 2: using a time related system call for init of random */
++ {
++ /* generate a random port, with millisecond random init */
++#if 0
++ struct timeb tb;
++ ftime(&tb);
++ srandom(tb.time*1000+tb.millitm);
++#else
++ struct timeval tv;
++ struct timezone tz;
++ tz.tz_minuteswest = 0;
++ tz.tz_dsttime = 0;
++ if ((result = Gettimeofday(&tv, &tz)) < 0) {
++ Warn2("gettimeofday(%p, {0,0}): %s", &tv, strerror(errno));
++ }
++ srandom(tv.tv_sec*1000000+tv.tv_usec);
++#endif
++ }
++ /* Note: IPPORT_RESERVED is from includes, 1024 */
++ dv = div(random(), IPPORT_RESERVED-XIO_IPPORT_LOWER);
++ i = N = XIO_IPPORT_LOWER + dv.rem;
++ do { /* loop over lowport bind() attempts */
++ *port = htons(i);
++ if (Bind(xfd->fd, &sinp->soa, sizeof(*sinp)) < 0) {
++ Msg4(errno==EADDRINUSE?E_INFO:level,
++ "bind(%d, {%s}, "F_Zd"): %s", xfd->fd,
++ sockaddr_info(&sinp->soa, sizeof(*sinp), infobuff, sizeof(infobuff)),
++ sizeof(*sinp), strerror(errno));
++ if (errno != EADDRINUSE) {
++ Close(xfd->fd);
++ return STAT_RETRYLATER;
++ }
++ } else {
++ break; /* could bind to port, good, continue past loop */
++ }
++ --i; if (i < XIO_IPPORT_LOWER) i = IPPORT_RESERVED-1;
++ if (i == N) {
++ Msg(level, "no low port available");
++ /*errno = EADDRINUSE; still assigned */
++ Close(xfd->fd);
++ return STAT_RETRYLATER;
++ }
++ } while (i != N);
++ } else
++#endif /* WITH_TCP || WITH_UDP */
++
++ if (us) {
++#if WITH_UNIX
++ if (pf == PF_UNIX && us != NULL) {
++ applyopts_named(us->un.sun_path, opts, PH_PREOPEN);
++ }
++#endif
++ if (Bind(xfd->fd, &us->soa, uslen) < 0) {
++ Msg4(level, "bind(%d, {%s}, "F_Zd"): %s",
++ xfd->fd, sockaddr_info(&us->soa, uslen, infobuff, sizeof(infobuff)),
++ uslen, strerror(errno));
++ Close(xfd->fd);
++ return STAT_RETRYLATER;
++ }
++ }
++#if WITH_UNIX
++ if (pf == PF_UNIX && us != NULL) {
++ applyopts_named(us->un.sun_path, opts, PH_PASTOPEN);
++ }
++#endif
++
++ applyopts(xfd->fd, opts, PH_PASTBIND);
++ return 0;
++}
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-socket.h socat-1.7.4.4/xio-socket.h
+--- socat-1.7.4.3/xio-socket.h 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/xio-socket.h 2022-10-30 16:21:47.896474048 +0100
+@@ -102,7 +102,7 @@
+ union sockaddr_union *us, socklen_t uslen,
+ struct opt *opts,
+ int xioflags, xiosingle_t *xfd, unsigned groups,
+- int pf, int socktype, int ipproto);
++ int pf, int socktype, int ipproto, bool alt);
+ extern
+ int _xioopen_dgram_recvfrom(struct single *xfd, int xioflags,
+ struct sockaddr *us, socklen_t uslen,
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-termios.c socat-1.7.4.4/xio-termios.c
+--- socat-1.7.4.3/xio-termios.c 2019-04-04 10:59:55.000000000 +0200
++++ socat-1.7.4.4/xio-termios.c 2022-10-30 16:21:47.896474048 +0100
+@@ -475,7 +475,7 @@
+ _xiotermios_data.termarg.c_iflag = 0;
+ _xiotermios_data.termarg.c_oflag = 0;
+ _xiotermios_data.termarg.c_lflag = 0;
+- _xiotermios_data.termarg.c_cflag = (CS8);
++ _xiotermios_data.termarg.c_cflag = (CREAD|CS8);
+ _xiotermios_data.termarg.c_cc[VMIN] = 1;
+ _xiotermios_data.termarg.c_cc[VTIME] = 0;
+ break;
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-udp.c socat-1.7.4.4/xio-udp.c
+--- socat-1.7.4.3/xio-udp.c 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/xio-udp.c 2022-10-30 16:21:47.896474048 +0100
+@@ -410,26 +410,12 @@
+ }
+
+ retropt_bool(opts, OPT_LOWPORT, &xfd->para.socket.ip.lowport);
+- if (xfd->para.socket.ip.lowport) {
+- switch (pf) {
+-#if WITH_IP4
+- case PF_INET:
+- /*!!! this is buggy */
+- us.ip4.sin_port = htons(xfd->para.socket.ip.lowport); break;
+-#endif
+-#if WITH_IP6
+- case PF_INET6:
+- /*!!! this is buggy */
+- us.ip6.sin6_port = htons(xfd->para.socket.ip.lowport); break;
+-#endif
+- }
+- needbind = true;
+- }
+
+ xfd->dtype = XIODATA_RECVFROM;
+ return _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
+ opts, xioflags, xfd, groups,
+- pf, socktype, ipproto);
++ pf, socktype, ipproto,
++ xfd->para.socket.ip.lowport);
+ }
+
+
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-unix.c socat-1.7.4.4/xio-unix.c
+--- socat-1.7.4.3/xio-unix.c 2022-01-08 21:59:57.000000000 +0100
++++ socat-1.7.4.4/xio-unix.c 2022-10-30 16:21:47.896474048 +0100
+@@ -15,7 +15,7 @@
+
+ #if WITH_UNIX
+
+-/* to avoid unneccessary "live" if () conditionals when no abstract support is
++/* to avoid unneccessary runtime if () conditionals when no abstract support is
+ compiled in (or at least to give optimizing compilers a good chance) we need
+ a constant that can be used in C expressions */
+ #if WITH_ABSTRACT_UNIXSOCKET
+@@ -218,6 +218,10 @@
+ socklen_t themlen, uslen = sizeof(us);
+ bool needbind = false;
+ bool opt_unlink_close = true;
++ bool dofork = false;
++ struct opt *opts0;
++ char infobuff[256];
++ int level;
+ int result;
+
+ if (argc != 2) {
+@@ -258,13 +262,91 @@
+ xfd->opt_unlink_close = true;
+ }
+
+- if ((result =
+- xioopen_connect(xfd,
++ retropt_bool(opts, OPT_FORK, &dofork);
++
++ opts0 = copyopts(opts, GROUP_ALL);
++
++ Notice1("opening connection to %s",
++ sockaddr_info((struct sockaddr *)&them, themlen, infobuff, sizeof(infobuff)));
++
++ do { /* loop over retries and forks */
++
++#if WITH_RETRY
++ if (xfd->forever || xfd->retry) {
++ level = E_INFO;
++ } else
++#endif /* WITH_RETRY */
++ level = E_ERROR;
++
++ result =
++ _xioopen_connect(xfd,
+ needbind?(union sockaddr_union *)&us:NULL, uslen,
+ (struct sockaddr *)&them, themlen,
+- opts, pf, socktype, protocol, false)) != 0) {
+- return result;
+- }
++ opts, pf, socktype, protocol, false, level);
++ if (result != 0) {
++ char infobuff[256];
++ /* we caller must handle this */
++ Msg3(level, "connect(, %s, "F_socklen"): %s",
++ sockaddr_info((struct sockaddr *)&them, themlen, infobuff, sizeof(infobuff)),
++ themlen, strerror(errno));
++ }
++ switch (result) {
++ case STAT_OK: break;
++#if WITH_RETRY
++ case STAT_RETRYLATER:
++ if (xfd->forever || xfd->retry) {
++ --xfd->retry;
++ if (result == STAT_RETRYLATER) {
++ Nanosleep(&xfd->intervall, NULL);
++ }
++ dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
++ continue;
++ }
++ return STAT_NORETRY;
++#endif /* WITH_RETRY */
++ default:
++ return result;
++ }
++
++ if (dofork) {
++ xiosetchilddied(); /* set SIGCHLD handler */
++ }
++
++#if WITH_RETRY
++ if (dofork) {
++ pid_t pid;
++ int level = E_ERROR;
++ if (xfd->forever || xfd->retry) {
++ level = E_WARN; /* most users won't expect a problem here,
++ so Notice is too weak */
++ }
++
++ while ((pid = xio_fork(false, level)) < 0) {
++ --xfd->retry;
++ if (xfd->forever || xfd->retry) {
++ dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
++ Nanosleep(&xfd->intervall, NULL); continue;
++ }
++ return STAT_RETRYLATER;
++ }
++
++ if (pid == 0) { /* child process */
++ break;
++ }
++
++ /* parent process */
++ Close(xfd->fd);
++ /* with and without retry */
++ Nanosleep(&xfd->intervall, NULL);
++ dropopts(opts, PH_ALL); opts = copyopts(opts0, GROUP_ALL);
++ continue; /* with next socket() bind() connect() */
++ } else
++#endif /* WITH_RETRY */
++ {
++ break;
++ }
++ } while (true);
++
+ if ((result = _xio_openlate(xfd, opts)) < 0) {
+ return result;
+ }
+@@ -329,7 +411,7 @@
+ return
+ _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
+ opts, xioflags, xfd, groups,
+- pf, socktype, protocol);
++ pf, socktype, protocol, 0);
+ }
+
+
+@@ -500,6 +582,7 @@
+ }
+
+
++/* generic UNIX socket client, tries connect, SEQPACKET, send(to) */
+ static int xioopen_unix_client(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xxfd, unsigned groups, int abstract, int dummy2, int dummy3) {
+ /* we expect the form: filename */
+ if (argc != 2) {
+@@ -607,7 +690,7 @@
+ if ((result =
+ _xioopen_dgram_sendto(needbind?&us:NULL, uslen,
+ opts, xioflags, xfd, groups,
+- pf, SOCK_DGRAM, protocol))
++ pf, SOCK_DGRAM, protocol, 0))
+ == 0) {
+ xfd->dtype = XIODATA_RECVFROM;
+ break;
+@@ -615,6 +698,7 @@
+ } while (0);
+
+ if (result != 0) {
++ Error2("UNIX-CLIENT:%s: %s", name, strerror(errno));
+ if (needbind) {
+ Unlink(us.un.sun_path);
+ }
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-vsock.c socat-1.7.4.4/xio-vsock.c
+--- socat-1.7.4.3/xio-vsock.c 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/xio-vsock.c 2022-10-30 16:21:47.896474048 +0100
+@@ -3,7 +3,7 @@
+ /* Author: Stefano Garzarella svm_cid);
++ return 1;
++ case 1:
++ strcpy(namebuff, "PORT");
++ snprintf(valuebuff, valuelen, F_uint32_t, sa->svm_port);
++ return 0;
++ }
++ return -1;
++}
++
+ #endif /* WITH_VSOCK */
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xio-vsock.h socat-1.7.4.4/xio-vsock.h
+--- socat-1.7.4.3/xio-vsock.h 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/xio-vsock.h 2022-10-30 16:21:47.896474048 +0100
+@@ -8,4 +8,8 @@
+ extern const struct addrdesc addr_vsock_connect;
+ extern const struct addrdesc addr_vsock_listen;
+
++extern int xiosetsockaddrenv_vsock(int idx, char *namebuff, size_t namelen,
++ char *valuebuff, size_t valuelen,
++ struct sockaddr_vm *sa, int ipproto);
++
+ #endif /* !defined(__xio_vsock_h_included) */
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xioopen.c socat-1.7.4.4/xioopen.c
+--- socat-1.7.4.3/xioopen.c 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/xioopen.c 2022-10-30 16:21:47.896474048 +0100
+@@ -308,9 +308,11 @@
+ { "unix-sendto", &xioaddr_unix_sendto },
+ #endif
+ #if WITH_VSOCK
++ { "vsock", &addr_vsock_connect },
+ { "vsock-connect", &addr_vsock_connect },
+ #endif
+ #if WITH_VSOCK && WITH_LISTEN
++ { "vsock-l", &addr_vsock_listen },
+ { "vsock-listen", &addr_vsock_listen },
+ #endif
+ #else /* !0 */
+@@ -494,6 +496,7 @@
+ char token[512], *tokp;
+ size_t len;
+ int i;
++ int result;
+
+ /* init */
+ i = 0;
+@@ -510,9 +513,12 @@
+ sfd->argc = 0;
+
+ len = sizeof(token); tokp = token;
+- if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
+- true, true, false) < 0) {
++ result = nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
++ true, true, false);
++ if (result < 0) {
+ Error2("keyword too long, in address \"%s%s\"", token, *addr);
++ } else if (result > 0){
++ Error1("unexpected end of address \"%s\"", *addr);
+ }
+ *tokp = '\0'; /*! len? */
+ ae = (struct addrname *)
+@@ -564,9 +570,12 @@
+ while (!strncmp(*addr, xioopts.paramsep, strlen(xioopts.paramsep))) {
+ *addr += strlen(xioopts.paramsep);
+ len = sizeof(token); tokp = token;
+- if (nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
+- true, true, false) != 0) {
+- Error1("syntax error in address \"%s\"", addr0);
++ result = nestlex(addr, &tokp, &len, ends, hquotes, squotes, nests,
++ true, true, false);
++ if (result < 0) {
++ Error1("address \"%s\" too long", addr0);
++ } else if (result > 0){
++ Error1("unexpected end of address \"%s\"", addr0);
+ }
+ *tokp = '\0';
+ if ((sfd->argv[sfd->argc++] = strdup(token)) == NULL) {
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xioopts.c socat-1.7.4.4/xioopts.c
+--- socat-1.7.4.3/xioopts.c 2021-01-03 19:23:22.000000000 +0100
++++ socat-1.7.4.4/xioopts.c 2022-10-30 16:21:47.896474048 +0100
+@@ -164,7 +164,7 @@
+ #ifdef IP_ADD_MEMBERSHIP
+ IF_IP ("add-membership", &opt_ip_add_membership)
+ #endif
+-#ifdef IP_ADD_SOURCE_MEMBERSHIP
++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
+ IF_IP ("add-source-membership", &opt_ip_add_source_membership)
+ #endif
+ IF_TUN ("allmulti", &opt_iff_allmulti)
+@@ -678,7 +678,7 @@
+ #ifdef IP_ADD_MEMBERSHIP
+ IF_IP ("ip-add-membership", &opt_ip_add_membership)
+ #endif
+-#ifdef IP_ADD_SOURCE_MEMBERSHIP
++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
+ IF_IP ("ip-add-source-membership", &opt_ip_add_source_membership)
+ #endif
+ #ifdef IP_FREEBIND
+@@ -1563,7 +1563,7 @@
+ IF_SOCKS4 ("socksport", &opt_socksport)
+ IF_SOCKS4 ("socksuser", &opt_socksuser)
+ IF_SOCKET ("socktype", &opt_so_type)
+-#ifdef IP_ADD_SOURCE_MEMBERSHIP
++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
+ IF_IP ("source-membership", &opt_ip_add_source_membership)
+ #endif
+ IF_IPAPP ("sourceport", &opt_sourceport)
+@@ -1926,7 +1926,7 @@
+ nestlex(a, &tokp, &len, endkey, hquotes, squotes, nests,
+ true, true, false);
+ if (parsres < 0) {
+- Error1("option too long: \"%s\"", *a);
++ Error1("option too long: \"%s\"", *a);
+ return -1;
+ } else if (parsres > 0) {
+ Error1("syntax error in \"%s\"", *a);
+@@ -2006,9 +2006,9 @@
+ if (assign) {
+ unsigned long ul;
+ char *rest;
+- ul = strtoul(token, &rest/*!*/, 0);
++ ul = Strtoul(token, &rest, 0, a0);
+ if (ul > UCHAR_MAX) {
+- Error3("parseopts_table(%s): byte value exceeds limit (%lu vs. %u), using max",
++ Error3("parseopts(): option \"%s\": byte value exceeds limit (%lu vs. %u), using max",
+ a0, ul, UCHAR_MAX);
+ (*opts)[i].value.u_byte = UCHAR_MAX;
+ } else {
+@@ -2026,7 +2026,7 @@
+ case TYPE_INT:
+ if (assign) {
+ char *rest;
+- (*opts)[i].value.u_int = strtoul(token, &rest/*!*/, 0);
++ (*opts)[i].value.u_int = Strtoul(token, &rest, 0, a0);
+ } else {
+ (*opts)[i].value.u_int = 1;
+ }
+@@ -2038,10 +2038,7 @@
+ (*opts)[i].value.u_bool = 1;
+ } else {
+ char *rest;
+- (*opts)[i].value.u_bool = strtoul(token, &rest, 0);
+- if (rest && *rest) {
+- Error1("error in option \"%s\": \"0\" or \"1\" required", a0);
+- }
++ (*opts)[i].value.u_bool = Strtoul(token, &rest, 0, a0);
+ }
+ Info2("setting option \"%s\" to %d", ent->desc->defname,
+ (*opts)[i].value.u_bool);
+@@ -2055,11 +2052,7 @@
+ (*opts)[i].value.u_uint = 1;
+ } else {
+ char *rest;
+- ulongval = strtoul(token, &rest/*!*/, 0);
+- if (ulongval > UINT_MAX) {
+- Error3("parseopts_table(%s): unsigned int value exceeds limit (%lu vs. %u), using max",
+- a0, ulongval, UINT_MAX);
+- }
++ ulongval = Strtoul(token, &rest, 0, a0);
+ (*opts)[i].value.u_uint = ulongval;
+ }
+ Info2("setting option \"%s\" to %u", ent->desc->defname,
+@@ -2074,11 +2067,7 @@
+ (*opts)[i].value.u_ushort = 1;
+ } else {
+ char *rest;
+- ulongval = strtoul(token, &rest/*!*/, 0);
+- if (ulongval > USHRT_MAX) {
+- Error3("parseopts_table(%s): unsigned short value exceeds limit (%lu vs. %u), using max",
+- a0, ulongval, USHRT_MAX);
+- }
++ ulongval = Strtoul(token, &rest, 0, a0);
+ (*opts)[i].value.u_ushort = ulongval;
+ }
+ Info2("setting option \"%s\" to %u", ent->desc->defname,
+@@ -2096,7 +2085,7 @@
+ (*opts)[i].value.u_long = 1;
+ } else {
+ char *rest;
+- slongval = strtol(token, &rest, 0);
++ slongval = Strtoul(token, &rest, 0, a0);
+ (*opts)[i].value.u_long = slongval;
+ }
+ Info2("setting option \"%s\" to %lu", ent->desc->defname,
+@@ -2111,7 +2100,7 @@
+ (*opts)[i].value.u_ulong = 1;
+ } else {
+ char *rest;
+- ulongval = strtoul(token, &rest, 0);
++ ulongval = Strtoul(token, &rest, 0, a0);
+ (*opts)[i].value.u_ulong = ulongval;
+ }
+ Info2("setting option \"%s\" to %lu", ent->desc->defname,
+@@ -2131,11 +2120,14 @@
+ } else {
+ char *rest;
+ # if HAVE_STRTOLL
+- slonglongval = strtoll(token, &rest, 0);
++ slonglongval = Strtoll(token, &rest, 0, a0);
+ # else
+ /* in this case, input value range is limited */
+- slonglongval = strtol(token, &rest, 0);
++ slonglongval = Strtol(token, &rest, 0, a0);
+ # endif /* HAVE_STRTOLL */
++ if (*rest != '\0') {
++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0);
++ }
+ (*opts)[i].value.u_longlong = slonglongval;
+ }
+ Info2("setting option \"%s\" to %Lu", ent->desc->defname,
+@@ -2150,7 +2142,7 @@
+ }
+ if (isdigit((*token)&0xff)) {
+ char *rest;
+- (*opts)[i].value.u_uidt = strtoul(token, &rest/*!*/, 0);
++ (*opts)[i].value.u_uidt = Strtoul(token, &rest, 0, a0);
+ } else {
+ struct passwd *pwd;
+ if ((pwd = getpwnam(token)) == NULL) {
+@@ -2168,7 +2160,7 @@
+ continue; }
+ if (isdigit((token[0])&0xff)) {
+ char *rest;
+- (*opts)[i].value.u_gidt = strtoul(token, &rest/*!*/, 0);
++ (*opts)[i].value.u_gidt = Strtoul(token, &rest, 0, a0);
+ } else {
+ struct group *grp;
+ grp = getgrnam(token);
+@@ -2188,7 +2180,7 @@
+ }
+ {
+ char *rest;
+- (*opts)[i].value.u_modet = strtoul(token, &rest/*!*/, 8);
++ (*opts)[i].value.u_modet = Strtoul(token, &rest, 8, a0);
+ }
+ Info2("setting option \"%s\" to %u", ent->desc->defname,
+ (*opts)[i].value.u_modet);
+@@ -2229,7 +2221,8 @@
+ continue;
+ } else {
+ double val;
+- val = strtod(token, NULL);
++ char *rest;
++ val = Strtod(token, &rest, a0);
+ if (val == HUGE_VAL || val == -HUGE_VAL ||
+ val == 0.0 && errno == ERANGE) {
+ Error2("strtod(\"%s\", NULL): %s", token, strerror(errno));
+@@ -2248,7 +2241,8 @@
+ continue;
+ } else {
+ double val;
+- val = strtod(token, NULL);
++ char *rest;
++ val = Strtod(token, &rest, a0);
+ if (val == HUGE_VAL || val == -HUGE_VAL ||
+ val == 0.0 && errno == ERANGE) {
+ Error2("strtod(\"%s\", NULL): %s", token, strerror(errno));
+@@ -2270,7 +2264,7 @@
+ (*opts)[i].value.u_linger.l_onoff = 1;
+ {
+ char *rest;
+- (*opts)[i].value.u_linger.l_linger = strtoul(token, &rest/*!*/, 0);
++ (*opts)[i].value.u_linger.l_linger = Strtoul(token, &rest, 0, a0);
+ }
+ Info3("setting option \"%s\" to {%d,%d}", ent->desc->defname,
+ (*opts)[i].value.u_linger.l_onoff,
+@@ -2287,12 +2281,15 @@
+ {
+ char *rest;
+ (*opts)[i].value.u_int = strtoul(token, &rest, 0);
+- if (*rest != ':') {
+- Error1("option \"%s\": 2 arguments required",
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
++ Error1("parseopts(): option \"%s\": 2 arguments required",
+ ent->desc->defname);
+ }
+ ++rest;
+- (*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
++ (*opts)[i].value2.u_int = Strtoul(rest, &rest, 0, a0);
+ }
+ Info3("setting option \"%s\" to %d:%d", ent->desc->defname,
+ (*opts)[i].value.u_int, (*opts)[i].value2.u_int);
+@@ -2306,8 +2303,14 @@
+ {
+ char *rest;
+ (*opts)[i].value.u_int = strtoul(token, &rest, 0);
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
+ if (*rest != ':') {
+- Error1("option \"%s\": 2 arguments required",
++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
++ Error1("parseopts(): option \"%s\": 2 arguments required",
+ ent->desc->defname);
+ }
+ ++rest;
+@@ -2334,8 +2337,14 @@
+ {
+ char *rest;
+ (*opts)[i].value.u_int = strtoul(token, &rest, 0);
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
+ if (*rest != ':') {
+- Error1("option \"%s\": 2 arguments required",
++ Error1("parseopts(): trailing garbage in numerical arg of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
++ Error1("parseopts(): option \"%s\": 2 arguments required",
+ ent->desc->defname);
+ }
+ ++rest;
+@@ -2355,18 +2364,28 @@
+ {
+ char *rest;
+ (*opts)[i].value.u_int = strtoul(token, &rest, 0);
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
++ Error1("parseopts(): option \"%s\": 3 arguments required", ent->desc->defname);
++ }
+ if (*rest != ':') {
+- Error1("option \"%s\": 3 arguments required",
+- ent->desc->defname);
++ Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0);
+ }
+ ++rest;
+ (*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
++ Error1("parseopts(): option \"%s\": 3 arguments required", ent->desc->defname);
++ }
+ if (*rest != ':') {
+- Error1("option \"%s\": 3 arguments required",
+- ent->desc->defname);
++ Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0);
+ }
+ ++rest;
+- (*opts)[i].value3.u_int = strtoul(rest, &rest, 0);
++ (*opts)[i].value3.u_int = Strtoul(rest, &rest, 0, a0);
+ }
+ Info4("setting option \"%s\" to %d:%d:%d", ent->desc->defname,
+ (*opts)[i].value.u_int, (*opts)[i].value2.u_int, (*opts)[i].value3.u_int);
+@@ -2381,16 +2400,28 @@
+ {
+ char *rest;
+ (*opts)[i].value.u_int = strtoul(token, &rest, 0);
+- if (*rest != ':') {
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
+ Error1("option \"%s\": 3 arguments required",
+ ent->desc->defname);
+ }
++ if (*rest != ':') {
++ Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0);
++ }
+ ++rest;
+ (*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
+- if (*rest != ':') {
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
+ Error1("option \"%s\": 3 arguments required",
+ ent->desc->defname);
+ }
++ if (*rest != ':') {
++ Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0);
++ }
+ ++rest;
+ optlen = 0;
+ if ((result = dalan(rest, optbuf, &optlen, sizeof(optbuf), 'i')) != 0) {
+@@ -2415,16 +2446,28 @@
+ {
+ char *rest;
+ (*opts)[i].value.u_int = strtoul(token, &rest, 0);
+- if (*rest != ':') {
+- Error1("option \"%s\": 3 arguments required",
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
++ Error1("parseopts(): option \"%s\": 3 arguments required",
+ ent->desc->defname);
+ }
++ if (*rest != ':') {
++ Error1("parseopts(): trailing garbage in 1st numerical arg of option \"%s\"", a0);
++ }
+ ++rest;
+ (*opts)[i].value2.u_int = strtoul(rest, &rest, 0);
+- if (*rest != ':') {
+- Error1("option \"%s\": 3 arguments required",
++ if (token == rest) {
++ Error1("parseopts(): missing numerical value of option \"%s\"", a0);
++ }
++ if (*rest == '\0') {
++ Error1("parseopts(): option \"%s\": 3 arguments required",
+ ent->desc->defname);
+ }
++ if (*rest != ':') {
++ Error1("parseopts(): trailing garbage in 2nd numerical arg of option \"%s\"", a0);
++ }
+ ++rest;
+ if (((*opts)[i].value3.u_string = strdup(rest)) == NULL) {
+ Error("out of memory"); return -1;
+@@ -2507,7 +2550,7 @@
+ break;
+ #endif /* defined(HAVE_STRUCT_IP_MREQ) || defined (HAVE_STRUCT_IP_MREQN) */
+
+-#if HAVE_STRUCT_IP_MREQ_SOURCE
++#if defined(HAVE_STRUCT_IP_MREQ_SOURCE) && defined(IP_ADD_SOURCE_MEMBERSHIP)
+ case TYPE_IP_MREQ_SOURCE:
+ xiotype_ip_add_source_membership(token, ent, opt);
+ break;
+@@ -2873,9 +2916,14 @@
+
+ while (opt->desc != ODESC_END) {
+ if (opt->desc != ODESC_DONE && opt->desc->optcode == optcode) {
++ char *rest;
+ switch (opt->desc->type) {
+ case TYPE_INT: *result = opt->value.u_int; break;
+- case TYPE_STRING: *result = strtol(opt->value.u_string, NULL, 0);
++ case TYPE_STRING: *result = strtol(opt->value.u_string, &rest, 0);
++ if (*rest != '\0') {
++ Error1("retropts: trailing garbage in numerical arg of option \"%s\"",
++ opt->desc->defname);
++ }
+ break;
+ default: Error2("cannot convert type %d of option %s to int",
+ opt->desc->type, opt->desc->defname);
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xioread.c socat-1.7.4.4/xioread.c
+--- socat-1.7.4.3/xioread.c 2021-10-31 19:06:09.000000000 +0100
++++ socat-1.7.4.4/xioread.c 2022-10-30 16:21:47.896474048 +0100
+@@ -119,6 +119,7 @@
+ socklen_t fromlen = sizeof(from);
+ char infobuff[256];
+ char ctrlbuff[1024]; /* ancillary messages */
++ int rc;
+
+ msgh.msg_name = &from;
+ msgh.msg_namelen = fromlen;
+@@ -128,14 +129,16 @@
+ #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
+ msgh.msg_controllen = sizeof(ctrlbuff);
+ #endif
+- if (xiogetpacketsrc(pipe->fd, &msgh,
++
++ while ((rc = xiogetpacketsrc(pipe->fd, &msgh,
+ MSG_PEEK
+ #ifdef MSG_TRUNC
+ |MSG_TRUNC
+ #endif
+- ) < 0) {
+- return -1;
+- }
++ )) < 0 &&
++ errno == EINTR) ;
++ if (rc < 0) return -1;
++
+ do {
+ bytes =
+ Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen);
+@@ -319,6 +322,7 @@
+ char infobuff[256];
+ struct msghdr msgh = {0};
+ char ctrlbuff[1024]; /* ancillary messages */
++ int rc;
+
+ socket_init(pipe->para.socket.la.soa.sa_family, &from);
+ /* get source address */
+@@ -330,14 +334,15 @@
+ #if HAVE_STRUCT_MSGHDR_MSGCONTROLLEN
+ msgh.msg_controllen = sizeof(ctrlbuff);
+ #endif
+- if (xiogetpacketsrc(pipe->fd, &msgh,
++ while ((rc = xiogetpacketsrc(pipe->fd, &msgh,
+ MSG_PEEK
+ #ifdef MSG_TRUNC
+ |MSG_TRUNC
+ #endif
+- ) < 0) {
+- return -1;
+- }
++ )) < 0 &&
++ errno == EINTR) ;
++ if (rc < 0) return -1;
++
+ xiodopacketinfo(&msgh, true, false);
+ if (xiocheckpeer(pipe, &from, &pipe->para.socket.la) < 0) {
+ Recvfrom(pipe->fd, buff, bufsiz, 0, &from.soa, &fromlen); /* drop */
+diff -r -N -U 3 --no-dereference socat-1.7.4.3/xiosysincludes.h socat-1.7.4.4/xiosysincludes.h
+--- socat-1.7.4.3/xiosysincludes.h 2017-01-06 21:58:40.000000000 +0100
++++ socat-1.7.4.4/xiosysincludes.h 2022-10-30 16:21:47.896474048 +0100
+@@ -9,5 +9,7 @@
+ #include "xioconfig.h" /* what features are enabled */
+
+ #include "sysincludes.h"
++//#undef IP_ADD_SOURCE_MEMBERSHIP
++#undef HAVE_STRUCT_IP_MREQ_SOURCE
+
+ #endif /* !defined(__xiosysincludes_h_included) */
diff --git a/socat-1.7.4.4.tar.gz b/socat-1.7.4.4.tar.gz
new file mode 100644
index 0000000000000000000000000000000000000000..969b5a355f8483fbab040ec19088d465a69feaea
Binary files /dev/null and b/socat-1.7.4.4.tar.gz differ
diff --git a/socat.spec b/socat.spec
index 62bfee1d920f33ddf8281567dcacd9031a89d4ff..55d0989171f6d0c0b68b5d750761920f6d1f986d 100644
--- a/socat.spec
+++ b/socat.spec
@@ -2,11 +2,12 @@
Summary: Multipurpose relay
Name: socat
-Version: 1.7.4.3
+Version: 1.7.4.4
Release: 1
License: GPLv2
Url: http://www.dest-unreach.org/socat/
Source: http://www.dest-unreach.org/socat/download/%{name}-%{version}.tar.gz
+Patch0000: socat-1.7.4.4.patch
BuildRequires: gcc openssl-devel readline-devel ncurses-devel
BuildRequires: autoconf kernel-headers > 2.6.18
@@ -38,7 +39,6 @@ mv CHANGES.utf8 CHANGES
--enable-openssl --enable-sycls --enable-filan \
--enable-system --enable-pty --enable-readline
-
%make_build
%install
@@ -60,8 +60,11 @@ cp -a *.sh %{buildroot}/%{_docdir}/socat/
%doc %{_mandir}/man1/socat.1*
%changelog
+* Sat Nov 5 2022 hkgy - 1.7.4.4-1
+- Upgrade to v1.7.4.4
+
* Thu Jul 28 2022 fushanqing - 1.7.4.3-1
- update to 1.7.4.3
* Tue Nov 19 2019 mengxian - 1.7.3.2-8
-- Package init
\ No newline at end of file
+- Package init