Skip to content

Commit

Permalink
Merge branch '1.16' into 1.17
Browse files Browse the repository at this point in the history
  • Loading branch information
bitprophet committed Jul 26, 2016
2 parents 714595e + e0d6687 commit 60878f3
Show file tree
Hide file tree
Showing 2 changed files with 16 additions and 14 deletions.
26 changes: 12 additions & 14 deletions paramiko/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class ProxyCommand(ClosingContextManager):
`.Transport` and `.Packetizer` classes. Using this class instead of a
regular socket makes it possible to talk with a Popen'd command that will
proxy traffic between the client and a server hosted in another machine.
Instances of this class may be used as context managers.
"""
def __init__(self, command_line):
Expand All @@ -50,9 +50,9 @@ class can be passed as an argument to the `.Transport` class.
the command that should be executed and used as the proxy.
"""
self.cmd = shlsplit(command_line)
self.process = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE)
self.process = Popen(self.cmd, stdin=PIPE, stdout=PIPE, stderr=PIPE,
bufsize=0)
self.timeout = None
self.buffer = []

def send(self, content):
"""
Expand All @@ -77,11 +77,12 @@ def recv(self, size):
:param int size: how many chars should be read
:return: the length of the read content, as an `int`
:return: the string of bytes read, which may be shorter than requested
"""
try:
buffer = b''
start = time.time()
while len(self.buffer) < size:
while len(buffer) < size:
select_timeout = None
if self.timeout is not None:
elapsed = (time.time() - start)
Expand All @@ -92,16 +93,13 @@ def recv(self, size):
r, w, x = select(
[self.process.stdout], [], [], select_timeout)
if r and r[0] == self.process.stdout:
b = os.read(
self.process.stdout.fileno(), size - len(self.buffer))
# Store in class-level buffer for persistence across
# timeouts; this makes us act more like a real socket
# (where timeouts don't actually drop data.)
self.buffer.extend(b)
result = ''.join(self.buffer)
self.buffer = []
return result
buffer += os.read(
self.process.stdout.fileno(), size - len(buffer))
return buffer
except socket.timeout:
if buffer:
# Don't raise socket.timeout, return partial result instead
return buffer
raise # socket.timeout is a subclass of IOError
except IOError as e:
raise ProxyCommandFailure(' '.join(self.cmd), e.strerror)
Expand Down
4 changes: 4 additions & 0 deletions sites/www/changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
Changelog
=========

* :bug:`673` (via :issue:`681`) Fix protocol banner read errors
(``SSHException``) which would occasionally pop up when using
``ProxyCommand`` gatewaying. Thanks to ``@Depado`` for the initial report and
Paul Kapp for the fix.
* :bug:`774 (1.16+)` Add a ``_closed`` private attribute to
`~paramiko.channel.Channel` objects so that they continue functioning when
used as proxy sockets under Python 3 (e.g. as ``direct-tcpip`` gateways for
Expand Down

0 comments on commit 60878f3

Please sign in to comment.