summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorRobey Pointer <robey@lag.net>2004-04-05 10:37:18 +0000
committerRobey Pointer <robey@lag.net>2004-04-05 10:37:18 +0000
commit70faf02f3eb9ecd6d33f23881fca9b9057ff297f (patch)
tree26144b0985d27101055dd983cb58c1b274a0ee46
parentc9d301b782f972eaabbbb8dbaadb28781599aed6 (diff)
[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-39]
add global request mechanism add transport.global_request() to make a global-style request (usually an extension to the protocol -- like keepalives) and handle requests from the remote host. incoming requests are now handled and responded to correctly, which should make openssh-style keepalives work. (before, we would silently ignore them, which was wrong.)
-rw-r--r--paramiko/common.py1
-rw-r--r--paramiko/message.py2
-rw-r--r--paramiko/transport.py105
3 files changed, 105 insertions, 3 deletions
diff --git a/paramiko/common.py b/paramiko/common.py
index 54c086c7..4aa2c34e 100644
--- a/paramiko/common.py
+++ b/paramiko/common.py
@@ -28,6 +28,7 @@ MSG_KEXINIT, MSG_NEWKEYS = range(20, 22)
MSG_USERAUTH_REQUEST, MSG_USERAUTH_FAILURE, MSG_USERAUTH_SUCCESS, \
MSG_USERAUTH_BANNER = range(50, 54)
MSG_USERAUTH_PK_OK = 60
+MSG_GLOBAL_REQUEST, MSG_REQUEST_SUCCESS, MSG_REQUEST_FAILURE = range(80, 83)
MSG_CHANNEL_OPEN, MSG_CHANNEL_OPEN_SUCCESS, MSG_CHANNEL_OPEN_FAILURE, \
MSG_CHANNEL_WINDOW_ADJUST, MSG_CHANNEL_DATA, MSG_CHANNEL_EXTENDED_DATA, \
MSG_CHANNEL_EOF, MSG_CHANNEL_CLOSE, MSG_CHANNEL_REQUEST, \
diff --git a/paramiko/message.py b/paramiko/message.py
index 86154649..bb79d609 100644
--- a/paramiko/message.py
+++ b/paramiko/message.py
@@ -243,6 +243,8 @@ class Message (object):
return self.add_mpint(i)
else:
return self.add_int(i)
+ elif type(i) is bool:
+ return self.add_boolean(i)
elif type(i) == types.ListType:
return self.add_list(i)
else:
diff --git a/paramiko/transport.py b/paramiko/transport.py
index 58508c08..63762ccc 100644
--- a/paramiko/transport.py
+++ b/paramiko/transport.py
@@ -307,7 +307,7 @@ class BaseTransport (threading.Thread):
@type filename: string
@return: True if a moduli file was successfully loaded; False
otherwise.
- @rtype: boolean
+ @rtype: bool
@since: doduo
@@ -364,7 +364,7 @@ class BaseTransport (threading.Thread):
Return true if this session is active (open).
@return: True if the session is still active (open); False if the session is closed.
- @rtype: boolean
+ @rtype: bool
"""
return self.active
@@ -454,7 +454,7 @@ class BaseTransport (threading.Thread):
@return: True if the renegotiation was successful, and the link is
using new keys; False if the session dropped during renegotiation.
- @rtype: boolean
+ @rtype: bool
"""
self.completion_event = threading.Event()
self._send_kex_init()
@@ -466,6 +466,44 @@ class BaseTransport (threading.Thread):
break
return True
+ def global_request(self, kind, data=None, wait=True):
+ """
+ Make a global request to the remote host. These are normally
+ extensions to the SSH2 protocol.
+
+ @param kind: name of the request.
+ @type kind: string
+ @param data: an optional tuple containing additional data to attach
+ to the request.
+ @type data: tuple
+ @param wait: C{True} if this method should not return until a response
+ is received; C{False} otherwise.
+ @type wait: bool
+ @return: a L{Message} containing possible additional data if the
+ request was successful (or an empty L{Message} if C{wait} was
+ C{False}); C{None} if the request was denied.
+ @rtype: L{Message}
+ """
+ if wait:
+ self.completion_event = threading.Event()
+ m = Message()
+ m.add_byte(chr(MSG_GLOBAL_REQUEST))
+ m.add_string(kind)
+ m.add_boolean(wait)
+ if data is not None:
+ for item in data:
+ m.add(item)
+ self._send_message(m)
+ if not wait:
+ return True
+ while True:
+ self.completion_event.wait(0.1)
+ if not self.active:
+ return False
+ if self.completion_event.isSet():
+ break
+ return self.global_response
+
def check_channel_request(self, kind, chanid):
"""
I{(subclass override)}
@@ -496,6 +534,36 @@ class BaseTransport (threading.Thread):
"""
return None
+ def check_global_request(self, kind, msg):
+ """
+ I{(subclass override)}
+ Handle a global request of the given C{kind}. This method is called
+ in server mode and client mode, whenever the remote host makes a global
+ request. If there are any arguments to the request, they will be in
+ C{msg}.
+
+ There aren't any useful global requests defined, aside from port
+ forwarding, so usually this type of request is an extension to the
+ protocol.
+
+ If the request was successful and you would like to return contextual
+ data to the remote host, return a tuple. Items in the tuple will be
+ sent back with the successful result. (Note that the items in the
+ tuple can only be strings, ints, longs, or bools.)
+
+ The default implementation always returns C{False}, indicating that it
+ does not support any global requests.
+
+ @param kind: the kind of global request being made.
+ @type kind: string
+ @param msg: any extra arguments to the request.
+ @type msg: L{Message}
+ @return: C{True} or a tuple of data if the request was granted;
+ C{False} otherwise.
+ @rtype: bool
+ """
+ return False
+
def accept(self, timeout=None):
try:
self.lock.acquire()
@@ -1081,6 +1149,34 @@ class BaseTransport (threading.Thread):
desc = m.get_string()
self._log(INFO, 'Disconnect (code %d): %s' % (code, desc))
+ def _parse_global_request(self, m):
+ kind = m.get_string()
+ want_reply = m.get_boolean()
+ ok = self.check_global_request(kind, m)
+ extra = ()
+ if type(ok) is tuple:
+ extra = ok
+ ok = True
+ if want_reply:
+ msg = Message()
+ if ok:
+ msg.add_byte(chr(MSG_REQUEST_SUCCESS))
+ for item in extra:
+ msg.add(item)
+ else:
+ msg.add_byte(chr(MSG_REQUEST_FAILURE))
+ self._send_message(msg)
+
+ def _parse_request_success(self, m):
+ self.global_response = m
+ if self.completion_event is not None:
+ self.completion_event.set()
+
+ def _parse_request_failure(self, m):
+ self.global_response = None
+ if self.completion_event is not None:
+ self.completion_event.set()
+
def _parse_channel_open_success(self, m):
chanid = m.get_int()
server_chanid = m.get_int()
@@ -1187,6 +1283,9 @@ class BaseTransport (threading.Thread):
_handler_table = {
MSG_NEWKEYS: _parse_newkeys,
+ MSG_GLOBAL_REQUEST: _parse_global_request,
+ MSG_REQUEST_SUCCESS: _parse_request_success,
+ MSG_REQUEST_FAILURE: _parse_request_failure,
MSG_CHANNEL_OPEN_SUCCESS: _parse_channel_open_success,
MSG_CHANNEL_OPEN_FAILURE: _parse_channel_open_failure,
MSG_CHANNEL_OPEN: _parse_channel_open,