Example #1
0
 def __init__(self, port=soscoap.COAP_PORT):
     '''Pass in port for non-standard CoAP port.
     '''
     self._server = CoapServer(port=port)
     self._server.registerForResourceGet(self._getResource)
     self._server.registerForResourcePut(self._putResource)
     self._server.registerForResourcePost(self._postResource)
     self._delay = 0
     self._verIgnores = 0
Example #2
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 #3
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 #4
0
 def __init__(self, uripath, filename):
     self.uripath   = uripath
     self.filename  = filename
     # Must be defined for use by close().
     self._chanfile = None
     
     self._server = CoapServer()
     self._server.registerForResourceGet(self._getResource)
     self._server.registerForResourcePut(self._putResource)
     self._server.registerForResourcePost(self._postResource)
class ConIgnoreServer(object):
    def __init__(self, ignores):
        """Pass in count of confirmable messages to ignore."""
        self._server = CoapServer(port=5683)
        self._server.registerForResourceGet(self._getResource)
        self._ignores = ignores

    def _getResource(self, resource):
        """Sets the value for the provided resource, for a GET request."""
        if resource.path == '/time':
            if self._ignores > 0:
                self._ignores = self._ignores - 1
                raise IgnoreRequestException
                return
            else:
                resource.type = 'string'
                now = datetime.datetime.now()
                resource.value = now.strftime("%Y-%m-%d %H:%M").encode('ascii')
        else:
            raise NotImplementedError('Unknown path')
            return

    def start(self):
        self._server.start()
Example #6
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 #7
0
        :return: The created host
        :rtype: Host
        '''
        host = Host()
        host.interface_id = resource.value
        host.address      = resource.sourceAddress[0]
        host.name         = getInvariantName(host)    # requires ipAddress
        host.coords       = "100,100"                 # arbitrary values, so shows on map
        
        return host

    
if __name__ == "__main__":
    logging.basicConfig(filename='nethead.log', level=logging.DEBUG, 
                        format='%(asctime)s %(module)s %(message)s')
    log.info('Initializing Nethead server')

    formattedPath = '\n\t'.join(str(p) for p in sys.path)
    log.info('Running server with sys.path:\n\t{0}'.format(formattedPath))

    server = None
    try:
        coapServer = CoapServer()
        if coapServer:
            server = HostManager( coapServer )
            coapServer.start()
    except KeyboardInterrupt:
        pass
    except:
        log.exception('Catch-all handler for Nethead server')
 def __init__(self, ignores):
     """Pass in count of confirmable messages to ignore."""
     self._server = CoapServer(port=5683)
     self._server.registerForResourceGet(self._getResource)
     self._ignores = ignores
Example #9
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()
Example #10
0
class ValueRecorder(object):
    '''Records the values posted to a provided URI. Records the values to a file.
    
    Attributes:
        :uripath:  str URI for resource
        :filename: str Name of target file for recording
        :_chanfile: File Recording target
        :_server:   CoapServer Provides CoAP message protocol
    
    Usage:
        #. cr = ValueRecorder(uripath, filename)  -- Create instance
        #. cr.start()  -- Starts to listen and record messages
        #. cr.close()  -- Releases sytem resources
        
    URIs:
        | /ver -- GET program version
        | /<uripath-attribute> -- PUT/POST to <filename-attribute> file, where
                                  the attribute names are provided to the class
                                  constructor
    '''
    def __init__(self, uripath, filename):
        self.uripath   = uripath
        self.filename  = filename
        # Must be defined for use by close().
        self._chanfile = None
        
        self._server = CoapServer()
        self._server.registerForResourceGet(self._getResource)
        self._server.registerForResourcePut(self._putResource)
        self._server.registerForResourcePost(self._postResource)
        
    def close(self):
        '''Releases system resources.
        '''
        if self._chanfile:
            self._chanfile.close() 
                
    def _getResource(self, resource):
        '''Sets the value for the provided resource, for a GET request.
        '''
        log.debug('Resource path is {0}'.format(resource.path))
        if resource.path == '/ver':
            resource.type  = 'string'
            resource.value = VERSION
            log.debug('Got resource value')
        else:
            log.debug('Unknown path')
    
    def _postResource(self, resource):
        '''Records the value for the provided resource, for a POST request.
        
        :param resource.value: str ASCII in CSV format, with two fields:
                               1. int Time
                               2. int Value
        '''
        log.debug('Resource path is {0}'.format(resource.path))
        if resource.path == self.uripath:
            self._chanfile.writelines((resource.value, '\n'))
            self._chanfile.flush()
            log.debug('POST resource value done')
        else:
            raise NotImplementedError('Unknown path')
    
    def _putResource(self, resource):
        '''Records the value for the provided resource, for a PUT request.
        
        :param resource.value: str ASCII in CSV format, with two fields:
                               1. int Time
                               2. int Value
        '''
        log.debug('Resource path is {0}'.format(resource.path))
        if resource.path == self.uripath:
            self._chanfile.writelines((resource.value, '\n'))
            self._chanfile.flush()
            log.debug('PUT resource value done')
        else:
            raise NotImplementedError('Unknown path')
    
    def start(self):
        '''Creates the server, and opens the file for this recorder.
        
        :raises IOError: If cannot open file
        '''
        self._chanfile = open(self.filename, 'w')
        self._server.start()
Example #11
0
class GcoapTester(object):
    '''Provides a server for testing gcoap client commands.
    
    Attributes:
        :_server:   CoapServer Provides CoAP message protocol
        :_delay:    Time in seconds to delay a response; useful for testing
    
    Usage:
        #. cr = GcoapTester()  -- Create instance
        #. cr.start()  -- Starts to listen
        #. cr.close()  -- Releases sytem resources
        
    URIs:
        | /ver -- GET program version
        | /toobig -- GET large text payload. CoAP PDU exceeds 128-byte buffer
                     used by gcoap.
        | /ignore -- GET that does not respond.
        | Configuration
        | /cf/delay -- POST integer seconds to delay future responses
        | /ver/ignores -- PUT count of /ver requests to ignore before responding;
                          tests client retry mechanism
    '''
    def __init__(self, port=soscoap.COAP_PORT):
        '''Pass in port for non-standard CoAP port.
        '''
        self._server = CoapServer(port=port)
        self._server.registerForResourceGet(self._getResource)
        self._server.registerForResourcePut(self._putResource)
        self._server.registerForResourcePost(self._postResource)
        self._delay = 0
        self._verIgnores = 0

    def close(self):
        '''Releases system resources.
        '''
        pass

    def _getResource(self, resource):
        '''Sets the value for the provided resource, for a GET request.
        '''
        log.debug('Resource path is {0}'.format(resource.path))
        if resource.path == '/ver':
            if self._verIgnores > 0:
                self._verIgnores = self._verIgnores - 1
                raise IgnoreRequestException
                return
            else:
                resource.type = 'string'
                resource.value = VERSION
        elif resource.path == '/toobig':
            resource.type = 'string'
            resource.value = '1234567890' * 13
        elif resource.path == '/ignore':
            time.sleep(self._delay)
            raise IgnoreRequestException
            return
        else:
            time.sleep(self._delay)
            raise NotImplementedError('Unknown path')
            return

        time.sleep(self._delay)

    def _postResource(self, resource):
        '''Accepts the value for the provided resource, for a POST request.
        '''
        log.debug('Resource path is {0}'.format(resource.path))
        if resource.path == '/cf/delay':
            self._delay = int(resource.value)
            log.debug('Post delay value: {0}'.format(self._delay))
        else:
            time.sleep(self._delay)
            raise NotImplementedError('Unknown path: {0}'.format(
                resource.path))

    def _putResource(self, resource):
        '''Accepts the value for the provided resource, for a PUT request.
        '''
        if resource.path == '/ver/ignores':
            self._verIgnores = int(resource.value)
            log.debug('Ignores for /ver: {0}'.format(self._verIgnores))
        else:
            raise NotImplementedError('Unknown path: {0}'.format(
                resource.path))

    def start(self):
        '''Creates the server, and opens the file for this recorder.
        
        :raises IOError: If cannot open file
        '''
        self._server.start()