upleb.uk

Public git repos — served from a NIP-34 GRASP relay at git.upleb.uk

summaryrefslogtreecommitdiff
path: root/src/proxy.cpp
diff options
context:
space:
mode:
authorbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 17:39:50 +0000
committerbitflash-maintainer <noreply@bitflash.invalid>2026-09-02 17:39:50 +0000
commit0a8c445742ce871c6b9352bf406d2232a6fd3134 (patch)
tree058ed75eee5a1559d8c19f3411bd2ec729e1439c /src/proxy.cpp
parent0b566b4869b9e86c90162befd87f9882b6dd143c (diff)
tunnel: give both pumps shared ownership of the sockets they close
PumpIn's wrapper closed pumpEnd and the rendezvous socket the moment it exited, without waiting for PumpOut, which then called shutdown() on both at its own exit. Which of the two got there first decided whether that shutdown addressed a live descriptor or a number the kernel had already handed back out -- in which case it tears down an unrelated connection. The inbound pump wins that race whenever the rendezvous socket dies before the app socket, which is the ordinary shape of a relay restart or a far side hanging up. The failure path added in 0b566b4 has the same hole. Its catch shuts down rv to wake an inbound pump it assumes is parked in RvReadN. PumpIn does not park when the rendezvous connection is already dead: it returns on its first length read and its wrapper closes both descriptors. A refused pthread_create and a dead rv are not independent -- both are symptoms of a loaded process -- so that is the likely case, not the exotic one. Both descriptors now belong to a shared_ptr the two pumps hold for the whole of their bodies, so the close happens after the last pump has stopped touching them and no shutdown can precede it. appEnd is unchanged: the caller gets it on success, StartTunnel closes it on every failure path, no pump ever touches it. 0b566b4's message says of that catch that "closing those descriptors from the failure path instead would race it". True as far as it goes, but it reads as though what the code did instead was safe, and it was not -- the shutdown raced the same close. There was no ordering there to prefer, only a missing owner. Measured against the real code with the relay in a separate process, every close() and shutdown() traced and pthread_create refused on demand: normal teardown, 25 tunnels 29 shutdowns on a closed fd -> 0 refused outbound spawn, 25 25 shutdowns on a closed fd -> 0 Close counts are identical before and after (8 and 5 per tunnel, every one accounted for) and live descriptors return to their starting count, so the defect was only ever the ordering, never a leak or a double close.
Diffstat (limited to 'src/proxy.cpp')
0 files changed, 0 insertions, 0 deletions