Example #1
0
    def __init__(self, hostAddr, hostPort, sourcePort):
        '''Initializes on destination host and source port.

        Also uses sourcePort + 1 for the server to receive commands.
        '''
        self._hostTuple = (hostAddr, hostPort)
        self._client = CoapClient(sourcePort=sourcePort, dest=self._hostTuple)
        self._client.registerForResponse(self._responseClient)

        self._server = CoapServer(port=sourcePort + 1)
        self._server.registerForResourcePost(self._postServerResource)

        self._registeredPaths = {}
        self._notificationAction = None
Example #2
0
    def __init__(self, hostAddr, hostPort, sourcePort, query):
        '''Initializes on destination host and source port.'''
        self._hostTuple  = (hostAddr, hostPort)
        self._client     = CoapClient(sourcePort=sourcePort, dest=self._hostTuple)
        self._client.registerForResponse(self._responseClient)

        self._server     = CoapServer(port=5681)
        self._server.registerForResourcePost(self._postServerResource)

        self._queryName  = query
Example #3
0
class StatsReader(object):
    """Reads statistics from a RIOT gcoap URL.

    NB: As shown in the Usage section below, StatsReader starts the asyncore
    loop before sending the query, like a server. This approach means the
    query must be called via another thread. Another approach would be to use
    asyncore's capabilities to create a single-use CoapClient and send the
    query at startup, in the same thread.
    
    Attributes:
        :_addrTuple:  tuple IPv6 address tuple for message destination
        :_client:   CoapClient Provides CoAP message protocol
    
    Usage:
        #. sr = StatsReader(sourcePort, hostAddr)  -- Create instance
        #. sr.start() -- Starts asyncore networking loop
        #. sr.query() -- Runs a named query. Must be called from a different
                         thread, for example from a timer.
        #. sr.close() -- Cleanup
    """

    def __init__(self, hostAddr, hostPort, sourcePort):
        """Initializes on destination host and source port."""
        self._hostTuple = (hostAddr, hostPort)
        self._client = CoapClient(sourcePort=sourcePort, dest=self._hostTuple)

    def start(self):
        """Starts networking; returns when networking is stopped."""
        self._client.start()

    def query(self, queryName):
        """Runs a named query"""
        # create message
        msg = CoapMessage(self._hostTuple)
        msg.messageType = MessageType.NON
        msg.codeClass = CodeClass.Request
        msg.codeDetail = RequestCode.GET
        msg.messageId = random.randint(0, 65535)

        if queryName == "core":
            msg.addOption(CoapOption(OptionType.UriPath, ".well-known"))
            msg.addOption(CoapOption(OptionType.UriPath, "core"))

        # send message
        log.debug("Sending query")
        self._client.send(msg)

    def close(self):
        """Releases resources"""
        self._client.close()
Example #4
0
class GcoapObserver(object):
    '''Reads statistics from a RIOT gcoap URL.

    Attributes:
        :_hostuple: tuple IPv6 address tuple for message destination
        :_client:    CoapClient Provides CoAP client for server queries
        :_registeredPaths: string:bytearray, where the key is the short name
                           for the path, and the value is the token used to
                           register for Observe notifications for the path
        :_server:    CoapServer Provides CoAP server for remote client commands
        :_notificationAction: If None, sends a normal 'ACK' response for a
                              confirmable notification.
                              If 'reset', sends a 'RST' response, which directs
                              the server to deregister the client from further
                              notifications.
                              If 'ignore', does not send a response, which
                              also directs the server to deregister the client
                              for a confirmable notification.
                              Note: 'reset_non' is NOT supported.

    Usage:
        #. sr = StatsReader(hostAddr, hostPort, sourcePort, query)  -- Create instance
        #. sr.start() -- Starts asyncore networking loop
        #. sr.close() -- Cleanup
    '''
    def __init__(self, hostAddr, hostPort, sourcePort):
        '''Initializes on destination host and source port.

        Also uses sourcePort + 1 for the server to receive commands.
        '''
        self._hostTuple = (hostAddr, hostPort)
        self._client = CoapClient(sourcePort=sourcePort, dest=self._hostTuple)
        self._client.registerForResponse(self._responseClient)

        self._server = CoapServer(port=sourcePort + 1)
        self._server.registerForResourcePost(self._postServerResource)

        self._registeredPaths = {}
        self._notificationAction = None

    def _responseClient(self, message):
        '''Reads a response to a request
        '''
        log.debug('Running client response handler')

        prefix = '0' if message.codeDetail < 10 else ''
        obsList = message.findOption(OptionType.Observe)
        obsValue = '<none>' if len(obsList) == 0 else obsList[0].value
        obsText = 'len: {0}; val: {1}'.format(len(obsList), obsValue)

        print('Response code: {0}.{1}{2}; Observe {3}'.format(
            message.codeClass, prefix, message.codeDetail, obsText))

        if message.token in self._registeredPaths.values():
            if message.messageType == MessageType.CON:
                if self._notificationAction == 'reset':
                    self._sendNotifResponse(message, 'reset')
                elif self._notificationAction == None:
                    self._sendNotifResponse(message, 'ack')
                else:
                    # no response when _notificationAction is 'ignore'
                    pass

            elif message.messageType == MessageType.NON:
                if self._notificationAction == 'reset_non':
                    self._sendNotifResponse(message, 'reset')

    def _postServerResource(self, resource):
        '''Reads a command
        '''
        log.debug('Resource path is {0}'.format(resource.path))

        observeAction = None
        observePath = None
        if resource.path == '/reg/stats':
            observeAction = 'reg'
            observePath = 'stats'
        elif resource.path == '/reg/core':
            observeAction = 'reg'
            observePath = 'core'
        elif resource.path == '/reg/stats2':
            observeAction = 'reg'
            observePath = 'stats2'
        elif resource.path == '/dereg/stats':
            observeAction = 'dereg'
            observePath = 'stats'
        elif resource.path == '/dereg/core':
            observeAction = 'dereg'
            observePath = 'core'
        elif resource.path == '/dereg/stats2':
            observeAction = 'dereg'
            observePath = 'stats2'
        elif resource.path == '/notif/con_ignore':
            self._notificationAction = 'ignore'
        elif resource.path == '/notif/con_reset':
            self._notificationAction = 'reset'
        elif resource.path == '/notif/non_reset':
            self._notificationAction = 'reset_non'
        elif resource.path == '/ping':
            print('Got ping post')

        if observePath:
            if observeAction == 'reg' and resource.pathQuery:
                self._query(observeAction,
                            observePath,
                            tokenText=resource.pathQuery)
            else:
                self._query(observeAction, observePath)

    def _query(self, observeAction, observePath, tokenText=None):
        '''Runs the reader's query.

        Uses a randomly generated two byte token, or the provided string encoded
        bytes.

        :param observeAction: string -- reg (register), dereg (deregister);
                              triggers inclusion of Observe option
        :param observePath: string Path for register/deregister
        :param tokenText: string String encoding of token bytes; must by an
                                 even-numbered length of characters like '05'
                                 or '05a6'
        '''
        # create message
        msg = CoapMessage(self._hostTuple)
        msg.messageType = MessageType.NON
        msg.codeClass = CodeClass.Request
        msg.codeDetail = RequestCode.GET
        msg.messageId = random.randint(0, 65535)

        if observePath == 'core':
            msg.addOption(CoapOption(OptionType.UriPath, '.well-known'))
            msg.addOption(CoapOption(OptionType.UriPath, 'core'))
        elif observePath == 'stats':
            msg.addOption(CoapOption(OptionType.UriPath, 'cli'))
            msg.addOption(CoapOption(OptionType.UriPath, 'stats'))
        elif observePath == 'stats2':
            msg.addOption(CoapOption(OptionType.UriPath, 'cli'))
            msg.addOption(CoapOption(OptionType.UriPath, 'stats2'))

        if observeAction == 'reg':
            # register
            msg.addOption(CoapOption(OptionType.Observe, 0))
            if tokenText:
                msg.tokenLength = len(tokenText) / 2
                msg.token = bytearray(msg.tokenLength)
                for i in range(0, msg.tokenLength):
                    msg.token[i] = int(tokenText[2 * i:2 * (i + 1)], base=16)
            else:
                msg.tokenLength = 2
                msg.token = bytearray(2)
                msg.token[0] = random.randint(0, 255)
                msg.token[1] = random.randint(0, 255)
            self._registeredPaths[observePath] = msg.token
        elif observeAction == 'dereg':
            # deregister
            msg.addOption(CoapOption(OptionType.Observe, 1))
            msg.tokenLength = 2
            msg.token = self._registeredPaths[observePath]
            # assume deregistration will succeed
            del self._registeredPaths[observePath]

        # send message
        log.debug('Sending query')
        self._client.send(msg)

    def _sendNotifResponse(self, notif, responseType):
        '''Sends an empty ACK or RST response to a notification

        :param notif: CoapMessage Observe notification from server
        '''
        msg = CoapMessage(notif.address)
        msg.codeClass = CodeClass.Empty
        msg.codeDetail = ClientResponseCode.Empty
        msg.messageId = notif.messageId
        msg.tokenLength = 0
        msg.token = None

        if responseType == 'reset':
            msg.messageType = MessageType.RST
        else:
            msg.messageType = MessageType.ACK

        log.debug('Sending {0} for notification response'.format(responseType))
        self._client.send(msg)

    def start(self):
        '''Starts networking; returns when networking is stopped.

        Only need to start client, which automatically starts server, too.
        '''
        self._client.start()

    def close(self):
        '''Releases resources'''
        self._client.close()
Example #5
0
 def __init__(self, hostAddr, hostPort, sourcePort):
     """Initializes on destination host and source port."""
     self._hostTuple = (hostAddr, hostPort)
     self._client = CoapClient(sourcePort=sourcePort, dest=self._hostTuple)
Example #6
0
class StatsReader(object):
    '''Reads statistics from a RIOT gcoap URL.

    NB: As shown in the Usage section below, StatsReader starts the asyncore
    loop before sending the query, like a server. This approach means the
    query must be called via another thread. Another approach would be to use
    asyncore's capabilities to create a single-use CoapClient and send the
    query at startup, in the same thread.
    
    Attributes:
        :_addrTuple:  tuple IPv6 address tuple for message destination
        :_client:   CoapClient Provides CoAP message protocol
        :_queryName: string GET query to send to CoAP server
    
    Usage:
        #. sr = StatsReader(hostAddr, hostPort, sourcePort, query)  -- Create instance
        #. sr.start() -- Starts asyncore networking loop
        #. sr.close() -- Cleanup
    '''
    def __init__(self, hostAddr, hostPort, sourcePort, query):
        '''Initializes on destination host and source port.'''
        self._hostTuple  = (hostAddr, hostPort)
        self._client     = CoapClient(sourcePort=sourcePort, dest=self._hostTuple)
        self._client.registerForResponse(self._responseClient)

        self._server     = CoapServer(port=5681)
        self._server.registerForResourcePost(self._postServerResource)

        self._queryName  = query

    def _responseClient(self, message):
        '''Reads a response to a request
        '''
        prefix   = '0' if message.codeDetail < 10 else ''
        obsList  = message.findOption(OptionType.Observe)
        obsValue = '<none>' if len(obsList) == 0 else obsList[0].value
        obsText  = 'len: {0}; val: {1}'.format(len(obsList), obsValue)
        
        print('Response code: {0}.{1}{2}; Observe {3}'.format(message.codeClass, prefix,
                                                              message.codeDetail, obsText))

    def _postServerResource(self, resource):
        '''Reads a command
        '''
        log.debug('Resource path is {0}'.format(resource.path))
        
        observeAction = None
        if resource.path == '/reg':
            observeAction = 'reg'
        elif resource.path == '/dereg':
            observeAction = 'dereg'

        self._query(observeAction)

    def _query(self, observeAction):
        '''Runs the reader's query

        :param observeAction: reg (register), dereg (deregister), or None;
                              triggers inclusion of Observe option
        '''
        # create message
        msg             = CoapMessage(self._hostTuple)
        msg.messageType = MessageType.NON
        msg.codeClass   = CodeClass.Request
        msg.codeDetail  = RequestCode.GET
        msg.messageId   = random.randint(0, 65535)
        msg.tokenLength = 2
        msg.token       = (0x35, 0x61)

        if self._queryName == 'core':
            msg.addOption( CoapOption(OptionType.UriPath, '.well-known') )
            msg.addOption( CoapOption(OptionType.UriPath, 'core') )
        elif self._queryName == 'stats':
            msg.addOption( CoapOption(OptionType.UriPath, 'cli') )
            msg.addOption( CoapOption(OptionType.UriPath, 'stats') )

        if observeAction == 'reg':
            # register
            msg.addOption( CoapOption(OptionType.Observe, 0) )
        elif observeAction == 'dereg':
            # deregister
            msg.addOption( CoapOption(OptionType.Observe, 1) )

        # send message
        log.debug('Sending query')
        self._client.send(msg)

    def start(self):
        '''Starts networking; returns when networking is stopped.

        Only need to start client, which automatically starts server, too.
        '''
        self._client.start()

    def close(self):
        '''Releases resources'''
        self._client.close()