root/branch/UMPA/umpa/_packets.py @ 3632

Revision 3632, 6.6 kB (checked in by getxsick, 5 years ago)

Removed double functions.

Line 
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"""
23Packets management.
24
25Packet class is a protocol container.
26Use it to build a packet which contains several protocols.
27"""
28
29import struct
30import warnings
31
32import umpa.utils.bits
33from umpa.utils.exceptions import UMPAException, UMPAStrictException
34
35BYTE = 8
36
37class StrictWarning(Warning):
38    """
39    New category of warning.
40
41    It's being used for warning message with reference
42    to strict attribute of Packet's objects.
43    """
44
45    pass
46
47def _strict_warn(layer_a, layer_b):
48    """
49    Issue the warning with prepared message as a StrictWarning category.
50
51    @type layer_a: C{int}
52    @param layer_a: layer for first protocol.
53
54    @type layer_b: C{int}
55    @param layer_b: layer for second protocol.
56    """
57
58    msg = "bad protocols ordering. first layer %d, second %d." % (layer_a,
59                                                                    layer_b)
60    warnings.warn(msg, StrictWarning, stacklevel=3)
61
62class Packet(object):
63    """
64    This is a protocol container.
65
66    Use this to build a completely packets.
67    An instance of the class should contains protocols which you want to send.
68    """
69
70    def __init__(self, *protos, **options):
71        """
72        Create a new Packet().
73
74        @type protos: Optional C{Protocol}
75        @param protos: protocols which will be included into the object.
76
77        @type options: Optional C{bool}
78        @param options: 2 keys are proper:
79            - strict (default: True): if True object will keep protocols order.
80            It avoids to build odd packets with with unsaved layer order
81            - warn (default: True): if True and strict is True, object will
82            issue warnings. Otherwise warnings are ignored.
83        """
84       
85        # parsing options dictionary
86        available_options = { 'strict' : True, 'warn' : True }
87        for opt in available_options:
88            if opt in options:
89                setattr(self, opt, options[opt])
90                options.pop(opt)
91            else:
92                setattr(self, opt, available_options[opt])
93        if len(options) != 0:
94            raise UMPAException("Undefined options " + str(options.keys()))
95
96        self.protos = []
97        self._add_new_protocols(protos)
98        self.raw = None
99        self.bits = 0
100
101    def __str__(self):
102        """
103        Print in human-readable tree-style a content of the packet.
104
105        Call print statement for protocols.
106
107        @return: call __str__ method of super-class.
108        """
109
110        print "Packet contains %d protocols" % len(self.protos)
111        for proto in self.protos:
112            print proto
113        return super(Packet, self).__str__()
114
115    def include(self, *protos):
116        """
117        Add protocols into packet.
118
119        @type protos: C{Protocol}
120        @param protos: protocols which will be included into the packet.
121        """
122
123        self._add_new_protocols(protos)
124
125    def _add_new_protocols(self, protos):
126        """
127        Add protocols into packet.
128
129        Check the strict attribute and
130        raise UMPAStrictException or issues warnings if needed.
131
132        @param protos: protocols which will be included into the packet.
133        """
134
135        for p in protos:
136            if len(self.protos) > 0:
137                last_proto = self.protos[-1]
138                # FIXME: should we allow only the distance no less and
139                # no more than 1 between layers?
140                if p.layer - last_proto.layer != 1: 
141                    if self.strict:
142                        raise UMPAStrictException("bad protocols ordering."
143                            "first layer %d, second %d."
144                            % (last_proto.layer, p.layer))
145                    else:
146                        _strict_warn(last_proto.layer, p.layer)
147                last_proto.__dict__['payload'] = p
148            self.protos.append(p)
149
150    def _get_raw(self):
151        """
152        Return raw packet in the bit-mode (big-endian).
153
154        Call every protocols to get the raw bits of them,
155        collect the results and return the raw packet.
156
157        @return: Struct packed bits of every protocols in big-endian order.
158        """
159
160        self.raw = 0
161        self.bits = 0
162        proto_id = 0
163        for proto in reversed(self.protos):
164            # unfortunately we must pass list of protocols to every protocol
165            # because some fields handle with other protocols, so they need
166            # an access to them
167            raw_proto, bit_proto = proto._get_raw(tuple(self.protos),
168                                                                    self.bits)
169            self.raw |= raw_proto << self.bits
170            self.bits += bit_proto
171        # split into chunks
172        # we make it because we need string for socket object
173        # so after that we pack it by struct module.pack()
174        byte_chunks = umpa.utils.bits.split_number_into_chunks(self.raw)
175        return struct.pack('!' + 'B'*(self.bits/BYTE), *byte_chunks)
176
177    def _getwarn(self):
178        """
179        Return warn attribute.
180
181        Warn attribute set a behaviour of strict attribute.
182        If warn is True and strict is True, object will
183        issue warnings if needed. Otherwise warnings are ignored.
184
185        @returns: warn attribute.
186        """
187        return self._warn
188
189    def _setwarn(self, value):
190        """
191        Set warn attribute
192
193        Warn attribute set a behaviour of strict attribute.
194        If warn is True and strict is True, object will
195        issue warnings if needed. Otherwise warnings are ignored.
196
197        @type value: C{bool}
198        @param value: bool value.
199        """
200
201        self._warn = value
202        if self._warn:
203            warnings.simplefilter('always', StrictWarning)
204        else:
205            warnings.simplefilter('ignore', StrictWarning)
206
207    warn = property(_getwarn, _setwarn, doc="""
208    Control if issue warnings or ignore them
209    @type: C{bool}
210    """)
Note: See TracBrowser for help on using the browser.