In magic-wormhole/magic-wormhole#408 I think a client received ERROR(crowded) (eventually, because of #19, so only after the server was rebooted and the client reconnected, and re-sent the OPEN), and then tried to release the mailbox by sending CLOSE, but was thwarted because the server sent back another ERROR(crowded). I think the client then got stuck, unable to exit (because it thinks it still has a hold on the mailbox), not sending a new CLOSE (because it already sent one and it's just waiting for CLOSED).
The fix is probably to have handle_close() (in the clause that does self._app.open_mailbox(), because this connection didn't have one already) react to CrowdedError by doing most of the rest of the function, instead of raising Error("crowded"). We can't do anything that touches self._mailbox, since we don't have one, but we can set self._did_close and (most importantly) do self.send("closed"). That should satisfy the unsettled ghost client and allow it to finally exit.
In magic-wormhole/magic-wormhole#408 I think a client received
ERROR(crowded)(eventually, because of #19, so only after the server was rebooted and the client reconnected, and re-sent the OPEN), and then tried to release the mailbox by sending CLOSE, but was thwarted because the server sent back anotherERROR(crowded). I think the client then got stuck, unable to exit (because it thinks it still has a hold on the mailbox), not sending a new CLOSE (because it already sent one and it's just waiting for CLOSED).The fix is probably to have
handle_close()(in the clause that doesself._app.open_mailbox(), because this connection didn't have one already) react toCrowdedErrorby doing most of the rest of the function, instead of raisingError("crowded"). We can't do anything that touchesself._mailbox, since we don't have one, but we can setself._did_closeand (most importantly) doself.send("closed"). That should satisfy the unsettled ghost client and allow it to finally exit.