Repository navigation
common: fail RPC receive when the peer closes mid-payload - #113
Open
transmogrify-cell wants to merge 1 commit into
Open
transmogrify-cell wants to merge 1 commit into
transmogrify-cell wants to merge 1 commit into
Conversation
SoapyRPCUnpacker::recv() reads the payload in a loop and only treats a negative recv() result as an error. When the server closes the connection after the header but before the whole payload has arrived, recv() keeps returning 0, bytesReceived never advances and the loop spins forever at full CPU, holding the device mutex. Every other call on that device then blocks as well. Throw a runtime_error when recv() returns 0, like the header receive already does, so the caller sees the dead link instead of hanging.
Author
|
@AsciiWolf could you take a look pls? It's a 6-line change in |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
SoapyRPCUnpacker::recv()reads the payload in a loop that only treats a negativerecv()result as an error:If the server closes the connection after sending the header but before the whole payload has arrived,
recv()returns 0 on every call.bytesReceivednever advances, and the client spins at 100% CPU forever. For device calls this happens while holding_mutex, so every other call on that device blocks too. This PR throws aruntime_errorwhenrecv()returns 0, as the header receive already does withMSG_WAITALL.It only matters when the server goes away part-way through sending a reply, which in practice means a reply longer than one TCP segment. It is a hang rather than a crash, so it's rare but hard to diagnose. The change is independent of #112: it touches a different file, and that PR doesn't cover this path.
Reproducing
A fake server that sends a valid header announcing a 4096-byte packet, then 8 payload bytes, then FIN:
The client side is a one-line program calling
SoapySDR::Device::make("driver=remote,remote=tcp://127.0.0.1:PORT"):SoapyRPCUnpacker::recv()→SoapyRPCSocket::recv()(SoapyRPCUnpacker.cpp:107), reached viafindRemote(). I killed it after 12 s.SoapyRemote::find(tcp://127.0.0.1:…) -- transact FAIL: SoapyRPCUnpacker::recv(payload) FAIL: connection closed by peer, andmake()throws.Testing
SoapySDRServerserving a fake RX device, over the default UDP stream: 100 activate/deactivate cycles at 250 kS/s plussetFrequency. Behaviour was identical to master: no errors, and samples kept flowing.Disclosure: I found and tested this while looking into gqrx-sdr/gqrx#1445. That issue is fixed by #112, not by this PR.