Skip to content

Fix a bad race condition that causes intermittent socket receive failures #171

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions adafruit_wiznet5k/adafruit_wiznet5k_socketpool.py
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,14 @@ def recv_into( # pylint: disable=unused-argument
self._buffer = self._buffer[bytes_to_read:]
# explicitly recheck num_to_read to avoid extra checks
continue

# We need to read the socket status here before seeing if any bytes are available.
# Why? Because otherwise we have a bad race condition in the if/elif/... logic below
# that can cause recv_into to fail when the other side closes the connection after
# sending bytes. The problem is that initially we can have num_avail=0 while the
# socket state is not in CLOSED or CLOSED_WAIT. Then after the if but before the elif
# that checks the socket state, bytes arrive and the other end closes the connection.
# So now bytes are available but we see the CLOSED/CLOSED_WAIT state and ignore them.
status_before_getting_available = self._status
num_avail = self._available()
if num_avail > 0:
last_read_time = ticks_ms()
Expand All @@ -620,7 +627,9 @@ def recv_into( # pylint: disable=unused-argument
elif num_read > 0:
# We got a message, but there are no more bytes to read, so we can stop.
break
elif self._status in (
# See note where we set status_before_getting_available for why we can't just check
# _status here
elif status_before_getting_available in (
wiznet5k.adafruit_wiznet5k.SNSR_SOCK_CLOSED,
wiznet5k.adafruit_wiznet5k.SNSR_SOCK_CLOSE_WAIT,
):
Expand Down