Potentially horrible attempt at manual subprocess-read timeouts
This commit is contained in:
parent
5b6059c4bd
commit
58489c893e
|
@ -20,10 +20,13 @@
|
||||||
L{ProxyCommand}.
|
L{ProxyCommand}.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
import os
|
import os
|
||||||
from shlex import split as shlsplit
|
from shlex import split as shlsplit
|
||||||
import signal
|
import signal
|
||||||
from subprocess import Popen, PIPE
|
from subprocess import Popen, PIPE
|
||||||
|
from select import select
|
||||||
|
import socket
|
||||||
|
|
||||||
from paramiko.ssh_exception import ProxyCommandFailure
|
from paramiko.ssh_exception import ProxyCommandFailure
|
||||||
|
|
||||||
|
@ -48,6 +51,7 @@ class ProxyCommand(object):
|
||||||
"""
|
"""
|
||||||
self.cmd = shlsplit(command_line)
|
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)
|
||||||
|
self.timeout = None
|
||||||
|
|
||||||
def send(self, content):
|
def send(self, content):
|
||||||
"""
|
"""
|
||||||
|
@ -78,7 +82,25 @@ class ProxyCommand(object):
|
||||||
@rtype: int
|
@rtype: int
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
return os.read(self.process.stdout.fileno(), size)
|
start = datetime.now()
|
||||||
|
read = []
|
||||||
|
while len(read) < size:
|
||||||
|
if self.timeout is not None:
|
||||||
|
elapsed = (datetime.now() - start).microseconds
|
||||||
|
timeout = self.timeout * 1000 * 1000 # to microseconds
|
||||||
|
# Unsure why the 'default' timeout is too short here -
|
||||||
|
# causes us to raise before e.g. the SSH banner is read,
|
||||||
|
# probably generally awful for slow connections.
|
||||||
|
# Try inflating it some.
|
||||||
|
timeout = timeout * 2
|
||||||
|
if elapsed >= timeout:
|
||||||
|
raise socket.timeout()
|
||||||
|
r, w, x = select([self.process.stdout], [], [], 0.0)
|
||||||
|
if r and r[0] == self.process.stdout:
|
||||||
|
b = os.read(self.process.stdout.fileno(), 1)
|
||||||
|
read.append(b)
|
||||||
|
result = ''.join(read)
|
||||||
|
return result
|
||||||
except IOError, e:
|
except IOError, e:
|
||||||
raise BadProxyCommand(' '.join(self.cmd), e.strerror)
|
raise BadProxyCommand(' '.join(self.cmd), e.strerror)
|
||||||
|
|
||||||
|
@ -86,6 +108,4 @@ class ProxyCommand(object):
|
||||||
os.kill(self.process.pid, signal.SIGTERM)
|
os.kill(self.process.pid, signal.SIGTERM)
|
||||||
|
|
||||||
def settimeout(self, timeout):
|
def settimeout(self, timeout):
|
||||||
# Timeouts are meaningless for this implementation, but are part of the
|
self.timeout = timeout
|
||||||
# spec, so must be present.
|
|
||||||
pass
|
|
||||||
|
|
Loading…
Reference in New Issue