Esempio n. 1
0
    def prepare_notification_deletion(self, t):
        """
        Create the notification message for deleted resource.

        :type t: (resource, request, old_response)
        :param t: the arguments of the notification message
        :return: the notification message
        """
        resource, request, old_response = t
        response = Response()
        response.destination = old_response.destination
        response.token = old_response.token
        response.code = defines.responses['NOT_FOUND']
        response.payload = None
        # Blockwise
        response, resource = self._parent.blockwise_response(request, response, resource)
        host, port = request.source
        key = hash(str(host) + str(port) + str(request.token))
        if key in self._parent.blockwise:
            del self._parent.blockwise[key]
        # Reliability
        request.acknowledged = True
        response = self._parent.message_layer.reliability_response(request, response)
        # Matcher
        response = self._parent.message_layer.matcher_response(response)
        return resource, request, response
Esempio n. 2
0
 def map(self, request):
     path = request.uri_path
     if request.uri_path == defines.DISCOVERY_URL:
         response = Response()
         response.destination = request.source
         response = self._resource_layer.discover(request, response)
         self.result_forward(response, request)
     server = self.root.find_complete(path)
     if server is not None:
         new_request = Request()
         segments = server.find_path().split("/")
         path = segments[2:]
         path = "/".join(path)
         segments = segments[1].split(":")
         host = segments[0]
         port = int(segments[1])
         # new_request.destination = (host, port)
         new_request.source = request.source
         new_request.type = request.type
         new_request._mid = (self._currentMID + 1) % (1 << 16)
         new_request.code = request.code
         new_request.proxy_uri = "coap://" + str(host) + ":" + str(port) + "/" + path
         new_request.payload = request.payload
         for option in request.options:
             if option.name == defines.inv_options["Uri-Path"]:
                 continue
             if option.name == defines.inv_options["Uri-Query"]:
                 continue
             if option.name == defines.inv_options["Uri-Host"]:
                 continue
             new_request.add_option(option)
         return new_request
     return None
Esempio n. 3
0
    def handle_get(self, request):
        """
        Handles a GET request.

        :param request: the request
        :return: the response
        """
        path = request.uri_path
        response = Response()
        response.destination = request.source
        if path == defines.DISCOVERY_URL:
            response = self._parent.discover(request, response)
        else:
            path = path.strip("/")
            node = self._parent.root.find_complete(path)
            if node is not None:
                resource = node.value
            else:
                resource = None
            if resource is None:
                # Not Found
                response = self._parent.send_error(request, response, 'NOT_FOUND')
            else:
                response = self._parent.get_resource(request, response, resource)
        return response
    def error(self, mid, host, port):
        """
        Handler of errors. Send an error message to the client.

        :param mid: the mid of the response that generates the error.
        :param host: the host of the server.
        :param port: the port of the server.
        """
        key = hash(str(host) + str(port) + str(mid))
        request = self._forward_mid.get(key)
        if request is not None:
            response = Response()
            host, port = request.source
            response.destination = request.source
            response.token = request.token
            response._mid = self._currentMID
            response.type = defines.inv_types["NON"]
            response.code = defines.responses["GATEWAY_TIMEOUT"]
            key = hash(str(host) + str(port) + str(response.token))
            del self._forward[key]
            key = hash(str(host) + str(port) + str(mid))
            try:
                del self._forward_mid[key]
            except KeyError:
                # log.err("MID has not been deleted")
                pass
            self.send(response, host, port)
Esempio n. 5
0
    def handle_delete(self, request):
        """
        Handles a DELETE request.

        :param request: the request
        :return: the response
        """
        path = request.uri_path
        path = path.strip("/")
        node = self._parent.root.find_complete(path)
        if node is not None:
            resource = node.value
        else:
            resource = None
        response = Response()
        response.destination = request.source
        if resource is None:
            # Create request
            response = self._parent.send_error(request, response, 'NOT_FOUND')
            log.msg("Resource Not Found")
            return response
        else:
            # Delete
            response = self._parent.delete_resource(request, response, node)
            return response
Esempio n. 6
0
 def handle_post(self, request):
     """
     Handles a POST request.
     :param request: the request
     :return: the response
     """
     path = str("/" + request.uri_path)
     response = Response()
     response.destination = request.source
     # Create request
     response = self._parent.resource_layer.create_resource(path, request, response)
     return response
Esempio n. 7
0
    def prepare_notification(self, t):
        """
        Create the notification message.

        :type t: (resource, request, old_response)
        :param t: the arguments of the notification message
        :return: the notification message
        """
        resource, request, old_response = t
        assert(isinstance(resource, Resource))
        response = Response()
        response.destination = old_response.destination
        response.token = old_response.token

        option = Option()
        option.number = defines.inv_options['Observe']
        option.value = resource.observe_count
        response.add_option(option)
        method = getattr(resource, 'render_GET', None)
        if hasattr(method, '__call__'):
            # Render_GET
            response.code = defines.responses['CONTENT']
            resource = method(request)
            response.payload = resource.payload
            # Blockwise
            response, resource = self._parent.blockwise_response(request, response, resource)
            host, port = request.source
            key = hash(str(host) + str(port) + str(request.token))
            if key in self._parent.blockwise:
                del self._parent.blockwise[key]
            # Reliability
            request.acknowledged = True
            response = self._parent.message_layer.reliability_response(request, response)
            # Matcher
            response = self._parent.message_layer.matcher_response(response)
            return resource, request, response
        else:
            response.code = defines.responses['METHOD_NOT_ALLOWED']
            # Blockwise
            response, resource = self._parent.blockwise_response(request, response, resource)
            host, port = request.source
            key = hash(str(host) + str(port) + str(request.token))
            if key in self._parent.blockwise:
                del self._parent.blockwise[key]
            # Reliability
            request.acknowledged = True
            response = self._parent.message_layer.reliability_response(request, response)
            # Matcher
            response = self._parent.message_layer.matcher_response(response)
            return resource, request, response
Esempio n. 8
0
    def datagramReceived(self, data, addr):
        """
        Handler for received UDP datagram.

        :param data: the UDP datagram
        :param host: source host
        :param port: source port
        """
        try:
            host, port = addr
        except ValueError:
            host, port, tmp1, tmp2 = addr
        log.msg("Datagram received from " + str(host) + ":" + str(port))
        serializer = Serializer()
        message = serializer.deserialize(data, host, port)
        print "Message received from " + host + ":" + str(port)
        print "----------------------------------------"
        print message
        print "----------------------------------------"
        if isinstance(message, Request):
            log.msg("Received request")
            ret = self.request_layer.handle_request(message)
            if isinstance(ret, Request):
                response = self.request_layer.process(ret)
            else:
                response = ret
            self.schedule_retrasmission(message, response, None)
            log.msg("Send Response")
            self.send(response, host, port)
        elif isinstance(message, Response):
            log.err("Received response")
            rst = Message.new_rst(message)
            rst = self.message_layer.matcher_response(rst)
            log.msg("Send RST")
            self.send(rst, host, port)
        elif isinstance(message, tuple):
            message, error = message
            response = Response()
            response.destination = (host, port)
            response.code = defines.responses[error]
            response = self.reliability_response(message, response)
            response = self.message_layer.matcher_response(response)
            log.msg("Send Error")
            self.send(response, host, port)
        elif message is not None:
            # ACK or RST
            log.msg("Received ACK or RST")
            self.message_layer.handle_message(message)
Esempio n. 9
0
    def finish_request(self, args):
        """
        Handler for received UDP datagram.

        :param args: (data, (client_ip, client_port)
        """
        data, client_address = args
        host = client_address[0]
        port = client_address[1]

        # logging.log(logging.INFO, "Datagram received from " + str(host) + ":" + str(port))
        serializer = Serializer()
        message = serializer.deserialize(data, host, port)
        # print "Message received from " + host + ":" + str(port)
        # print "----------------------------------------"
        # print message
        # print "----------------------------------------"
        if isinstance(message, Request):
            # log.msg("Received request")
            ret = self.request_layer.handle_request(message)
            if isinstance(ret, Request):
                response = self.request_layer.process(ret)
            else:
                response = ret
            self.schedule_retrasmission(message, response, None)
            # log.msg("Send Response")
            return response, host, port
        elif isinstance(message, Response):
            # log.err("Received response")
            rst = Message.new_rst(message)
            rst = self.message_layer.matcher_response(rst)
            # log.msg("Send RST")
            return rst, host, port
        elif isinstance(message, tuple):
            message, error = message
            response = Response()
            response.destination = (host, port)
            response.code = defines.responses[error]
            response = self.message_layer.reliability_response(message, response)
            response = self.message_layer.matcher_response(response)
            # log.msg("Send Error")
            return response, host, port
        elif message is not None:
            # ACK or RST
            # log.msg("Received ACK or RST")
            self.message_layer.handle_message(message)
            return None
Esempio n. 10
0
    def handle_put(self, request):
        """
        Handles a PUT request

        :param request: the request
        :return: the response
        """
        response = Response()
        response.destination = request.source
        path = request.uri_path
        path = path.strip("/")
        node = self._parent.root.find_complete(path)
        if node is None:
            response = self._parent.send_error(request, response, 'NOT_FOUND')
            return response

        # Update request
        response = self._parent.update_resource(request, response, node)
        return response
Esempio n. 11
0
    def handle_put(self, request):
        """
        Handles a PUT request
        :param request: the request
        :return: the response
        """
        response = Response()
        response.destination = request.source
        path = str("/" + request.uri_path)
        try:
            resource = self._parent.root[path]
        except KeyError:
            resource = None
        if resource is None:
            response = self._parent.send_error(request, response, 'NOT_FOUND')
            return response

        # Update request
        response = self._parent.resource_layer.update_resource(request, response, resource)
        return response
Esempio n. 12
0
    def test_td_coap_obs_03(self):
        print("TD_COAP_OBS_03")
        path = "/obs"
        req = Request()

        req.code = defines.Codes.GET.number
        req.uri_path = path
        req.type = defines.Types["CON"]
        req._mid = self.current_mid
        req.destination = self.server_address
        req.observe = 0

        expected = Response()
        expected.type = defines.Types["ACK"]
        expected._mid = self.current_mid
        expected.code = defines.Codes.CONTENT.number
        expected.token = None
        expected.payload = "Observable Resource"
        expected.observe = 1

        self.current_mid += 1

        expected2 = Response()
        expected2.type = defines.Types["CON"]
        expected2._mid = self.server_mid
        expected2.code = defines.Codes.CONTENT.number
        expected2.token = None
        expected2.payload = "Observable Resource"
        expected2.observe = 1

        rst = Response()
        rst.type = defines.Types["RST"]
        rst._mid = self.server_mid
        rst.code = defines.Codes.EMPTY.number
        rst.destination = self.server_address
        rst.token = None
        rst.payload = None

        self.current_mid += 1
        self.server_mid += 1
        self._test_plugtest([(req, expected), (None, expected2), (rst, None)])
Esempio n. 13
0
    def test_td_coap_obs_03(self):
        print "TD_COAP_OBS_03"
        path = "/obs"
        req = Request()

        req.code = defines.inv_codes['GET']
        req.uri_path = path
        req.type = defines.inv_types["CON"]
        req._mid = self.current_mid
        req.destination = self.server_address
        req.observe = 0

        expected = Response()
        expected.type = defines.inv_types["ACK"]
        expected._mid = self.current_mid
        expected.code = defines.responses["CONTENT"]
        expected.token = None
        expected.payload = "Observable Resource"
        expected.observe = 1

        self.current_mid += 1

        expected2 = Response()
        expected2.type = defines.inv_types["CON"]
        expected2._mid = self.server_mid
        expected2.code = defines.responses["CONTENT"]
        expected2.token = None
        expected2.payload = "Observable Resource"
        expected2.observe = 2

        rst = Response()
        rst.type = defines.inv_types["RST"]
        rst._mid = self.server_mid
        rst.code = defines.inv_codes["EMPTY"]
        rst.destination = self.server_address
        rst.token = None
        rst.payload = None

        self.current_mid += 1
        self.server_mid += 1
        self._test_plugtest([(req, expected), (None, expected2), (rst, None)])
Esempio n. 14
0
    def finish_request(self, request, client_address):
       
        
        host = client_address[0]
        port = client_address[1]
        data = request[0]
        self.socket = request[1]
 
        # log.msg("Datagram received from " + str(host) + ":" + str(port))
        serializer = Serializer()
        message = serializer.deserialize(data, host, port)
        # print "Message received from " + host + ":" + str(port)
        # print "----------------------------------------"
        # print message
        # print "----------------------------------------"
        if isinstance(message, Request):
            # log.msg("Received request")
            ret = self.request_layer.handle_request(message)
            if isinstance(ret, Request):
                self.forward_request(ret)
        elif isinstance(message, Response):
            # log.err("Received response")
            rst = Message.new_rst(message)
            rst = self.message_layer.matcher_response(rst)
            # log.msg("Send RST")
            self.send(rst, host, port)
        elif isinstance(message, tuple):
            message, error = message
            response = Response()
            response.destination = (host, port)
            response.code = defines.responses[error]
            response = self.message_layer.reliability_response(message, response)
            response = self.message_layer.matcher_response(response)
            # log.msg("Send Error")
            self.send(response, host, port)
        elif message is not None:
            # ACK or RST
            # log.msg("Received ACK or RST")
            self.message_layer.handle_message(message)
Esempio n. 15
0
 def handle_get(self, request):
     """
     Handles a GET request.
     :param request: the request
     :return: the response
     """
     path = str("/" + request.uri_path)
     response = Response()
     response.destination = request.source
     if path == defines.DISCOVERY_URL:
         response = self._parent.resource_layer.discover(request, response)
     else:
         try:
             resource = self._parent.root[path]
         except KeyError:
             resource = None
         if resource is None:
             # Not Found
             response = self._parent.send_error(request, response, 'NOT_FOUND')
         else:
             response = self._parent.resource_layer.get_resource(request, response, resource)
     return response
Esempio n. 16
0
    def handle_delete(self, request):
        """
        Handles a DELETE request.
        :param request: the request
        :return: the response
        """
        path = str("/" + request.uri_path)
        try:
            resource = self._parent.root[path]
        except KeyError:
            resource = None

        response = Response()
        response.destination = request.source
        if resource is None:
            # Create request
            response = self._parent.send_error(request, response, 'NOT_FOUND')
            return response
        else:
            # Delete
            response = self._parent.resource_layer.delete_resource(request, response, path)
            return response
Esempio n. 17
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
            if token_length > 0:
                fmt = "%ss" % token_length
                s = struct.Struct(fmt)
                token_value = s.unpack_from(datagram[pos:])[0]
                message.token = token_value.decode("utf-8")
            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:
                            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)
                            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")
                        raise AttributeError("Packet length %s, pos %s" % (length_packet, pos))
                    message.payload = ""
                    payload = values[pos:]
                    try:
                        if message.payload_type == defines.Content_types["application/octet-stream"]:
                            message.payload = payload
                        else:
                            message.payload = payload.decode("utf-8")
                    except AttributeError:
                        message.payload = payload.decode("utf-8")
                    pos += len(payload)

            return message
        except AttributeError:
            return defines.Codes.BAD_REQUEST.number
        except struct.error:
            return defines.Codes.BAD_REQUEST.number
Esempio n. 18
0
    def deserialize(datagram, source):
        """
        De-serialize a stream of byte to a message.

        :type datagram: String
        :param datagram:
        :param source:
        """
        try:
            fmt = "!BBH"
            pos = 4
            length = len(datagram)
            while pos < length:
                fmt += "c"
                pos += 1
            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
            pos = 3
            if token_length > 0:
                message.token = "".join(values[pos: pos + token_length])
            else:
                message.token = None

            pos += token_length
            current_option = 0
            length_packet = len(values)
            while pos < length_packet:
                next_byte = struct.unpack("B", values[pos])[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
                    delta = (next_byte & 0xF0) >> 4
                    # the second 4 bits represent the option length
                    # length = self._reader.read(4).uint
                    length = (next_byte & 0x0F)
                    num, pos = Serializer.read_option_value_from_nibble(delta, pos, values)
                    option_length, pos = Serializer.read_option_value_from_nibble(length, pos, values)
                    current_option += num
                    # read option
                    try:
                        option_item = defines.OptionRegistry.LIST[current_option]
                    except KeyError:
                        # log.err("unrecognized option")
                        raise AttributeError
                    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)[0]
                    elif option_item.value_type == defines.OPAQUE:
                        tmp = values[pos: pos + option_length]
                        value = bytearray(tmp)
                    else:
                        tmp = values[pos: pos + option_length]
                        value = ""
                        for b in tmp:
                            value += str(b)

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

                    message.add_option(option)
                else:

                    if length_packet <= pos:
                        # log.err("Payload Marker with no payload")
                        raise AttributeError
                    message.payload = ""
                    payload = values[pos:]
                    for b in payload:
                        message.payload += str(b)
                        pos += 1
            return message
        except AttributeError:
            return defines.Codes.BAD_REQUEST.number
        except struct.error:
            return defines.Codes.BAD_REQUEST.number
Esempio n. 19
0
    def forward_request(self, request):
        """
        Forward an incoming request to the specified server.

        :param request: the request to be forwarded
        :return: None if success, send an error otherwise
        """
        uri = request.proxy_uri
        response = Response()
        response.destination = request.source
        if uri is None:
            return self.send_error(request, response, "BAD_REQUEST")
        host, port, path = self.parse_path(uri)
        server = (str(host), int(port))
        token = self.generate_token()
        key = hash(str(host) + str(port) + str(token))
        to_store = copy.deepcopy(request)
        self._forward[key] = to_store
        # print request
        to_delete = []
        for option in request.options:
            if option.name == "Proxy-Uri" or not option.safe:
                to_delete.append(option)

        for option in to_delete:
            request.del_option(option)

        client = HelperClientSynchronous()
        self._currentMID += 1
        client.starting_mid = self._currentMID % (1 << 16)
        method = defines.codes[request.code]
        if method == 'GET':
            function = client.get
            req = copy.deepcopy(request)
            req.destination = server
            req.uri_path = path
            req.token = str(token)

        elif method == 'POST':
            function = client.post
            req = copy.deepcopy(request)
            req.destination = server
            req.uri_path = path
            req.token = str(token)

        elif method == 'PUT':
            function = client.put
            req = copy.deepcopy(request)
            req.destination = server
            req.uri_path = path
            req.token = str(token)

        elif method == 'DELETE':
            function = client.delete
            req = copy.deepcopy(request)
            req.destination = server
            req.uri_path = path
            req.token = str(token)

        else:
            return self.send_error(to_store, response, "BAD_REQUEST")
        req.source = None
        args = (req,)

        key = hash(str(host) + str(port) + str((client.starting_mid + 1) % (1 << 16)))
        self._forward_mid[key] = req
        # Render_GET
        with ThreadPoolExecutor(max_workers=100) as executor:
            self.timer[request.mid] = executor.submit(self.send_delayed_ack, request)
        # with ThreadPoolExecutor(max_workers=100) as executor:
        #     future = executor.submit(client.start, [(function, args, {})])
        #     future.add_done_callback(self.result_forward)
        # print req
        operations = [(function, args, {})]
        function, args, kwargs = operations[0]
        response = function(*args, **kwargs)
        self.result_forward(response=response)
        return None
Esempio n. 20
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 = 4
            length = len(datagram)
            while pos < length:
                fmt += "c"
                pos += 1
            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
            pos = 3
            if token_length > 0:
                message.token = "".join(values[pos:pos + token_length])
            else:
                message.token = None

            pos += token_length
            current_option = 0
            length_packet = len(values)
            while pos < length_packet:
                next_byte = struct.unpack("B", values[pos])[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
                    delta = (next_byte & 0xF0) >> 4
                    # the second 4 bits represent the option length
                    # length = self._reader.read(4).uint
                    length = (next_byte & 0x0F)
                    num, pos = Serializer.read_option_value_from_nibble(
                        delta, pos, values)
                    option_length, pos = Serializer.read_option_value_from_nibble(
                        length, pos, values)
                    current_option += num
                    # read option
                    try:
                        option_item = defines.OptionRegistry.LIST[
                            current_option]
                    except KeyError:
                        # log.err("unrecognized option")
                        raise AttributeError
                    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)[0]
                    elif option_item.value_type == defines.OPAQUE:
                        tmp = values[pos:pos + option_length]
                        value = bytearray(tmp)
                    else:
                        tmp = values[pos:pos + option_length]
                        value = ""
                        for b in tmp:
                            value += str(b)

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

                    message.add_option(option)
                else:

                    if length_packet <= pos:
                        # log.err("Payload Marker with no payload")
                        raise AttributeError
                    message.payload = ""
                    payload = values[pos:]
                    for b in payload:
                        message.payload += str(b)
                        pos += 1
            return message
        except AttributeError:
            return defines.Codes.BAD_REQUEST.number
        except struct.error:
            return defines.Codes.BAD_REQUEST.number
Esempio n. 21
0
    def deserialize(self, raw, host, port):
        """
        De-serialize a stream of byte to a message.

        :param raw: received bytes
        :param host: source host
        :param port: source port
        :return: the message
        """
        self._reader = BitStream(bytes=raw, length=(len(raw) * 8))
        version = self._reader.read(defines.VERSION_BITS).uint
        message_type = self._reader.read(defines.TYPE_BITS).uint
        token_length = self._reader.read(defines.TOKEN_LENGTH_BITS).uint
        code = self._reader.read(defines.CODE_BITS).uint
        mid = self._reader.read(defines.MESSAGE_ID_BITS).uint
        if self.is_response(code):
            message = Response()
            message.code = code
        elif self.is_request(code):
            message = Request()
            message.code = code
        else:
            message = Message()
        message.source = (host, port)
        message.destination = None
        message.version = version
        message.type = message_type
        message._mid = mid

        if token_length > 0:
            message.token = self._reader.read(token_length * 8).bytes
        else:
            message.token = None

        current_option = 0
        try:
            while self._reader.pos < self._reader.len:
                next_byte = self._reader.peek(8).uint
                if next_byte != int(defines.PAYLOAD_MARKER):
                    # the first 4 bits of the byte represent the option delta
                    delta = self._reader.read(4).uint
                    # the second 4 bits represent the option length
                    length = self._reader.read(4).uint
                    current_option += self.read_option_value_from_nibble(delta)
                    option_length = self.read_option_value_from_nibble(length)

                    # read option
                    try:
                        option_name, option_type, option_repeatable, default = defines.options[current_option]
                    except KeyError:
                        log.err("unrecognized option")
                        return message, "BAD_OPTION"
                    if option_length == 0:
                        value = None
                    elif option_type == defines.INTEGER:
                        value = self._reader.read(option_length * 8).uint
                    else:
                        value = self._reader.read(option_length * 8).bytes

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

                    message.add_option(option)
                else:
                    self._reader.pos += 8  # skip payload marker
                    if self._reader.len <= self._reader.pos:
                        log.err("Payload Marker with no payload")
                        return message, "BAD_REQUEST"
                    to_end = self._reader.len - self._reader.pos
                    message.payload = self._reader.read(to_end).bytes
            return message
        except ReadError, e:
            log.err("Error parsing message: " + str(e))
Esempio n. 22
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
            if token_length > 0:
                fmt = "%ss" % token_length
                s = struct.Struct(fmt)
                token_value = s.unpack_from(datagram[pos:])[0]
                message.token = token_value
            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])[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:
                            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)
                            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)[0]
                        elif option_item.value_type == defines.OPAQUE:
                            tmp = values[pos: pos + option_length]
                            value = bytearray(tmp)
                        else:
                            tmp = values[pos: pos + option_length]
                            value = ""
                            for b in tmp:
                                value += str(b)

                        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")
                        raise AttributeError("Packet length %s, pos %s" % (length_packet, pos))
                    message.payload = ""
                    payload = values[pos:]
                    for b in payload:
                        message.payload += str(b)
                        pos += 1
            return message
        except AttributeError:
            return defines.Codes.BAD_REQUEST.number
        except struct.error:
            return defines.Codes.BAD_REQUEST.number
Esempio n. 23
0
    def deserialize(self, raw, host, port):
        """
        De-serialize a stream of byte to a message.

        :param raw: received bytes
        :param host: source host
        :param port: source port
        :return: the message
        """

        fmt = "!BBH"
        pos = 4
        length = len(raw)
        while pos < length:
            fmt += "c"
            pos += 1
        s = struct.Struct(fmt)
        self._reader = raw
        values = s.unpack_from(self._reader)
        first = values[0]
        code = values[1]
        mid = values[2]
        version = (first & 0xC0) >> 6
        message_type = (first & 0x30) >> 4
        token_length = (first & 0x0F)
        if self.is_response(code):
            message = Response()
            message.code = code
        elif self.is_request(code):
            message = Request()
            message.code = code
        else:
            message = Message()
        message.source = (host, port)
        message.destination = None
        message.version = version
        message.type = message_type
        message._mid = mid
        pos = 3
        if token_length > 0:
                message.token = "".join(values[pos: pos + token_length])
        else:
            message.token = None

        pos += token_length
        current_option = 0
        length_packet = len(values)
        while pos < length_packet:
            next_byte = struct.unpack("B", values[pos])[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
                delta = (next_byte & 0xF0) >> 4
                # the second 4 bits represent the option length
                # length = self._reader.read(4).uint
                length = (next_byte & 0x0F)
                num, pos = self.read_option_value_from_nibble(delta, pos, values)
                option_length, pos = self.read_option_value_from_nibble(length, pos, values)
                current_option += num
                # read option
                try:
                    option_name, option_type, option_repeatable, default = defines.options[current_option]
                except KeyError:
                    # log.err("unrecognized option")
                    return message, "BAD_OPTION"
                if option_length == 0:
                    value = None
                elif option_type == defines.INTEGER:
                    tmp = values[pos: pos + option_length]
                    value = 0
                    for b in tmp:
                        value = (value << 8) | struct.unpack("B", b)[0]
                else:
                    tmp = values[pos: pos + option_length]
                    value = ""
                    for b in tmp:
                        value += str(b)

                pos += option_length
                option = Option()
                option.number = current_option
                option.value = self.convert_to_raw(current_option, value, option_length)

                message.add_option(option)
            else:

                if length_packet <= pos:
                    # log.err("Payload Marker with no payload")
                    return message, "BAD_REQUEST"
                message.payload = ""
                payload = values[pos:]
                for b in payload:
                    message.payload += str(b)
                    pos += 1
        return message
Esempio n. 24
0
    def forward_request(self, request):
        """
        Forward an incoming request to the specified server.

        :param request: the request to be forwarded
        :return: None if success, send an error otherwise
        """
        # print "FORWARD REQUEST\n"
        uri = request.proxy_uri
        response = Response()
        response.destination = request.source
        token = self.generate_token()
        if uri is None:
            return self.send_error(request, response, "BAD_REQUEST")
        host, port, path = self.parse_path(uri)

        request.uri_path = path
        self._currentMID += 1
        method = defines.codes[request.code]
        if method == 'GET':
            function = self.client.protocol.get
            req = Request()
            req.destination = (str(host), int(port))
            req.mid = self._currentMID % (1 << 16)
            req.token = str(token)
            req.uri_path = path
            req.type = defines.inv_types["CON"]
            req.code = defines.inv_codes['GET']
            args = (req,)
            kwargs = {}
            callback = self.result_forward
            err_callback = self.error
        elif method == 'POST':
            function = self.client.protocol.post
            req = Request()
            req.destination = (str(host), int(port))
            req.mid = self._currentMID % (1 << 16)
            req.token = str(token)
            req.uri_path = path
            req.payload = request.payload
            req.type = defines.inv_types["CON"]
            req.code = defines.inv_codes['POST']
            args = (req,)
            kwargs = {}
            callback = self.result_forward
            err_callback = self.error
        elif method == 'PUT':
            function = self.client.protocol.put
            req = Request()
            req.destination = (str(host), int(port))
            req.mid = self._currentMID % (1 << 16)
            req.token = str(token)
            req.uri_path = path
            req.payload = request.payload
            req.type = defines.inv_types["CON"]
            req.code = defines.inv_codes['PUT']
            args = (req,)
            kwargs = {}
            callback = self.result_forward
            err_callback = self.error
        elif method == 'DELETE':
            function = self.client.protocol.delete
            req = Request()
            req.destination = (str(host), int(port))
            req.mid = self._currentMID % (1 << 16)
            req.token = str(token)
            req.uri_path = path
            req.type = defines.inv_types["CON"]
            req.code = defines.inv_codes['DELETE']
            args = (req,)
            kwargs = {}
            callback = self.result_forward
            err_callback = self.error
        else:
            return self.send_error(request, response, "BAD_REQUEST")
        for option in request.options:
            if option.safe:
                kwargs[option.name] = option.value
        self.send_ack([request])
        operations = [(function, args, kwargs, (callback, err_callback))]
        key = hash(str(host) + str(port) + str(token))
        self._forward[key] = request
        key = hash(str(host) + str(port) + str(self._currentMID % (1 << 16)))
        self._forward_mid[key] = request
        # print "************"
        # print str(host),  str(port), str(self._currentMID % (1 << 16))
        # print req
        # print "************"
        key = req.mid
        self.sent[key] = (req, time.time())
        # self.sent[str(self._currentMID % (1 << 16))] = (req, time.time())
        self.client.start(operations)
        # Render_GET
        # key_timer = hash(str(request.source[0]) + str(request.source[1]) + str(request.mid))
        # self.timer[key_timer] = reactor.callLater(defines.SEPARATE_TIMEOUT, self.send_ack, [request])
        return None