def _fill_soft_ctx(self, start_pdu: bytes, ctx: SoftContext) -> SoftContext: afk = start_pdu[0] & 0x40 >> 6 aid = start_pdu[0] & 0x3f if afk == 1: app_name = self.__search_application_by_aid(aid) if not app_name: return None ctx.application_name = app_name ctx.is_devkey = False else: ctx.application_name = '' ctx.is_devkey = True return ctx
async def model_subscription_add(client_element: Element, target: str, model_id: bytes, addr: bytes) -> bool: node_data = NodeData.load(base_dir + node_dir + target + '.yml') opcode = b'\x80\x1b' r_opcode = b'\x80\x1f' parameters = node_data.addr[::-1] + addr[::-1] + model_id[::-1] context = SoftContext(src_addr=b'\x00\x01', dst_addr=node_data.addr, node_name=node_data.name, network_name=node_data.network, application_name='', is_devkey=True, ack_timeout=3, segment_timeout=3) success = await client_element.send_message(opcode=opcode, parameters=parameters, ctx=context) if not success: return False r_content = await client_element.recv_message(opcode=r_opcode, segment_timeout=1, timeout=3, ctx=context) if r_content: if r_content[0] == 0 and r_content[1:] == parameters: return True return False
def send(target, opcode, parameters, devkey, app): '''Send a message to node''' click.echo(click.style(f'Sending message [{opcode}, {parameters}] to ' f'"{target}" node', fg='green')) node_data = NodeData.load(base_dir + node_dir + target + '.yml') opcode = bytes.fromhex(opcode) parameters = bytes.fromhex(parameters) try: loop = asyncio.get_event_loop() client_element = Element() if devkey: app_name = '' is_devkey = True elif not node_data.apps: click.echo(click.style('Using devkey beacuse node hasn\'t ' 'application registred', fg='yellow')) app_name = '' is_devkey = True else: if app in node_data.apps: app_name = app is_devkey = False else: app_name = node_data.apps[0] is_devkey = False context = SoftContext(src_addr=b'\x00\x01', dst_addr=node_data.addr, node_name=node_data.name, network_name=node_data.network, application_name=app_name, is_devkey=is_devkey, ack_timeout=30, segment_timeout=10) run_seq_t = run_seq([ client_element.spwan_tasks(loop), client_element.send_message(opcode=opcode, parameters=parameters, ctx=context) ]) loop.run_until_complete(run_seq_t) except KeyboardInterrupt: click.echo(click.style('Interruption by user', fg='yellow')) except RuntimeError: click.echo('Runtime error') except Exception as e: click.echo(f'Unknown error\n[{e}]') finally: client_element.disconnect() tasks_running = asyncio.Task.all_tasks() for t in tasks_running: t.cancel() loop.stop() # 4d096b543184ab000000000000000000000000 # PublishTTL default 7 (4.3.2.16)
async def recv_pdu(self): while True: self.log.debug(f'Waiting message...') msg_type, net_pdu = await self.recv_queue.get() # got a message from another channel if msg_type != b'message': continue # get network by nid nid = net_pdu[0] & 0x7f net_data = self.__search_network_by_nid(nid) if not net_data: continue # remove obsfucation clean_pdu = self._clean_message(net_pdu, net_data) # update seq, is_ctrl_msg self._fill_hard_ctx(clean_pdu) # decrypting src_addr = clean_pdu[-2:] mic_size = 8 if self.hard_ctx.is_ctrl_msg else 4 net_mic = net_pdu[-mic_size:] encrypted_pdu = net_pdu[7:-mic_size] decrypted_pdu, mic_is_ok = self._decrypt(encrypted_pdu, src_addr, net_data, net_mic) if not mic_is_ok: self.log.debug(f'Src addr: {src_addr.hex()}') self.log.debug(f'NetMIC wrong. Receive "{net_mic.hex()}"') continue # update seq number in node_data YAML file node_data = self.__search_node_by_addr(src_addr) if not node_data: self.log.debug(f'Node with addr {src_addr} is unknown') continue node_data.seq = self.hard_ctx.seq node_data.save() soft_ctx = SoftContext(src_addr=b'', dst_addr=b'', node_name='', network_name='', application_name='', is_devkey=False, ack_timeout=0, segment_timeout=0) soft_ctx.src_addr = src_addr soft_ctx.dst_addr = decrypted_pdu[0:2] soft_ctx.node_name = node_data.name soft_ctx.network_name = net_data.name transport_pdu = decrypted_pdu[2:] await self.transport_pdus.put( (transport_pdu, soft_ctx, self.hard_ctx.seq))
async def send_cmd(client_element: Element, target: str, opcode: bytes, parameters: bytes, application: str): node_data = NodeData.load(base_dir + node_dir + target + '.yml') app_name = application if application else node_data.apps[0] context = SoftContext(src_addr=b'\x00\x01', dst_addr=node_data.addr, node_name=node_data.name, network_name=node_data.network, application_name=app_name, is_devkey=False, ack_timeout=3, segment_timeout=3) success = await client_element.send_message(opcode=opcode, parameters=parameters, ctx=context) return success
async def appkey_add(client_element: Element, target: str, application: str) -> bool: node_data = NodeData.load(base_dir + node_dir + target + '.yml') app_data = ApplicationData.load(base_dir + app_dir + application + '.yml') net_data = NetworkData.load(base_dir + net_dir + app_data.network + '.yml') net_key = int.from_bytes(net_data.key_index, 'big') app_key = int.from_bytes(app_data.key_index, 'big') key_index = (net_key | (app_key << 12)).to_bytes(3, 'big')[::-1] opcode = b'\x00' r_opcode = b'\x80\x03' parameters = key_index + app_data.key context = SoftContext(src_addr=b'\x00\x01', dst_addr=node_data.addr, node_name=node_data.name, network_name=node_data.network, application_name='', is_devkey=True, ack_timeout=3, segment_timeout=3) success = await client_element.send_message(opcode=opcode, parameters=parameters, ctx=context) if not success: return False r_content = await client_element.recv_message(opcode=r_opcode, segment_timeout=1, timeout=3, ctx=context) if r_content: if r_content[0] == 0 and r_content[1:] == key_index: if app_data.name not in node_data.apps: node_data.apps.append(app_data.name) node_data.save() if node_data.name not in app_data.nodes: app_data.nodes.append(node_data.name) app_data.save() return True return False
async def model_publication_set(client_element: Element, target: str, model_id: bytes, addr: bytes, application: str) -> bool: node_data = NodeData.load(base_dir + node_dir + target + '.yml') app_data = ApplicationData.load(base_dir + app_dir + application + '.yml') key_index = app_data.key_index default_ttl = b'\x07' period = b'\x00' default_xmit_int = b'\x40' opcode = b'\x03' r_opcode = b'\x80\x19' parameters = node_data.addr[::-1] + addr[::-1] + key_index[::-1] + \ default_ttl[::-1] + period[::-1] + default_xmit_int[::-1] + \ model_id[::-1] context = SoftContext(src_addr=b'\x00\x01', dst_addr=node_data.addr, node_name=node_data.name, network_name=node_data.network, application_name='', is_devkey=True, ack_timeout=3, segment_timeout=3) success = await client_element.send_message(opcode=opcode, parameters=parameters, ctx=context) if not success: return False r_content = await client_element.recv_message(opcode=r_opcode, segment_timeout=1, timeout=3, ctx=context) if r_content: if r_content[0] == 0 and r_content[1:] == parameters: return True return False
def add_appkey(target, app): '''Add a appkey to node''' click.echo( click.style( f'Add the appkey of "{app}" application to ' f'"{target}" node', fg='green')) node_data = NodeData.load(base_dir + node_dir + target + '.yml') app_data = ApplicationData.load(base_dir + app_dir + app + '.yml') net_data = NetworkData.load(base_dir + net_dir + node_data.network + '.yml') net_key = int.from_bytes(net_data.key_index, 'big') app_key = int.from_bytes(app_data.key_index, 'big') key_index = (net_key | (app_key << 12)).to_bytes(3, 'big')[::-1] opcode = b'\x00' r_opcode = b'\x80\x03' parameters = key_index + app_data.key try: loop = asyncio.get_event_loop() client_element = Element() context = SoftContext(src_addr=b'\x00\x01', dst_addr=node_data.addr, node_name=node_data.name, network_name=node_data.network, application_name='', is_devkey=True, ack_timeout=10, segment_timeout=3) run_seq_t = run_seq([ client_element.spwan_tasks(loop), client_element.send_message(opcode=opcode, parameters=parameters, ctx=context), client_element.recv_message(opcode=r_opcode, segment_timeout=3, timeout=10, ctx=context) ]) results = loop.run_until_complete(run_seq_t) content = results[2][0] if content: if content[0] == 0: if content[1:] == key_index: click.echo( click.style('App key add with successful', fg='green')) if app_data.name not in node_data.apps: node_data.apps.append(app_data.name) node_data.save() if node_data.name not in app_data.nodes: app_data.nodes.append(node_data.name) app_data.save() else: click.echo( click.style(f'Wrong key index: {content[1:].hex()}', fg='red')) else: click.echo( click.style(f'Fail. Error code: {content[0:1].hex()}', fg='red')) except KeyboardInterrupt: click.echo(click.style('Interruption by user', fg='yellow')) except RuntimeError: click.echo('Runtime error') except Exception: click.echo(traceback.format_exc()) finally: client_element.disconnect() tasks_running = asyncio.Task.all_tasks() for t in tasks_running: t.cancel() loop.stop()
def req(target, opcode, parameters, r_opcode, devkey, app): '''Request a message to node (Send a message and wait the response)''' click.echo( click.style( f'Sending message [{opcode}, {parameters}] to ' f'"{target}" node and wait receive a message with ' f'opcode {r_opcode}', fg='green')) node_data = NodeData.load(base_dir + node_dir + target + '.yml') print(f'node addr: {node_data.addr}') opcode = bytes.fromhex(opcode) r_opcode = bytes.fromhex(r_opcode) parameters = bytes.fromhex(parameters) try: loop = asyncio.get_event_loop() client_element = Element() if devkey: app_name = '' is_devkey = True elif not node_data.apps: click.echo( click.style( 'Using devkey beacuse node hasn\'t ' 'application registred', fg='yellow')) app_name = '' is_devkey = True else: if app in node_data.apps: app_name = app is_devkey = False else: app_name = node_data.apps[0] is_devkey = False context = SoftContext(src_addr=b'\x00\x01', dst_addr=node_data.addr, node_name=node_data.name, network_name=node_data.network, application_name=app_name, is_devkey=is_devkey, ack_timeout=30, segment_timeout=10) run_seq_t = run_seq([ client_element.spwan_tasks(loop), client_element.send_message(opcode=opcode, parameters=parameters, ctx=context), client_element.recv_message(opcode=r_opcode, segment_timeout=3, timeout=10, ctx=context) ]) results = loop.run_until_complete(run_seq_t) content = results[2][0] if content: click.echo( click.style(f'Message received: {content.hex()}', fg='white')) else: click.echo( click.style( f'No message with opcode {r_opcode.hex()} ' f'received', fg='red')) except KeyboardInterrupt: click.echo(click.style('Interruption by user', fg='yellow')) except RuntimeError: click.echo('Runtime error') except Exception as e: click.echo(f'Unknown error\n[{e}]') finally: client_element.disconnect() tasks_running = asyncio.Task.all_tasks() for t in tasks_running: t.cancel() loop.stop()