[project @ Arch-1:robey@lag.net--2003-public%secsh--dev--1.0--patch-24]
document more of Message; add get_int64 all of the get_* methods are now documented, but there's a bit more to do. get_int64 added for eventual sftp support.
This commit is contained in:
parent
35ed103572
commit
ea8c1378e8
|
@ -26,46 +26,108 @@ import string, types, struct
|
||||||
from util import inflate_long, deflate_long
|
from util import inflate_long, deflate_long
|
||||||
|
|
||||||
|
|
||||||
class Message(object):
|
class Message (object):
|
||||||
"represents the encoding of an SSH2 message"
|
"""
|
||||||
|
An SSH2 I{Message} is a stream of bytes that encodes some combination of
|
||||||
|
strings, integers, bools, and infinite-precision integers (known in python
|
||||||
|
as I{long}s). This class builds or breaks down such a byte stream.
|
||||||
|
"""
|
||||||
|
|
||||||
def __init__(self, content=''):
|
def __init__(self, content=''):
|
||||||
|
"""
|
||||||
|
Create a new SSH2 Message.
|
||||||
|
|
||||||
|
@param content: the byte stream to use as the Message content (usually
|
||||||
|
passed in only when decomposing a Message).
|
||||||
|
@type content: string
|
||||||
|
"""
|
||||||
self.packet = content
|
self.packet = content
|
||||||
self.idx = 0
|
self.idx = 0
|
||||||
self.seqno = -1
|
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
|
"""
|
||||||
|
Return the byte stream content of this Message, as a string.
|
||||||
|
|
||||||
|
@return: the contents of this Message.
|
||||||
|
@rtype: string
|
||||||
|
"""
|
||||||
return self.packet
|
return self.packet
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
"""
|
||||||
|
Returns a string representation of this object, for debugging.
|
||||||
|
|
||||||
|
@rtype: string
|
||||||
|
"""
|
||||||
return 'Message(' + repr(self.packet) + ')'
|
return 'Message(' + repr(self.packet) + ')'
|
||||||
|
|
||||||
def get_remainder(self):
|
def get_remainder(self):
|
||||||
"remaining bytes still unparsed"
|
"""
|
||||||
|
Return the bytes of this Message that haven't already been parsed and
|
||||||
|
returned.
|
||||||
|
|
||||||
|
@return: a string of the bytes not parsed yet.
|
||||||
|
@rtype: string
|
||||||
|
"""
|
||||||
return self.packet[self.idx:]
|
return self.packet[self.idx:]
|
||||||
|
|
||||||
def get_so_far(self):
|
def get_so_far(self):
|
||||||
"bytes that have been parsed"
|
"""
|
||||||
|
Returns the bytes of this Message that have been parsed and returned.
|
||||||
|
The string passed into a Message's constructor can be regenerated by
|
||||||
|
concatenating C{get_so_far} and L{get_remainder}.
|
||||||
|
|
||||||
|
@return: a string of the bytes parsed so far.
|
||||||
|
@rtype: string
|
||||||
|
"""
|
||||||
return self.packet[:self.idx]
|
return self.packet[:self.idx]
|
||||||
|
|
||||||
def get_bytes(self, n):
|
def get_bytes(self, n):
|
||||||
|
"""
|
||||||
|
Return the next C{n} bytes of the Message, without decomposing into
|
||||||
|
an int, string, etc. Just the raw bytes are returned.
|
||||||
|
|
||||||
|
@return: a string of the next C{n} bytes of the Message, or a string
|
||||||
|
of C{n} zero bytes, if there aren't C{n} bytes remaining.
|
||||||
|
@rtype: string
|
||||||
|
"""
|
||||||
if self.idx + n > len(self.packet):
|
if self.idx + n > len(self.packet):
|
||||||
return '\x00'*n
|
return '\x00'*n
|
||||||
b = self.packet[self.idx:self.idx+n]
|
b = self.packet[self.idx:self.idx+n]
|
||||||
self.idx = self.idx + n
|
self.idx = self.idx + n
|
||||||
return b
|
return b
|
||||||
|
|
||||||
def get_byte(self):
|
def get_byte(self):
|
||||||
|
"""
|
||||||
|
Return the next byte of the Message, without decomposing it. This
|
||||||
|
is equivalent to L{get_bytes(1)<get_bytes>}.
|
||||||
|
|
||||||
|
@return: the next byte of the Message, or C{'\000'} if there aren't
|
||||||
|
any bytes remaining.
|
||||||
|
@rtype: string
|
||||||
|
"""
|
||||||
return self.get_bytes(1)
|
return self.get_bytes(1)
|
||||||
|
|
||||||
def get_boolean(self):
|
def get_boolean(self):
|
||||||
|
"""
|
||||||
|
Fetch a boolean from the stream.
|
||||||
|
|
||||||
|
@return: C{True} or C{False} (from the Message).
|
||||||
|
@rtype: bool
|
||||||
|
"""
|
||||||
b = self.get_bytes(1)
|
b = self.get_bytes(1)
|
||||||
if b == '\x00':
|
if b == '\x00':
|
||||||
return 0
|
return False
|
||||||
else:
|
else:
|
||||||
return 1
|
return True
|
||||||
|
|
||||||
def get_int(self):
|
def get_int(self):
|
||||||
|
"""
|
||||||
|
Fetch an int from the stream.
|
||||||
|
|
||||||
|
@return: a 32-bit unsigned integer.
|
||||||
|
@rtype: int
|
||||||
|
"""
|
||||||
x = self.packet
|
x = self.packet
|
||||||
i = self.idx
|
i = self.idx
|
||||||
if i + 4 > len(x):
|
if i + 4 > len(x):
|
||||||
|
@ -74,10 +136,39 @@ class Message(object):
|
||||||
self.idx = i+4
|
self.idx = i+4
|
||||||
return n
|
return n
|
||||||
|
|
||||||
|
def get_int64(self):
|
||||||
|
"""
|
||||||
|
Fetch a 64-bit int from the stream.
|
||||||
|
|
||||||
|
@return: a 64-bit unsigned integer.
|
||||||
|
@rtype: long
|
||||||
|
"""
|
||||||
|
x = self.packet
|
||||||
|
i = self.idx
|
||||||
|
if i + 8 > len(x):
|
||||||
|
return 0L
|
||||||
|
n = struct.unpack('>Q', x[i:i+8])[0]
|
||||||
|
self.idx += 8
|
||||||
|
return n
|
||||||
|
|
||||||
def get_mpint(self):
|
def get_mpint(self):
|
||||||
|
"""
|
||||||
|
Fetch a long int (mpint) from the stream.
|
||||||
|
|
||||||
|
@return: an arbitrary-length integer.
|
||||||
|
@rtype: long
|
||||||
|
"""
|
||||||
return inflate_long(self.get_string())
|
return inflate_long(self.get_string())
|
||||||
|
|
||||||
def get_string(self):
|
def get_string(self):
|
||||||
|
"""
|
||||||
|
Fetch a string from the stream. This could be a byte string and may
|
||||||
|
contain unprintable characters. (It's not unheard of for a string to
|
||||||
|
contain another byte-stream Message.)
|
||||||
|
|
||||||
|
@return: a string.
|
||||||
|
@rtype: string
|
||||||
|
"""
|
||||||
l = self.get_int()
|
l = self.get_int()
|
||||||
if self.idx + l > len(self.packet):
|
if self.idx + l > len(self.packet):
|
||||||
return ''
|
return ''
|
||||||
|
@ -86,6 +177,13 @@ class Message(object):
|
||||||
return str
|
return str
|
||||||
|
|
||||||
def get_list(self):
|
def get_list(self):
|
||||||
|
"""
|
||||||
|
Fetch a list of strings from the stream. These are trivially encoded
|
||||||
|
as comma-separated values in a string.
|
||||||
|
|
||||||
|
@return: a list of strings.
|
||||||
|
@type: list of strings
|
||||||
|
"""
|
||||||
str = self.get_string()
|
str = self.get_string()
|
||||||
l = string.split(str, ',')
|
l = string.split(str, ',')
|
||||||
return l
|
return l
|
||||||
|
|
Loading…
Reference in New Issue