Skip to content

Commit

Permalink
read in >1 byte chunks, and set a useful timeout on select()
Browse files Browse the repository at this point in the history
this way, we're not rolling this loop over nearly as much, while still
preserving the overall timeout semantics
  • Loading branch information
jwm authored and bitprophet committed Dec 18, 2014
1 parent fc59b7d commit b4e9dc3
Showing 1 changed file with 12 additions and 7 deletions.
19 changes: 12 additions & 7 deletions paramiko/proxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
from subprocess import Popen, PIPE
from select import select
import socket
import time

from paramiko.ssh_exception import ProxyCommandFailure

Expand Down Expand Up @@ -76,20 +77,24 @@ def recv(self, size):
:return: the length of the read content, as an `int`
"""
try:
start = datetime.now()
start = time.time()
while len(self.buffer) < size:
select_timeout = None
if self.timeout is not None:
elapsed = (datetime.now() - start).microseconds
timeout = self.timeout * 1000 * 1000 # to microseconds
if elapsed >= timeout:
elapsed = (time.time() - start)
if elapsed >= self.timeout:
raise socket.timeout()
r, w, x = select([self.process.stdout], [], [], 0.0)
select_timeout = self.timeout - elapsed

r, w, x = select(
[self.process.stdout], [], [], select_timeout)
if r and r[0] == self.process.stdout:
b = os.read(self.process.stdout.fileno(), 1)
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.append(b)
self.buffer.extend(b)
result = ''.join(self.buffer)
self.buffer = []
return result
Expand Down

0 comments on commit b4e9dc3

Please sign in to comment.