issue #131: disable non-blocking IO during UNIX accept()

accept() (per interface) returns a non-blocking socket because the
listener socket is in non-blocking mode, therefore it is pure scheduling
luck that a connecting-in child has a chance to write anything for the
top-level processs to read during the subsequent .recv().

A higher forks setting in ansible.cfg was enough to cause our luck to
run out, causing the .recv() to crashi with EGAIN, and the multiplexer
to respond to the handler's crash by calling its disconnect method. This
is why some reports mentioned ECONNREFUSED -- the listener really was
gone, because its Stream class had crashed.

Meanwhile since the window where we're waiting for the remote process to
identify itself is tiny, simply flip off O_NONBLOCK for the duration of
the connection handshake. Stream.accept() (via Side.__init__) will
reenable O_NONBLOCK for the descriptors it duplicates, so we don't even
need to bother turning this back off.

A better solution entails splitting Stream up into a state machine and
doing the handshake with non-blocking IO, but that isn't going to be
available until asynchronous connect is implemented. Meanwhile in
reality this solution is probably 100% fine.
wip-fakessh-exit-status
David Wilson 6 years ago
parent 44d36eccba
commit 017e8105cf

@ -78,6 +78,7 @@ class Listener(mitogen.core.BasicStream):
def on_receive(self, broker):
sock, _ = self._sock.accept()
sock.setblocking(True)
pid, = struct.unpack('>L', sock.recv(4))
context_id = self._router.id_allocator.allocate()

Loading…
Cancel
Save