wolfssl/scripts/dtlscid.test

198 lines
6.2 KiB
Bash
Executable File

#!/usr/bin/env bash
# timeout(1) is GNU coreutils and absent on macOS; where it's missing, run the
# command unbounded (the flaky hang this guards against is Linux-only CI).
# A prefix variable rather than a shell function: backgrounding a function
# makes $! the forked subshell, so a later "kill $server_pid" would stop the
# wrapper and orphan the server it was meant to kill.
if command -v timeout >/dev/null 2>&1; then
TIMEOUT_KILL_2M="timeout -s KILL 2m"
TIMEOUT_KILL_1M="timeout -s KILL 1m"
else
TIMEOUT_KILL_2M=""
TIMEOUT_KILL_1M=""
fi
# dtlscid.test
# Copyright wolfSSL 2022-2024
[ ! -x ./examples/client/client ] && printf '\n\n%s\n' "Client doesn't exist" \
&& exit 0
[ ! -x ./examples/server/server ] && printf '\n\n%s\n' "Server doesn't exist" \
&& exit 0
if ./examples/client/client -? 2>&1 | grep "Client not compiled in!" ; then
echo 'skipping dtlscid.test because client not compiled in.' 1>&2
exit 77
fi
if ./examples/server/server -? 2>&1 | grep "Server not compiled in!" ; then
echo 'skipping dtlscid.test because server not compiled in.' 1>&2
exit 77
fi
# if we can, isolate the network namespace to eliminate port collisions.
if [[ -n "$NETWORK_UNSHARE_HELPER" ]]; then
if [[ -z "$NETWORK_UNSHARE_HELPER_CALLED" ]]; then
export NETWORK_UNSHARE_HELPER_CALLED=yes
exec "$NETWORK_UNSHARE_HELPER" "$0" "$@" || exit $?
fi
elif [ "${AM_BWRAPPED-}" != "yes" ]; then
bwrap_path="$(command -v bwrap)"
if [ -n "$bwrap_path" ]; then
export AM_BWRAPPED=yes
exec "$bwrap_path" --unshare-net --dev-bind / / "$0" "$@"
fi
unset AM_BWRAPPED
fi
cleanup () {
echo "Cleaning up..."
if [ ! -z "$SERVER_PID" ];then
echo "Killing server $SERVER_PID"
kill $SERVER_PID
fi
rm -f "$READY_FILE"
}
trap cleanup err exit
CCID="AA"
SCID="BB"
HEXCID=$(printf $CCID | od -An -tx1 | tr -d ' \n')
HEXSCID=$(printf $SCID | od -An -tx1 | tr -d ' \n')
WOLFSSL_ROOT=$(pwd)
# The server reports the port it bound in this file. The pid keeps concurrent
# runs - a second "make check" in another source tree, say - from sharing one.
READY_FILE="$WOLFSSL_ROOT/wolfssl_dtlscid_ready$$"
# A usable port is a non-zero decimal below 65536. Worth checking rather than
# assuming: a SINGLE_THREADED or WOLFSSL_TIRTOS build never resolves the
# ephemeral port in udp_accept(), so the ready file legitimately contains 0.
valid_port() {
case "$1" in
''|*[!0-9]*) return 1 ;;
esac
[ "$1" -gt 0 ] && [ "$1" -lt 65536 ]
}
# The test below depends on the server being able to report the port it bound.
# Besides the SINGLE_THREADED/WOLFSSL_TIRTOS case above, a NO_FILESYSTEM or
# NETOS build compiles write_ready_file() to a no-op and never creates the file
# at all. Probe the capability once and skip, rather than report a build-wide
# limitation as a CID test failure.
check_ready_file_support() {
local probe_pid counter port
rm -f "$READY_FILE"
$WOLFSSL_ROOT/examples/server/server -v4 -u -p 0 -R "$READY_FILE" \
>/dev/null 2>&1 &
probe_pid=$!
counter=0
while [ ! -s "$READY_FILE" -a "$counter" -lt 50 ]; do
if ! kill -0 "$probe_pid" 2>&- && [ ! -s "$READY_FILE" ]; then
break
fi
sleep 0.1
counter=$((counter + 1))
done
port=""
if [ -s "$READY_FILE" ]; then
sleep 0.1
port=$(cat "$READY_FILE")
fi
kill -9 "$probe_pid" 2>&-
wait "$probe_pid" 2>&-
rm -f "$READY_FILE"
valid_port "$port"
}
if ! check_ready_file_support; then
echo 'skipping dtlscid.test because the server cannot report an ephemeral' 1>&2
echo 'port with -p 0 -R (needs threads and a filesystem in the build).' 1>&2
exit 77
fi
# Report a failed check, with the output of both sides, and stop the test.
fail () {
echo "$1"
echo "--- server output ---"
cat "$SERVER_FILE"
echo "--- client output ---"
cat "$CLIENT_FILE"
rm -f "$SERVER_FILE" "$CLIENT_FILE"
exit 1
}
test_cid () {
echo "Running test_cid"
SERVER_FILE=$(mktemp)
CLIENT_FILE=$(mktemp)
rm -f "$READY_FILE"
# Bind an ephemeral port (-p 0) and wait for the server to report it, rather
# than taking the default port and assuming a fixed sleep is long enough for
# the bind. The default port also collides with any other test using it when
# the network namespace could not be unshared above.
$TIMEOUT_KILL_2M $WOLFSSL_ROOT/examples/server/server -v4 -u \
--cid $SCID -p 0 -R "$READY_FILE" 1> $SERVER_FILE &
SERVER_PID=$!
counter=0
while [ ! -s "$READY_FILE" -a "$counter" -lt 50 ]; do
sleep 0.1
counter=$((counter + 1))
done
if [ ! -s "$READY_FILE" ]; then
fail "server did not become ready"
fi
# sleep for an additional 0.1 to mitigate race on write/read of $READY_FILE:
sleep 0.1
PORT=$(cat "$READY_FILE")
if ! valid_port "$PORT"; then
fail "server reported unusable port '$PORT'"
fi
echo "Server listening on port $PORT"
# Bound below the server's timeout: a DTLS client with nothing to talk to
# retransmits for over two minutes, so without this the server would be
# killed first and the client left running against nothing.
$TIMEOUT_KILL_1M $WOLFSSL_ROOT/examples/client/client -v4 -u \
--cid $CCID -p $PORT 1> $CLIENT_FILE
CLIENT_RESULT=$?
if [ $CLIENT_RESULT != 0 ]; then
fail "client failed with $CLIENT_RESULT"
fi
wait $SERVER_PID
SERVER_RESULT=$?
SERVER_PID=
if [ $SERVER_RESULT != 0 ]; then
fail "server failed with $SERVER_RESULT"
fi
# Each side reports the CID it sends, which is the one its peer chose. These
# checks are the point of the test, so a mismatch has to fail the script -
# as the last commands in the function their status was previously
# discarded by the echo below.
if ! grep -q "Sending CID is ${HEXSCID}" $CLIENT_FILE; then
fail "client did not report sending CID ${HEXSCID}"
fi
if ! grep -q "Sending CID is ${HEXCID}" $SERVER_FILE; then
fail "server did not report sending CID ${HEXCID}"
fi
rm -f "$SERVER_FILE" "$CLIENT_FILE"
echo "test_cid has passed"
}
test_cid