Skip to content
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

Tolerate EPIPE socket exceptions #244

Merged
merged 1 commit into from
Jan 15, 2025

Conversation

puxlit
Copy link
Contributor

@puxlit puxlit commented Jan 11, 2025

Motivation

When a player on an iOS client is connected to a stable (e.g., desktop) server and the player locks their device, then the server displays the error message SocketException: Broken pipe (OS Error: Broken pipe, errno = 32), address = 0.0.0.0, port = 4567 and shuts down.

This means players on iOS clients need to refrain from locking their device, or risk booting all other clients from the server.

Steps to reproduce

No specific notes apply for the server. I tested on a Debian VM against the tip of main (commit 7f987ea) in debug mode.

Server environment specifics (for completeness)
$ uname -a
Linux devbox 6.1.0-28-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.119-1 (2024-11-22) x86_64 GNU/Linux
$ dpkg -l curl git unzip xz-utils zip libglu1-mesa clang cmake ninja-build pkg-config libgtk-3-dev liblzma-dev libstdc++-12-dev
Desired=Unknown/Install/Remove/Purge/Hold
| Status=Not/Inst/Conf-files/Unpacked/halF-conf/Half-inst/trig-aWait/Trig-pend
|/ Err?=(none)/Reinst-required (Status,Err: uppercase=bad)
||/ Name                   Version             Architecture Description
+++-======================-===================-============-==================================================================
ii  clang                  1:14.0-55.7~deb12u1 amd64        C, C++ and Objective-C compiler (LLVM based), clang binary
ii  cmake                  3.25.1-1            amd64        cross-platform, open-source make system
ii  curl                   7.88.1-10+deb12u8   amd64        command line tool for transferring data with URL syntax
ii  git                    1:2.39.5-0+deb12u1  amd64        fast, scalable, distributed revision control system
ii  libglu1-mesa:amd64     9.0.2-1.1           amd64        Mesa OpenGL utility library (GLU)
ii  libgtk-3-dev:amd64     3.24.38-2~deb12u3   amd64        development files for the GTK library
ii  liblzma-dev:amd64      5.4.1-0.2           amd64        XZ-format compression library - development files
ii  libstdc++-12-dev:amd64 12.2.0-14           amd64        GNU Standard C++ Library v3 (development files)
ii  ninja-build            1.11.1-2~deb12u1    amd64        small build system closest in spirit to Make
ii  pkg-config:amd64       1.8.1-1             amd64        manage compile and link flags for libraries (transitional package)
ii  unzip                  6.0-28              amd64        De-archiver for .zip files
ii  xz-utils               5.4.1-0.2           amd64        XZ-format compression utilities
ii  zip                    3.0-13              amd64        Archiver for .zip files
$ flutter --version
Flutter 3.27.1 • channel stable • https://github.com/flutter/flutter.git
Framework • revision 17025dd882 (4 weeks ago) • 2024-12-17 03:23:09 +0900
Engine • revision cb4b5fff73
Tools • Dart 3.6.0 • DevTools 2.40.2

For the client, I tested on iOS 18.12.1 against release v1.10.1.

❗️ Do not run the iOS client in debug mode (as that'll start a background task to keep the Flutter debug connection alive).

❗️ Do not have another app running that keeps Wi-Fi active (e.g., Twitch or YouTube with a live stream playing).

  1. On the server device, run the app and Start Host Server. (Optionally, also start a Wireshark capture with filter tcp port 4567.)
  2. On the iOS device, run the app and Connect as Client. After a few seconds, lock the device.
  3. Wait a few seconds.
  4. On the server device, observe that (in most cases) a SocketException: Broken pipe error is displayed, and the host server shuts down.

Digging deeper

A few seconds after the the iOS device is locked, usually one of the following occurs.

  • Almost always, the client sends a FIN (as if starting a graceful connection termination) then RST.
    • Almost always, the server's onError handler trips on an EPIPE error, and shuts down.
  • Occasionally, the client sends just a RST.
    • The server's onError handler swallows an ECONNRESET error, then the onDone handler cleans up and displays the Client left. message.
  • Occasionally, the client completes a graceful connection termination with the server.

Handling of EPIPE was introduced in commit 35a03b7. I'm not sure why EPIPEs are so fatal as to require stopping the server.

This patch assumes that socket exceptions (like EPIPE) are only fatal if we're midway through assembling a message.

If this is a faulty assumption, and there are cases where EPIPE should be treated as fatal, please let me know.

(I have not explicitly tested this patch against other combinations of client and server devices.)

(Also, as an aside, I suspect leftOverMessage should be per-client, but that's a race we can prove/fix later.)

@Tarmslitaren Tarmslitaren merged commit 99fb17e into Tarmslitaren:main Jan 15, 2025
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants