socat/SOURCES/socat-1.7.4.1-tcp-address-with-connect-timeout.patch

102 lines
3.1 KiB
Diff

diff --git a/test.sh b/test.sh
index 99323ad..2869658 100755
--- a/test.sh
+++ b/test.sh
@@ -15017,6 +15017,60 @@ PORT=$((PORT+1))
N=$((N+1))
+
+# 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))
+
# end of common tests
##################################################################################
diff --git a/xio-socket.c b/xio-socket.c
index c1495e8..d6b935c 100644
--- a/xio-socket.c
+++ b/xio-socket.c
@@ -859,6 +859,8 @@ int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
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",
@@ -894,7 +896,21 @@ int _xioopen_connect(struct single *xfd, union sockaddr_union *us, size_t uslen,
#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",