コード例 #1
0
ファイル: transport.py プロジェクト: cyl-e/raiden
class UDPTransport(object):
    """ Node communication using the UDP protocol. """
    def __init__(self, host, port, protocol=None):
        self.protocol = protocol
        self.server = DatagramServer((host, port), handle=self.receive)
        self.server.start()
        self.host = self.server.server_host
        self.port = self.server.server_port

    def receive(self, data, host_port):  # pylint: disable=unused-argument
        self.protocol.receive(data)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.track_recv(self.protocol.raiden, host_port, data)

    def send(self, sender, host_port, bytes_):
        """ Send `bytes_` to `host_port`.

        Args:
            sender (address): The address of the running node.
            host_port (Tuple[(str, int)]): Tuple with the host name and port number.
            bytes_ (bytes): The bytes that are going to be sent throught the wire.
        """
        self.server.sendto(bytes_, host_port)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.network.track_send(sender, host_port, bytes_)

    def register(self, proto, host, port):  # pylint: disable=unused-argument
        assert isinstance(proto, RaidenProtocol)
        self.protocol = proto

    def stop(self):
        self.server.stop()
コード例 #2
0
ファイル: transport.py プロジェクト: raiden-network/raiden
class UDPTransport(object):
    """ Node communication using the UDP protocol. """

    def __init__(self, host, port, protocol=None):
        self.protocol = protocol
        self.server = DatagramServer((host, port), handle=self.receive)
        self.server.start()
        self.host = self.server.server_host
        self.port = self.server.server_port

    def receive(self, data, host_port):  # pylint: disable=unused-argument
        self.protocol.receive(data)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.track_recv(self.protocol.raiden, host_port, data)

    def send(self, sender, host_port, bytes_):
        """ Send `bytes_` to `host_port`.

        Args:
            sender (address): The address of the running node.
            host_port (Tuple[(str, int)]): Tuple with the host name and port number.
            bytes_ (bytes): The bytes that are going to be sent through the wire.
        """
        self.server.sendto(bytes_, host_port)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.network.track_send(sender, host_port, bytes_)

    def register(self, proto, host, port):  # pylint: disable=unused-argument
        assert isinstance(proto, RaidenProtocol)
        self.protocol = proto

    def stop(self):
        self.server.stop()
コード例 #3
0
ファイル: transport.py プロジェクト: maddee2145/raiden
class UDPTransport(object):
    """ Node communication using the UDP protocol. """
    def __init__(self,
                 host,
                 port,
                 socket=None,
                 protocol=None,
                 throttle_policy=DummyPolicy()):

        self.protocol = protocol
        if socket is not None:
            self.server = DatagramServer(socket, handle=self.receive)
        else:
            self.server = DatagramServer((host, port), handle=self.receive)
        self.host = self.server.server_host
        self.port = self.server.server_port
        self.throttle_policy = throttle_policy

    def receive(self, data, host_port):  # pylint: disable=unused-argument
        self.protocol.receive(data)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.track_recv(self.protocol.raiden, host_port, data)

    def send(self, sender, host_port, bytes_):
        """ Send `bytes_` to `host_port`.

        Args:
            sender (address): The address of the running node.
            host_port (Tuple[(str, int)]): Tuple with the host name and port number.
            bytes_ (bytes): The bytes that are going to be sent through the wire.
        """
        sleep_timeout = self.throttle_policy.consume(1)

        # Don't sleep if timeout is zero, otherwise a context-switch is done
        # and the message is delayed, increasing it's latency
        if sleep_timeout:
            gevent.sleep(sleep_timeout)

        if not hasattr(self.server, 'socket'):
            raise RuntimeError('trying to send a message on a closed server')

        self.server.sendto(bytes_, host_port)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.network.track_send(sender, host_port, bytes_)

    def stop(self):
        self.server.stop()

    def stop_accepting(self):
        self.server.stop_accepting()

    def start(self):
        assert not self.server.started
        # server.stop() clears the handle, since this may be a restart the
        # handle must always be set
        self.server.set_handle(self.receive)
        self.server.start()
コード例 #4
0
class UdpServer(TcpRpcServer):
    def __init__(self, port):
        self.port = port
        self.server = DatagramServer(('', self.port), handle=self.handle)
        self.protocol = PT_UDP

    def handle(self, data, address):
        self.server.sendto(data, address)
コード例 #5
0
ファイル: transport.py プロジェクト: ryepdx/raiden
class UDPTransport(object):
    def __init__(self, host, port, protocol=None):
        self.protocol = protocol
        self.server = DatagramServer(('', 0), handle=self.receive)
        self.server.start()
        self.host = self.server.server_host
        self.port = self.server.server_port

    def receive(self, data, host_port):
        self.protocol.receive(data)

    def send(self, sender, host_port, data):
        log.info('TRANSPORT SENDS')
        self.server.sendto(data, host_port)
        DummyTransport.network.track_send(sender, host_port, data)  # debuging

    def register(self, proto, host, port):
        assert isinstance(proto, RaidenProtocol)
        self.protocol = proto
コード例 #6
0
ファイル: transport.py プロジェクト: cubedro/raiden
class UDPTransport(object):

    def __init__(self, host, port, protocol=None):
        self.protocol = protocol
        self.server = DatagramServer(('', 0), handle=self.receive)
        self.server.start()
        self.host = self.server.server_host
        self.port = self.server.server_port

    def receive(self, data, host_port):
        self.protocol.receive(data)

    def send(self, sender, host_port, data):
        log.info('TRANSPORT SENDS')
        self.server.sendto(data, host_port)
        DummyTransport.network.track_send(sender, host_port, data)  # debuging

    def register(self, proto, host, port):
        assert isinstance(proto, RaidenProtocol)
        self.protocol = proto
コード例 #7
0
class UdpServerActor(Actor):
    def __init__(self, address="0.0.0.0", port=5011):
        Actor.__init__(self)
        self.address, self.port = address, port
        self.server = DatagramServer((self.address, self.port), self.socket_read) # creates a new server
        gevent.spawn(self.server.serve_forever)

    def socket_read(self, data, address):
        print "server actor received", data, address
        print "server makes echo: "
        self.socket_write(data, address)

    def socket_write(self, data, target=None):
        if target is None:
            print "target is empty!"
        else:
            try:
                self.server.sendto(data, target)
            except Exception as e:
                print "didn't write to socket..", e
                pass
コード例 #8
0
ファイル: transport.py プロジェクト: sbellem/raiden
class UDPTransport(object):

    def __init__(self, host, port, protocol=None):
        self.protocol = protocol
        self.server = DatagramServer(('', 0), handle=self.receive)
        self.server.start()
        self.host = self.server.server_host
        self.port = self.server.server_port

    def receive(self, data, host_port):
        self.protocol.receive(data)

    def send(self, sender, host_port, data):
        # print "TRANSPORT SENDS", datas.decode(data)
        try:
            self.server.sendto(data, host_port)
        except gevent.socket.error as e:
            raise e
        DummyTransport.network.track_send(sender, host_port, data)  # debuging

    def register(self, proto, host, port):
        assert isinstance(proto, RaidenProtocol)
        self.protocol = proto
コード例 #9
0
class DMServerCore(OperationRequest):
    def __init__(self, server_ip, server_port, client_ip, client_port):
        super(DMServerCore, self).__init__()

        self.lwm2m_dm_server_ip = server_ip
        self.lwm2m_dm_server_port = server_port
        self.local_client_ip_ = client_ip
        self.local_client_port_ = client_port
        self.sem = Semaphore()
        self.sem_counter = 0

        self.lwm2m_resources = LWM2MResourceTree()
        self.registration = Registration(self.lwm2m_resources)
        self.execution = Execution(self.lwm2m_resources)
        self.discover = Discovery(lwm2m_resources=self.lwm2m_resources)
        self.observation = ObservationNotificationEngine(self.lwm2m_resources)
        self.read = Read(self.lwm2m_resources)
        self.write = Write(self.lwm2m_resources)
        self.create_object_instance = Create(self.lwm2m_resources)
        self.write_attributes = WriteAttributes(self.lwm2m_resources)

    def create_server(self, ):
        """ Creates and starts a LWM2M DM Server using Gevent DatagramServer. The server
        listens at the ip and port specified below. A handler is used to entertain the
        requests coming at that port """

        self.dm_server = DatagramServer((self.lwm2m_dm_server_ip, \
                                         self.lwm2m_dm_server_port), self.handle_request)
        self.dm_server.start()

    def stop_server(self, ):
        """ Stops the LWM2M DM Server """

        self.dm_server.stop()

    def handle_request(self, message, remote):
        """ Handles the requests coming at the specified ip and port """

        rx_record = connection.ReceptionRecord(None, message, remote)
        msg = rx_record.message
        uri_query = msg.findOption(options.UriQuery)
        self.process(rx_record, remote, uri_query)

    def handle_lwm2m_put(self, msg, uri_query, remote, rx_record):
        """ It consists of Normal Update, Write Operation, Write Attribute Operation.
        Write Operation is used to update the resource(s) as per the request. Write
        Attributes operation is used to update the attributes of the object, object
        instance or resource. """

        method = None
        try:
            method = uri_query[0].value.split("=")[1]
        except:
            pass

        if method == "write":
            path = msg.findOption(URI_PATH_VALUE)
            content_type_number = msg.findOption(options.ContentType)
            if content_type_number is None:
                content_type = "text/plain"
            else:
                content_type = constants.media_types[content_type_number.value]
            self.write.write_resource(msg.payload, path, content_type)

            payload_forward = msg.payload

            msg = connection.Message(connection.Message.ACK,
                                     code=constants.CHANGED,
                                     payload="Resource Updated")
            self.dm_server.sendto(msg._pack(rx_record.transaction_id), remote)

            client_port = self.generate_client_port()
            self.write.forward_write_request(path, payload_forward, \
                                        content_type, remote, client_port)

        elif method == "write_attributes":
            path = msg.findOption(URI_PATH_VALUE)
            content_type_number = msg.findOption(options.ContentType)
            if content_type_number is None:
                content_type = "text/plain"
            else:
                content_type = constants.media_types[content_type_number.value]
            payload = loads(msg.payload)
            self.write_attributes.set_attributes(path, remote, payload)
            msg = connection.Message(connection.Message.ACK,
                                     code=constants.CHANGED,
                                     payload="Resource Attributes Updated")
            self.dm_server.sendto(msg._pack(rx_record.transaction_id), remote)

            client_port = self.generate_client_port()
            self.write_attributes.forward_request(path, remote, payload,
                                                  content_type, client_port)

        else:

            endpoint_location = msg.findOption(URI_PATH_VALUE)[0].value
            if msg.payload == "":
                self.logger.info("Updating the Registration Params")
                endpoint_object = self.lwm2m_resources.return_endpoint_object(
                    endpoint_location=endpoint_location)
                endpoint_object.listener_ip = uri_query[6].value.split("=")[1]
                endpoint_object.local_ip = uri_query[6].value.split("=")[1]

                msg = connection.Message(connection.Message.ACK,
                                         code=constants.CHANGED,
                                         payload="Resource Updated")
                self.dm_server.sendto(msg._pack(rx_record.transaction_id),
                                      remote)
            else:
                self.logger.info("Adding/Updating the Resources")
                payload = self.update_resource(
                    loads(msg.payload), endpoint_location=endpoint_location)

                msg = connection.Message(connection.Message.ACK,
                                         code=constants.CHANGED,
                                         payload="Resource Updated")
                self.dm_server.sendto(msg._pack(rx_record.transaction_id),
                                      remote)

                self.logger.info("Forwarding the Notification")
                request = lwm2m_api()
                client_port = self.generate_client_port()

                response = request.send_notification(self.general_observation.listener_ip, self.general_observation.listener_port, \
                                                     self.general_observation.token_id, payload, content_type="application/json", client_port=client_port)

    def update_resource(self,
                        res_payload,
                        endpoint_location=None,
                        endpoint_name=None):

        total_res_dict = {}
        total_object_info = {}

        payload = res_payload
        endpoint_object = self.registration.handle_put_resource_updates(
            res_payload,
            endpoint_location=endpoint_location,
            endpoint_name=endpoint_name)

        for item, value in payload.iteritems():
            resources_dict = endpoint_object.objects_dict[item][
                "object"].resources_id_dict
            res_dict = {}
            for item1, value1 in resources_dict.iteritems():
                res_dict.update({item1: value1["object"].res_value})
            total_res_dict.update({item: {"resources": res_dict}})

        total_object_info = {endpoint_object.endpoint_name: total_res_dict}
        return total_object_info

    def process(self, rx_record, remote, uri_query):
        """ Processes various requests like CON (POST, PUT, GET) or NON.
        POST requests : Generally used for Registration and Execution
        PUT requests : Generally used for Updating the resources
        GET requests : Generally used for Discovery, Observation, Cancel Observation """

        msg = rx_record.message
        self.uri_query = uri_query
        if msg.transaction_type == connection.Message.CON:
            if constants.POST == msg.code:
                method = None
                try:
                    method = uri_query[0].value.split("=")[1]
                except:
                    pass
                if method == "create":
                    path = msg.findOption(URI_PATH_VALUE)
                    content_type_number = msg.findOption(options.ContentType)
                    if content_type_number is None:
                        content_type = "text/plain"
                    else:
                        content_type = constants.media_types[
                            content_type_number.value]
                    self.create_object_instance.create_instance(
                        path, remote, content_type, loads(msg.payload))
                    resources = loads(msg.payload)
                    msg = connection.Message(connection.Message.ACK,
                                             code=constants.CREATED,
                                             payload="Resource Created")
                    self.dm_server.sendto(msg._pack(rx_record.transaction_id),
                                          remote)

                    client_port = self.generate_client_port()
                    self.create_object_instance.forward_request(
                        path, remote, resources, content_type, client_port)

                elif method == "execute":
                    path = msg.findOption(URI_PATH_VALUE)
                    content_type_number = msg.findOption(options.ContentType)
                    if content_type_number is None:
                        content_type = "text/plain"
                    else:
                        content_type = constants.media_types[
                            content_type_number.value]
                    self.execution.execute_resource(path, remote, msg.payload)
                    execute_payload = msg.payload
                    msg = connection.Message(connection.Message.ACK,
                                             code=constants.CHANGED,
                                             payload="Resource Executed")
                    self.dm_server.sendto(msg._pack(rx_record.transaction_id),
                                          remote)

                    client_port = self.generate_client_port()
                    self.execution.forward_request(path, remote,
                                                   execute_payload,
                                                   client_port)

                elif method == "notify":
                    self.logger.info("Notification Received")
                    client_port = self.generate_client_port()
                    for item1, item2 in loads(msg.payload).iteritems():
                        if item1 == "observer_ip":
                            observer_ip = item2
                        elif item1 == "observer_port":
                            observer_port = item2
                        elif item1 != "observer_ip" and item1 != "observer_port":
                            endpoint_name = item1
                            for item3, item4 in item2.iteritems():
                                for item5, item6 in item4[
                                        "resources"].iteritems():
                                    pass

                    res = {
                        item3: {
                            "resources": {
                                item5.split("_")[0]: {
                                    "res_value": item6,
                                    "res_inst_id": item5.split("_")[1]
                                }
                            }
                        }
                    }
                    payload = {}
                    payload = self.update_resource(res,
                                                   endpoint_name=endpoint_name)

                    payload["observer_ip"] = observer_ip
                    payload["observer_port"] = observer_port

                    token_id = msg.token
                    observe_value = msg.findOption(options.Observe).value
                    self.logger.info("Forwarding Notification")

                    content_type = "application/json"
                    request = lwm2m_api()
                    response = request.send_notification(self.general_observation.listener_ip, self.general_observation.listener_port, token_id, payload, \
                                content_type=content_type, time_elapse=observe_value, client_port=client_port)

                    msg = connection.Message(connection.Message.ACK,
                                             code=constants.CREATED,
                                             payload="Notification Received")
                    self.dm_server.sendto(msg._pack(rx_record.transaction_id),
                                          remote)

                else:
                    """ Handles the Client Registration Request """

                    self.logger.info(
                        "Registering Client Endpoint in the LWM2M DM Server")

                    endpoint = self.registration.process_registration(
                        msg, uri_query)

                    response = self.registration.register_client(endpoint)
                    registered_client_location = response
                    if registered_client_location is not None:
                        self.logger.info(
                            "Client Endpoint Registration Successful for Endpoint : %s",
                            endpoint.endpoint_name)
                        self.logger.info("The registered location is %s",
                                         registered_client_location)
                        payload = self.set_general_observation_params()
                    else:
                        self.logger.info("Client Endpoint Registration Failed")

                    msg = connection.Message(
                        connection.Message.ACK,
                        code=constants.CREATED,
                        location=registered_client_location)
                    self.dm_server.sendto(msg._pack(rx_record.transaction_id),
                                          remote)

                    #Send the General Observation to the Registered Client
                    #self.send_general_observation(registered_client_location)

            elif constants.PUT == msg.code:
                """ It consists of Normal Update, Write Operation, Write Attribute Operation.
                Write Operation is used to update the resource(s) as per the request. Write
                Attributes operation is used to update the attributes of the object, object
                instance or resource. """
                self.handle_lwm2m_put(msg, uri_query, remote, rx_record)

            elif constants.GET == msg.code:
                """ Handles Requests like Discovery, Observation """
                try:
                    observe_value = msg.findOption(options.Observe).value
                except:
                    observe_value = ""

                if observe_value == OBSERVE_OPTION_VALUE_OBSERVATION:
                    """ Sets the Observation. Two types of observations. General Observation
                    and Specific Observation. General Observation is used for anything that is
                    not observed and updates are sent as general notifications using a general
                    token. Specific observation is implicitly defined by the observer(as request) 
                    and handled as specific notification with a specific token """

                    path = msg.findOption(URI_PATH_VALUE)
                    if len(path) == 1:
                        self.set_m2m_server_adapter_params(rx_record, remote)
                    else:
                        self.logger.info(
                            "Specific Observation Request Received")

                        content_type_number = msg.findOption(
                            options.ContentType)
                        if content_type_number is None:
                            content_type = "text/plain"
                        else:
                            content_type = constants.media_types[
                                content_type_number.value]

                        token_id = msg.token
                        app_ip = loads(msg.payload)["app_ip"]
                        app_port = loads(msg.payload)["app_port"]
                        client_port = self.generate_client_port()

                        response = self.observation.forward_request(path, remote, observe_value, \
                                            self.lwm2m_dm_server_ip, self.lwm2m_dm_server_port, \
                                            app_ip, app_port, token_id, client_port)

                        msg = connection.Message(connection.Message.ACK, code=constants.CONTENT, \
                                                 payload="test") #todo: payload to be replaced
                        self.dm_server.sendto(
                            msg._pack(rx_record.transaction_id, token_id),
                            remote)

                elif observe_value == OBSERVE_OPTION_VALUE_CANCEL_OBSERVATION:
                    """ Removes the observation from the List """
                    self.logger.info("Cancel Observation Request Received")
                    path = msg.findOption(URI_PATH_VALUE)
                    token_id = msg.token
                    app_ip = loads(msg.payload)["app_ip"]
                    app_port = loads(msg.payload)["app_port"]
                    client_port = self.generate_client_port()

                    response = self.observation.forward_request(path, remote, observe_value, \
                                self.lwm2m_dm_server_ip, self.lwm2m_dm_server_port, \
                                app_ip, app_port, token_id, client_port)

                    def _handle_response(response):
                        msg = connection.Message(connection.Message.ACK,
                                                 code=constants.CONTENT,
                                                 payload=response)
                        self.dm_server.sendto(
                            msg._pack(rx_record.transaction_id), remote)

                    response.then(_handle_response)

                else:
                    method = None
                    try:
                        method = uri_query[0].value.split("=")[1]
                    except:
                        pass

                    if method == "read":
                        path = msg.findOption(URI_PATH_VALUE)
                        self.read.read_resource(path, remote)
                        msg = connection.Message(connection.Message.ACK, code=constants.CONTENT, \
                                             payload="info read", content_type="text/plain")
                        self.dm_server.sendto(
                            msg._pack(rx_record.transaction_id), remote)

                    elif method == "discover":
                        if msg.payload == "/.well-known/core":
                            payload = dumps(self.discover.get_all_resources())
                        else:
                            path = msg.findOption(URI_PATH_VALUE)
                            client_port = self.generate_client_port()
                            payload = self.discover.forward_request(
                                path, remote, client_port)

                        def _handle_response(payload):
                            msg = connection.Message(connection.Message.ACK, code=constants.CONTENT, \
                                                 payload=payload, content_type="application/json")
                            self.dm_server.sendto(
                                msg._pack(rx_record.transaction_id), remote)

                        if payload is Promise:
                            payload.then(_handle_response)
                        else:
                            _handle_response(payload)

        elif msg.transaction_type == connection.Message.NON:
            print "reached msg non"
            payload = msg.payload
            print payload

    def set_general_observation_params(self, ):
        return {
            "listener_ip": self.lwm2m_dm_server_ip,
            "listener_port": self.lwm2m_dm_server_port
        }

    def send_general_observation(self, registered_client_location):
        if registered_client_location is not None:
            payload = dumps(self.set_general_observation_params())
            endpoint_object = self.lwm2m_resources.return_endpoint_object(
                endpoint_location=registered_client_location)
            client_listener_ip = endpoint_object.listener_ip
            client_listener_port = endpoint_object.listener_port

            request = lwm2m_api()
            response = request.observe_resource(client_listener_ip, client_listener_port, \
                                                payload=payload, client_port=self.generate_client_port())

    def set_m2m_server_adapter_params(self, rx_record, remote):
        msg = rx_record.message
        #content_type is application/json
        listener_ip = loads(msg.payload)["listener_ip"]
        listener_port = loads(msg.payload)["listener_port"]
        token_id = msg.token

        self.general_observation = GeneralObservationInformation(
            listener_ip, listener_port, token_id)

        response = "Observation Started on the LWM2M Server"
        msg = connection.Message(connection.Message.ACK,
                                 code=constants.CONTENT,
                                 payload=response)
        self.dm_server.sendto(msg._pack(rx_record.transaction_id, token_id),
                              remote)

    def generate_client_port(self, ):
        if self.sem_counter >= 1000:
            self.sem_counter = 0

        self.sem.acquire()
        self.sem_counter += 1

        sem_counter = self.sem_counter
        self.sem.release()

        client_port = self.local_client_port_ + sem_counter
        return client_port
コード例 #10
0
class DMClient_CoAP_Server(DeviceClass):
    """ Handles and process the CoAP requests for Registration, Discovery, Observation/Notifications and etc """
    
    def __init__(self, api, dm_server_ip, dm_server_port, local_server_ip, local_server_port,
                 local_client_ip, local_client_port):
        super(DMClient_CoAP_Server, self).__init__()
        self.subscription_list = []
        self.sender_info = []
        self.lwm2m_dm_server_ip = dm_server_ip
        self.lwm2m_dm_server_port = dm_server_port
        self.local_server_ip = local_server_ip
        self.local_server_port = local_server_port
        self.local_client_ip = local_client_ip
        self.local_client_port = local_client_port
        #TODO: change datagram server to wrapper of coap server
        self.local_server = DatagramServer((self.local_server_ip, self.local_server_port), self.handle_request)
        self.api = api
    
    def handle_request(self, message, remote):
        rx_record = connection.ReceptionRecord(None, message, remote)
        msg = rx_record.message
        uriQuery = msg.findOption(options.UriQuery)
        self.process(rx_record, remote, uriQuery)
    
    def start_server(self, ):
        print "Local Server Started"
        self.local_server.start()
        
    def stop_server(self, ):
        print "Local Server Stopped"
        self.local_server.stop()
    
    def process(self, rx_record, remote, uriQ):
        """ Processes the POST, PUT and GET requests """
        msg=rx_record.message
        self.uriQuery1 = uriQ
        self.payload = msg.payload
        global resourceString
        if constants.POST == msg.code:
            #Registration Client
            global server_ip_port, location_address

            q = rx_record.message.findOption(URI_QUERY_VALUE)[0].value
            #TODO: check if coap says somthing about execute messages
            if str(q).find("execute") != -1:
                print "entered in client:: execute field"
                self.executeResource(rx_record)
                msg = connection.Message(connection.Message.ACK, code=constants.CHANGED, payload="execution")
                self.local_server.sendto(msg._pack(rx_record.transaction_id), remote)
            else:
                server_ip = self.lwm2m_dm_server_ip
                server_port = self.lwm2m_dm_server_port
                server_ip_port = server_ip + ":" + str(server_port)
                payload = msg.payload
                path = "rd?"
                query = rx_record.message.findOption(URI_QUERY_VALUE)[0].value.strip()
                #Creates objects in the local database
                local_lwm2m_client.create_mgmt_objects(query, payload)
                
                msg = connection.Message(connection.Message.ACK, code=constants.CREATED, payload="Client Registered")
                self.local_server.sendto(msg._pack(rx_record.transaction_id), remote)
                #Registration in the Server
                res_register = client_request.clientRegistration(lwm2m_server_ip_port, path, query, payload, client_port = 5683)

                location_address = res_register.findOption(LOCATION_VALUE)[0].value
                self.storeDiscoverPaths.append({ "path" : "rd", "location" : location_address, "objectID" : None, "objectInstID" : None, "resID" : None})
            
        elif constants.PUT == msg.code:
            check_pmax = 0
            #pmin and pmax imposed from the dm server, upath related to an object
            for val1 in uriQ:
                if str(val1).find("pmax") != -1:
                    check_pmax = 1
            if check_pmax == 1:
               	path = []
                for v in rx_record.message.findOption(URI_PATH_VALUE):
                    path.append(v.value)
                upath = "/".join(path)

        	pmax = str(rx_record.message.findOption(URI_QUERY_VALUE)[0].value).split("=")[1]
        	pmin = str(rx_record.message.findOption(URI_QUERY_VALUE)[1].value).split("=")[1]
                check_pmax = 0
                filtered_resources = self.write_attributes(upath, pmax, pmin)
                
                msg = connection.Message(connection.Message.ACK, code=constants.CHANGED, payload=filtered_resources)
                self.local_server.sendto(msg._pack(rx_record.transaction_id), remote)
            else:
                #TODO: Write: standard exists for writing resources?
                self.resource_update(rx_record, self.uriQuery1, remote)
            
        elif constants.GET == msg.code:
            try:
                observe_value = rx_record.message.findOption(options.Observe).value
            except ValueError:
                observe_value = None #-1
            
            if observe_value == OBSERVE_OPTION_VALUE_OBSERVATION:
                filtered_resources = self.observe_resource(rx_record, self.uriQuery1)
            elif observe_value == OBSERVE_OPTION_VALUE_CANCEL_OBSERVATION:
                filtered_resources = self.cancel_observe_resource(rx_record)
            elif str(rx_record.message.findOption(URI_PATH_VALUE)[0].value).find("rd") != -1:
                filtered_resources = self.handle_discover_request(rx_record)
                
            msg = connection.Message(connection.Message.ACK, code=constants.CONTENT, payload=json.dumps(filtered_resources))
            self.local_server.sendto(msg._pack(rx_record.transaction_id), remote)
    
    def resource_update(self, rx_record, uriQuery1, remote):
        """ Updates the resources in the local database and LWM2M server  """
        
        store_query = []
        for val in self.uriQuery1:
            splitQuery = str(str(val).split(":")[1]).strip()
            store_query.append({"id" : -1,
                                "code" : str(splitQuery).split("=")[0],
                                "value" : str(splitQuery).split("=")[1]})
        split_payload = str(rx_record.message.payload).split("/")

        local_lwm2m_client.update_mgmt_object(split_payload[0], split_payload[1], store_query)        
        payloadForServer = rx_record.message.payload
        
        msg = connection.Message(connection.Message.ACK, code=constants.CHANGED, payload="Resource Updated")
        self.local_server.sendto(msg._pack(rx_record.transaction_id), remote)
        
        # Updates the LWM2M Server
        path = "rd/" + location_address +"?"
        query = str(splitQuery).split("=")[0] + "=" + str(splitQuery).split("=")[1]
        payload = payloadForServer
        client_request.clientUpdate(lwm2m_server_ip_port, query, payload, path=path, client_port=self.local_client_port)

    def myfunc(self,):
        self.p1 = subprocess.Popen(['sh', 'webcamstart.sh', '127.0.0.1', '34000']) #, stdout = subprocess.PIPE)
        self.p1.communicate()
    
    def executeResource(self, rx_record):
        for path_element in rx_record.message.findOption(URI_PATH_VALUE):
            print "client: elements %s" %path_element            
        
        objectID = rx_record.message.findOption(URI_PATH_VALUE)[2].value
        objectInstID = rx_record.message.findOption(URI_PATH_VALUE)[3].value
        resID = rx_record.message.findOption(URI_PATH_VALUE)[4].value
        
        print objectID, objectInstID, resID
        print rx_record.message.payload
        
        storeQuery = []
        storeQuery.append({"id" : int(resID), "code" : "Null", "value" : int(rx_record.message.payload)})
        
        local_lwm2m_client.update_mgmt_object(objectID, objectInstID, storeQuery)
        
        #self.p = subprocess.Popen(['sh', 'webcamstart.sh', '127.0.0.1', '34000'], stdout = subprocess.PIPE)
        #self.api.run_task(self.p.communicate)
        #self.api.run_task(self.myfunc)
        #self.myfunc()
        #print "reached down:: client"
        self.api.run_task(call, ["cheese"])
        #call(["cheese"])

    def handle_discover_request(self, rx_record):
        path = []
        for v in rx_record.message.findOption(URI_PATH_VALUE):
            path.append(v.value)
        pload = str(rx_record.message.payload).split("&")
        app_ip = str(pload[0]).split("=")[1]
        app_port = str(pload[1]).split("=")[1]

        if len(path) == 2:
            filtered_resources = self.discover_resource(app_ip, app_port, endPoint = path[1],
                                                        objectID = None, objectInstID = None, resID = None)
        elif len(path) == 3:
            filtered_resources = self.discover_resource(app_ip, app_port, endPoint = path[1],
                                                        objectID = path[2], objectInstID = None, resID = None)
        elif len(path) == 4:
            filtered_resources = self.discover_resource(app_ip, app_port, endPoint = path[1],
                                                        objectID = path[2], objectInstID = path[3], resID = None)
        elif len(path) == 5:
            filtered_resources = self.discover_resource(app_ip, app_port, endPoint = path[1],
                                                        objectID = path[2], objectInstID = path[3], resID = path[4])
    
        return filtered_resources

    def discover_resource(self, app_ip, app_port, endPoint, objectID=None, objectInstID=None, resID=None):
        total_result = []
        if objectID is None:
            answer = local_lwm2m_client.return_maintain_objects()
            for ans in answer:
                total_result.append({"app_ip" : app_ip, "app_port" : app_port, "endPointName" : endPoint,
                                     "objectID" : ans["objectID"], "objectInstID" : ans["objectInstID"],
                                     "pmax" : ans["pmax"], "pmin" : ans["pmin"]})
        elif objectID != None and objectInstID != None and resID == None:
            answer = local_lwm2m_client.return_resources(objectID, objectInstID)
            for ans in answer:
                total_result.append({"app_ip" : app_ip, "app_port" : app_port, "endPointName" : endPoint,
                                     "objectID" : objectID, "objectInstID" : objectInstID, "pmax" : ans["pmax"],
                                     "pmin" : ans["pmin"], "resID" : ans["resID"], "resValue" : ans["resValue"]})
        return total_result
        
    def observe_resource(self, rx_record, query):
        first_notification = None
        uri_port = rx_record.message.findOption(URI_PORT_VALUE).value
        uri_host = rx_record.message.findOption(URI_HOST_VALUE).value
        s_list = {}
        sender_details = {}
        path = []
        for v in rx_record.message.findOption(URI_PATH_VALUE):
            path.append(v.value)
        pload = str(rx_record.message.payload).split("&")
        app_ip = str(pload[0]).split("=")[1]
        app_port = str(pload[1]).split("=")[1]
        #check if the path includes the object instance id or just the object id
        if len(path) == 3:
            #observation to object id
            path.append("None")
            path.append("None")
        elif len(path) == 4:
            #observation to resource id
            path.append("None")
        
        objectID = path[2]
        objectInstID = path[3]
        resID = path[4]
 
        s_list = {"app_ip" : app_ip, "app_port" : app_port, "objectID" : objectID,
                  "objectInstID" : objectInstID, "resID" : resID}
        sender_details = {"transaction_id" : rx_record.transaction_id, "uri_host" : uri_host, "uri_port" : uri_port}
        #store the new observation
        if len(self.subscription_list) == 0:
            self.subscription_list.append(s_list)
            self.sender_info.append(sender_details) 
            first_notification = local_lwm2m_client.observe_res(self.subscription_list, s_list, self.sender_info)
        else:
            for test in self.subscription_list:
                if test != s_list:
                    self.subscription_list.append(s_list)
                    self.sender_info.append(sender_details) 
                    first_notification = local_lwm2m_client.observe_res(self.subscription_list, s_list, self.sender_info)

        return first_notification
    
    def cancel_observe_resource(self, rx_record):
        counter = 0
        path = []
        for v in rx_record.message.findOption(URI_PATH_VALUE):
            path.append(v.value) 
        pload = str(rx_record.message.payload).split("&")
        app_ip = str(pload[0]).split("=")[1]
        app_port = str(pload[1]).split("=")[1]
        
        if len(path) == 3:
            path.append("None")
            path.append("None")
        elif len(path) == 4:
            path.append("None")
        
        objectID = path[2]
        objectInstID = path[3]
        resID = path[4]
        
        try:
            for val in self.subscription_list:
                if val["app_ip"] == app_ip and val["app_port"] == app_port and val["objectID"] == objectID:
                    self.subscription_list.remove({"app_ip" : app_ip, "app_port" : app_port,
                                                   "objectID" : objectID, "objectInstID" : objectInstID, "resID" : resID})
                    self.sender_info.pop(counter)
                counter += 1
            local_lwm2m_client.cancel_obs_res(objectID, self.subscription_list)
        except:
            print "The Object ID %s is not present" %objectID
        
        return "Unsubscribed Successful"
        
    def write_attributes(self, upath, pmax, pmin):
        splitPath = str(upath).split("/")
        create_str = []
        create_str.append({"attCode" : "pmax", "attValue" : pmax})
        create_str.append({"attCode" : "pmin", "attValue" : pmin})
        return local_lwm2m_client.write_attr(create_str, splitPath[2])
コード例 #11
0
        except ValueError:
            continue
    if (headers.get('x-user-agent', None) == 'redsonic'):
        location = headers.get('location', None)
        if location is not None and location not in CLIENTS:
            print("Found WeMo at {0}".format(location))
            CLIENTS[location] = headers
            #gevent.spawn(discovered.send, self, address=address,
            #        headers=headers)


server = DatagramServer(get_ip_address() + ':54321', _response_received)

request = '\r\n'.join(
    ("M-SEARCH * HTTP/1.1", "HOST:{}:{}", "ST:upnp:rootdevice", "MX:2",
     'MAN:"ssdp:discover"', "", "")).format(MCAST_IP, MCAST_PORT)

with gevent.Timeout(2, KeyboardInterrupt):
    while True:
        try:
            server.set_spawn(1)
            server.init_socket()
            server.socket.setsockopt(_socket.IPPROTO_IP,
                                     _socket.IP_MULTICAST_TTL, MCAST_TTL)
            server.start()
            server.sendto(request.encode(), (MCAST_IP, MCAST_PORT))
            gevent.sleep(2)
        except KeyboardInterrupt:
            print('Scan Complete')
            break
コード例 #12
0
class UDPTransport:
    """ Node communication using the UDP protocol. """

    def __init__(
            self,
            host,
            port,
            socket=None,
            protocol=None,
            throttle_policy=DummyPolicy()):

        self.protocol = protocol
        if socket is not None:
            self.server = DatagramServer(socket, handle=self.receive)
        else:
            self.server = DatagramServer((host, port), handle=self.receive)
        self.host = self.server.server_host
        self.port = self.server.server_port
        self.throttle_policy = throttle_policy

    def receive(self, data, host_port):  # pylint: disable=unused-argument
        try:
            self.protocol.receive(data)
        except InvalidProtocolMessage as e:
            log.warning("Can't decode: {} (data={}, len={})".format(str(e), data, len(data)))
            return
        except RaidenShuttingDown:  # For a clean shutdown
            return

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.track_recv(self.protocol.raiden, host_port, data)

    def send(self, sender, host_port, bytes_):
        """ Send `bytes_` to `host_port`.

        Args:
            sender (address): The address of the running node.
            host_port (Tuple[(str, int)]): Tuple with the host name and port number.
            bytes_ (bytes): The bytes that are going to be sent through the wire.
        """
        sleep_timeout = self.throttle_policy.consume(1)

        # Don't sleep if timeout is zero, otherwise a context-switch is done
        # and the message is delayed, increasing it's latency
        if sleep_timeout:
            gevent.sleep(sleep_timeout)

        if not hasattr(self.server, 'socket'):
            raise RuntimeError('trying to send a message on a closed server')

        self.server.sendto(bytes_, host_port)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.network.track_send(sender, host_port, bytes_)

    def stop(self):
        self.server.stop()
        # Calling `.close()` on a gevent socket doesn't actually close the underlying os socket
        # so we do that ourselves here.
        # See: https://github.com/gevent/gevent/blob/master/src/gevent/_socket2.py#L208
        # and: https://groups.google.com/forum/#!msg/gevent/Ro8lRra3nH0/ZENgEXrr6M0J
        try:
            self.server._socket.close()
        except socket.error:
            pass

    def stop_accepting(self):
        self.server.stop_accepting()

    def start(self):
        assert not self.server.started
        # server.stop() clears the handle, since this may be a restart the
        # handle must always be set
        self.server.set_handle(self.receive)
        self.server.start()
コード例 #13
0
class BigBrother(control.Control):
    def __init__(self):
        self.Comps = {}
        self.Robots = {}
        self.Nodes = {}
        self.host = self._etc["ip"]
        self.port = self._etc["port"]
        self.broadcast = self._etc["broadcast_port"]

    def __Run__(self):
        self.L_info("starting BigBrother")
        self.bcast = DatagramServer(('', self.broadcast), handle=self.receive)
        self.bcast.start()
        self.start_worker(self.cleaner, )

    def __Close__(self):
        self.worker_run = False

    def cleaner(self):
        while self.worker_run:
            delete = []
            for comp in self.Comps:
                ser = self.Control_Service(comp)
                control = Proxy(ser)
                if not control():
                    delete.append(comp)
            for c in delete:
                del (self.Comps[c])
                self.L_info("{} disconnected".format(c))
            Robots = list(self.Robots)
            for R in Robots:
                if len(self.Components(R)) == 0:
                    self.Unregister_Robot(R)
                    self.L_info("{} Unregistered ".format(R))
            Nodes = list(self.Nodes)
            delete = []
            for N in Nodes:
                ser = self.Nodes[N][1][1]
                control = Proxy(ser)
                if not control():
                    delete.append(N)
                for c in delete:
                    del (self.Nodes[N])
                    self.L_info("{} Node disconnected".format(c))
            time.sleep(2)

    def receive(self, data, address):
        if data.decode() == "hi BigBrother":
            send = "{}:{}".format(self.host, self.port)
            self.bcast.sendto(send.encode(), address)
        else:
            self.bcast.sendto("0.0.0.0:0".encode(), address)

    def Register_Node(self, node, uri):
        if node not in self.Nodes:
            self.Nodes[node] = uri
            self.L_info("Node {} Registered at {}".format(node, uri))
            return True
        self.L_info("Node {} is on line at {}".format(node, uri))
        return False

    def Unregister_Node(self, node):
        if node in self.Nodes:
            del (self.Nodes[node])
            return True
        return False

    def Get_Node(self, node):
        if node in self.Nodes:
            return self.Nodes[node][0][1]
        else:
            return "0.0.0.0:0"

    def Unregister_Robot(self, robot):
        if robot in self.Robots:
            del (self.Robots[robot])

    def Register_Robot(self, robot, default):
        if robot not in self.Robots:
            self.Robots[robot] = {}
            self.Robots[robot]["default"] = default
            self.L_info("Robot {} Registered".format(robot))
            return True
        else:
            return False

    def Get_Robots(self):
        return self.Robots

    def Get_Robot(self, robot):
        default = {}
        if robot in self.Robots:
            default = self.Robots[robot]
        return default

    def Register_Comp(self, name, comp):
        general = comp["GENERAL"]
        del (comp["GENERAL"])
        robot = general["robot"]
        if robot not in self.Robots:
            self.Register_Robot(robot, general)
        if name not in self.Comps:
            self.Comps[name] = comp
            self.L_info("Component {} Registered".format(name))
            return True
        else:
            return False

    def Get_Comp(self, name):
        try:
            return self.Comps[name]
        except:
            return {}

    def Components(self, robot):
        return [x for x in self.Comps if x.find(robot + "/") == 0]

    def Services(self, robot):
        comps = self.Components(robot)
        ser = [
            x + "/" + k[0] for x in comps for k in self.Comps[x]["INTERFACES"]
            if k[0] != "Control_Interface"
        ]
        return ser

    def Get_Interface_Uri(self, interface):
        robot, comp, interface = interface.split("/")
        comps = self.Components(robot)
        ser = [
            k[1] for x in comps for k in self.Comps[x]["INTERFACES"]
            if k[0] == interface
        ]
        if len(ser) == 1:
            return ser[0]
        else:
            return "0.0.0.0:0"

    def Control_Service(self, comp):
        if comp in self.Comps:
            interfaces = list(self.Comps[comp]["INTERFACES"])
            ser = [k[1] for k in interfaces if k[0] == "Control_Interface"]
            if len(ser) == 1:
                return ser[0]
            else:
                return None

    def Topics(self, robot):
        comps = self.Components(robot)
        top = [
            "{}/{}".format(x, k) for x in comps for k in self.Comps[x]["PUB"]
        ]
        return top

    def Events(self, robot):
        comps = self.Components(robot)
        events = [
            "{}/{}".format(x, k) for x in comps
            for k in self.Comps[x]["EVENTS"]
        ]
        #events=[k for x in comps for k in self.Comps[x]["EVENTS"]]
        return events

    def Sub_Topics(self, robot):
        comps = self.Components(robot)
        top = [k for x in comps for k in self.Comps[x]["SUB"]]
        return top

    def Broker(self, robot):
        if robot in self.Robots:
            return self.Robots[robot]["default"]["MQTT_uri"]
        else:
            return "0.0.0.0:0"
コード例 #14
0
ファイル: udp_transport.py プロジェクト: AlphaX-IBS/raiden
class UDPTransport:
    UDP_MAX_MESSAGE_SIZE = 1200

    def __init__(self, discovery, udpsocket, throttle_policy, config):
        # these values are initialized by the start method
        self.queueids_to_queues: typing.Dict
        self.raiden: RaidenService

        self.discovery = discovery
        self.config = config

        self.retry_interval = config['retry_interval']
        self.retries_before_backoff = config['retries_before_backoff']
        self.nat_keepalive_retries = config['nat_keepalive_retries']
        self.nat_keepalive_timeout = config['nat_keepalive_timeout']
        self.nat_invitation_timeout = config['nat_invitation_timeout']

        self.event_stop = Event()

        self.greenlets = list()
        self.addresses_events = dict()

        self.messageids_to_asyncresults = dict()

        # Maps the addresses to a dict with the latest nonce (using a dict
        # because python integers are immutable)
        self.nodeaddresses_to_nonces = dict()

        cache = cachetools.TTLCache(
            maxsize=50,
            ttl=CACHE_TTL,
        )
        cache_wrapper = cachetools.cached(cache=cache)
        self.get_host_port = cache_wrapper(discovery.get)

        self.throttle_policy = throttle_policy
        self.server = DatagramServer(udpsocket, handle=self._receive)

    def start(
            self,
            raiden: RaidenService,
            queueids_to_queues: typing.List[SendMessageEvent],
    ):
        self.raiden = raiden
        self.queueids_to_queues = dict()

        # server.stop() clears the handle. Since this may be a restart the
        # handle must always be set
        self.server.set_handle(self._receive)

        for (recipient, queue_name), queue in queueids_to_queues.items():
            encoded_queue = list()

            for sendevent in queue:
                message = message_from_sendevent(sendevent, raiden.address)
                raiden.sign(message)
                encoded = message.encode()

                encoded_queue.append((encoded, sendevent.message_identifier))

            self.init_queue_for(recipient, queue_name, encoded_queue)

        self.server.start()

    def stop_and_wait(self):
        # Stop handling incoming packets, but don't close the socket. The
        # socket can only be safely closed after all outgoing tasks are stopped
        self.server.stop_accepting()

        # Stop processing the outgoing queues
        self.event_stop.set()
        gevent.wait(self.greenlets)

        # All outgoing tasks are stopped. Now it's safe to close the socket. At
        # this point there might be some incoming message being processed,
        # keeping the socket open is not useful for these.
        self.server.stop()

        # Calling `.close()` on a gevent socket doesn't actually close the underlying os socket
        # so we do that ourselves here.
        # See: https://github.com/gevent/gevent/blob/master/src/gevent/_socket2.py#L208
        # and: https://groups.google.com/forum/#!msg/gevent/Ro8lRra3nH0/ZENgEXrr6M0J
        try:
            self.server._socket.close()  # pylint: disable=protected-access
        except socket.error:
            pass

        # Set all the pending results to False
        for async_result in self.messageids_to_asyncresults.values():
            async_result.set(False)

    def get_health_events(self, recipient):
        """ Starts a healthcheck task for `recipient` and returns a
        HealthEvents with locks to react on its current state.
        """
        if recipient not in self.addresses_events:
            self.start_health_check(recipient)

        return self.addresses_events[recipient]

    def start_health_check(self, recipient):
        """ Starts a task for healthchecking `recipient` if there is not
        one yet.
        """
        if recipient not in self.addresses_events:
            ping_nonce = self.nodeaddresses_to_nonces.setdefault(
                recipient,
                {'nonce': 0},  # HACK: Allows the task to mutate the object
            )

            events = healthcheck.HealthEvents(
                event_healthy=Event(),
                event_unhealthy=Event(),
            )

            self.addresses_events[recipient] = events

            greenlet_healthcheck = gevent.spawn(
                healthcheck.healthcheck,
                self,
                recipient,
                self.event_stop,
                events.event_healthy,
                events.event_unhealthy,
                self.nat_keepalive_retries,
                self.nat_keepalive_timeout,
                self.nat_invitation_timeout,
                ping_nonce,
            )
            greenlet_healthcheck.name = f'Healthcheck for {pex(recipient)}'
            self.greenlets.append(greenlet_healthcheck)

    def init_queue_for(
            self,
            recipient: typing.Address,
            queue_name: bytes,
            items: typing.List[QueueItem_T],
    ) -> Queue_T:
        """ Create the queue identified by the pair `(recipient, queue_name)`
        and initialize it with `items`.
        """
        queueid = (recipient, queue_name)
        queue = self.queueids_to_queues.get(queueid)
        assert queue is None

        queue = NotifyingQueue(items=items)
        self.queueids_to_queues[queueid] = queue

        events = self.get_health_events(recipient)

        greenlet_queue = gevent.spawn(
            single_queue_send,
            self,
            recipient,
            queue,
            self.event_stop,
            events.event_healthy,
            events.event_unhealthy,
            self.retries_before_backoff,
            self.retry_interval,
            self.retry_interval * 10,
        )

        if queue_name == b'global':
            greenlet_queue.name = f'Queue for {pex(recipient)} - global'
        else:
            greenlet_queue.name = f'Queue for {pex(recipient)} - {pex(queue_name)}'

        self.greenlets.append(greenlet_queue)

        log.debug(
            'new queue created for',
            node=pex(self.raiden.address),
            token=pex(queue_name),
            to=pex(recipient),
        )

        return queue

    def get_queue_for(
            self,
            recipient: typing.Address,
            queue_name: bytes,
    ) -> Queue_T:
        """ Return the queue identified by the pair `(recipient, queue_name)`.

        If the queue doesn't exist it will be instantiated.
        """
        queueid = (recipient, queue_name)
        queue = self.queueids_to_queues.get(queueid)

        if queue is None:
            items = ()
            queue = self.init_queue_for(recipient, queue_name, items)

        return queue

    def send_async(
            self,
            recipient: typing.Address,
            queue_name: bytes,
            message: 'Message',
    ):
        """ Send a new ordered message to recipient.

        Messages that use the same `queue_name` are ordered.
        """

        if not is_binary_address(recipient):
            raise ValueError('Invalid address {}'.format(pex(recipient)))

        # These are not protocol messages, but transport specific messages
        if isinstance(message, (Delivered, Ping, Pong)):
            raise ValueError('Do not use send for {} messages'.format(message.__class__.__name__))

        messagedata = message.encode()
        if len(messagedata) > self.UDP_MAX_MESSAGE_SIZE:
            raise ValueError(
                'message size exceeds the maximum {}'.format(self.UDP_MAX_MESSAGE_SIZE),
            )

        # message identifiers must be unique
        message_id = message.message_identifier

        # ignore duplicates
        if message_id not in self.messageids_to_asyncresults:
            self.messageids_to_asyncresults[message_id] = AsyncResult()

            queue = self.get_queue_for(recipient, queue_name)
            queue.put((messagedata, message_id))

            log.debug(
                'MESSAGE QUEUED',
                node=pex(self.raiden.address),
                queue_name=queue_name,
                to=pex(recipient),
                message=message,
            )

    def maybe_send(self, recipient: typing.Address, message: Message):
        """ Send message to recipient if the transport is running. """

        if not is_binary_address(recipient):
            raise InvalidAddress('Invalid address {}'.format(pex(recipient)))

        messagedata = message.encode()
        host_port = self.get_host_port(recipient)

        self.maybe_sendraw(host_port, messagedata)

    def maybe_sendraw_with_result(
            self,
            recipient: typing.Address,
            messagedata: bytes,
            message_id: typing.MessageID,
    ) -> AsyncResult:
        """ Send message to recipient if the transport is running.

        Returns:
            An AsyncResult that will be set once the message is delivered. As
            long as the message has not been acknowledged with a Delivered
            message the function will return the same AsyncResult.
        """
        async_result = self.messageids_to_asyncresults.get(message_id)
        if async_result is None:
            async_result = AsyncResult()
            self.messageids_to_asyncresults[message_id] = async_result

        host_port = self.get_host_port(recipient)
        self.maybe_sendraw(host_port, messagedata)

        return async_result

    def maybe_sendraw(self, host_port: typing.Tuple[int, int], messagedata: bytes):
        """ Send message to recipient if the transport is running. """

        # Don't sleep if timeout is zero, otherwise a context-switch is done
        # and the message is delayed, increasing it's latency
        sleep_timeout = self.throttle_policy.consume(1)
        if sleep_timeout:
            gevent.sleep(sleep_timeout)

        # Check the udp socket is still available before trying to send the
        # message. There must be *no context-switches after this test*.
        if hasattr(self.server, 'socket'):
            self.server.sendto(
                messagedata,
                host_port,
            )

    def _receive(self, data, host_port):  # pylint: disable=unused-argument
        try:
            self.receive(data)
        except RaidenShuttingDown:  # For a clean shutdown
            return

    def receive(self, messagedata: bytes):
        """ Handle an UDP packet. """
        # pylint: disable=unidiomatic-typecheck

        if len(messagedata) > self.UDP_MAX_MESSAGE_SIZE:
            log.error(
                'INVALID MESSAGE: Packet larger than maximum size',
                node=pex(self.raiden.address),
                message=hexlify(messagedata),
                length=len(messagedata),
            )
            return

        message = decode(messagedata)

        if type(message) == Pong:
            self.receive_pong(message)
        elif type(message) == Ping:
            self.receive_ping(message)
        elif type(message) == Delivered:
            self.receive_delivered(message)
        elif message is not None:
            self.receive_message(message)
        else:
            log.error(
                'INVALID MESSAGE: Unknown cmdid',
                node=pex(self.raiden.address),
                message=hexlify(messagedata),
            )

    def receive_message(self, message: Message):
        """ Handle a Raiden protocol message.

        The protocol requires durability of the messages. The UDP transport
        relies on the node's WAL for durability. The message will be converted
        to a state change, saved to the WAL, and *processed* before the
        durability is confirmed, which is a stronger property than what is
        required of any transport.
        """
        # pylint: disable=unidiomatic-typecheck

        if on_message(self.raiden, message):

            # Sending Delivered after the message is decoded and *processed*
            # gives a stronger guarantee than what is required from a
            # transport.
            #
            # Alternatives are, from weakest to strongest options:
            # - Just save it on disk and asynchronously process the messages
            # - Decode it, save to the WAL, and asynchronously process the
            #   state change
            # - Decode it, save to the WAL, and process it (the current
            #   implementation)
            delivered_message = Delivered(message.message_identifier)
            self.raiden.sign(delivered_message)

            self.maybe_send(
                message.sender,
                delivered_message,
            )

    def receive_delivered(self, delivered: Delivered):
        """ Handle a Delivered message.

        The Delivered message is how the UDP transport guarantees persistence
        by the partner node. The message itself is not part of the raiden
        protocol, but it's required by this transport to provide the required
        properties.
        """
        processed = ReceiveDelivered(delivered.delivered_message_identifier)
        self.raiden.handle_state_change(processed)

        message_id = delivered.delivered_message_identifier
        async_result = self.raiden.transport.messageids_to_asyncresults.get(message_id)

        # clear the async result, otherwise we have a memory leak
        if async_result is not None:
            del self.messageids_to_asyncresults[message_id]
            async_result.set()

    # Pings and Pongs are used to check the health status of another node. They
    # are /not/ part of the raiden protocol, only part of the UDP transport,
    # therefore these messages are not forwarded to the message handler.
    def receive_ping(self, ping: Ping):
        """ Handle a Ping message by answering with a Pong. """

        log.debug(
            'PING RECEIVED',
            node=pex(self.raiden.address),
            message_id=ping.nonce,
            message=ping,
            sender=pex(ping.sender),
        )

        pong = Pong(ping.nonce)
        self.raiden.sign(pong)

        try:
            self.maybe_send(ping.sender, pong)
        except (InvalidAddress, UnknownAddress) as e:
            log.debug("Couldn't send the `Delivered` message", e=e)

    def receive_pong(self, pong: Pong):
        """ Handles a Pong message. """

        message_id = ('ping', pong.nonce, pong.sender)
        async_result = self.messageids_to_asyncresults.get(message_id)

        if async_result is not None:
            log.debug(
                'PONG RECEIVED',
                node=pex(self.raiden.address),
                sender=pex(pong.sender),
                message_id=pong.nonce,
            )

            async_result.set(True)

    def get_ping(self, nonce: int) -> Ping:
        """ Returns a signed Ping message.

        Note: Ping messages don't have an enforced ordering, so a Ping message
        with a higher nonce may be acknowledged first.
        """
        message = Ping(nonce)
        self.raiden.sign(message)
        message_data = message.encode()

        return message_data

    def set_node_network_state(self, node_address: typing.Address, node_state):
        state_change = ActionChangeNodeNetworkState(node_address, node_state)
        self.raiden.handle_state_change(state_change)
コード例 #15
0
class CoapServer(LoggerMixin):
    block_size_exponent = 10
    """Server handling CoAP requests and generates RequestIndications."""
    DEFAULT_CONTENT_TYPE = "application/json"
    __cached_addresses = {}

    def __init__(self,
                 request_handler,
                 connector,
                 address="0.0.0.0",
                 server_port=5682,
                 ssl_args=None,
                 *args,
                 **kw):
        """Initializes the CoAP server.

        :param request_handler: Handler called with generated RequestIndications
        :param connector: Base uri used to reach this server (coap://IP:PORT or
                         coaps://IP:PORT)
        :param address: IP listening to
        :param server_port: Port listening to
        :param ssl_args: contains two keywords: "keyfile" and "certfile"
                         containing paths to respective files, None for regular
                         CoAP
        """
        self.server_port = server_port
        self.connector = connector
        self.request_handler = request_handler
        self.subs = {}
        self.address = address
        if address == "::":
            self.__addresses = self._get_addresses(AF_INET6) | \
                               self._get_addresses(AF_INET)
            self._resolve_host = self._resolve_host_ipv6
        elif address in ("", "0.0.0.0"):
            self.__addresses = self._get_addresses(AF_INET)
        else:
            self.__addresses = get_iterable(address)

        do_patch()

        self.logger.debug("Starting Coap Server on %s:%s" %
                          (self.address, self.server_port))

        if ssl_args:
            self.server = DtlsServer((address, self.server_port),
                                     self.handle_request, **ssl_args)
        else:
            self.server = DatagramServer((address, self.server_port),
                                         self.handle_request)

        self.block1_pending_payload = {}
        self.block2_pending_payload = {}
        self.actual_requests = []
        self.req_queue = Queue.Queue()
        start_new_thread(self.request_runner, ())

    def _add_headers(self, msg):
        """Reads the set of UriQuery options and extract additional headers in
        a dict.

        Used mainly for Store and Forward functionnalities, recognized headers
        are formated as: X-etsi-<headername>

        :param msg: CoAP message containing UriQuery options
        :return: Dictionnary containing headers
        """
        params = MultiDict()
        opts = msg.findOption(options.UriQuery)
        self.logger.debug("Message: %s", msg)
        self.logger.debug("List of UriQuery options: %s", opts)
        if not opts:
            return params
        for opt in opts:
            try:
                opt_split = opt.value.split("=")
                opt_name = opt_split[0]
                opt_value = opt_split[1]
                try:
                    opt_type = opt_name.split('-')[2]
                except:
                    opt_type = opt_name
                params.add(opt_type, opt_value)
            except:
                self.logger.debug("Unknown header : %s" % opt.value)
        return params

    # TODO: map to new scheme
    def _handle_observe(self, path, msg, rx_record, obs):
        """Handles the presence of the Observe Option.

        Creates or deletes a subscription to a resource depending on the Observe
        value.

        :param path: Resource path
        :param msg: CoAP message
        :param obs: Observe option Object
        """

        params = self._add_headers(msg)
        username = None

        accept = self._get_accept(msg)

        if obs.value == 0:
            sub_path = path + "/subscriptions"
            sub_payload = ('{"subscription": {"contact": "coap://%s:%s"}}' %
                           (self.remote, ))
            request = GenericRequest(RequestMethod.create,
                                     sub_path,
                                     sub_payload,
                                     self.DEFAULT_CONTENT_TYPE,
                                     id=rx_record.message.token,
                                     username=username,
                                     params=params,
                                     accept=accept,
                                     connector=self.connector)
            p = self.request_handler(request)

            def __handle_result(result):
                if not (self.remote in self.subs):
                    self.subs[self.remote] = {}
                self.subs[self.remote][path] = result.resourceURI

            p.then(__handle_result)

        else:
            request = GenericRequest(RequestMethod.delete,
                                     self.subs[self.remote][path],
                                     id=rx_record.message.token,
                                     username=username,
                                     params=params,
                                     accept=accept,
                                     connector=self.connector)
            self.request_handler(request)
            del self.subs[self.remote][path]
            if self.subs[self.remote] == {}:
                del self.subs[self.remote]

    def _generic_map_put(self, path, msg, rx_record):
        """Creates an generic update Request Object from a path and a CoAP
        message.

        :param path: Resource path
        :param msg: CoAP message
        :return: Request Object
        """
        params = self._add_headers(msg)
        username = None

        accept = self._get_accept(msg)

        return GenericRequest(RequestMethod.update,
                              path,
                              msg.payload,
                              msg.content_type,
                              id=rx_record.message.token,
                              username=username,
                              params=params,
                              accept=accept,
                              connector=self.connector)

    def _generic_map_post(self, path, msg, rx_record):
        """Creates an generic create Request Object from a path and a CoAP
        message.

        :param path: Resource path
        :param msg: CoAP message
        :return: Request Object
        """
        method = RequestMethod.create
        # TODO: does this need to be done more generically?
        if msg.payload.startswith("m2m:operation="):
            _, _, rest = msg.payload.partition("=")
            if rest:
                method_value = rest[0]
                msg.payload = rest[1:]
                if int(method_value) == 5:
                    method = RequestMethod.notify

        params = self._add_headers(msg)
        username = None

        accept = self._get_accept(msg)

        return GenericRequest(method,
                              path,
                              msg.payload,
                              msg.content_type,
                              id=rx_record.message.token,
                              username=username,
                              params=params,
                              accept=accept,
                              connector=self.connector)

    def _generic_map_get(self, path, msg, rx_record):
        """Creates an generic retrieve Request Object from a path and a CoAP
        message

        Checks for the Observe option and handles it if needed.

        :param path: Resource path
        :param msg: CoAP message
        :return: Request Object
        """
        obs = msg.findOption(options.Observe)
        if obs:
            return self._handle_observe(path, msg, rx_record, obs)

        params = self._add_headers(msg)
        username = None

        accept = self._get_accept(msg)

        return GenericRequest(RequestMethod.retrieve,
                              path,
                              id=rx_record.message.token,
                              username=username,
                              params=params,
                              accept=accept,
                              connector=self.connector)

    def _generic_map_delete(self, path, msg, rx_record):
        """Creates an generic delete Request Object from a path and a CoAP
        message

        :param path: Resource path
        :param msg: CoAP message
        :return: Request Object
        """
        params = self._add_headers(msg)
        username = None

        accept = self._get_accept(msg)

        return GenericRequest(RequestMethod.delete,
                              path,
                              id=rx_record.message.token,
                              username=username,
                              params=params,
                              accept=accept,
                              connector=self.connector)

    def _get_addresses(self, family):
        try:
            return self.__cached_addresses[family]
        except KeyError:
            from netifaces import interfaces, ifaddresses

            addresses = self.__cached_addresses[family] = set()

            for interface in interfaces():
                try:
                    ifdata = ifaddresses(interface)[family]
                    ifaddrs = map(lambda x: x.split("%")[0],
                                  pluck("addr", ifdata))
                    addresses.update(ifaddrs)
                except KeyError:
                    pass

            return addresses

    def _getaddrinfo(self, host, family):
        self.logger.debug("Resolving %s", host)
        try:
            info = getaddrinfo(host, 0, family, SOCK_DGRAM)
            return set(map(itemgetter(0), map(itemgetter(-1), info)))
        except gaierror as e:
            self.logger.error("Failed to resolve %s: %s", host, e)
            return set()

    def _resolve_host(self, host):
        if is_ipv4(host):
            return {host}
        return self._getaddrinfo(host, AF_INET)

    def _resolve_host_ipv6(self, host):
        self.logger.debug("Resolving: %s", host)
        if is_ipv6(host):
            return {host}
        # TODO: kca: optimize
        return self._getaddrinfo(host, AF_INET) | \
               self._getaddrinfo(host, AF_INET6)

    def _get_real_path(self, msg):
        """Returns the URI needed for further processing. This is either a
        relative path if the request is to be processed internally or a
        full URI if the request is retargeted

        :param msg: CoAP message
        :return: Uri string
        """
        path = msg.uri
        parsed = urlparse(path)

        # prefer the HOST header
        try:
            uri_host = msg.findOption(options.UriHost).value
            uri_port = msg.findOption(options.UriPort).value
            if ':' in uri_host:
                netloc = '[' + uri_host + ']:' + str(uri_port)
            else:
                netloc = uri_host + ':' + str(uri_port)
        except AttributeError:
            netloc = parsed.netloc
        if not netloc:
            # no absolute URI and no host header -> not retargeted
            return path

        if netloc[0] == "[":
            target_host, _, target_port = netloc[1:].partition(']')
            if target_port:
                target_port = target_port[1:]
        else:
            target_host, _, target_port = netloc.partition(":")

        if not target_port:
            target_port = "5684"

        if target_port == self.server_port and self._resolve_host(
                target_host) & self.__addresses:
            # port and host match -> not retargeted
            return urlunparse(ParseResult("", "", *parsed[2:]))

        # request is retargeted
        #
        # construct full URI if needed
        if not parsed.netloc:
            path = netloc + path
            if not parsed.scheme:
                path = "coap://" + path
        elif not parsed.scheme:
            path = "coap://" + path

        return path

    def handle_block1(self, block1, rx_record, remote, msg):
        """Handles the presence of the Block1 Option.

        Block1 informs the server that the payload of a client request is
        fragmented.
        This function aggregates the various fragments, and queries the client
        for the next fragment.

        :param block1: Block1 option Object
        :param rx_record: CoAP message transfer information
        :param remote: tuple(Client IP, Client PORT)
        :param msg: CoAP message
        :return: Completed payload or None if the payload is not complete
        """
        try:
            self.block1_pending_payload[remote] += msg.payload
        except (KeyError, TypeError):
            if block1.block_number != 0:
                # We discard fragments with block number > 0 if we haven't
                # received the first one yet
                return None
            self.block1_pending_payload[remote] = msg.payload

        if block1.more:
            msg = connection.Message(connection.Message.ACK,
                                     code=constants.CONTINUE)
            # block1.block_number += 1
            msg.addOption(block1)
            self.server.sendto(
                msg._pack(rx_record.transaction_id, rx_record.message.token),
                remote)
            return None
        payload = self.block1_pending_payload[remote]
        self.block1_pending_payload[remote] = None
        return payload

    def handle_block2(self, block2, remote, mesg):
        """Handles the presence of the Block2 Option.

        Block2 informs the server that the payload of a server response has to
        be fragmented.
        This function returns a specific fragment of a message, as requested by
        a client.

        :param block2: Block2 option Object
        :param remote: tuple(Client IP, Client PORT)
        :param mesg: CoAP message
        :return: CoAP message containing a the requested fragment
        """
        msg = copy(mesg)
        length = 2**block2.size_exponent
        start = length * block2.block_number
        end = start + length
        if end <= len(msg.payload):
            more = True
        else:
            more = False
            end = len(msg.payload)
            # This means the last block has to be requested before a new request
            # with block is created
            self.block2_pending_payload[remote] = None
        msg.payload = msg.payload[start:end]
        new_block2 = options.Block2(block_number=block2.block_number,
                                    more=more,
                                    size_exponent=block2.size_exponent)
        msg.replaceOption(new_block2)

        return msg

    def _get_accept(self, msg):
        """Retrives the Accept option value from a CoAP message.

        :param msg: CoAP message
        :return: String representation of Accept option
        """
        opt = msg.findOption(options.Accept)
        if opt:
            accept = opt.value_as_string
        else:
            accept = msg.content_type or None

        return accept

    def _generate_error(self, e):
        """Generates a CoAP RST message from the exception e.

        :param e: Exception
        :return: CoAP Message
        """
        code = constants.INTERNAL_SERVER_ERROR
        data = str(e)
        return connection.Message(connection.Message.RST,
                                  code=code,
                                  payload=data)

    def process(self, rx_record, remote):
        """Processes a CoAP message using its transfer information.

        Triggers the different options handlers if needed.
        Performs a mapping between RESTful methods and ETSI RequestIndications.

        :param rx_record: CoAP message transfer information
        :param remote: tuple(Client IP, Client PORT)
        """
        self.logger.debug("process: %s (%s)", rx_record, remote)
        msg = rx_record.message
        block1 = rx_record.message.findOption(options.Block1)
        if block1:
            block_payload = self.handle_block1(block1, rx_record, remote, msg)
            if not msg or not block_payload:
                return
            msg.payload = block_payload
        block2 = rx_record.message.findOption(options.Block2)
        try:
            self.block2_pending_payload[remote]
        except KeyError:
            self.block2_pending_payload[remote] = None
        finally:
            block2_pending_payload = self.block2_pending_payload[remote]

        if block2 and block2_pending_payload:
            msg = self.handle_block2(block2, remote, block2_pending_payload)
            return self.server.sendto(
                msg._pack(rx_record.transaction_id, rx_record.message.token),
                remote)

        generic_mappers = {
            constants.PUT: self._generic_map_put,
            constants.POST: self._generic_map_post,
            constants.GET: self._generic_map_get,
            constants.DELETE: self._generic_map_delete
        }
        path = self._get_real_path(msg)

        mapping_function = generic_mappers[msg.code]

        generic_req = mapping_function(path, msg, rx_record)

        def handle_generic_result(result):
            """Handles a successful response from the Request handler.

            Generates CoAP Response from a response after converting it to a
            generic Response Object.
            Triggers Block2 fragmentation if needed.

            :param result: response Object
            """
            # result = res
            self.logger.debug("handle_generic_result(%s)", vars(result))
            if result.statusCode == 202:
                response_msg = connection.Message(
                    connection.Message.ACK,
                    code=http2coap_codes[result.statusCode],
                    payload="Request Accepted")
            else:
                pt = rx_record.message.code
                if pt == constants.GET:
                    accept = self._get_accept(rx_record.message)
                    content_type, data = serialize_generic_result(
                        result, accept=accept)
                    if data is None:
                        response_msg = connection.Message(
                            connection.Message.ACK,
                            code=http2coap_codes[result.statusCode])
                    else:
                        response_msg = connection.Message(
                            connection.Message.ACK,
                            code=http2coap_codes[result.statusCode],
                            content_type=content_type,
                            payload=data)
                elif pt == constants.POST:
                    accept = self._get_accept(rx_record.message)
                    content_type, data = serialize_generic_result(
                        result, accept=accept)
                    if data is None:
                        response_msg = connection.Message(
                            connection.Message.ACK,
                            code=http2coap_codes[result.statusCode])
                    else:
                        response_msg = connection.Message(
                            connection.Message.ACK,
                            code=http2coap_codes[result.statusCode],
                            # Set location option
                            #  FIXME: needs to be handled somewhere else
                            # location=(generic_req.path + '/' +
                            #           generic_req.params.get('nm', "")),
                            location=result.location,
                            content_type=content_type,
                            payload=data)
                elif pt == constants.PUT:
                    response_msg = connection.Message(
                        connection.Message.ACK,
                        code=http2coap_codes[result.statusCode])
                elif pt == constants.DELETE:
                    response_msg = connection.Message(
                        connection.Message.ACK,
                        code=http2coap_codes[result.statusCode])
                else:
                    raise NotImplementedError("Coap result mapping for %s", pt)
            self.logger.debug("Sending CoAP reply: %s", response_msg)

            block2 = rx_record.message.findOption(options.Block2)
            if block2:
                self.block2_pending_payload[remote] = response_msg
                response_msg = self.handle_block2(block2, remote, response_msg)

            elif (response_msg.payload
                  and len(response_msg.payload) > 2**self.block_size_exponent):
                nr_blocks, r = divmod(len(response_msg.payload),
                                      2**self.block_size_exponent)
                if r > 0:
                    nr_blocks += 1

                self.logger.debug(
                    "Message is too long, sending first "
                    "fragment (of %s)", nr_blocks)
                block2 = options.Block2(block_number=0,
                                        more=True,
                                        size_exponent=self.block_size_exponent)
                self.block2_pending_payload[remote] = response_msg
                response_msg = self.handle_block2(block2, remote, response_msg)

            if block1:
                response_msg.addOption(block1)
            self.server.sendto(
                response_msg._pack(rx_record.transaction_id,
                                   rx_record.message.token), remote)
            self.actual_requests.remove(
                (rx_record.transaction_id, rx_record.message.token))

        def handle_error(x):
            """Handles a failed response from the RequestIndication handler.

            Generates CoAP Response from ETSI ResponseConfirmation Object.

            :param x: ETSI ResponseConfirmation Object
            """
            self.logger.debug("handle_error(%s)", vars(result))
            try:
                code = constants.http2coap_codes[x.statusCode]
            except AttributeError:
                code = constants.INTERNAL_SERVER_ERROR
            except KeyError:
                self.logger.warning(
                    "Failed to map result code to coap: "
                    "%s (%s)", x.statusCode, x)
                code = constants.INTERNAL_SERVER_ERROR

            accept = self._get_accept(rx_record.message)
            content_type, data = encode_error(x, accept=accept)

            msg = connection.Message(connection.Message.RST,
                                     code=code,
                                     payload=data,
                                     content_type=content_type)

            self.logger.debug("Sending CoAP error reply: %s", msg)
            self.server.sendto(
                msg._pack(rx_record.transaction_id, rx_record.message.token),
                remote)
            self.actual_requests.remove(
                (rx_record.transaction_id, rx_record.message.token))

        try:
            result_promise = self.request_handler(generic_req)
            result = result_promise.get()
            if isinstance(result, ErrorResponse):
                return handle_error(result)
        except ErrorResponse as result:
            return handle_error(result)
        except Exception as exc:
            self.logger.exception("Caught exception while handling request")
            return handle_error(exc)

        return handle_generic_result(result)

    @staticmethod
    def get_id_and_token(packed):
        # rst: copy of the begin of the Connection.decode function before
        # the potential UnrecognizedOptionError
        vtoc = ord(packed[0])
        if 1 != 0x03 & (vtoc >> 6):
            raise Exception()
        # transaction_type = 0x03 & (vtoc >> 4)
        token_len = (vtoc & 0x0F)
        (_, transaction_id) = struct.unpack('!BH', packed[1:4])
        token = packed[4:4 + token_len]
        return transaction_id, token

    def handle_request(self, message, remote):
        req = self.get_id_and_token(message)
        if req in self.actual_requests:
            return

        self.actual_requests.append(req)
        self.req_queue.put((message, remote))

    def _handle_request(self, message, remote):
        """Entry points of requests, converts a buffer into CoAP message
        transfer information

        :param message: Buffer containing a CoAP message
        :param remote: tuple(Client IP, Client Port)
        """

        if message and remote:
            self.remote = remote
            # TODO(rst): put this later into constants, when coap lib is updated
            # TODO:      newer versions
            CONSTANTS_EMPTY = 0
            CONSTANTS_NOT_IMPLEMENTED = 161  # 5.01
            try:
                rx_record = connection.ReceptionRecord(None, message, remote)
                if (rx_record.message.code == CONSTANTS_EMPTY
                        and rx_record.message.transaction_type
                        == connection.Message.RST):
                    return
            except UnrecognizedOptionError:
                code = CONSTANTS_NOT_IMPLEMENTED
                msg = connection.Message(connection.Message.RST, code=code)
                self.server.sendto(msg._pack(*self.get_id_and_token(message)),
                                   remote)
                raise UnrecognizedOptionError
            else:
                return self.process(rx_record, remote)
                # start_new_thread(self.process, (rx_record, remote))
                # self.req_queue.put((rx_record, remote))

    def request_runner(self):
        while True:
            message, remote = self.req_queue.get()
            self._handle_request(message, remote)
            # start_new_thread(self._handle_request, (message, remote))

    def start(self):
        """Starts the Server"""
        self.logger.debug("Coap Server launched")
        self.server.start()

    def stop(self):
        """Stops the Server gracefully"""
        self.server.stop()
コード例 #16
0
ファイル: bjdns2_client.py プロジェクト: zhezhe168/bjdns
class Bjdns2:
    def __init__(self, listen, bjdns2_url):
        self.cache = Cache()

        ip, port_str = listen.split(':')
        self.server = DatagramServer((ip, int(port_str)), self.handle)
        self.session = requests.Session()

        url = urlparse(bjdns2_url).netloc
        self.bjdns2_host = url[:url.rfind(':')]
        # self.bjdns2_ip = bjdns2_ip

    def query_by_https(self, host, cli_ip):
        url_template = bjdns2_url + '/?dn={}&ip={}'

        # if host == self.bjdns2_host:
        #     return self.bjdns2_ip, 3600

        # else:
        if is_private_ip(cli_ip):
            url = url_template.format(host, '')
        else:
            url = url_template.format(host, cli_ip)

        r = self.session.get(url)
        result = json.loads(r.text)
        if result['Status'] == 0:
            self.cache.write(cli_ip, result['Question'][0], result, None)
            ip, ttl = resp_from_json(result)
            return ip, ttl
        else:
            return '', 0

    def query(self, data, host, q_type, cli_addr) -> bytes:
        src_ip, _ = cli_addr
        question = dict(name=host, type=q_type)
        cache_resp = self.cache.select(src_ip, question)

        if cache_resp:
            if host == self.bjdns2_host or q_type != 1:
                resp = data[:2] + cache_resp
                log(cli_addr, '[cache]', '[Type:{}]'.format(q_type), host)
            else:
                ip, ttl = resp_from_json(cache_resp)
                log(cli_addr, '[cache]', host, ip, '(ttl:{})'.format(ttl))
                resp = make_data(data, ip, ttl)

        else:
            if host == self.bjdns2_host or q_type != 1:
                resp = query_by_udp(data)
                self.cache.write(src_ip, question, None, resp[2:])
                log(cli_addr, '[Type:{}]'.format(q_type), host)

            else:
                ip, ttl = self.query_by_https(host, src_ip)
                log(cli_addr, host, ip, '(ttl:{})'.format(ttl))
                resp = make_data(data, ip, ttl)

        # if ip:
        # log(data, resp)
        return resp
        # else:
        #     return b''

    def handle(self, data, cli_addr):
        host, q_type = parse_query(data)

        # if host == self.bjdns2_host or type != 1:
        #     log(host, type)
        #     resp = query_by_udp(data)
        #     log(cli_addr, '[Type:{}]'.format(type), host)

        # elif type == 1:
        try:
            resp = self.query(data, host, q_type, cli_addr)
        except Exception as e:
            log(e)
            resp = b''

        self.server.sendto(resp, cli_addr)

    def start(self):
        self.server.serve_forever()
コード例 #17
0
ファイル: protocol.py プロジェクト: nguyenquangminh/raiden
class UDPTransport:
    def __init__(self, discovery, udpsocket, throttle_policy, config):
        # these values are initialized by the start method
        self.queueids_to_queues: typing.Dict
        self.raiden: 'RaidenService'

        self.discovery = discovery
        self.config = config

        self.retry_interval = config['retry_interval']
        self.retries_before_backoff = config['retries_before_backoff']
        self.nat_keepalive_retries = config['nat_keepalive_retries']
        self.nat_keepalive_timeout = config['nat_keepalive_timeout']
        self.nat_invitation_timeout = config['nat_invitation_timeout']

        self.event_stop = Event()

        self.greenlets = list()
        self.addresses_events = dict()

        # Maps the message_id to a SentMessageState
        self.messageids_to_asyncresults = dict()

        # Maps the addresses to a dict with the latest nonce (using a dict
        # because python integers are immutable)
        self.nodeaddresses_to_nonces = dict()

        cache = cachetools.TTLCache(
            maxsize=50,
            ttl=CACHE_TTL,
        )
        cache_wrapper = cachetools.cached(cache=cache)
        self.get_host_port = cache_wrapper(discovery.get)

        self.throttle_policy = throttle_policy
        self.server = DatagramServer(udpsocket, handle=self._receive)

    def start(self, raiden, queueids_to_queues):
        self.raiden = raiden
        self.queueids_to_queues = dict()

        # server.stop() clears the handle. Since this may be a restart the
        # handle must always be set
        self.server.set_handle(self._receive)

        for (recipient, queue_name), queue in queueids_to_queues.items():
            queue_copy = list(queue)
            self.init_queue_for(recipient, queue_name, queue_copy)

        self.server.start()

    def stop_and_wait(self):
        # Stop handling incoming packets, but don't close the socket. The
        # socket can only be safely closed after all outgoing tasks are stopped
        self.server.stop_accepting()

        # Stop processing the outgoing queues
        self.event_stop.set()
        gevent.wait(self.greenlets)

        # All outgoing tasks are stopped. Now it's safe to close the socket. At
        # this point there might be some incoming message being processed,
        # keeping the socket open is not useful for these.
        self.server.stop()

        # Calling `.close()` on a gevent socket doesn't actually close the underlying os socket
        # so we do that ourselves here.
        # See: https://github.com/gevent/gevent/blob/master/src/gevent/_socket2.py#L208
        # and: https://groups.google.com/forum/#!msg/gevent/Ro8lRra3nH0/ZENgEXrr6M0J
        try:
            self.server._socket.close()  # pylint: disable=protected-access
        except socket.error:
            pass

        # Set all the pending results to False
        for async_result in self.messageids_to_asyncresults.values():
            async_result.set(False)

    def get_health_events(self, recipient):
        """ Starts a healthcheck taks for `recipient` and returns a
        HealthEvents with locks to react on its current state.
        """
        if recipient not in self.addresses_events:
            self.start_health_check(recipient)

        return self.addresses_events[recipient]

    def start_health_check(self, recipient):
        """ Starts a task for healthchecking `recipient` if there is not
        one yet.
        """
        if recipient not in self.addresses_events:
            ping_nonce = self.nodeaddresses_to_nonces.setdefault(
                recipient,
                {'nonce': 0},  # HACK: Allows the task to mutate the object
            )

            events = HealthEvents(
                event_healthy=Event(),
                event_unhealthy=Event(),
            )

            self.addresses_events[recipient] = events

            self.greenlets.append(
                gevent.spawn(
                    healthcheck,
                    self,
                    recipient,
                    self.event_stop,
                    events.event_healthy,
                    events.event_unhealthy,
                    self.nat_keepalive_retries,
                    self.nat_keepalive_timeout,
                    self.nat_invitation_timeout,
                    ping_nonce,
                ))

    def init_queue_for(self, recipient, queue_name, items):
        """ Create the queue identified by the pair `(recipient, queue_name)`
        and initialize it with `items`.
        """
        queueid = (recipient, queue_name)
        queue = self.queueids_to_queues.get(queueid)
        assert queue is None

        queue = NotifyingQueue(items=items)
        self.queueids_to_queues[queueid] = queue

        events = self.get_health_events(recipient)

        self.greenlets.append(
            gevent.spawn(
                single_queue_send,
                self,
                recipient,
                queue,
                self.event_stop,
                events.event_healthy,
                events.event_unhealthy,
                self.retries_before_backoff,
                self.retry_interval,
                self.retry_interval * 10,
            ))

        if log.isEnabledFor(logging.DEBUG):
            log.debug(
                'new queue created for',
                node=pex(self.raiden.address),
                token=pex(queue_name),
                to=pex(recipient),
            )

        return queue

    def get_queue_for(self, recipient, queue_name):
        """ Return the queue identified by the pair `(recipient, queue_name)`.

        If the queue doesn't exist it will be instantiated.
        """
        queueid = (recipient, queue_name)
        queue = self.queueids_to_queues.get(queueid)

        if queue is None:
            items = ()
            queue = self.init_queue_for(recipient, queue_name, items)

        return queue

    def send_async(self, queue_name, recipient, message):
        """ Send a new ordered message to recipient.

        Messages that use the same `queue_name` are ordered.
        """

        if not isaddress(recipient):
            raise ValueError('Invalid address {}'.format(pex(recipient)))

        # These are not protocol messages, but transport specific messages
        if isinstance(message, (Delivered, Ping, Pong)):
            raise ValueError('Do not use send for {} messages'.format(
                message.__class__.__name__))

        messagedata = message.encode()
        if len(messagedata) > UDP_MAX_MESSAGE_SIZE:
            raise ValueError('message size exceeds the maximum {}'.format(
                UDP_MAX_MESSAGE_SIZE))

        # message identifiers must be unique
        message_id = message.message_identifier

        # ignore duplicates
        if message_id not in self.messageids_to_asyncresults:
            self.messageids_to_asyncresults[message_id] = AsyncResult()

            queue = self.get_queue_for(recipient, queue_name)
            queue.put((messagedata, message_id))

            if log.isEnabledFor(logging.DEBUG):
                log.debug(
                    'MESSAGE QUEUED',
                    node=pex(self.raiden.address),
                    queue_name=queue_name,
                    to=pex(recipient),
                    message=message,
                )

    def maybe_send(self, recipient, message):
        """ Send message to recipient if the transport is running. """

        if not isaddress(recipient):
            raise InvalidAddress('Invalid address {}'.format(pex(recipient)))

        messagedata = message.encode()
        host_port = self.get_host_port(recipient)

        self.maybe_sendraw(host_port, messagedata)

    def maybe_sendraw_with_result(self, recipient, messagedata, message_id):
        """ Send message to recipient if the transport is running.

        Returns:
            An AsyncResult that will be set once the message is delivered. As
            long as the message has not been acknowledged with a Delivered
            message the function will return the same AsyncResult.
        """
        async_result = self.messageids_to_asyncresults.get(message_id)
        if async_result is None:
            async_result = AsyncResult()
            self.messageids_to_asyncresults[message_id] = async_result

        host_port = self.get_host_port(recipient)
        self.maybe_sendraw(host_port, messagedata)

        return async_result

    def maybe_sendraw(self, host_port, messagedata):
        """ Send message to recipient if the transport is running. """

        # Don't sleep if timeout is zero, otherwise a context-switch is done
        # and the message is delayed, increasing it's latency
        sleep_timeout = self.throttle_policy.consume(1)
        if sleep_timeout:
            gevent.sleep(sleep_timeout)

        # Check the udp socket is still available before trying to send the
        # message. There must be *no context-switches after this test*.
        if hasattr(self.server, 'socket'):
            self.server.sendto(
                messagedata,
                host_port,
            )

    def _receive(self, data, host_port):  # pylint: disable=unused-argument
        try:
            self.receive(data)
        except RaidenShuttingDown:  # For a clean shutdown
            return

    def receive(self, messagedata):
        """ Handle an UDP packet. """
        # pylint: disable=unidiomatic-typecheck

        if len(messagedata) > UDP_MAX_MESSAGE_SIZE:
            log.error(
                'INVALID MESSAGE: Packet larger than maximum size',
                node=pex(self.raiden.address),
                message=hexlify(messagedata),
                length=len(messagedata),
            )
            return

        message = decode(messagedata)

        if type(message) == Pong:
            self.receive_pong(message)
        elif type(message) == Ping:
            self.receive_ping(message)
        elif type(message) == Delivered:
            self.receive_delivered(message)
        elif message is not None:
            self.receive_message(message)
        elif log.isEnabledFor(logging.ERROR):
            log.error(
                'INVALID MESSAGE: Unknown cmdid',
                node=pex(self.raiden.address),
                message=hexlify(messagedata),
            )

    def receive_message(self, message):
        """ Handle a Raiden protocol message.

        The protocol requires durability of the messages. The UDP transport
        relies on the node's WAL for durability. The message will be converted
        to a state change, saved to the WAL, and *processed* before the
        durability is confirmed, which is a stronger property than what is
        required of any transport.
        """
        # pylint: disable=unidiomatic-typecheck

        if on_udp_message(self.raiden, message):

            # Sending Delivered after the message is decoded and *processed*
            # gives a stronger guarantee than what is required from a
            # transport.
            #
            # Alternatives are, from weakest to strongest options:
            # - Just save it on disk and asynchronously process the messages
            # - Decode it, save to the WAL, and asynchronously process the
            #   state change
            # - Decode it, save to the WAL, and process it (the current
            #   implementation)
            delivered_message = Delivered(message.message_identifier)
            self.raiden.sign(delivered_message)

            self.maybe_send(
                message.sender,
                delivered_message,
            )

    def receive_delivered(self, delivered: Delivered):
        """ Handle a Delivered message.

        The Delivered message is how the UDP transport guarantees persistence
        by the partner node. The message itself is not part of the raiden
        protocol, but it's required by this transport to provide the required
        properties.
        """
        processed = ReceiveDelivered(delivered.delivered_message_identifier)
        self.raiden.handle_state_change(processed)

        message_id = delivered.delivered_message_identifier
        async_result = self.raiden.protocol.messageids_to_asyncresults.get(
            message_id)

        # clear the async result, otherwise we have a memory leak
        if async_result is not None:
            del self.messageids_to_asyncresults[message_id]
            async_result.set()

    # Pings and Pongs are used to check the health status of another node. They
    # are /not/ part of the raiden protocol, only part of the UDP transport,
    # therefore these messages are not forwarded to the message handler.
    def receive_ping(self, ping):
        """ Handle a Ping message by answering with a Pong. """

        if ping_log.isEnabledFor(logging.DEBUG):
            ping_log.debug(
                'PING RECEIVED',
                node=pex(self.raiden.address),
                message_id=ping.nonce,
                message=ping,
                sender=pex(ping.sender),
            )

        pong = Pong(ping.nonce)
        self.raiden.sign(pong)

        try:
            self.maybe_send(ping.sender, pong)
        except (InvalidAddress, UnknownAddress) as e:
            log.debug("Couldn't send the `Delivered` message", e=e)

    def receive_pong(self, pong):
        """ Handles a Pong message. """

        message_id = ('ping', pong.nonce, pong.sender)
        async_result = self.messageids_to_asyncresults.get(message_id)

        if async_result is not None:
            if log.isEnabledFor(logging.DEBUG):
                log.debug(
                    'PONG RECEIVED',
                    node=pex(self.raiden.address),
                    message_id=pong.nonce,
                )

            async_result.set(True)

    def get_ping(self, nonce):
        """ Returns a signed Ping message.

        Note: Ping messages don't have an enforced ordering, so a Ping message
        with a higher nonce may be acknowledged first.
        """
        message = Ping(nonce)
        self.raiden.sign(message)
        message_data = message.encode()

        return message_data

    def set_node_network_state(self, node_address, node_state):
        state_change = ActionChangeNodeNetworkState(node_address, node_state)
        self.raiden.handle_state_change(state_change)
コード例 #18
0
class nscl_dm_adapter(Plugin):
    def _init(self, ):
        self._initialized()

    def _start(self, ):
        self.sem = Semaphore()
        self.sem_counter = 0
        self.set_configurations()
        self.api.run_task(self.create_server)
        self.subscribe_nscl()
        self.api.run_task(self.subscribe_dm_server)
        if self.config["enable_test"]:
            pass
            # self.api.run_task(self.send_execute_command)
            # Uncomment to check these operations
            # self.api.run_task(self.send_specific_observation)
            # self.api.run_task(self.send_specific_observation1)
            # self.api.run_task(self.send_cancel_observation)
            #self.api.run_task(self.send_discover_resources)
            #self.api.run_task(self.send_write_attributes)
            #self.api.run_task(self.send_create)
        self._started()

    def _stop(self, ):
        self.local_server.stop()
        self._stopped()

    def set_configurations(self, ):
        self.lwm2m_server_ip = self.config["lwm2m_dm_server_ip"]
        self.lwm2m_server_port = self.config["lwm2m_dm_server_port"]
        self.nscl_dm_adapter_listener_ip = self.config[
            "nscl_dm_adapter_listener_ip"]
        self.nscl_dm_adapter_listener_port = self.config[
            "nscl_dm_adapter_listener_port"]
        self.nscl_dm_adapter_client_ip = self.config[
            "nscl_dm_adapter_client_ip"]
        self.nscl_dm_adapter_client_port = self.config[
            "nscl_dm_adapter_client_port"]

    def create_server(self, ):
        self.local_server = DatagramServer(
            (self.nscl_dm_adapter_listener_ip,
             self.nscl_dm_adapter_listener_port), self.handle_request)
        self.local_server.start()

    def handle_request(self, message, remote):
        rx_record = connection.ReceptionRecord(None, message, remote)
        msg = rx_record.message
        uriQuery = msg.findOption(options.UriQuery)
        self.process(rx_record, remote, uriQuery)

    def process(self, rx_record, remote, uri_query):
        if rx_record.message.transaction_type == connection.Message.CON:
            if constants.POST == rx_record.message.code:
                if self.general_notification_token == rx_record.message.token:
                    self.logger.info("General Notification received")
                    msg = connection.Message(connection.Message.ACK,
                                             code=constants.CREATED)
                    self.local_server.sendto(
                        msg._pack(rx_record.transaction_id), remote)

                    self.process_resources(
                        json.loads(rx_record.message.payload))
                else:
                    self.logger.info("Specific Notification received")
                    msg = connection.Message(connection.Message.ACK,
                                             code=constants.CREATED)
                    self.local_server.sendto(
                        msg._pack(rx_record.transaction_id), remote)

                    payload = json.loads(rx_record.message.payload)
                    observer_ip = payload["observer_ip"]
                    observer_port = payload["observer_port"]
                    del payload["observer_ip"]
                    del payload["observer_port"]
                    self.process_resources(payload,
                                           observer_ip=observer_ip,
                                           observer_port=observer_port)

        elif rx_record.message.transaction_type == connection.Message.NON:
            if self.general_notification_token == rx_record.message.token:
                self.logger.info("General Notification received")
                self.process_resources(json.loads(rx_record.message.payload))
            else:
                self.logger.info("Specific Notification received")
                payload = json.loads(rx_record.message.payload)
                observer_ip = payload["observer_ip"]
                observer_port = payload["observer_port"]
                del payload["observer_ip"]
                del payload["observer_port"]
                self.process_resources(payload,
                                       observer_ip=observer_ip,
                                       observer_port=observer_port)

    def process_resources(self, payload, observer_ip=None, observer_port=None):
        total_resources = payload
        if observer_ip != None and observer_port != None:
            self.logger.info("The notification should be sent to %s:%s",
                             observer_ip, observer_port)

        for ep_name, object_resources in total_resources.iteritems():
            endpoint_name = ep_name
            for object_ids, resources in object_resources.iteritems():
                object_id = object_ids.split("_")[0]
                object_inst_id = object_ids.split("_")[1]
                resources_dict = {}
                for res_ids, res_value in resources["resources"].iteritems():
                    res_id = res_ids.split("_")[0]
                    res_inst_id = res_ids.split("_")[1]
                    res_value = res_value
                    resource_name = lwm2m_dict_objects[str(
                        object_id)]["resource_list"][str(res_id)]["resName"]
                    is_multi_inst = lwm2m_dict_objects[str(
                        object_id)]["resource_list"][str(res_id)]["multiInst"]
                    if not is_multi_inst:
                        resources_dict.update({resource_name: res_value})
                    else:
                        resources_dict.update({
                            resource_name + "_" + str(res_inst_id):
                            res_value
                        })

                self.handle_m2m_server(endpoint_name, object_id,
                                       object_inst_id, res_id, res_inst_id,
                                       resource_name, res_value,
                                       resources_dict)

    def handle_m2m_server(self, endpoint_name, object_id, object_inst_id,
                          res_id, res_inst_id, res_name, res_value,
                          resources_dict):
        preferred_scl = endpoint_name.split("/")[0]
        if endpoint_name.find("attachedDevices") == -1:
            bool_attachedDevices = False
        else:
            attached_device_name = endpoint_name.split("/")[-1]
            bool_attachedDevices = True
        object_name = lwm2m_dict_objects[str(object_id)]["object_name"]
        resource_name = lwm2m_dict_objects[str(object_id)]["resource_list"][
            str(res_id)]["resName"]
        moID_value = lwm2m_dict_objects[str(object_id)]["urn"]
        res_name_res_inst_id = resource_name + "_" + str(res_inst_id)

        def add_parameters(response):
            path = response.resource.path
            resource = ('{"mgmtObjs" : ' + json.dumps(resources_dict) + '}')
            request = UpdateRequestIndication(path,
                                              resource,
                                              content_type="application/json")
            response = self.api.handle_request_indication(request)

        def handle_mgmtobjs(response):
            mgmtobj_exists = False
            for mgmtobj in response.resource.mgmtObjCollection:
                if mgmtobj.name == object_name + "_" + str(object_inst_id):
                    mgmtobj_exists = True
                    path = mgmtobj.path
                    request = RetrieveRequestIndication(path)
                    response = self.api.handle_request_indication(request)
                    try:
                        if res_name_res_inst_id in response.value.resource.flex_values:
                            if response.value.resource.flex_values[
                                    res_name_res_inst_id] == str(res_value):
                                continue
                        elif res_name in response.value.resource.flex_values:
                            if response.value.resource.flex_values[
                                    res_name] == str(res_value):
                                continue
                    except:
                        pass
                    resource = ('{"mgmtObjs" : ' + json.dumps(resources_dict) +
                                '}')
                    request = UpdateRequestIndication(
                        path, resource, content_type="application/json")
                    response = self.api.handle_request_indication(request)
                    break

            if not mgmtobj_exists:
                mgmtobj_ = MgmtObj(id=str(object_name) + "_" +
                                   str(object_inst_id),
                                   moID=moID_value)
                path = response.resource.path
                request = CreateRequestIndication(path, mgmtobj_)
                response = self.api.handle_request_indication(request)
                response.then(add_parameters)

        def retrieve_mgmtobjs(response):
            path = response.resource.path + "/mgmtObjs"
            request = RetrieveRequestIndication(path)
            response = self.api.handle_request_indication(request)
            response.then(handle_mgmtobjs)

        def handle_attached_devices(response):
            attached_device_exists = False
            for attached_device in response.resource.attachedDeviceCollection:
                if attached_device.name == attached_device_name:
                    attached_device_exists = True
                    path = attached_device.path + "/mgmtObjs"
                    request = RetrieveRequestIndication(path)
                    response = self.api.handle_request_indication(request)
                    response.then(handle_mgmtobjs)
                    break
            if not attached_device_exists:
                attached_device_object = AttachedDevice(
                    id=attached_device_name)
                path = response.resource.path
                request = CreateRequestIndication(
                    path=path, resource=attached_device_object)
                response = self.api.handle_request_indication(request)
                response.then(retrieve_mgmtobjs)

        def retrieve_attached_devices(response):
            path = response.resource.path + "/attachedDevices"
            request = RetrieveRequestIndication(path)
            response = self.api.handle_request_indication(request)
            response.then(handle_attached_devices)

        def handle_scl(response):
            scl_exists = False
            for _scl in response.resource.sclCollection:
                if _scl.name == preferred_scl:
                    scl_exists = True
                    if bool_attachedDevices:
                        path = _scl.path + "/attachedDevices"
                    else:
                        path = _scl.path + "/mgmtObjs"
                    request = RetrieveRequestIndication(path)
                    response = self.api.handle_request_indication(request)
                    if bool_attachedDevices:
                        response.then(handle_attached_devices)
                    else:
                        response.then(handle_mgmtobjs)
                    break
            if not scl_exists:
                scl_object = Scl(sclId=preferred_scl,
                                 link="127.0.0.1",
                                 sclType="GSCL",
                                 mgmtProtocolType="LWM2M")
                request = CreateRequestIndication(path="/m2m/scls",
                                                  resource=scl_object)
                response = self.api.handle_request_indication(request)
                if bool_attachedDevices:
                    response.then(retrieve_attached_devices)
                else:
                    response.then(retrieve_mgmtobjs)

        path = "/m2m/scls"
        request = RetrieveRequestIndication(path)
        response = self.api.handle_request_indication(request)
        response.then(handle_scl)

    def _handle_mgmtcmd_created(self, instance, request_indication):
        pass

    def _handle_mgmtcmd_updated(self, instance, request_indication):
        pass

    def _handle_mgmtobj_created(self, instance, request_indication):
        pass

    def _handle_mgmtobj_updated(self, instance, request_indication):
        filter_keyword = "TransportMgmtPolicy"
        filter_keyword1 = "DeviceCapability"

        mgmtobj_name = instance.path.split("/")[-1]
        if mgmtobj_name.startswith(filter_keyword):
            self.handle_transport_mgmt_policy(instance, mgmtobj_name)
        elif mgmtobj_name.startswith(filter_keyword1):
            self.handle_device_capability(instance, mgmtobj_name,
                                          request_indication)

    def handle_device_capability(self, instance, mgmtobj_name,
                                 request_indication):
        generate_endpoint = instance.path.split("/")[3:-2]
        endpoint_name = "/".join(generate_endpoint)
        object_name = mgmtobj_name.split("_")[0]
        object_id = lwm2m_reverse_dict_objects[object_name]["object_id"]
        object_inst_id = mgmtobj_name.split("_")[1]

        if "opEnable" in request_indication.resource and "opDisable" in request_indication.resource:
            return
        elif "opEnable" in request_indication.resource:
            res_id = 5
            res_inst_id = 0
        elif "opDisable" in request_indication.resource:
            res_id = 6
            res_inst_id = 0
        else:
            return
        self.send_execute_resource(endpoint_name, object_id, object_inst_id,
                                   res_id, res_inst_id)

    def handle_transport_mgmt_policy(self, instance, mgmtobj_name):
        res_value_exists = False
        resources_dict = {}
        total_dict = {}
        endpoint_dict = {}
        generate_endpoint = instance.path.split("/")[3:-2]
        endpoint_name = "/".join(generate_endpoint)

        object_name = mgmtobj_name.split("_")[0]
        object_id = lwm2m_reverse_dict_objects[object_name]["object_id"]
        object_inst_id = mgmtobj_name.split("_")[1]
        for key, value in instance.flex_values.iteritems():
            res_name = key.split("_")[0]
            try:
                res_inst_id = key.split("_")[1]
            except:
                res_inst_id = 0
            res_value = value
            res_id = lwm2m_reverse_dict_objects[object_name]["resource_list"][
                res_name]["resId"]
            resources_dict.update(
                {res_id: {
                    "res_inst_id": res_inst_id,
                    "res_value": res_value
                }})
            if res_value != "" and not res_value_exists:
                res_value_exists = True

        if res_value_exists:
            self.logger.info("Sending the Resource Updates to LWM2M Server")
            payload = json.dumps(resources_dict)
            content_type = "application/json"

            request = lwm2m_api()
            self.sem.acquire()
            client_port = self.generate_client_port()
            response = request.write_resource(self.lwm2m_server_ip,
                                              self.lwm2m_server_port,
                                              endpoint_name,
                                              object_id,
                                              payload,
                                              content_type,
                                              object_inst_id=object_inst_id,
                                              client_port=client_port)
            self.sem.release()

    def generate_client_port(self, ):
        if self.sem_counter >= 1000:
            self.sem_counter = 0

        self.sem_counter += 1

        sem_counter = self.sem_counter

        client_port = self.nscl_dm_adapter_client_port + sem_counter
        return client_port

    def subscribe_dm_server(self, ):
        self.logger.info(
            "Trying to subscribe to LWM2M DM Server for General Subscription")
        payload = json.dumps({"listener_ip": self.nscl_dm_adapter_listener_ip, "listener_port": \
            self.nscl_dm_adapter_listener_port})
        content_type = "application/json"
        request = lwm2m_api()
        response = request.observe_resource(
            self.lwm2m_server_ip,
            self.lwm2m_server_port,
            payload=payload,
            content_type=content_type,
            client_port=self.generate_client_port())

        def _handle_response(response):
            self.logger.info(
                "Successfully subscribed to LWM2M DM Server for General Subscription"
            )
            self.general_notification_token = response.token

        def _handle_error(*args):
            self.subscribe_dm_server()

        response.then(_handle_response, _handle_error)

    def subscribe_nscl(self, ):
        self.events.resource_created.register_handler(
            self._handle_mgmtobj_created, MgmtObj)
        self.events.resource_updated.register_handler(
            self._handle_mgmtobj_updated, MgmtObj)
        self.events.resource_created.register_handler(
            self._handle_mgmtcmd_created, MgmtCmd)
        self.events.resource_updated.register_handler(
            self._handle_mgmtcmd_updated, MgmtCmd)

    def send_discover_resources(self, ):
        sleep(20)
        self.logger.info("Sending discover request to Dm server")
        server_ip = self.lwm2m_server_ip
        server_port = self.lwm2m_server_port
        payload = "/.well-known/core"
        request = lwm2m_api()
        response = request.discover_resources(
            server_ip,
            server_port,
            payload=payload,
            client_port=self.generate_client_port())
        discover = Discovery()
        payload = json.loads(response.payload)
        discover.display_all_resources(payload)

    def send_write_attributes(self, ):
        sleep(10)
        self.logger.info("Sending attributes info to DM server")
        server_ip = self.lwm2m_server_ip
        server_port = self.lwm2m_server_port

        endpoint_name = "emulated_device_nb_0"
        object_id = 3
        object_inst_id = 0
        res_id = 1
        res_inst_id = 0

        pmax = 50
        pmin = 10
        gt = None
        lt = None
        st = None
        cancel = None

        content_type = "application/json"
        payload = json.dumps({
            "pmax": pmax,
            "pmin": pmin,
            "gt": gt,
            "lt": lt,
            "st": st,
            "cancel": cancel
        })

        request = lwm2m_api()
        response = request.write_attributes(
            server_ip,
            server_port,
            endpoint_name,
            object_id,
            payload,
            content_type,
            object_inst_id=object_inst_id,
            res_id=res_id,
            res_inst_id=res_inst_id,
            client_port=self.generate_client_port())

    def send_create(self, ):
        sleep(10)
        self.logger.info("Sending create info to DM server")

        server_ip = self.lwm2m_server_ip
        server_port = self.lwm2m_server_port

        endpoint_name = "emulated_device_nb_0"
        object_id = 3
        object_inst_id = 4
        res_id = 0
        res_inst_id = 0
        res_value = "fokus"
        res_id_res_inst_id = str(res_id) + "_" + str(res_inst_id)
        payload = {}
        res_id_res_inst_id = str(res_id) + "_" + str(res_inst_id)
        payload[res_id_res_inst_id] = {
            "res_id": res_id,
            "res_inst_id": res_inst_id,
            "res_value": res_value
        }
        content_type = "application/json"

        request = lwm2m_api()
        response = request.create_object_instance(
            server_ip,
            server_port,
            endpoint_name,
            object_id,
            json.dumps(payload),
            content_type,
            object_inst_id=object_inst_id,
            client_port=self.generate_client_port())

    def send_specific_observation(self, ):
        sleep(15)
        self.logger.info("Sending specific observation to DM server")

        app_ip = "localhost"
        app_port = "1111"

        server_ip = self.lwm2m_server_ip
        server_port = self.lwm2m_server_port

        endpoint_name = "gscl/attachedDevices/PulseOximeter"
        object_id = 4200
        object_inst_id = 0
        res_id = 1
        res_inst_id = 0

        request = lwm2m_api()
        response = request.observe_resource(
            server_ip,
            server_port,
            app_ip=app_ip,
            app_port=app_port,
            endpoint_name=endpoint_name,
            object_id=object_id,
            object_inst_id=object_inst_id,
            res_id=res_id,
            res_inst_id=res_inst_id,
            client_port=self.generate_client_port())

        def _handle_response(response):
            self.logger.info("response token: %s", response.token)

        response.then(_handle_response)

    def send_specific_observation1(self, ):
        sleep(20)
        self.logger.info("Sending specific observation to DM server")

        app_ip = "localhost"
        app_port = "1115"

        server_ip = self.lwm2m_server_ip
        server_port = self.lwm2m_server_port

        endpoint_name = "gscl_PulseOximeter"
        object_id = 4200
        object_inst_id = 0
        res_id = 0
        res_inst_id = 0

        request = lwm2m_api()
        response = request.observe_resource(
            server_ip,
            server_port,
            app_ip=app_ip,
            app_port=app_port,
            endpoint_name=endpoint_name,
            object_id=object_id,
            object_inst_id=object_inst_id,
            res_id=res_id,
            res_inst_id=res_inst_id,
            client_port=self.generate_client_port())

        def _handle_response(response):
            self.logger.info("response token: %s", response.token)

        response.then(_handle_response)

    def send_cancel_observation(self, ):
        sleep(22)
        self.logger.info("Sending Cancel Observation to DM server")

        app_ip = "localhost"
        app_port = "1111"

        server_ip = self.lwm2m_server_ip
        server_port = self.lwm2m_server_port

        endpoint_name = "gscl/attachedDevices/PulseOximeter"
        object_id = 4200
        object_inst_id = 0
        res_id = 1
        res_inst_id = 0

        request = lwm2m_api()
        response = request.cancel_observe_resource(
            server_ip,
            server_port,
            app_ip,
            app_port,
            endpoint_name,
            object_id,
            object_inst_id=object_inst_id,
            res_id=res_id,
            res_inst_id=res_inst_id,
            client_port=self.generate_client_port())

        def _handle_response(response):
            self.logger.info("response token: %s", response.token)
            self.logger.info("response %s", response.payload)

        response.then(_handle_response)

    def send_execute_resource(self,
                              endpoint_name,
                              object_id,
                              object_inst_id,
                              res_id,
                              res_inst_id,
                              payload=None):
        self.logger.info("Sending execution to DM server")

        server_ip = self.lwm2m_server_ip
        server_port = self.lwm2m_server_port

        payload = None
        request = lwm2m_api()
        response = request.execute_resource(
            server_ip,
            server_port,
            endpoint_name,
            object_id,
            object_inst_id,
            res_id,
            res_inst_id=res_inst_id,
            payload=payload,
            client_port=self.generate_client_port())

        self.logger.info("Updating M2M Resource Tree")
        resources_dict = {}
        object_id_res_id = str(object_id) + "/" + str(res_id)
        if object_id_res_id in action_mapping:
            res_id = action_mapping[object_id_res_id]["target_res_id"]
            res_value = action_mapping[object_id_res_id]["target_action"]
            res_name = lwm2m_dict_objects[str(object_id)]["resource_list"][str(
                res_id)]["resName"]
            is_multi_inst = lwm2m_dict_objects[str(
                object_id)]["resource_list"][str(res_id)]["multiInst"]
            if not is_multi_inst:
                resources_dict.update({res_name: res_value})
            else:
                resources_dict.update(
                    {res_name + "_" + str(res_inst_id): res_value})
            self.handle_m2m_server(endpoint_name, object_id, object_inst_id,
                                   res_id, res_inst_id, res_name, res_value,
                                   resources_dict)
コード例 #19
0
ファイル: udpnode.py プロジェクト: tetocode/fxarb
class UDPNode(NodeABC):
    def __init__(self, bind_address: Tuple[str, int] = None, handler=None):
        bind_address = bind_address or self.DEFAULT_ADDRESS
        handler = handler or (lambda data, address: None)

        def handle(data: bytes, address: Tuple[str, int]):
            deserialized = self.deserialize(data)
            handler(deserialized, address)

        super().__init__()
        self._bind_address = bind_address
        self._server = None  # type: DatagramServer
        self._stop = False

        def run():
            self._tls.gevent = True
            self._server = DatagramServer(self.bind_address, handle)
            self._server.start()
            while self.is_running() and not self._stop:
                gevent.sleep(0.5)
            self._server.stop()

        self._thread = threading.Thread(target=run, daemon=True)
        self._tls = threading.local()
        self._socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)

    def is_running(self):
        if self._server:
            return self._server.started
        return False

    @property
    def bind_address(self) -> Tuple[str, int]:
        if self._server:
            return self._server.address
        return self._bind_address

    def start(self):
        self._thread.start()
        n = 1000
        for _ in range(n):
            if self.is_running():
                return self
            time.sleep(1.0 / n)
        self.stop()
        raise Exception('start timeouted 1.0sec')

    def stop(self, timeout: float = None):
        self._stop = True
        self.join(timeout=timeout)
        return self

    def join(self, timeout: float = None):
        self._thread.join(timeout=timeout)

    def sendto(self, data: Any, address: Tuple[str, int]):
        serialized = self.serialize(data)
        assert len(serialized) <= 4096, 'len={} {}'.format(
            len(serialized), data)
        try:
            _ = self._tls.gevent
            self._server.sendto(serialized, address)
        except AttributeError:
            self._socket.sendto(serialized, address)

    def serialize(self, obj: Any):
        return pickle.dumps(obj)

    def deserialize(self, obj: Any):
        return pickle.loads(obj)
コード例 #20
0
ファイル: udp_transport.py プロジェクト: onyb/raiden
class UDPTransport(Runnable):
    UDP_MAX_MESSAGE_SIZE = 1200

    def __init__(self, discovery, udpsocket, throttle_policy, config):
        super().__init__()
        # these values are initialized by the start method
        self.queueids_to_queues: typing.Dict
        self.raiden: RaidenService

        self.discovery = discovery
        self.config = config

        self.retry_interval = config['retry_interval']
        self.retries_before_backoff = config['retries_before_backoff']
        self.nat_keepalive_retries = config['nat_keepalive_retries']
        self.nat_keepalive_timeout = config['nat_keepalive_timeout']
        self.nat_invitation_timeout = config['nat_invitation_timeout']

        self.event_stop = Event()
        self.event_stop.set()

        self.greenlets = list()
        self.addresses_events = dict()

        self.messageids_to_asyncresults = dict()

        # Maps the addresses to a dict with the latest nonce (using a dict
        # because python integers are immutable)
        self.nodeaddresses_to_nonces = dict()

        cache = cachetools.TTLCache(
            maxsize=50,
            ttl=CACHE_TTL,
        )
        cache_wrapper = cachetools.cached(cache=cache)
        self.get_host_port = cache_wrapper(discovery.get)

        self.throttle_policy = throttle_policy
        self.server = DatagramServer(udpsocket, handle=self.receive)

    def start(
        self,
        raiden: RaidenService,
        message_handler: MessageHandler,
    ):
        if not self.event_stop.ready():
            raise RuntimeError('UDPTransport started while running')

        self.event_stop.clear()
        self.raiden = raiden
        self.message_handler = message_handler
        self.queueids_to_queues = dict()

        # server.stop() clears the handle. Since this may be a restart the
        # handle must always be set
        self.server.set_handle(self.receive)

        self.server.start()
        super().start()

    def _run(self):
        """ Runnable main method, perform wait on long-running subtasks """
        try:
            self.event_stop.wait()
        except gevent.GreenletExit:  # killed without exception
            self.event_stop.set()
            gevent.killall(self.greenlets)  # kill children
            raise  # re-raise to keep killed status
        except Exception:
            self.stop()  # ensure cleanup and wait on subtasks
            raise

    def stop(self):
        if self.event_stop.ready():
            return  # double call, happens on normal stop, ignore

        self.event_stop.set()

        # Stop handling incoming packets, but don't close the socket. The
        # socket can only be safely closed after all outgoing tasks are stopped
        self.server.stop_accepting()

        # Stop processing the outgoing queues
        gevent.wait(self.greenlets)

        # All outgoing tasks are stopped. Now it's safe to close the socket. At
        # this point there might be some incoming message being processed,
        # keeping the socket open is not useful for these.
        self.server.stop()

        # Calling `.close()` on a gevent socket doesn't actually close the underlying os socket
        # so we do that ourselves here.
        # See: https://github.com/gevent/gevent/blob/master/src/gevent/_socket2.py#L208
        # and: https://groups.google.com/forum/#!msg/gevent/Ro8lRra3nH0/ZENgEXrr6M0J
        try:
            self.server._socket.close()  # pylint: disable=protected-access
        except socket.error:
            pass

        # Set all the pending results to False
        for async_result in self.messageids_to_asyncresults.values():
            async_result.set(False)

    def get_health_events(self, recipient):
        """ Starts a healthcheck task for `recipient` and returns a
        HealthEvents with locks to react on its current state.
        """
        if recipient not in self.addresses_events:
            self.start_health_check(recipient)

        return self.addresses_events[recipient]

    def start_health_check(self, recipient):
        """ Starts a task for healthchecking `recipient` if there is not
        one yet.
        """
        if recipient not in self.addresses_events:
            ping_nonce = self.nodeaddresses_to_nonces.setdefault(
                recipient,
                {'nonce': 0},  # HACK: Allows the task to mutate the object
            )

            events = healthcheck.HealthEvents(
                event_healthy=Event(),
                event_unhealthy=Event(),
            )

            self.addresses_events[recipient] = events

            greenlet_healthcheck = gevent.spawn(
                healthcheck.healthcheck,
                self,
                recipient,
                self.event_stop,
                events.event_healthy,
                events.event_unhealthy,
                self.nat_keepalive_retries,
                self.nat_keepalive_timeout,
                self.nat_invitation_timeout,
                ping_nonce,
            )
            greenlet_healthcheck.name = f'Healthcheck for {pex(recipient)}'
            greenlet_healthcheck.link_exception(self.on_error)
            self.greenlets.append(greenlet_healthcheck)

    def init_queue_for(
        self,
        queue_identifier: QueueIdentifier,
        items: typing.List[QueueItem_T],
    ) -> Queue_T:
        """ Create the queue identified by the queue_identifier
        and initialize it with `items`.
        """
        recipient = queue_identifier.recipient
        queue = self.queueids_to_queues.get(queue_identifier)
        assert queue is None

        queue = NotifyingQueue(items=items)
        self.queueids_to_queues[queue_identifier] = queue

        events = self.get_health_events(recipient)

        greenlet_queue = gevent.spawn(
            single_queue_send,
            self,
            recipient,
            queue,
            queue_identifier,
            self.event_stop,
            events.event_healthy,
            events.event_unhealthy,
            self.retries_before_backoff,
            self.retry_interval,
            self.retry_interval * 10,
        )

        if queue_identifier.channel_identifier == CHANNEL_IDENTIFIER_GLOBAL_QUEUE:
            greenlet_queue.name = f'Queue for {pex(recipient)} - global'
        else:
            greenlet_queue.name = (
                f'Queue for {pex(recipient)} - {queue_identifier.channel_identifier}'
            )

        greenlet_queue.link_exception(self.on_error)
        self.greenlets.append(greenlet_queue)

        log.debug(
            'new queue created for',
            node=pex(self.raiden.address),
            queue_identifier=queue_identifier,
            items_qty=len(items),
        )

        return queue

    def get_queue_for(
        self,
        queue_identifier: QueueIdentifier,
    ) -> Queue_T:
        """ Return the queue identified by the given queue identifier.

        If the queue doesn't exist it will be instantiated.
        """
        queue = self.queueids_to_queues.get(queue_identifier)

        if queue is None:
            items = ()
            queue = self.init_queue_for(queue_identifier, items)

        return queue

    def send_async(
        self,
        queue_identifier: QueueIdentifier,
        message: 'Message',
    ):
        """ Send a new ordered message to recipient.

        Messages that use the same `queue_identifier` are ordered.
        """
        recipient = queue_identifier.recipient
        if not is_binary_address(recipient):
            raise ValueError('Invalid address {}'.format(pex(recipient)))

        # These are not protocol messages, but transport specific messages
        if isinstance(message, (Delivered, Ping, Pong)):
            raise ValueError('Do not use send for {} messages'.format(
                message.__class__.__name__))

        messagedata = message.encode()
        if len(messagedata) > self.UDP_MAX_MESSAGE_SIZE:
            raise ValueError(
                'message size exceeds the maximum {}'.format(
                    self.UDP_MAX_MESSAGE_SIZE), )

        # message identifiers must be unique
        message_id = message.message_identifier

        # ignore duplicates
        if message_id not in self.messageids_to_asyncresults:
            self.messageids_to_asyncresults[message_id] = AsyncResult()

            queue = self.get_queue_for(queue_identifier)
            queue.put((messagedata, message_id))
            assert queue.is_set()

            log.debug(
                'Message queued',
                node=pex(self.raiden.address),
                queue_identifier=queue_identifier,
                queue_size=len(queue),
                message=message,
            )

    def maybe_send(self, recipient: typing.Address, message: Message):
        """ Send message to recipient if the transport is running. """

        if not is_binary_address(recipient):
            raise InvalidAddress('Invalid address {}'.format(pex(recipient)))

        messagedata = message.encode()
        host_port = self.get_host_port(recipient)

        self.maybe_sendraw(host_port, messagedata)

    def maybe_sendraw_with_result(
        self,
        recipient: typing.Address,
        messagedata: bytes,
        message_id: typing.MessageID,
    ) -> AsyncResult:
        """ Send message to recipient if the transport is running.

        Returns:
            An AsyncResult that will be set once the message is delivered. As
            long as the message has not been acknowledged with a Delivered
            message the function will return the same AsyncResult.
        """
        async_result = self.messageids_to_asyncresults.get(message_id)
        if async_result is None:
            async_result = AsyncResult()
            self.messageids_to_asyncresults[message_id] = async_result

        host_port = self.get_host_port(recipient)
        self.maybe_sendraw(host_port, messagedata)

        return async_result

    def maybe_sendraw(self, host_port: typing.Tuple[int, int],
                      messagedata: bytes):
        """ Send message to recipient if the transport is running. """

        # Don't sleep if timeout is zero, otherwise a context-switch is done
        # and the message is delayed, increasing it's latency
        sleep_timeout = self.throttle_policy.consume(1)
        if sleep_timeout:
            gevent.sleep(sleep_timeout)

        # Check the udp socket is still available before trying to send the
        # message. There must be *no context-switches after this test*.
        if hasattr(self.server, 'socket'):
            self.server.sendto(
                messagedata,
                host_port,
            )

    def receive(
            self,
            messagedata: bytes,
            host_port: typing.Tuple[str, int],  # pylint: disable=unused-argument
    ) -> bool:
        """ Handle an UDP packet. """
        # pylint: disable=unidiomatic-typecheck

        if len(messagedata) > self.UDP_MAX_MESSAGE_SIZE:
            log.warning(
                'Invalid message: Packet larger than maximum size',
                node=pex(self.raiden.address),
                message=hexlify(messagedata),
                length=len(messagedata),
            )
            return False

        try:
            message = decode(messagedata)
        except InvalidProtocolMessage as e:
            log.warning(
                'Invalid protocol message',
                error=str(e),
                node=pex(self.raiden.address),
                message=hexlify(messagedata),
            )
            return False

        if type(message) == Pong:
            self.receive_pong(message)
        elif type(message) == Ping:
            self.receive_ping(message)
        elif type(message) == Delivered:
            self.receive_delivered(message)
        elif message is not None:
            self.receive_message(message)
        else:
            log.warning(
                'Invalid message: Unknown cmdid',
                node=pex(self.raiden.address),
                message=hexlify(messagedata),
            )
            return False

        return True

    def receive_message(self, message: Message):
        """ Handle a Raiden protocol message.

        The protocol requires durability of the messages. The UDP transport
        relies on the node's WAL for durability. The message will be converted
        to a state change, saved to the WAL, and *processed* before the
        durability is confirmed, which is a stronger property than what is
        required of any transport.
        """
        self.message_handler.on_message(self.raiden, message)

        # Sending Delivered after the message is decoded and *processed*
        # gives a stronger guarantee than what is required from a
        # transport.
        #
        # Alternatives are, from weakest to strongest options:
        # - Just save it on disk and asynchronously process the messages
        # - Decode it, save to the WAL, and asynchronously process the
        #   state change
        # - Decode it, save to the WAL, and process it (the current
        #   implementation)
        delivered_message = Delivered(message.message_identifier)
        self.raiden.sign(delivered_message)

        self.maybe_send(
            message.sender,
            delivered_message,
        )

    def receive_delivered(self, delivered: Delivered):
        """ Handle a Delivered message.

        The Delivered message is how the UDP transport guarantees persistence
        by the partner node. The message itself is not part of the raiden
        protocol, but it's required by this transport to provide the required
        properties.
        """
        self.message_handler.on_message(self.raiden, delivered)

        message_id = delivered.delivered_message_identifier
        async_result = self.raiden.transport.messageids_to_asyncresults.get(
            message_id)

        # clear the async result, otherwise we have a memory leak
        if async_result is not None:
            del self.messageids_to_asyncresults[message_id]
            async_result.set()
        else:
            log.warn(
                'Unknown delivered message received',
                message_id=message_id,
            )

    # Pings and Pongs are used to check the health status of another node. They
    # are /not/ part of the raiden protocol, only part of the UDP transport,
    # therefore these messages are not forwarded to the message handler.
    def receive_ping(self, ping: Ping):
        """ Handle a Ping message by answering with a Pong. """

        log_healthcheck.debug(
            'Ping received',
            node=pex(self.raiden.address),
            message_id=ping.nonce,
            message=ping,
            sender=pex(ping.sender),
        )

        pong = Pong(ping.nonce)
        self.raiden.sign(pong)

        try:
            self.maybe_send(ping.sender, pong)
        except (InvalidAddress, UnknownAddress) as e:
            log.debug("Couldn't send the `Delivered` message", e=e)

    def receive_pong(self, pong: Pong):
        """ Handles a Pong message. """

        message_id = ('ping', pong.nonce, pong.sender)
        async_result = self.messageids_to_asyncresults.get(message_id)

        if async_result is not None:
            log_healthcheck.debug(
                'Pong received',
                node=pex(self.raiden.address),
                sender=pex(pong.sender),
                message_id=pong.nonce,
            )

            async_result.set(True)

        else:
            log_healthcheck.warn(
                'Unknown pong received',
                message_id=message_id,
            )

    def get_ping(self, nonce: int) -> Ping:
        """ Returns a signed Ping message.

        Note: Ping messages don't have an enforced ordering, so a Ping message
        with a higher nonce may be acknowledged first.
        """
        message = Ping(
            nonce=nonce,
            current_protocol_version=constants.PROTOCOL_VERSION,
        )
        self.raiden.sign(message)
        message_data = message.encode()

        return message_data

    def set_node_network_state(self, node_address: typing.Address, node_state):
        state_change = ActionChangeNodeNetworkState(node_address, node_state)
        self.raiden.handle_state_change(state_change)
コード例 #21
0
class dmServer(Plugin):
    count_client = 0
    discover_client_paths = []

    def _init(self):
        self._initialized()

    def _start(self):
        self.start_observation_nscl = False
        self.total_clients = {}
        self.setting_address()
        self.server = DatagramServer(
            (self.lwm2m_dm_server_ip, self.lwm2m_dm_server_port),
            self.handle_request)
        self.start_server()

        self._started()

    def _stop(self):
        self.stop_server()
        self._stopped()

    def setting_address(self, ):
        self.lwm2m_dm_server_ip = self.config["lwm2m_dm_server_ip"]
        self.lwm2m_dm_server_port = self.config["lwm2m_dm_server_port"]
        self.client_ip = self.config["client_ip"]
        self.client_port = self.config["client_port"]
        self.nscl_dm_adapter_listener_ip = self.config[
            "nscl_dm_adapter_listener_ip"]
        self.nscl_dm_adapter_listener_port = self.config[
            "nscl_dm_adapter_listener_port"]
        self.nscl_dm_adapter_client_ip = self.config[
            "nscl_dm_adapter_client_ip"]
        self.nscl_dm_adapter_client_port = self.config[
            "nscl_dm_adapter_client_port"]

    def handle_request(self, message, remote):
        rx_record = connection.ReceptionRecord(None, message, remote)
        msg = rx_record.message
        uriQuery = msg.findOption(options.UriQuery)
        self.process(rx_record, remote, uriQuery)

    def start_server(self, ):
        print "LWM2M Server Started"
        self.server.start()

    def stop_server(self, ):
        print "LWM2M Server Stopped"
        self.server.stop()

    def process(self, rx_record, remote, uriQ):
        position_client = 0
        msg = rx_record.message
        self.uriQuery1 = uriQ
        payload_type = False
        if msg.transaction_type == connection.Message.CON:
            if constants.POST == msg.code:
                check_for_execute = 0
                for val1 in uriQ:
                    if str(val1).find("execute") != -1:
                        check_for_execute = 1

                if check_for_execute == 1:
                    check_for_execute = 0
                    msg = connection.Message(connection.Message.ACK,
                                             code=constants.CREATED)
                    self.server.sendto(msg._pack(rx_record.transaction_id),
                                       remote)
                    self.execute_resource(rx_record)
                else:
                    notify_list = self.client_registration(
                        rx_record, msg, payload_type, remote)
                    self.send_notifications_nscl_adapter(notify_list)

            elif constants.PUT == msg.code:
                check_pmax = 0
                try:
                    for val1 in uriQ:
                        if str(val1).find("pmax") != -1:
                            check_pmax = 1
                except:
                    pass

                if check_pmax == 1:
                    self.write_attributes(rx_record)
                    check_pmax = 0
                else:
                    pars.parse_uri_query(self.uriQuery1)
                    pars.parse_payload(str(msg.payload), payload_type)

                    location_address = str(str(
                        msg.options[1]).split(":")[1]).strip()

                    for val1 in maintain_clients:
                        if (val1["client_ip"] == rx_record.remote[0]
                                and val1["client_port"] == rx_record.remote[1]
                            ) or val1["location"] == location_address:
                            position_client = val1["client_id"]
                            endpoint_name = val1["endPointName"]
                            notify_list = self.total_clients[
                                position_client].update_mgmt_object(
                                    pars.return_parse_uri_query(),
                                    pars.return_parse_payload(), endpoint_name,
                                    self.start_observation_nscl
                                )  #mayn't be about creating objects:: so can be calling another function

                            if self.start_observation_nscl:
                                self.send_notifications_nscl_adapter(
                                    notify_list)
                            break

                msg = connection.Message(connection.Message.ACK,
                                         code=constants.CHANGED,
                                         payload="Changed")
                self.server.sendto(msg._pack(rx_record.transaction_id), remote)

            elif constants.DELETE == msg.code:
                self.__storage = ""
                print 'Deleting value: %s' % (self.__storage, )

                msg = connection.Message(connection.Message.ACK,
                                         code=constants.DELETED,
                                         payload='Deleting value: %s' %
                                         (self.__storage, ))
                #sendto line msising

            elif constants.GET == msg.code:
                try:
                    observe_value = rx_record.message.findOption(
                        options.Observe).value
                except ValueError:
                    observe_value = None  #-1
                if observe_value == OBSERVE_OPTION_VALUE_OBSERVATION:
                    if rx_record.remote[
                            0] == self.nscl_dm_adapter_client_ip and rx_record.remote[
                                1] == self.nscl_dm_adapter_client_port:
                        for v in rx_record.message.findOption(URI_PATH_VALUE):
                            self.start_observation_nscl = True
                            self.msg_transaction_id = rx_record.transaction_id
                            self.msg_uri_port = rx_record.message.findOption(
                                URI_PORT_VALUE).value
                            self.msg_uri_host = rx_record.message.findOption(
                                URI_HOST_VALUE).value
                    else:
                        self.resource_observation(rx_record)
                elif observe_value == OBSERVE_OPTION_VALUE_CANCEL_OBSERVATION:
                    self.cancel_observation(rx_record)
                elif str(
                        rx_record.message.findOption(URI_PATH_VALUE)
                    [0].value).find(".well-known") != -1:
                    print "Discovered Clients .."
                    for val4 in dmServer.discover_client_paths:
                        print ''.join(
                            ["/", val4["path"], "/", val4["endPointName"]])
                elif str(
                        rx_record.message.findOption(URI_PATH_VALUE)
                    [0].value).find("rd") != -1:
                    self.resource_discovery(rx_record)

                msg = connection.Message(connection.Message.ACK,
                                         code=constants.CONTENT,
                                         payload="Request Received")
                self.server.sendto(msg._pack(rx_record.transaction_id), remote)
        elif msg.transaction_type == connection.Message.ACK:
            self.notifications_display(msg.payload)

    def myfunc(self, ):
        self.p = subprocess.Popen(['sh', 'recv_mp4v.sh',
                                   '34000'])  #, stdout=subprocess.PIPE)
        self.p.communicate()

    def execute_resource(self, rx_record):
        path = []
        upath = ""
        i = 0
        for v in rx_record.message.findOption(11):
            print "inside execute : server:: %s" % v
            path.append(
                str(rx_record.message.findOption(URI_PATH_VALUE)[i].value))
            upath += path[i] + "/"
            i += 1
        upath = upath[:len(upath) - 1]

        for val2 in maintain_clients:
            if val2["location"] == path[1]:
                c_server_ip = val2["serverIPInClient"]
                c_server_port = val2["serverPortInClient"]
                break

        c_server_ip_port = str(c_server_ip) + ":" + str(c_server_port)
        #self.p.communicate()
        print "reached down :: after runtask"
        client_request.executeResource(c_server_ip_port,
                                       rx_record.message.payload,
                                       path=upath,
                                       client_port=self.client_port)
        print "after executeresource:: server"
        #self.p = subprocess.Popen(['sh', 'recv_mp4v.sh', '34000'], stdout=subprocess.PIPE)
        #self.api.run_task(self.p.communicate)
        #self.api.run_task(self.myfunc)  ###
        #self.myfunc()
        print "reached last ..."

    def client_registration(self, rx_record, msg, payload_type, remote):
        temp = []
        endpoint_name = rx_record.message.findOption(
            URI_QUERY_VALUE)[0].value.split("=")[1]
        server_ip_in_client = rx_record.message.findOption(
            URI_QUERY_VALUE)[1].value.split("=")[1]  #option 15 is for UriQuery
        server_port_in_client = rx_record.message.findOption(
            URI_QUERY_VALUE)[2].value.split("=")[1]

        temp.append(self.uriQuery1[0])
        self.uriQuery1 = temp

        pars.parse_uri_query(self.uriQuery1)
        pars.parse_payload(str(msg.payload), payload_type)
        pars.return_parse_payload()

        locationAddr = self.locID_generator(10)
        info_dict = {
            "client_ip": rx_record.remote[0],
            "client_port": rx_record.remote[1],
            "serverIPInClient": server_ip_in_client,
            "serverPortInClient": server_port_in_client,
            "client_id": dmServer.count_client,
            "location": locationAddr,
            "endPointName": endpoint_name
        }

        dmServer.discover_client_paths.append({
            "path": "rd",
            "location": locationAddr,
            "endPointName": endpoint_name,
            "objectID": None,
            "objectInstID": None,
            "resID": None
        })

        maintain_clients.append(info_dict)
        position_client = dmServer.count_client
        self.total_clients[position_client] = ClientCollection()

        dmServer.count_client += 1

        msg = connection.Message(connection.Message.ACK,
                                 code=constants.CREATED,
                                 location=locationAddr)
        self.server.sendto(msg._pack(rx_record.transaction_id), remote)

        return self.total_clients[position_client].create_mgmt_objects(
            pars.return_parse_uri_query(), pars.return_parse_payload(),
            endpoint_name, self.start_observation_nscl)

    def send_notifications_nscl_adapter(self, notify_list):
        if self.start_observation_nscl:
            sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
            msg_notify = connection.Message(connection.Message.ACK,
                                            code=constants.CONTENT,
                                            payload=json.dumps(notify_list))
            sock.sendto(msg_notify._pack(self.msg_transaction_id),
                        (self.msg_uri_host, int(self.msg_uri_port)))
            sock.close()

    def notifications_display(self, notifications):
        print "NOTIFICATIONS ..."
        storeNotification = json.loads(notifications)
        for val2 in storeNotification:
            print "App. IP : %s, App. Port: %s, ObjectID : %s, Instance ID : %s, Resource Name : %s, Resource Value : %s" % (
                val2["app_ip"], val2["app_port"], val2["objectID"],
                val2["objectInstID"], val2["resName"], val2["resValue"])

        # Send to the app's ip (and port)
    def resource_discovery(self, rx_record):
        app_ip = rx_record.remote[0]
        app_port = rx_record.remote[1]
        path = []
        upath = ""
        for v in rx_record.message.findOption(URI_PATH_VALUE):
            path.append(v.value)
        upath = "/".join(path)
        for val2 in maintain_clients:
            if val2["endPointName"] == path[1] or val2["location"] == path[1]:
                c_server_ip = val2["serverIPInClient"]
                c_server_port = val2["serverPortInClient"]
                count_val = val2["client_id"]
                break
        c_server_ip_port = str(c_server_ip) + ":" + str(c_server_port)
        payload = ''.join(
            ["app_ip=", str(app_ip), "&app_port=",
             str(app_port)])
        discoveredResources = client_request.discoverResource(
            c_server_ip_port,
            path=upath,
            payload=payload,
            client_port=self.client_port)

        print "Discovered Resources .."
        for val3 in json.loads(
                discoveredResources.payload
        ):  #it contains requesting application ip and port :: val3["app_ip"] and val3["app_port"]
            if val3.has_key("resID"):
                print ''.join([
                    "/rd/", val3["endPointName"], "/", val3["objectID"], "/",
                    val3["objectInstID"], "/",
                    str(val3["resID"]), " ; pmax : ",
                    str(val3["pmax"]), " , pmin : ",
                    str(val3["pmin"]), " , value : ",
                    str(val3["resValue"])
                ])
            else:
                print ''.join([
                    "/rd/", val3["endPointName"], "/", val3["objectID"], "/",
                    val3["objectInstID"], " ; pmax :",
                    str(val3["pmax"]), " , pmin : ",
                    str(val3["pmin"])
                ])

    def resource_observation(self, rx_record):
        print "OBSERVATION STARTED .."

        self.observeCollection = []
        tempObserve = {}

        app_ip = rx_record.remote[0]
        app_port = rx_record.remote[1]
        #move below two lines in the init
        path = []
        for v in rx_record.message.findOption(URI_PATH_VALUE):
            path.append(v.value)
        upath = "/".join(path)

        if len(path) == 3:
            path.append("None")
            path.append("None")
        elif len(path) == 4:
            path.append("None")  #here client means app ip and port

        self.observeCollection.append({
            "clientIP": app_ip,
            "clientPort": app_port,
            "endPointName": path[1],
            "objectID": path[2],
            "objectInstID": path[3],
            "resID": path[4]
        })
        tempPayload = "clientIP=" + str(app_ip) + "&clientPort=" + str(
            app_port)

        for val2 in maintain_clients:
            if val2["endPointName"] == path[1] or val2["location"] == path[1]:
                c_server_ip = val2["serverIPInClient"]
                c_server_port = val2["serverPortInClient"]
                break

        c_server_ip_port = str(c_server_ip) + ":" + str(c_server_port)
        first_notification = client_request.observeResource(
            c_server_ip_port,
            path=upath,
            payload=tempPayload,
            uri_host=self.lwm2m_dm_server_ip,
            uri_port=self.lwm2m_dm_server_port,
            client_port=self.client_port)
        if first_notification.payload != "null":
            self.notifications_display(first_notification.payload)
        else:
            print "Already Exists"

    def cancel_observation(self, rx_record):
        print "CANCEL OBSERVATION .."
        app_ip = rx_record.remote[0]
        app_port = rx_record.remote[1]
        path = []
        for v in rx_record.message.findOption(URI_PATH_VALUE):
            path.append(
                str(rx_record.message.findOption(URI_PATH_VALUE)[i].value))
        upath = "/".join(path)
        tempObserve = {}

        if len(path) == 3:
            path.append("None")
            path.append("None")
        elif len(path) == 4:
            path.append("None")  #here client means app ip and port
        tempCancelObs = "clientIP=" + str(app_ip) + "&clientPort=" + str(
            app_port)

        for val2 in maintain_clients:
            if val2["endPointName"] == path[1] or val2["location"] == path[1]:
                c_server_ip = val2["serverIPInClient"]
                c_server_port = val2["serverPortInClient"]
                break

        c_server_ip_port = str(c_server_ip) + ":" + str(c_server_port)
        client_request.cancelSubscription(c_server_ip_port,
                                          path=upath,
                                          payload=tempCancelObs,
                                          client_port=self.client_port)

    def write_attributes(self, rx_record):
        path = []
        for v in rx_record.message.findOption(URI_PATH_VALUE):
            path.append(v.value)
        upath = "/".join(path)

        pmax = rx_record.message.findOption(URI_QUERY_VALUE)[0].value.split(
            "=")[1]
        pmin = rx_record.message.findOption(URI_QUERY_VALUE)[1].value.split(
            "=")[1]

        for val2 in maintain_clients:
            if val2["endPointName"] == path[1] or val2["location"] == path[1]:
                c_server_ip = val2["serverIPInClient"]
                c_server_port = val2["serverPortInClient"]
                break

        c_server_ip_port = str(c_server_ip) + ":" + str(c_server_port)

        query = ''.join(["pmax=", str(pmax), "&pmin=", str(pmin)])
        reply = client_request.writeAttributes(c_server_ip_port,
                                               query,
                                               path=upath,
                                               client_port=self.client_port)

        print reply
        #update pmax and pmin in server too

    def locID_generator(self,
                        str_size,
                        chars=string.ascii_uppercase + string.digits):
        return ''.join([random.choice(chars) for _ in range(str_size)])
コード例 #22
0
class UDPTransport:
    """ Node communication using the UDP protocol. """

    def __init__(
            self,
            host,
            port,
            socket=None,
            protocol=None,
            throttle_policy=DummyPolicy()):

        self.protocol = protocol
        if socket is not None:
            self.server = DatagramServer(socket, handle=self.receive)
        else:
            self.server = DatagramServer((host, port), handle=self.receive)
        self.host = self.server.server_host
        self.port = self.server.server_port
        self.throttle_policy = throttle_policy

    def receive(self, data, host_port):  # pylint: disable=unused-argument
        try:
            self.protocol.receive(data)
        except InvalidProtocolMessage as e:
            if log.isEnabledFor(logging.WARNING):
                log.warning("Can't decode: {} (data={}, len={})".format(str(e), data, len(data)))
            return
        except RaidenShuttingDown:  # For a clean shutdown
            return

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.track_recv(self.protocol.raiden, host_port, data)

    def send(self, sender, host_port, bytes_):
        """ Send `bytes_` to `host_port`.

        Args:
            sender (address): The address of the running node.
            host_port (Tuple[(str, int)]): Tuple with the host name and port number.
            bytes_ (bytes): The bytes that are going to be sent through the wire.
        """
        sleep_timeout = self.throttle_policy.consume(1)

        # Don't sleep if timeout is zero, otherwise a context-switch is done
        # and the message is delayed, increasing it's latency
        if sleep_timeout:
            gevent.sleep(sleep_timeout)

        if not hasattr(self.server, 'socket'):
            raise RuntimeError('trying to send a message on a closed server')

        self.server.sendto(bytes_, host_port)

        # enable debugging using the DummyNetwork callbacks
        DummyTransport.network.track_send(sender, host_port, bytes_)

    def stop(self):
        self.server.stop()
        # Calling `.close()` on a gevent socket doesn't actually close the underlying os socket
        # so we do that ourselves here.
        # See: https://github.com/gevent/gevent/blob/master/src/gevent/_socket2.py#L208
        # and: https://groups.google.com/forum/#!msg/gevent/Ro8lRra3nH0/ZENgEXrr6M0J
        try:
            self.server._socket.close()
        except socket.error:
            pass

    def stop_accepting(self):
        self.server.stop_accepting()

    def start(self):
        assert not self.server.started
        # server.stop() clears the handle, since this may be a restart the
        # handle must always be set
        self.server.set_handle(self.receive)
        self.server.start()
コード例 #23
0
class LocalClientCore(LoggerMixin):
    def __init__(self, local_listener_ip, local_listener_port, lwm2m_server_ip,
                 lwm2m_server_port, local_client_ip, local_client_port):

        self.ep_location_mapping = {}
        self.total_resources = {}
        self.res_dict = {}
        self.lwm2m_dm_server_ip = lwm2m_server_ip
        self.lwm2m_dm_server_port = lwm2m_server_port
        self.sem = Semaphore()
        self.local_listener_ip = local_listener_ip
        self.local_listener_port = local_listener_port
        self.local_client_ip_ = local_client_ip
        self.local_client_port = local_client_port  #local_client_port
        #self.local_client_port_end = local_client_port_end  #local_client_port
        self.dispatcher = EventDispatcher()
        self.lwm2m_resources = LWM2MResourceTree(self.dispatcher)
        self.registration = Registration(self.lwm2m_resources)
        self.read = Read(self.lwm2m_resources)
        self.write = Write(self.lwm2m_resources)
        self.write_attributes = WriteAttributes(self.lwm2m_resources)
        self.create_object_instance = Create(self.lwm2m_resources)
        self.observation = ObservationNotificationEngine(
            self.lwm2m_resources, self.dispatcher)
        self.execution = Execution(self.lwm2m_resources)
        self.discover = Discovery(lwm2m_resources=self.lwm2m_resources)

        self.observation_started = False

    def load_dm_adapter(self, dm_adapter):
        self.dm_adapter = dm_adapter

    def create_server(self, local_listener_ip=None):
        """ Creates and starts a local server using Gevent DatagramServer. The server
        listens at the ip and port specified below. A handler is used to entertain the
        requests coming at that port """

        if local_listener_ip is not None:
            self.local_listener_ip = local_listener_ip

        self.logger.info("Local Server Created")
        self.logger.info("local_listener_ip %s", self.local_listener_ip)
        self.logger.info("local_listener_port %s", self.local_listener_port)

        self.local_server = DatagramServer(
            (self.local_listener_ip, self.local_listener_port),
            self.handle_lwm2m_request)
        self.local_server.start()

    def stop_server(self, ):
        """ Stops the local server """

        self.local_server.stop()

    def handle_lwm2m_request(self, message, remote):
        """ Handles the requests coming at the specified ip and port """

        rx_record = connection.ReceptionRecord(None, message, remote)
        msg = rx_record.message
        uri_query = msg.findOption(options.UriQuery)
        self.process(rx_record, remote, uri_query)

    """ Used for Create Object Instance, Execution Operation Request """

    def handle_lwm2m_post(self, msg, uri_query, remote, rx_record):
        method = None
        try:
            method = uri_query[0].value.split("=")[1]
        except:
            pass

        if method == "create":
            path = msg.findOption(URI_PATH_VALUE)
            content_type_number = msg.findOption(options.ContentType)
            if content_type_number is None:
                content_type = "text/plain"
            else:
                content_type = constants.media_types[content_type_number.value]
            self.create_object_instance.create_instance(
                path, remote, content_type, loads(msg.payload))

            msg = connection.Message(connection.Message.ACK,
                                     code=constants.CREATED,
                                     payload="Resource Created")
            self.local_server.sendto(msg._pack(rx_record.transaction_id),
                                     remote)

        elif method == "execute":
            path = msg.findOption(URI_PATH_VALUE)
            content_type_number = msg.findOption(options.ContentType)
            if content_type_number is None:
                content_type = "text/plain"
            else:
                content_type = constants.media_types[content_type_number.value]

            endpoint_name, object_id, object_inst_id, res_id, res_value = \
                                self.execution.execute_resource(path, remote, msg.payload)

            msg = connection.Message(connection.Message.ACK,
                                     code=constants.CHANGED,
                                     payload="Resource Executed")
            self.local_server.sendto(msg._pack(rx_record.transaction_id),
                                     remote)

            resource = {}
            resource[res_id] = {"res_value": res_value}
            content_type = "application/json"
            self.dm_adapter.update_resources(endpoint_name,
                                             object_id,
                                             object_inst_id,
                                             dumps(resource),
                                             content_type=content_type)

    """ It consists of Normal Update, Write Operation, Write Attribute Operation.
    Write Operation is used to update the resource(s) as per the request. Write
    Attributes operation is used to update the attributes of the object, object
    instance or resource. """

    def handle_lwm2m_put(self, msg, remote, rx_record):
        uri_query = msg.findOption(options.UriQuery)

        method = None
        try:
            method = uri_query[0].value.split("=")[1]
        except:
            pass

        if method == "write":
            self.logger.info("Updating the Resources in the Client")

            path = msg.findOption(URI_PATH_VALUE)
            content_type_number = msg.findOption(options.ContentType)
            if content_type_number is None:
                content_type = "text/plain"
            else:
                content_type = constants.media_types[content_type_number.value]
            self.write.write_resource(msg.payload, path, content_type)

            payload_forward = msg.payload

            msg = connection.Message(connection.Message.ACK,
                                     code=constants.CHANGED,
                                     payload="CHANGED")
            self.local_server.sendto(msg._pack(rx_record.transaction_id),
                                     remote)

            endpoint_name, object_id, object_inst_id, res_id, res_inst_id, _, _ = OperationRequest(
            ).find_elements(path, remote)

            self.dm_adapter.update_resources(endpoint_name, object_id, object_inst_id, \
                                    payload_forward, content_type=content_type)

        elif method == "write_attributes":
            path = msg.findOption(URI_PATH_VALUE)
            content_type_number = msg.findOption(options.ContentType)
            if content_type_number is None:
                content_type = "text/plain"
            else:
                content_type = constants.media_types[content_type_number.value]
            payload = loads(msg.payload)
            self.write_attributes.set_attributes(path, remote, payload)

            msg = connection.Message(connection.Message.ACK,
                                     code=constants.CHANGED,
                                     payload="Resource Attributes Changed")
            self.local_server.sendto(msg._pack(rx_record.transaction_id),
                                     remote)

    """ Sets the Observation. Two types of observations. General Observation
    and Specific Observation. General Observation is used for anything that is
    not observed and updates are sent as general notifications using a general
    token. Specific observation is implicitly defined by the observer(as request)
    and handled as specific notification with a specific token """

    def handle_lwm2m_observe(self, msg, remote, rx_record):
        path = msg.findOption(URI_PATH_VALUE)
        if len(path) == 1:
            token_id = self.set_generation_observation_params(msg)
            payload = "General Observation Started at the Client"
            content_type = "text/plain"
        else:
            self.logger.info("Specific Observation Received")

            endpoint_name, object_id, object_inst_id, res_id, res_inst_id, _, _ = OperationRequest(
            ).find_elements(path, remote)

            token_id = msg.token
            payload = msg.payload

            self.observation.set_observation(endpoint_name,
                                             object_id,
                                             object_inst_id,
                                             res_id,
                                             token_id,
                                             payload,
                                             self.lwm2m_dm_server_ip,
                                             self.lwm2m_dm_server_port,
                                             res_inst_id=res_inst_id)

        msg = connection.Message(connection.Message.ACK,
                                 code=constants.CONTENT)
        self.local_server.sendto(msg._pack(rx_record.transaction_id, token_id),
                                 remote)

    """ Removes the observation from the List """

    def handle_lwm2m_cancel_observe(self, msg, remote, rx_record):
        self.logger.info("Cancel Observation Request Received")
        path = msg.findOption(URI_PATH_VALUE)

        endpoint_name, object_id, object_inst_id, res_id, res_inst_id, _, _ = OperationRequest(
        ).find_elements(path, remote)

        token_id = msg.token
        payload = msg.payload

        message = self.observation.cancel_observation(
            endpoint_name,
            object_id,
            object_inst_id,
            res_id,
            token_id,
            payload,
            self.lwm2m_dm_server_ip,
            self.lwm2m_dm_server_port,
            res_inst_id=res_inst_id)

        msg = connection.Message(connection.Message.ACK,
                                 code=constants.CONTENT,
                                 payload=message)
        self.local_server.sendto(msg._pack(rx_record.transaction_id), remote)

    def process(self, rx_record, remote, uri_query):
        """ Processes various requests like CON (POST, PUT, GET) or NON.
        POST requests : Generally used for Registration and Execution
        PUT requests : Generally used for updating the resources
        GET requests : Generally used for Discovery, Observation, Cancel Observation """

        msg = rx_record.message
        self.uri_query = uri_query

        if msg.transaction_type == connection.Message.CON:
            if constants.POST == msg.code:
                """ Used for Registration requests, Execution Operation Request """
                self.handle_lwm2m_post(msg, uri_query, remote, rx_record)

            elif constants.PUT == msg.code:
                """ It consists of Normal Update, Write Operation, Write Attribute Operation.
                Write Operation is used to update the resource(s) as per the request. Write
                Attributes operation is used to update the attributes of the object, object
                instance or resource. """

                self.handle_lwm2m_put(msg, remote, rx_record)

            elif constants.GET == msg.code:
                """ Handles Requests like Discovery, Observation """
                try:
                    observe_value = msg.findOption(options.Observe).value
                except:
                    observe_value = ""
                if observe_value == OBSERVE_OPTION_VALUE_OBSERVATION:
                    """ Sets the Observation. Two types of observations. General Observation
                    and Specific Observation. General Observation is used for anything that is
                    not observed and updates are sent as general notifications using a general
                    token. Specific observation is implicitly defined by the observer(as request) 
                    and handled as specific notification with a specific token """
                    self.handle_lwm2m_observe(msg, remote, rx_record)

                elif observe_value == OBSERVE_OPTION_VALUE_CANCEL_OBSERVATION:
                    """ Removes the observation from the List """

                    self.handle_lwm2m_cancel_observe(msg, remote, rx_record)

                else:
                    uri_query = msg.findOption(options.UriQuery)

                    method = None
                    try:
                        method = uri_query[0].value.split("=")[1]
                    except:
                        pass

                    if method == "discover":
                        path = msg.findOption(URI_PATH_VALUE)
                        payload = self.discover.get_resource(path, remote)

                        msg = connection.Message(connection.Message.ACK,
                                                 code=constants.CONTENT,
                                                 payload=dumps(payload))
                        self.local_server.sendto(
                            msg._pack(rx_record.transaction_id), remote)

    def set_generation_observation_params(self, msg):
        listener_address = json.loads(msg.payload)
        listener_ip = listener_address["listener_ip"]
        listener_port = listener_address["listener_port"]
        token_id = msg.token
        self.general_observation = GeneralObservationInformation(
            listener_ip, listener_port, token_id)
        return token_id

    def send_client_registration(self, endpoint, local_client_port):
        """ Client registration request to the LWM2M server """

        self.logger.info(
            "Preparing Client Registration parameters for LWM2M DM Server")
        registration_params = {
            "lt": self.lifetime,
            "lwm2m": self.version,
            "sms": self.sms_number,
            "b": self.binding_mode
        }
        client_object, response = self.registration.send_client_registration(endpoint, registration_params, self.lwm2m_dm_server_ip, \
                                self.lwm2m_dm_server_port, self.local_listener_ip, self.local_listener_port, \
                                local_client_port)
        self.client = client_object

        def _handle_response(response):
            location_address = response.findOption(LOCATION_VALUE)[0].value
            self.logger.debug(
                "The registered location address of Client in DM Server is %s",
                location_address)
            self.ep_location_mapping[endpoint.endpoint_name] = location_address

            temp_total_resources = deepcopy(self.total_resources)
            for ep_name, resdict in temp_total_resources.iteritems():
                for mgmt_obj_id, resources in resdict.iteritems():
                    if self.ep_location_mapping.has_key(ep_name):
                        self.logger.info(
                            "Endpoint Location now available. Forwarding saved resources"
                        )
                        self.send_add_resources(resources, ep_name,
                                                mgmt_obj_id)
                        del self.total_resources[ep_name][mgmt_obj_id]
                if not any(self.total_resources[ep_name]):
                    del self.total_resources[ep_name]
            return location_address

        return response.then(_handle_response)

    def load_registration_params(self,
                                 lifetime=None,
                                 version=None,
                                 sms_number=None,
                                 binding_mode=None):
        self.lifetime = lifetime
        self.version = version
        self.sms_number = sms_number
        self.binding_mode = binding_mode

    def local_registration(self, endpoint_name, local_client_port):
        """ Local registration of the resources in the local server """
        self.logger.info("Local Registration Started for Endpoint: %s",
                         endpoint_name)

        self_object = Endpoint(endpoint_name, objects=None, lifetime=self.lifetime, version=self.version, \
                                        sms_number=self.sms_number, binding_mode=self.binding_mode, \
                                        local_ip=self.local_client_ip_, local_port=local_client_port, \
                                        listener_ip=self.local_listener_ip, listener_port=self.local_listener_port)
        endpoint = self_object.endpoint
        response = self.registration.register_client(endpoint)
        """ Sending Client Registration to the DM Server """
        registration_location = self.send_client_registration(
            endpoint, local_client_port)
        return endpoint, registration_location

    def add_resource(self, emulated_device_name, lwm2m_mgmt_obj_id, lwm2m_resource_id, param_value, \
                     lwm2m_mgmt_obj_inst_id=None, lwm2m_resource_inst_id=None):

        self.logger.info("Adding Resources in the Resource Model")
        endpoint = self.lwm2m_resources.return_endpoint_object(
            emulated_device_name)

        resource_change_flag = self.lwm2m_resources.add_object_instance_resource_instance(endpoint, lwm2m_mgmt_obj_id, \
                             lwm2m_resource_id, param_value, object_inst_id=lwm2m_mgmt_obj_inst_id, \
                             res_inst_id=lwm2m_resource_inst_id)

        return resource_change_flag

    def send_add_resources(self, object_and_resources, endpoint_name,
                           mgmt_obj_id_inst_id):
        if self.ep_location_mapping.has_key(endpoint_name):
            location_address = self.ep_location_mapping[endpoint_name]
        else:
            location_address = None

        if location_address == None:
            self.logger.warning(
                "Location couldn't be fetched !! Saving the Resources")
            self.res_dict[mgmt_obj_id_inst_id] = object_and_resources
            self.total_resources[endpoint_name] = self.res_dict
        else:
            self.logger.info("Sending Updates on the Resources..")
            path = location_address
            query_params = ""
            payload = json.dumps(object_and_resources)
            request = lwm2m_api()
            response = request.client_registration_update(self.lwm2m_dm_server_ip, self.lwm2m_dm_server_port, \
                                                    path, query_params, payload, \
                                                    client=self.client)

    def send_total_resources(self, ):
        #Not used currently
        self.logger.info("Sending Updates on the Resources")
        path = self.location_address
        query_params = ""
        payload = json.dumps(self.total_resources)
        request = lwm2m_api()
        response = request.client_registration_update(self.lwm2m_dm_server_ip, self.lwm2m_dm_server_port, \
                                                path, query_params, payload, \
                                                client_port=self.local_client_port)

        self.total_resources = {}