diff options
-rw-r--r-- | paramiko/client.py | 5 | ||||
-rw-r--r-- | paramiko/transport.py | 4 | ||||
-rw-r--r-- | tests/test_client.py | 24 |
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): """ |