diff --git a/fabric/context_managers.py b/fabric/context_managers.py index 38f887a8..06f2330a 100644 --- a/fabric/context_managers.py +++ b/fabric/context_managers.py @@ -455,19 +455,30 @@ def shell_env(**kw): def _forwarder(chan, sock): - # Bidirectionally forward data between a socket and a Paramiko channel. - while True: - r, w, x = select.select([sock, chan], [], []) - if sock in r: - data = sock.recv(1024) - if len(data) == 0: - break - chan.send(data) - if chan in r: - data = chan.recv(1024) - if len(data) == 0: - break - sock.send(data) + """ + Bidirectionally forward data between a socket and a Paramiko channel. + """ + mapping = { + sock.fileno(): (sock, chan), + chan.fileno(): (chan, sock), + } + poller = select.poll() + for fd in mapping: + poller.register(fd, select.POLLIN) + active = True + while active: + events = poller.poll() + for fd, flag in events: + if flag & select.POLLIN: + sender, receiver = mapping[fd] + data = sender.recv(1024) + if data: + receiver.send(data) + else: + active = False + # Handle unexpected hangups + if flag & select.POLLHUP: + active = False chan.close() sock.close() diff --git a/fabric/io.py b/fabric/io.py index 3cd4ef42..8fd6bd46 100644 --- a/fabric/io.py +++ b/fabric/io.py @@ -2,7 +2,7 @@ import sys import socket import time -from select import select +import select from collections import deque import six @@ -268,8 +268,9 @@ def input_loop(chan, f, using_pty): if msvcrt.kbhit(): byte = msvcrt.getch() elif waitable: - r, w, x = select([f], [], [], 0.0) - if f in r: + poller = select.poll() + poller.register(f, select.POLLIN) + if poller.poll(0): byte = f.read(1) else: byte = f.read(1)