def _action_TXACK(self): # log log.debug('_action_TXACK()') with self.dataLock: (timestamp,srcIp,srcPort,message) = self.receivedResp # build ACK message = m.buildMessage( msgtype = d.TYPE_ACK, token = None, code = d.COAP_RC_NONE, messageId = message['messageId'], ) # send self.sendFunc( destIp = message['srcId'], destPort = message['srcPort'], msg = message, ) # successful end of FSM with self.dataLock: self.coapResponse = message # kick FSM self._kickFsm()
def _action_TXNON(self): # log log.debug('_action_TXNON()') # build message message = m.buildMessage( msgtype = d.TYPE_NON, token = self.token, code = self.code, messageId = self.messageId, options = self.options, payload = self.payload, securityContext = self.securityContext, partialIV = self.requestSeq, ) # send self.sendFunc( destIp = self.destIp, destPort = self.destPort, msg = message, ) # update FSM state self._setState(self.STATE_WAITFORRESP) # kick FSM self._kickFsm()
def on_message(ws, message): logging.info('Recv message:%s', message) retval = coapMessage.parseMessage(message) msg_id = retval['messageId'] token = retval['token'] payload = retval['payload'] device_id = ntohl(long(payload[0:7])) method = int(payload[8]) data = payload[9:] logging.info('code %d, msg_id %d, device_id %x, method %d', retval['code'], retval['messageId'], device_id, method) logging.info('Message data:%s', data) parameters = None parameters = json.loads(data) if parameters == None: logging.error('Invalid message parameters, Drop') return ''' code class can indicate a request (0), a success response (2), a client error response (4), or a server error response (5). (All other class values are reserved.) ''' code_class = retval['code'] >> 5 if code_class == 0: #request result = None if method == CONFIG_METHOD: result = devices_manager.device_config(device_id, parameters) elif method == RELOAD_METHOD: result = devices_manager.device_reload(device_id) else: logging.error('Unacceptable method:%d', method) if retval['type'] == TYPE_CON: if result: result = json.dumps(result, separators=(',', ':')) response_data = payload[0:8] + result response = coapMessage.buildMessage(msgtype=coapDefines.TYPE_ACK, token=token, code=(0x2 << 5 | 0x4), messageId=msg_id, payload=response_data) self.write_message(response) else: logging.info('Message result:%s', result) elif code_class == 2 or code_class == 4 or code_class == 5: #response logging.info('Resonpse received') else: logging.error('Unacceptable message code class:%d', code_class)
def device_info(self, device_id, device_info): if self.ws: request_data = utils.number2buf(device_id, 8) + utils.number2buf( INFO_METHOD, 1) + jsonp.print_JSON(device_info) request = coapMessage.buildMessage(msgtype=coapDefines.TYPE_NON, token=self._get_token(), code=coapDefines.METHOD_POST, messageId=self.transaction_id, payload=request_data) self.ws.send(request) self.transaction_id += 1
def test_buildMessage(logFixture, messageAndBytes): (msg,bytes) = messageAndBytes log.debug('msg: {0}'.format(msg)) log.debug('bytes: {0}'.format(u.formatBuf(bytes))) result = m.buildMessage( type = msg[0], token = msg[1], code = msg[2], messageId = msg[3], options = msg[4], payload = list(msg[5]), ) log.debug('result: {0}'.format(u.formatBuf(result))) assert tuple(result)==bytes
def test_buildMessage(logFixture, messageAndBytes): (msg, bytes) = messageAndBytes log.debug('msg: {0}'.format(msg)) log.debug('bytes: {0}'.format(u.formatBuf(bytes))) result = m.buildMessage( msgtype=msg[0], token=msg[1], code=msg[2], messageId=msg[3], options=msg[4], payload=list(msg[5]), ) log.debug('result: {0}'.format(u.formatBuf(result))) assert tuple(result) == bytes
def _action_TXCON(self): # log log.debug('_action_TXCON()') # flag error if max number of CON transmits reached if self.numTxCON>self.maxRetransmit+1: # this is an error case self.coapError = e.coapTimeout('No ACK received after {0} tries (max {1})'.format( self.numTxCON, self.maxRetransmit+1, ) ) return # build message message = m.buildMessage( msgtype = d.TYPE_CON, token = self.token, code = self.code, messageId = self.messageId, options = self.options, payload = self.payload, securityContext = self.securityContext, partialIV = self.requestSeq, ) # send self.sendFunc( destIp = self.destIp, destPort = self.destPort, msg = message, ) # increment number of transmitted messages self.numTxCON += 1 # update FSM state self._setState(self.STATE_WAITFORACK) # kick FSM self._kickFsm()
def _receive(self, timestamp, sender, rawbytes): # all UDP packets are received here output = [] output += ['\n{0} _receive message:'.format(self.name)] output += ['- timestamp: {0}'.format(timestamp)] output += ['- sender: {0}'.format(sender)] output += ['- bytes: {0}'.format(u.formatBuf(rawbytes))] output = '\n'.join(output) log.debug(output) srcIp = sender[0] srcIp = u.trimAddress(srcIp) srcPort = sender[1] # parse messages try: message = m.parseMessage(rawbytes) options = message['options'] except e.messageFormatError as err: log.warning('malformed message {0}: {1}'.format( u.formatBuf(rawbytes), str(err))) return # dispatch message try: if message['code'] in d.METHOD_ALL: # this is meant for a resource (request) #==== decrypt message if encrypted innerOptions = [] foundContext = None requestPartialIV = None if 'ciphertext' in message.keys(): # retrieve security context # before decrypting we don't know what resource this request is meant for # so we take the first binding with the correct context (recipientID) blindContext = self._securityContextLookup( u.buf2str(message['kid'])) if not blindContext: if self.secContextHandler: appContext = self.secContextHandler( u.buf2str(message['kid'])) if not appContext: raise e.coapRcUnauthorized( 'Security context not found.') else: raise e.coapRcUnauthorized( 'Security context not found.') foundContext = blindContext if blindContext != None else appContext requestPartialIV = u.zeroPadString( u.buf2str(message['partialIV']), foundContext.getIVLength()) # decrypt the message try: (innerOptions, plaintext) = oscoap.unprotectMessage( foundContext, version=message['version'], code=message['code'], options=message['options'], ciphertext=message['ciphertext'], partialIV=requestPartialIV) except e.oscoapError as err: raise e.coapRcBadRequest( 'OSCOAP unprotect failed: {0}'.format(str(err))) payload = plaintext else: # message not encrypted payload = message['payload'] options += innerOptions #==== find right resource # retrieve path path = coapUri.options2path(options) log.debug('path="{0}"'.format(path)) # find resource that matches this path resource = None with self.resourceLock: for r in self.resources: if r.matchesPath(path): resource = r break log.debug('resource={0}'.format(resource)) if not resource: raise e.coapRcNotFound() #==== check if appropriate security context was used for the resource (context, authorizedMethods) = resource.getSecurityBinding() if context is not None: if context != foundContext: raise e.coapRcUnauthorized( 'Unauthorized security context for the given resource' ) objectSecurity = oscoap.objectSecurityOptionLookUp(options) if objectSecurity: objectSecurity.setContext(foundContext) #==== get a response # call the right resource's method try: if message[ 'code'] == d.METHOD_GET and d.METHOD_GET in authorizedMethods: (respCode, respOptions, respPayload) = resource.GET(options=options) elif message[ 'code'] == d.METHOD_POST and d.METHOD_POST in authorizedMethods: (respCode, respOptions, respPayload) = resource.POST(options=options, payload=payload) elif message[ 'code'] == d.METHOD_PUT and d.METHOD_PUT in authorizedMethods: (respCode, respOptions, respPayload) = resource.PUT(options=options, payload=payload) elif message[ 'code'] == d.METHOD_DELETE and d.METHOD_DELETE in authorizedMethods: (respCode, respOptions, respPayload) = resource.DELETE(options=options) elif message['code'] not in d.METHOD_ALL: raise SystemError('unexpected code {0}'.format( message['code'])) else: raise e.coapRcUnauthorized( 'Unauthorized method for the given resource') except Exception as err: if isinstance(err, e.coapRc): raise else: raise e.coapRcInternalServerError() #==== send back response # determine type of response packet if message['type'] == d.TYPE_CON: responseType = d.TYPE_ACK elif message['type'] == d.TYPE_NON: responseType = d.TYPE_NON else: raise SystemError('unexpected type {0}'.format( message['type'])) # if resource is protected with a security context, add Object-Security option if foundContext: # verify that the Object-Security option was not set by the resource handler assert not any( isinstance(option, o.ObjectSecurity) for option in respOptions) objectSecurity = o.ObjectSecurity(context=foundContext) respOptions += [objectSecurity] # if Stateless-Proxy option was present in the request echo it for option in options: if isinstance(option, o.StatelessProxy): respOptions += [option] break # build response packets and pass partialIV from the request for OSCOAP's processing response = m.buildMessage(msgtype=responseType, token=message['token'], code=respCode, messageId=message['messageId'], options=respOptions, payload=respPayload, securityContext=foundContext, partialIV=requestPartialIV) # send self.socketUdp.sendUdp( destIp=srcIp, destPort=srcPort, msg=response, ) elif message['code'] in d.COAP_RC_ALL: # this is meant for a transmitter (response) # find transmitter msgkey = (srcIp, srcPort, message['token'], message['messageId']) found = False with self.transmittersLock: self._cleanupTransmitter() for (k, v) in self.transmitters.items(): # try matching if (msgkey[0] == k[0] and msgkey[1] == k[1] and (msgkey[2] == k[2] or msgkey[3] == k[3])): found = True v.receiveMessage(timestamp, srcIp, srcPort, message) break if found == False: raise e.coapRcBadRequest( 'could not find transmitter corresponding to {0}, transmitters are {1}' .format( msgkey, ','.join( [str(k) for k in self.transmitters.keys()]))) else: raise NotImplementedError() except e.coapRc as err: # log log.warning(err) # determine type of response packet if message['type'] == d.TYPE_CON: responseType = d.TYPE_ACK elif message['type'] == d.TYPE_NON: responseType = d.TYPE_NON else: raise SystemError('unexpected type {0}'.format( message['type'])) # if Stateless-Proxy option was present in the request echo it errorOptions = [] for option in options: if isinstance(option, o.StatelessProxy): errorOptions += [option] break # build response packets response = m.buildMessage( msgtype=responseType, token=message['token'], code=err.rc, messageId=message['messageId'], options=errorOptions, ) # send self.socketUdp.sendUdp( destIp=srcIp, destPort=srcPort, msg=response, ) except Exception as err: log.critical(traceback.format_exc())