Skip to content

Commit

Permalink
Handle close on redirected pipe, without getting an EOF first
Browse files Browse the repository at this point in the history
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!
  • Loading branch information
ronf committed Jun 4, 2024
1 parent 9ad9688 commit 5159542
Showing 1 changed file with 12 additions and 0 deletions.
12 changes: 12 additions & 0 deletions asyncssh/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,6 +365,12 @@ def connection_made(self, transport: asyncio.BaseTransport) -> None:

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

def connection_lost(self, exc: Optional[Exception]) -> None:
"""Handle closing of the pipe"""

self._process.feed_close(self._datatype)
self.close()

def data_received(self, data: bytes) -> None:
"""Forward data from the pipe"""

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

def feed_close(self, datatype: DataType) -> None:
"""Feed pipe close to the channel"""

if datatype in self._readers:
self.feed_eof(datatype)

def feed_recv_buf(self, datatype: DataType,
writer: _WriterProtocol[AnyStr]) -> None:
"""Feed current receive buffer to a newly set writer"""
Expand Down

0 comments on commit 5159542

Please sign in to comment.