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
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
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)
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
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
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
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)
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
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
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
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)])
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)])
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)
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
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
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
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
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
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
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))
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
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
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