From b51990fd4b2b0a0cb40b8efb5c72032957423383 Mon Sep 17 00:00:00 2001 From: mivirl <> Date: Sat, 2 Mar 2024 19:06:49 -0600 Subject: [PATCH] server: Add retries with random backoff for file uploads When binding a port on the server side, there's a chance that another process has already bound the port. Retries a few times with a random backoff to reduce the number of collisions Future versions will reduce the number of ports used by the server, and this change makes it possible with fewer issues. --- src/client.pl | 20 +++++++++++++++++--- src/server.sh | 32 +++++++++++++++++++++++++++----- 2 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/client.pl b/src/client.pl index dfaa3c2..8e20377 100644 --- a/src/client.pl +++ b/src/client.pl @@ -243,9 +243,23 @@ sub send_file { $socket->send("file\n"); $socket->send("$fileName\n"); $socket->send("$fileHash\n"); - sleep 2; - $socket->recv(my $port, 128); - ($port) = $port =~ m/(\d+)/; + $socket->recv(my $ignored, 128); + my $port = undef; + my $r; + my $sleeptime = 2; + my $attemptcount = 0; + while (! defined $port) { + sleep $sleeptime; + $sleeptime *= 2; + $sleeptime = 10 if ($sleeptime > 10); + $socket->recv($r, 128); + ($port) = $r =~ m/(\d+)/; + $attemptcount += 1; + if ($attemptcount >= 5) { + print_log "File: upload failure ($file)"; + exit; + } + } # Send file once print_log "File: upload port is $port ($file)"; diff --git a/src/server.sh b/src/server.sh index 0a9bc89..b6245d4 100644 --- a/src/server.sh +++ b/src/server.sh @@ -118,14 +118,36 @@ while read -r COMMAND; do FILENAME="${FILENAME}_${SUFFIX}" fi + # Grab an open port and listen for file. Use netcat since sh can't + # handle binary data well + ATTEMPTCOUNT=0 + SLEEPTIME=0 + while true; do + sleep $(( RANDOM % (SLEEPTIME + 5) + 1 )) + PORT=$(( (RANDOM * 2 + RANDOM % 2) % 64511 + 1024 )) + nc -w 7 -l -p "$PORT" > "$FILENAME" 2>/dev/null & + NC_PID=$! + # Wait for nc to fail. There seems to be a bug with busybox sh where + # using the builtin sleep when following the backgrounded nc + # doesn't sleep, so calling the binary again + ../../../busybox sleep 1 + if ps -o pid | grep -q -e $NC_PID ; then + break + fi + ATTEMPTCOUNT=$(( ATTEMPTCOUNT + 1 )) + SLEEPTIME=$(( SLEEPTIME + 2 )) + if [ $ATTEMPTCOUNT -gt 5 ]; then + echo "$CLIENTNAME: ($FILENAME) Failed to bind open port for file transfer, giving up" >&2 + echo "[${FILERECVTIME}] File transfer failed: ${FILENAME}" >> _files.log + exit + fi + done + echo "$PORT" + wait $NC_PID + FILERECVTIME="$(date '+%Y-%m-%d %H:%M:%S')" echo "[${FILERECVTIME}] File received: ${FILENAME}" >> _files.log - # Client should send with `cat file | nc ip port` - PORT=$(( (RANDOM * 2 + RANDOM % 2) % 64511 + 1024 )) - echo "$PORT" - nc -w 5 -l -p "$PORT" > "$FILENAME" - HASH=$(md5sum "$FILENAME" | cut -d' ' -f1) if [ "$HASH" != "$TMPHASH" ]; then echo "Checksum error" -- 2.39.5