Package paramiko :: Module message
[frames] | no frames]

Source Code for Module paramiko.message

  1  # Copyright (C) 2003-2007  Robey Pointer <robeypointer@gmail.com> 
  2  # 
  3  # This file is part of paramiko. 
  4  # 
  5  # Paramiko is free software; you can redistribute it and/or modify it under the 
  6  # terms of the GNU Lesser General Public License as published by the Free 
  7  # Software Foundation; either version 2.1 of the License, or (at your option) 
  8  # any later version. 
  9  # 
 10  # Paramiko is distrubuted in the hope that it will be useful, but WITHOUT ANY 
 11  # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR 
 12  # A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for more 
 13  # details. 
 14  # 
 15  # You should have received a copy of the GNU Lesser General Public License 
 16  # along with Paramiko; if not, write to the Free Software Foundation, Inc., 
 17  # 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA. 
 18   
 19  """ 
 20  Implementation of an SSH2 "message". 
 21  """ 
 22   
 23  import struct 
 24  import cStringIO 
 25   
 26  from paramiko import util 
 27   
 28   
29 -class Message (object):
30 """ 31 An SSH2 I{Message} is a stream of bytes that encodes some combination of 32 strings, integers, bools, and infinite-precision integers (known in python 33 as I{long}s). This class builds or breaks down such a byte stream. 34 35 Normally you don't need to deal with anything this low-level, but it's 36 exposed for people implementing custom extensions, or features that 37 paramiko doesn't support yet. 38 """ 39
40 - def __init__(self, content=None):
41 """ 42 Create a new SSH2 Message. 43 44 @param content: the byte stream to use as the Message content (passed 45 in only when decomposing a Message). 46 @type content: string 47 """ 48 if content != None: 49 self.packet = cStringIO.StringIO(content) 50 else: 51 self.packet = cStringIO.StringIO()
52
53 - def __str__(self):
54 """ 55 Return the byte stream content of this Message, as a string. 56 57 @return: the contents of this Message. 58 @rtype: string 59 """ 60 return self.packet.getvalue()
61
62 - def __repr__(self):
63 """ 64 Returns a string representation of this object, for debugging. 65 66 @rtype: string 67 """ 68 return 'paramiko.Message(' + repr(self.packet.getvalue()) + ')'
69
70 - def rewind(self):
71 """ 72 Rewind the message to the beginning as if no items had been parsed 73 out of it yet. 74 """ 75 self.packet.seek(0)
76
77 - def get_remainder(self):
78 """ 79 Return the bytes of this Message that haven't already been parsed and 80 returned. 81 82 @return: a string of the bytes not parsed yet. 83 @rtype: string 84 """ 85 position = self.packet.tell() 86 remainder = self.packet.read() 87 self.packet.seek(position) 88 return remainder
89
90 - def get_so_far(self):
91 """ 92 Returns the bytes of this Message that have been parsed and returned. 93 The string passed into a Message's constructor can be regenerated by 94 concatenating C{get_so_far} and L{get_remainder}. 95 96 @return: a string of the bytes parsed so far. 97 @rtype: string 98 """ 99 position = self.packet.tell() 100 self.rewind() 101 return self.packet.read(position)
102
103 - def get_bytes(self, n):
104 """ 105 Return the next C{n} bytes of the Message, without decomposing into 106 an int, string, etc. Just the raw bytes are returned. 107 108 @return: a string of the next C{n} bytes of the Message, or a string 109 of C{n} zero bytes, if there aren't C{n} bytes remaining. 110 @rtype: string 111 """ 112 b = self.packet.read(n) 113 max_pad_size = 1<<20 # Limit padding to 1 MB 114 if len(b) < n and n < max_pad_size: 115 return b + '\x00' * (n - len(b)) 116 return b
117
118 - def get_byte(self):
119 """ 120 Return the next byte of the Message, without decomposing it. This 121 is equivalent to L{get_bytes(1)<get_bytes>}. 122 123 @return: the next byte of the Message, or C{'\000'} if there aren't 124 any bytes remaining. 125 @rtype: string 126 """ 127 return self.get_bytes(1)
128
129 - def get_boolean(self):
130 """ 131 Fetch a boolean from the stream. 132 133 @return: C{True} or C{False} (from the Message). 134 @rtype: bool 135 """ 136 b = self.get_bytes(1) 137 return b != '\x00'
138
139 - def get_int(self):
140 """ 141 Fetch an int from the stream. 142 143 @return: a 32-bit unsigned integer. 144 @rtype: int 145 """ 146 return struct.unpack('>I', self.get_bytes(4))[0]
147
148 - def get_int64(self):
149 """ 150 Fetch a 64-bit int from the stream. 151 152 @return: a 64-bit unsigned integer. 153 @rtype: long 154 """ 155 return struct.unpack('>Q', self.get_bytes(8))[0]
156
157 - def get_mpint(self):
158 """ 159 Fetch a long int (mpint) from the stream. 160 161 @return: an arbitrary-length integer. 162 @rtype: long 163 """ 164 return util.inflate_long(self.get_string())
165
166 - def get_string(self):
167 """ 168 Fetch a string from the stream. This could be a byte string and may 169 contain unprintable characters. (It's not unheard of for a string to 170 contain another byte-stream Message.) 171 172 @return: a string. 173 @rtype: string 174 """ 175 return self.get_bytes(self.get_int())
176
177 - def get_list(self):
178 """ 179 Fetch a list of strings from the stream. These are trivially encoded 180 as comma-separated values in a string. 181 182 @return: a list of strings. 183 @rtype: list of strings 184 """ 185 return self.get_string().split(',')
186
187 - def add_bytes(self, b):
188 """ 189 Write bytes to the stream, without any formatting. 190 191 @param b: bytes to add 192 @type b: str 193 """ 194 self.packet.write(b) 195 return self
196
197 - def add_byte(self, b):
198 """ 199 Write a single byte to the stream, without any formatting. 200 201 @param b: byte to add 202 @type b: str 203 """ 204 self.packet.write(b) 205 return self
206
207 - def add_boolean(self, b):
208 """ 209 Add a boolean value to the stream. 210 211 @param b: boolean value to add 212 @type b: bool 213 """ 214 if b: 215 self.add_byte('\x01') 216 else: 217 self.add_byte('\x00') 218 return self
219
220 - def add_int(self, n):
221 """ 222 Add an integer to the stream. 223 224 @param n: integer to add 225 @type n: int 226 """ 227 self.packet.write(struct.pack('>I', n)) 228 return self
229
230 - def add_int64(self, n):
231 """ 232 Add a 64-bit int to the stream. 233 234 @param n: long int to add 235 @type n: long 236 """ 237 self.packet.write(struct.pack('>Q', n)) 238 return self
239
240 - def add_mpint(self, z):
241 """ 242 Add a long int to the stream, encoded as an infinite-precision 243 integer. This method only works on positive numbers. 244 245 @param z: long int to add 246 @type z: long 247 """ 248 self.add_string(util.deflate_long(z)) 249 return self
250
251 - def add_string(self, s):
252 """ 253 Add a string to the stream. 254 255 @param s: string to add 256 @type s: str 257 """ 258 self.add_int(len(s)) 259 self.packet.write(s) 260 return self
261
262 - def add_list(self, l):
263 """ 264 Add a list of strings to the stream. They are encoded identically to 265 a single string of values separated by commas. (Yes, really, that's 266 how SSH2 does it.) 267 268 @param l: list of strings to add 269 @type l: list(str) 270 """ 271 self.add_string(','.join(l)) 272 return self
273
274 - def _add(self, i):
275 if type(i) is str: 276 return self.add_string(i) 277 elif type(i) is int: 278 return self.add_int(i) 279 elif type(i) is long: 280 if i > 0xffffffffL: 281 return self.add_mpint(i) 282 else: 283 return self.add_int(i) 284 elif type(i) is bool: 285 return self.add_boolean(i) 286 elif type(i) is list: 287 return self.add_list(i) 288 else: 289 raise Exception('Unknown type')
290
291 - def add(self, *seq):
292 """ 293 Add a sequence of items to the stream. The values are encoded based 294 on their type: str, int, bool, list, or long. 295 296 @param seq: the sequence of items 297 @type seq: sequence 298 299 @bug: longs are encoded non-deterministically. Don't use this method. 300 """ 301 for item in seq: 302 self._add(item)
303