| 1 | #!/usr/bin/env python |
|---|
| 2 | # -*- coding: utf-8 -*- |
|---|
| 3 | |
|---|
| 4 | # Copyright (C) 2008 Adriano Monteiro Marques. |
|---|
| 5 | # |
|---|
| 6 | # Author: Bartosz SKOWRON <getxsick at gmail dot com> |
|---|
| 7 | # |
|---|
| 8 | # This library is free software; you can redistribute it and/or modify |
|---|
| 9 | # it under the terms of the GNU Lesser General Public License as published |
|---|
| 10 | # by the Free Software Foundation; either version 2.1 of the License, or |
|---|
| 11 | # (at your option) any later version. |
|---|
| 12 | # |
|---|
| 13 | # This library is distributed in the hope that it will be useful, but |
|---|
| 14 | # WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
|---|
| 15 | # or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public |
|---|
| 16 | # License for more details. |
|---|
| 17 | # |
|---|
| 18 | # You should have received a copy of the GNU Lesser General Public License |
|---|
| 19 | # along with this library; if not, write to the Free Software Foundation, |
|---|
| 20 | # Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
|---|
| 21 | |
|---|
| 22 | import struct |
|---|
| 23 | |
|---|
| 24 | from umpa import utils |
|---|
| 25 | from umpa.protocols._consts import * |
|---|
| 26 | from umpa.utils.my_exceptions import * |
|---|
| 27 | |
|---|
| 28 | class Field(object): |
|---|
| 29 | """Superclass for fields. |
|---|
| 30 | To implement new fields, create subclass of this. |
|---|
| 31 | |
|---|
| 32 | IMPORTANT: You should overwrite this __doc__ to get hints in some frontends |
|---|
| 33 | like the one provided by Umit Project. |
|---|
| 34 | """ |
|---|
| 35 | bits = 0 |
|---|
| 36 | auto = False |
|---|
| 37 | def __init__(self, name, value=None, bits=None, auto=None): |
|---|
| 38 | self.name = name |
|---|
| 39 | if auto: |
|---|
| 40 | self.auto = auto |
|---|
| 41 | elif value: |
|---|
| 42 | self.auto = True # if there's default value, auto should be True |
|---|
| 43 | |
|---|
| 44 | if bits: |
|---|
| 45 | self.bits = bits |
|---|
| 46 | self._value = value |
|---|
| 47 | |
|---|
| 48 | def set(self, value): |
|---|
| 49 | if self._is_valid(value): |
|---|
| 50 | self._value = value |
|---|
| 51 | else: |
|---|
| 52 | raise UMPAAttributeException, value + ' not allowed' |
|---|
| 53 | |
|---|
| 54 | def get(self): |
|---|
| 55 | return self._value |
|---|
| 56 | |
|---|
| 57 | def clear(self): |
|---|
| 58 | self._value = None |
|---|
| 59 | |
|---|
| 60 | def set_doc(self, text): |
|---|
| 61 | self.__doc__ = text |
|---|
| 62 | |
|---|
| 63 | def _is_valid(self, val): |
|---|
| 64 | raise NotImplementedError, "this is abstract class" |
|---|
| 65 | |
|---|
| 66 | def _pre_fillout(self): |
|---|
| 67 | pass |
|---|
| 68 | |
|---|
| 69 | def _raw_value(self): |
|---|
| 70 | raise NotImplementedError, "this is abstract class" |
|---|
| 71 | |
|---|
| 72 | def _generate_value(self): |
|---|
| 73 | raise UMPAException, "value is not defined or _generate_value() \ |
|---|
| 74 | method is not implemented." |
|---|
| 75 | |
|---|
| 76 | def fillout(self): |
|---|
| 77 | self._pre_fillout() |
|---|
| 78 | |
|---|
| 79 | # we have to clear self._value if it was not defined |
|---|
| 80 | # because of later usage |
|---|
| 81 | if not self._value: |
|---|
| 82 | self._value = self._generate_value() |
|---|
| 83 | raw = self._raw_value() |
|---|
| 84 | self.clear() |
|---|
| 85 | else: |
|---|
| 86 | raw = self._raw_value() |
|---|
| 87 | |
|---|
| 88 | return raw |
|---|
| 89 | |
|---|
| 90 | class IntField(Field): |
|---|
| 91 | def _raw_value(self): |
|---|
| 92 | return self._value |
|---|
| 93 | |
|---|
| 94 | def _is_valid(self, val): |
|---|
| 95 | """Check if a value is not bigger than expected. |
|---|
| 96 | """ |
|---|
| 97 | |
|---|
| 98 | if 2**self.bits > val: |
|---|
| 99 | return True |
|---|
| 100 | else: |
|---|
| 101 | return False |
|---|
| 102 | |
|---|
| 103 | class AddrField(Field): |
|---|
| 104 | pass |
|---|
| 105 | |
|---|
| 106 | class IPAddrField(AddrField): |
|---|
| 107 | """Main class for IP-style adresses. |
|---|
| 108 | It handles with 2 types of data: |
|---|
| 109 | 1 - strings as "127.0.0.1" or "0:0:0:0:0:0:0:1" |
|---|
| 110 | 2 - tuples as (127,0,0,1) or (0,0,0,0,0,0,0,1) |
|---|
| 111 | """ |
|---|
| 112 | def set(self, value): |
|---|
| 113 | # convert list to tuple |
|---|
| 114 | if type(value) is list: |
|---|
| 115 | value = tuple(value) |
|---|
| 116 | # validation |
|---|
| 117 | if self._is_valid(value): |
|---|
| 118 | self._value = value |
|---|
| 119 | else: |
|---|
| 120 | raise UMPAAttributeException, value + ' not allowed' |
|---|
| 121 | |
|---|
| 122 | def _raw_value(self): |
|---|
| 123 | if type(self._value) is str: |
|---|
| 124 | pieces = self._value.split(self.separator) |
|---|
| 125 | else: |
|---|
| 126 | pieces = self._value |
|---|
| 127 | |
|---|
| 128 | raw = 0 |
|---|
| 129 | for b in pieces: |
|---|
| 130 | raw += int(b, self.base) |
|---|
| 131 | raw <<= self.piece_size |
|---|
| 132 | raw >>= self.piece_size |
|---|
| 133 | |
|---|
| 134 | return raw |
|---|
| 135 | |
|---|
| 136 | def _is_valid(self, val): |
|---|
| 137 | if type(val) is str: |
|---|
| 138 | pieces = val.split(self.separator) |
|---|
| 139 | elif type(val) is tuple: |
|---|
| 140 | pieces = val |
|---|
| 141 | else: |
|---|
| 142 | return False |
|---|
| 143 | |
|---|
| 144 | if len(pieces) != self.pieces_amount: |
|---|
| 145 | return False |
|---|
| 146 | |
|---|
| 147 | for i in pieces: |
|---|
| 148 | if int(i, self.base) > 2**self.piece_size or int(i, self.base) < 0: |
|---|
| 149 | return False |
|---|
| 150 | |
|---|
| 151 | return True |
|---|
| 152 | |
|---|
| 153 | class IPv4AddrField(IPAddrField): |
|---|
| 154 | """Address in IPv4 style. |
|---|
| 155 | """ |
|---|
| 156 | separator = "." |
|---|
| 157 | piece_size = 8 |
|---|
| 158 | pieces_amount = 4 |
|---|
| 159 | base = 10 |
|---|
| 160 | |
|---|
| 161 | class IPv6AddrField(IPAddrField): |
|---|
| 162 | """Address in IPv6 style. |
|---|
| 163 | """ |
|---|
| 164 | separator = ":" |
|---|
| 165 | piece_size = 16 |
|---|
| 166 | pieces_amount = 8 |
|---|
| 167 | base = 16 |
|---|
| 168 | |
|---|
| 169 | class PaddingField(IntField): |
|---|
| 170 | def _is_valid(self, val): |
|---|
| 171 | if isinstance(val, int): |
|---|
| 172 | return True |
|---|
| 173 | return False |
|---|
| 174 | |
|---|
| 175 | def fillout(self): |
|---|
| 176 | self._pre_fillout() |
|---|
| 177 | |
|---|
| 178 | if not self._value: |
|---|
| 179 | self.bits = self._generate_value() |
|---|
| 180 | else: |
|---|
| 181 | self.bits = self._value |
|---|
| 182 | return self._raw_value() |
|---|
| 183 | |
|---|
| 184 | def _raw_value(self): |
|---|
| 185 | return 0 |
|---|
| 186 | |
|---|
| 187 | class Flags(Field): |
|---|
| 188 | """Most of protocols have a special field with bit-flags. |
|---|
| 189 | For those fields we use this subclass of Field. |
|---|
| 190 | """ |
|---|
| 191 | |
|---|
| 192 | def __init__(self, name, names, **preset): |
|---|
| 193 | """Names has to be in correct order. |
|---|
| 194 | If you use **preset, check if keys are in names list as well |
|---|
| 195 | because of order issue. |
|---|
| 196 | """ |
|---|
| 197 | super(Flags, self).__init__(name, bits=len(names)) |
|---|
| 198 | |
|---|
| 199 | self._ordered_fields = names |
|---|
| 200 | # we overwrite an attribute self._value |
|---|
| 201 | # because we need a list instead of simple var here |
|---|
| 202 | self._value = {} |
|---|
| 203 | for flag in self._ordered_fields: |
|---|
| 204 | self._value[flag] = BitField(flag) |
|---|
| 205 | #self._value = dict.fromkeys(self._ordered_fields, False) |
|---|
| 206 | |
|---|
| 207 | # if **preset exists then we update values |
|---|
| 208 | for name in preset: |
|---|
| 209 | if preset[name] == True: |
|---|
| 210 | self.set(name) |
|---|
| 211 | else: |
|---|
| 212 | self.unset(name) |
|---|
| 213 | |
|---|
| 214 | def _is_valid(self, name): |
|---|
| 215 | return self._value.has_key(name) |
|---|
| 216 | |
|---|
| 217 | def _set_bit(self, names, value): |
|---|
| 218 | for flag_name in names: |
|---|
| 219 | if self._is_valid(flag_name): |
|---|
| 220 | self._value[flag_name].set(value) |
|---|
| 221 | else: |
|---|
| 222 | raise UMPAAttributeException, attr + ' not allowed' |
|---|
| 223 | |
|---|
| 224 | def set(self, *names): |
|---|
| 225 | self._set_bit(names, True) |
|---|
| 226 | |
|---|
| 227 | def unset(self, *names): |
|---|
| 228 | self._set_bit(names, False) |
|---|
| 229 | |
|---|
| 230 | def get(self, *names): |
|---|
| 231 | # we check if name of the field in the flag is correct |
|---|
| 232 | result = [ self._value[val].get() for val in names |
|---|
| 233 | if self._is_valid(val) ] |
|---|
| 234 | |
|---|
| 235 | # if no results above we return whole list of values |
|---|
| 236 | if len(result) < 1: |
|---|
| 237 | result = self._value |
|---|
| 238 | return result |
|---|
| 239 | |
|---|
| 240 | def _pre_fillout(self): |
|---|
| 241 | pass |
|---|
| 242 | |
|---|
| 243 | def fillout(self): |
|---|
| 244 | self._pre_fillout() |
|---|
| 245 | |
|---|
| 246 | raw = 0 |
|---|
| 247 | for bitname in self._ordered_fields: |
|---|
| 248 | raw += self._value[bitname].fillout() |
|---|
| 249 | raw <<= 1 |
|---|
| 250 | raw >>= 1 |
|---|
| 251 | return raw |
|---|
| 252 | |
|---|
| 253 | class BitField(Field): |
|---|
| 254 | bits = 1 |
|---|
| 255 | def __init__(self, name, value=None, auto=None): |
|---|
| 256 | super(BitField, self).__init__(name, value, BitField.bits, auto) |
|---|
| 257 | |
|---|
| 258 | # we store value as a _default_view, it's necessary by generic |
|---|
| 259 | # fillout, so for most of cases we don't need to make subclasses with |
|---|
| 260 | # distinct fillout() method |
|---|
| 261 | self._default_value = value |
|---|
| 262 | if self._default_value: |
|---|
| 263 | self.auto = True |
|---|
| 264 | |
|---|
| 265 | def _is_valid(self, val): |
|---|
| 266 | # always True because it's bool type |
|---|
| 267 | return True |
|---|
| 268 | |
|---|
| 269 | def get(self): |
|---|
| 270 | return bool(self._value) |
|---|
| 271 | |
|---|
| 272 | def fillout(self): |
|---|
| 273 | if self._value is None: |
|---|
| 274 | self._value = self._generate_value() |
|---|
| 275 | raw = self._raw_value() |
|---|
| 276 | self.clear() |
|---|
| 277 | else: |
|---|
| 278 | raw = self._raw_value() |
|---|
| 279 | |
|---|
| 280 | return raw |
|---|
| 281 | |
|---|
| 282 | def _generate_value(self): |
|---|
| 283 | """Generate value of bit. |
|---|
| 284 | |
|---|
| 285 | Be default it checks if self._default_value is defined, |
|---|
| 286 | if so it returns this value. |
|---|
| 287 | |
|---|
| 288 | If you need more complex action, |
|---|
| 289 | create subclass and overwrite this method. |
|---|
| 290 | """ |
|---|
| 291 | if self._default_value: |
|---|
| 292 | return bool(self._default_value) |
|---|
| 293 | else: |
|---|
| 294 | raise UMPAException, "value is not defined or _generate_value() \ |
|---|
| 295 | method is not implemented." |
|---|
| 296 | |
|---|
| 297 | def _raw_value(self): |
|---|
| 298 | if self._value: |
|---|
| 299 | return 1 |
|---|
| 300 | else: |
|---|
| 301 | return 0 |
|---|
| 302 | |
|---|
| 303 | class Protocol(object): |
|---|
| 304 | """Superclass for protocols. |
|---|
| 305 | To implement new protocol, make a subclass. |
|---|
| 306 | |
|---|
| 307 | IMPORTANT: You should overwrite this __doc__ to get hints in some frontends |
|---|
| 308 | like the one provided by Umit Project. |
|---|
| 309 | """ |
|---|
| 310 | _ordered_fields = () |
|---|
| 311 | layer = None |
|---|
| 312 | |
|---|
| 313 | def __init__(self, fields, **kw): |
|---|
| 314 | #self._fields = {} |
|---|
| 315 | super(Protocol, self).__setattr__('_fields', fields) |
|---|
| 316 | |
|---|
| 317 | def __setattr__(self, attr, val): |
|---|
| 318 | """Set value of the field.""" |
|---|
| 319 | |
|---|
| 320 | # we can do the same without _is_valid() with just try/except section |
|---|
| 321 | # but Francesco asked me about this method |
|---|
| 322 | if self._is_valid(attr): |
|---|
| 323 | self._get_field(attr).set(val) |
|---|
| 324 | else: |
|---|
| 325 | raise UMPAAttributeException, attr + ' not allowed' |
|---|
| 326 | |
|---|
| 327 | def __getattr__(self, attr): |
|---|
| 328 | """Return value of the field.""" |
|---|
| 329 | if self._is_valid(attr): |
|---|
| 330 | return self._get_field(attr).get() |
|---|
| 331 | else: |
|---|
| 332 | raise UMPAAttributeException, attr + ' not allowed' |
|---|
| 333 | |
|---|
| 334 | def get_fields(self): |
|---|
| 335 | """Generator for ordered fields.""" |
|---|
| 336 | for field in self._ordered_fields: |
|---|
| 337 | yield self._get_field(field) |
|---|
| 338 | |
|---|
| 339 | @staticmethod |
|---|
| 340 | def get_fields_keys(): |
|---|
| 341 | """Generator for ordered names (keys) of header's fields. |
|---|
| 342 | |
|---|
| 343 | I don't see any reason to use this method but |
|---|
| 344 | Francesco asked me to make this. |
|---|
| 345 | |
|---|
| 346 | NOTE: You should use get_fields() method instead. |
|---|
| 347 | """ |
|---|
| 348 | for field in Protocol._ordered_fields: |
|---|
| 349 | yield field |
|---|
| 350 | |
|---|
| 351 | def _get_field(self, keyname): |
|---|
| 352 | if self._is_valid(keyname): |
|---|
| 353 | return self._fields[keyname] |
|---|
| 354 | else: |
|---|
| 355 | raise UMPAAttributeException, keyname + ' not allowed' |
|---|
| 356 | |
|---|
| 357 | def set_fields(self, *args, **kwargs): |
|---|
| 358 | """Set fields of the protocol. |
|---|
| 359 | There are 2 ways to do that with using tuple or dict-style. |
|---|
| 360 | """ |
|---|
| 361 | # converting args list to the dict and update our kwargs |
|---|
| 362 | kwargs.update(utils.dict_from_sequence(args)) |
|---|
| 363 | |
|---|
| 364 | for key in kwargs: |
|---|
| 365 | if self._is_valid(key): |
|---|
| 366 | setattr(self, key, kwargs[key]) |
|---|
| 367 | self.fields[key].set(kwargs[key]) |
|---|
| 368 | |
|---|
| 369 | def set_flags(self, name, *args, **kw): |
|---|
| 370 | """Set flags with dict using. |
|---|
| 371 | |
|---|
| 372 | There are 2 ways to do that with using tuple or dict-style. |
|---|
| 373 | |
|---|
| 374 | There is no effect if the protocol doesn't have this field. |
|---|
| 375 | """ |
|---|
| 376 | |
|---|
| 377 | # converting args list to the dict and update our kwargs |
|---|
| 378 | kw.update(util.dict_from_sequence(args)) |
|---|
| 379 | |
|---|
| 380 | flag_field = self._get_field(name) |
|---|
| 381 | if isinstance(flag_field, Flags): |
|---|
| 382 | for flag_name in kw: |
|---|
| 383 | if kw[flag_name]: |
|---|
| 384 | flag_field.set(flag_name) |
|---|
| 385 | else: |
|---|
| 386 | flag_field.unset(flag_name) |
|---|
| 387 | else: |
|---|
| 388 | raise UMPAAttributeException, "No Flags instance for " + name |
|---|
| 389 | |
|---|
| 390 | def get_flags(self, name, *args): |
|---|
| 391 | flag_field = self._get_field(name) |
|---|
| 392 | if isinstance(flag_field, Flags): |
|---|
| 393 | return flag_field.get(*args) |
|---|
| 394 | else: |
|---|
| 395 | raise UMPAAttributeException, "No Flags instance for " + name |
|---|
| 396 | |
|---|
| 397 | def get_raw(self): |
|---|
| 398 | """Return raw bits of the protocol's object.""" |
|---|
| 399 | |
|---|
| 400 | # The deal: we join all value's fields into one big number |
|---|
| 401 | # (with taking care about amount of bits). |
|---|
| 402 | # then we devide the number on byte-chunks |
|---|
| 403 | # and pack it by struct.pack() function |
|---|
| 404 | bit, raw_value = self._raw() |
|---|
| 405 | |
|---|
| 406 | # protocol should return byte-compatible length |
|---|
| 407 | if bit%BYTE != 0: |
|---|
| 408 | raise UMPAException, 'odd number of bits in ' + self.__name__ |
|---|
| 409 | |
|---|
| 410 | # check how many bytes we need |
|---|
| 411 | bytes = bit/BYTE |
|---|
| 412 | # split the number on byte-chunks |
|---|
| 413 | l = [ (raw_value & (0xff << (BYTE*i))) >> BYTE*i |
|---|
| 414 | for i in reversed(xrange(bytes)) ] |
|---|
| 415 | # and pack it |
|---|
| 416 | header_pack = struct.pack('!' + 'B'*bytes, *l) |
|---|
| 417 | return header_pack |
|---|
| 418 | |
|---|
| 419 | def _is_valid(self, field): |
|---|
| 420 | """Overload it in subclasses.""" |
|---|
| 421 | raise NotImplementedError |
|---|
| 422 | |
|---|
| 423 | def get_offset(self, field): |
|---|
| 424 | """Return offset for the field. |
|---|
| 425 | |
|---|
| 426 | NOTE: the argument field CAN be key or instance. |
|---|
| 427 | """ |
|---|
| 428 | |
|---|
| 429 | # checking if argument is a key or instance |
|---|
| 430 | if isinstance(field, str): |
|---|
| 431 | field_list = self._ordered_fields |
|---|
| 432 | elif isinstance(field, Field): |
|---|
| 433 | field_list = [ f for f in self.get_fields() ] |
|---|
| 434 | else: |
|---|
| 435 | raise UMPAException, type(field) + ' unsupported' |
|---|
| 436 | |
|---|
| 437 | if field not in field_list: |
|---|
| 438 | raise UMPAAttributeException, field + ' not allowed' |
|---|
| 439 | |
|---|
| 440 | offset = 0 |
|---|
| 441 | for i, f in enumerate(field_list): |
|---|
| 442 | if field == f: |
|---|
| 443 | break |
|---|
| 444 | offset += self._get_field(self._ordered_fields[i]).bits |
|---|
| 445 | return offset |
|---|