Esempio n. 1
0
    def deserialize(datagram, source):
        """
        De-serialize a stream of byte to a message.

        :param datagram: the incoming udp message
        :param source: the source address and port (ip, port)
        :return: the message
        :rtype: Message
        """
        try:
            fmt = "!BBH"
            pos = struct.calcsize(fmt)
            s = struct.Struct(fmt)
            values = s.unpack_from(datagram)
            first = values[0]
            code = values[1]
            mid = values[2]
            version = (first & 0xC0) >> 6
            message_type = (first & 0x30) >> 4
            token_length = (first & 0x0F)
            if Serializer.is_response(code):
                message = Response()
                message.code = code
            elif Serializer.is_request(code):
                message = Request()
                message.code = code
            else:
                message = Message()
            message.source = source
            message.destination = None
            message.version = version
            message.type = message_type
            message.mid = mid
            message.token_length = token_length
            #print (" first   ",first)
            #print (" version ", version)
            #print (" type    ", message_type)
            #print (" mid     ", mid)
            #print (" pos     ", pos)
            #print (" token_length ", token_length)
            if token_length > 0:
                fmt = "%ss" % token_length
                s = struct.Struct(fmt)
                token_value = s.unpack_from(datagram[pos:])[0]
                message.token = token_value
                print(" token   ", message.token.hex())
            else:
                message.token = None

            pos += token_length

            current_option = 0
            values = datagram[pos:]
            length_packet = len(values)
            pos = 0
            while pos < length_packet:
                next_byte = struct.unpack("B", values[pos].to_bytes(1,
                                                                    "big"))[0]
                pos += 1
                if next_byte != int(defines.PAYLOAD_MARKER):
                    # the first 4 bits of the byte represent the option delta
                    # delta = self._reader.read(4).uint
                    num, option_length, pos = Serializer.read_option_value_len_from_byte(
                        next_byte, pos, values)
                    current_option += num
                    # read option
                    try:
                        option_item = defines.OptionRegistry.LIST[
                            current_option]
                    except KeyError:
                        (opt_critical, _,
                         _) = defines.OptionRegistry.get_option_flags(
                             current_option)
                        if opt_critical:
                            print("Critical option unknown", current_option)
                            raise AttributeError("Critical option %s unknown" %
                                                 current_option)
                        else:
                            # If the non-critical option is unknown
                            # (vendor-specific, proprietary) - just skip it
                            #log.err("unrecognized option %d" % current_option)
                            print("unrecognized option %d", current_option)
                            pass
                    else:
                        if option_length == 0:
                            value = None
                        elif option_item.value_type == defines.INTEGER:
                            tmp = values[pos:pos + option_length]
                            value = 0
                            for b in tmp:
                                value = (value << 8) | struct.unpack(
                                    "B", b.to_bytes(1, "big"))[0]
                        elif option_item.value_type == defines.OPAQUE:
                            tmp = values[pos:pos + option_length]
                            value = tmp
                        else:
                            value = values[pos:pos + option_length]

                        option = Option()
                        option.number = current_option
                        option.value = Serializer.convert_to_raw(
                            current_option, value, option_length)

                        message.add_option(option)
                        if option.number == defines.OptionRegistry.CONTENT_TYPE.number:
                            message.payload_type = option.value
                    finally:
                        pos += option_length
                else:

                    if length_packet <= pos:
                        # log.err("Payload Marker with no payload")
                        print("Payload Marker with no payload")
                        raise AttributeError("Packet length %s, pos %s" %
                                             (length_packet, pos))
                    payload = values[pos:]
                    try:
                        message.payload = payload
                    except AttributeError:
                        message.payload = payload
                    pos += len(payload)

            return message
        except AttributeError as err:
            print("deserialize: attribute error", err)
            traceback.print_exc()
            #return defines.Codes.BAD_REQUEST.number
            ######traceback
        except struct.error:
            print("deserialize: struct error")
            return defines.Codes.BAD_REQUEST.number