diff --git a/CHANGES b/CHANGES index bfd6df1..580a120 100644 --- a/CHANGES +++ b/CHANGES @@ -32,6 +32,12 @@ Porting: Added configure option --enable-openssl-base to specify the location of a non-OS OpenSSL installation + There are systems whose kernel understands SCTP but getaddrinfo does + not. As workaround after EIA_SOCKTYPE on name and service resolution + fall back to ai_socktype=0; if it fails with EAI_SERVICE, set + ai_protocol=0 and try again + Test: SCTP_SERVICENAME + Testing: test.sh now produces a list of tests that could not be performed for any reason. This helps to analyse these cases. diff --git a/test.sh b/test.sh index 25888c5..618a8df 100755 --- a/test.sh +++ b/test.sh @@ -13573,6 +13573,48 @@ esac N=$((N+1)) +# Currently (2020) SCTP has not found its way into main distributions +# /etc/services file. A fallback mechanism has been implemented in Socat +# that allows use of TCP service names when service resolution for SCTP failed. +# Furthermore, older getaddrinfo() implementations to not handle SCTP as SOCK_STREAM +# at all, fall back to unspecified socktype then. +NAME=SCTP_SERVICENAME +case "$TESTS" in +*%$N%*|*%functions%*|*%socket%*|*%sctp%*|*%$NAME%*) +TEST="$NAME: Service name resolution works with SCTP" +# invoke socat with address SCTP4-CONNECT:$LOCALHOST:http; when this does fails with +# "Connection refused", or does not fail at all, the test succeeded +if ! eval $NUMCOND; then :; +elif ! runssctp4 "$((PORT))" >/dev/null; then + $PRINTF "test $F_n $TEST... ${YELLOW}SCTP4 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" +CMD0="$TRACE $SOCAT $opts -u /dev/null SCTP4-CONNECT:$LOCALHOST:http" +printf "test $F_n $TEST... " $N +$CMD0 >/dev/null 2>"${te}0" +if [ $? -eq 0 ]; then + $PRINTF "$OK\n" + numOK=$((numOK+1)) +elif grep -q "Connection refused" ${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)) + + ################################################################################## #================================================================================= # here come tests that might affect your systems integrity. Put normal tests diff --git a/xio-ip.c b/xio-ip.c index a7672ce..b13fbf0 100644 --- a/xio-ip.c +++ b/xio-ip.c @@ -202,9 +202,6 @@ int xiogetaddrinfo(const char *node, const char *service, if (node != NULL || service != NULL) { struct addrinfo *record; - /* here was code that helped SCTP to use service names. - If you need this feature enhance your /etc/services with sctp entries */ - hints.ai_flags |= AI_PASSIVE; hints.ai_family = family; hints.ai_socktype = socktype; @@ -214,7 +211,19 @@ int xiogetaddrinfo(const char *node, const char *service, hints.ai_canonname = NULL; hints.ai_next = NULL; - if ((error_num = Getaddrinfo(node, service, &hints, &res)) != 0) { + do { + error_num = Getaddrinfo(node, service, &hints, &res); + if (error_num == 0) break; + if (error_num == EAI_SOCKTYPE && socktype != 0) { + /* there are systems where kernel goes SCTP but not getaddrinfo() */ + hints.ai_socktype = 0; + continue; + } + if (error_num == EAI_SERVICE && protocol != 0) { + hints.ai_protocol = 0; + continue; + } + if (error_num != 0) { Error7("getaddrinfo(\"%s\", \"%s\", {%d,%d,%d,%d}, {}): %s", node?node:"NULL", service?service:"NULL", hints.ai_flags, hints.ai_family, @@ -231,7 +240,8 @@ int xiogetaddrinfo(const char *node, const char *service, } #endif return STAT_RETRYLATER; - } + } + } while (1); service = NULL; /* do not resolve later again */ record = res;