summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--paramiko/client.py5
-rw-r--r--paramiko/transport.py4
-rw-r--r--tests/test_client.py24
3 files changed, 32 insertions, 1 deletions
diff --git a/paramiko/client.py b/paramiko/client.py
index e9bcfb56..1fe14b07 100644
--- a/paramiko/client.py
+++ b/paramiko/client.py
@@ -233,6 +233,7 @@ class SSHClient(ClosingContextManager):
gss_host=None,
banner_timeout=None,
auth_timeout=None,
+ channel_timeout=None,
gss_trust_dns=True,
passphrase=None,
disabled_algorithms=None,
@@ -311,6 +312,8 @@ class SSHClient(ClosingContextManager):
for the SSH banner to be presented.
:param float auth_timeout: an optional timeout (in seconds) to wait for
an authentication response.
+ :param float channel_timeout: an optional timeout (in seconds) to wait
+ for a channel open response.
:param dict disabled_algorithms:
an optional dict passed directly to `.Transport` and its keyword
argument of the same name.
@@ -406,6 +409,8 @@ class SSHClient(ClosingContextManager):
t.banner_timeout = banner_timeout
if auth_timeout is not None:
t.auth_timeout = auth_timeout
+ if channel_timeout is not None:
+ t.channel_timeout = channel_timeout
if port == SSH_PORT:
server_hostkey_name = hostname
diff --git a/paramiko/transport.py b/paramiko/transport.py
index 569c5cdd..98cdae03 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -516,6 +516,8 @@ class Transport(threading.Thread, ClosingContextManager):
self.handshake_timeout = 15
# how long (seconds) to wait for the auth response.
self.auth_timeout = 30
+ # how long (seconds) to wait for opening a channel
+ self.channel_timeout = 60 * 60
self.disabled_algorithms = disabled_algorithms or {}
self.server_sig_algs = server_sig_algs
@@ -1015,7 +1017,7 @@ class Transport(threading.Thread, ClosingContextManager):
"""
if not self.active:
raise SSHException("SSH session not active")
- timeout = 3600 if timeout is None else timeout
+ timeout = self.channel_timeout if timeout is None else timeout
self.lock.acquire()
try:
window_size = self._sanitize_window_size(window_size)
diff --git a/tests/test_client.py b/tests/test_client.py
index dae5b13a..21ecd72a 100644
--- a/tests/test_client.py
+++ b/tests/test_client.py
@@ -564,6 +564,30 @@ class SSHClientTest(ClientTest):
auth_timeout=0.5,
)
+ @patch.object(
+ paramiko.Channel,
+ "_set_remote_channel",
+ lambda *args, **kwargs: time.sleep(100),
+ )
+ def test_channel_timeout(self):
+ """
+ verify that the SSHClient has a configurable channel timeout
+ """
+ threading.Thread(target=self._run).start()
+ # Client setup
+ self.tc = SSHClient()
+ self.tc.set_missing_host_key_policy(paramiko.AutoAddPolicy())
+
+ # Actual connection
+ self.tc.connect(
+ **dict(
+ self.connect_kwargs, password="pygmalion", channel_timeout=0.5
+ )
+ )
+ self.event.wait(1.0)
+
+ self.assertRaises(paramiko.SSHException, self.tc.open_sftp)
+
@requires_gss_auth
def test_auth_trickledown_gsskex(self):
"""