Skip to content

Commit 5159542

Browse files
committed
Handle close on redirected pipe, without getting an EOF first
This commit handles getting a close on a pipe used as a read redirect target on a pipe without ever receiving an EOF. This seems to happen on Linux when redirecting to a pseudo-TTY. When the slave TTY is closed, the master half gets an I/O error, triggering connection_lost to be called with an exception rather than eof_received. This prevented calls to drain() from properly unblocking, since the redirect was not properly cleaned up. Thanks go to GitHub user xuoguoto who helped to provide sample scripts showing the problem and ran multiple tests collecting data to help track this down!
1 parent 9ad9688 commit 5159542

File tree

1 file changed

+12
-0
lines changed

1 file changed

+12
-0
lines changed

asyncssh/process.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -365,6 +365,12 @@ def connection_made(self, transport: asyncio.BaseTransport) -> None:
365365

366366
self._transport = cast(asyncio.ReadTransport, transport)
367367

368+
def connection_lost(self, exc: Optional[Exception]) -> None:
369+
"""Handle closing of the pipe"""
370+
371+
self._process.feed_close(self._datatype)
372+
self.close()
373+
368374
def data_received(self, data: bytes) -> None:
369375
"""Forward data from the pipe"""
370376

@@ -1048,6 +1054,12 @@ def feed_eof(self, datatype: DataType) -> None:
10481054
self._readers[datatype].close()
10491055
self.clear_reader(datatype)
10501056

1057+
def feed_close(self, datatype: DataType) -> None:
1058+
"""Feed pipe close to the channel"""
1059+
1060+
if datatype in self._readers:
1061+
self.feed_eof(datatype)
1062+
10511063
def feed_recv_buf(self, datatype: DataType,
10521064
writer: _WriterProtocol[AnyStr]) -> None:
10531065
"""Feed current receive buffer to a newly set writer"""

0 commit comments

Comments
 (0)