def make_subdata_cmd(self, prefix, dataname, seq, lifetime=None, subinfo: SubInfo = None) -> (str, Any): """ make subdata command :param prefix: datarn_prefix :type prefix: str :param dataname: dataname :type dataname: str :param seq: sequence no. :type seq: int :param subinfo: subinfo :type subinfo: SubInfo :return: command, interest_param, app_param """ # make a subdatareq command name with args #command = Name.to_str(prefix + "/" + CMD_SUBDATAREQ + dataname + f'/{seq:d}') command = prefix + "/" + PSKCmd.commands[ "CMD_SD"] + dataname + "/" + str(seq) # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = (lifetime if lifetime else INT_LT_10) # make a app_params for subscription param = PSKParameters(subinfo=subinfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def test_app_param(): name = '/local/ndn/prefix' app_param = b'\x01\x02\x03\x04' interest, final_name = make_interest(name, InterestParam(), app_param, need_final_name=True) assert ( interest == b'\x05\x42\x07\x36\x08\x05local\x08\x03ndn\x08\x06prefix' b'\x02 \x47\x75\x6f\x21\xfe\x0e\xe2\x65\x14\x9a\xa2\xbe\x3c\x63\xc5\x38' b'\xa7\x23\x78\xe9\xb0\xa5\x8b\x39\xc5\x91\x63\x67\xd3\x5b\xda\x10' b'\x0c\x02\x0f\xa0\x24\x04\x01\x02\x03\x04') assert (final_name == Name.decode( b'\x07\x36\x08\x05local\x08\x03ndn\x08\x06prefix' b'\x02 \x47\x75\x6f\x21\xfe\x0e\xe2\x65\x14\x9a\xa2\xbe\x3c\x63\xc5\x38' b'\xa7\x23\x78\xe9\xb0\xa5\x8b\x39\xc5\x91\x63\x67\xd3\x5b\xda\x10' )[0]) name = '/test/params-sha256=FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF/ndn' interest = make_interest(name, InterestParam(), app_param) assert ( interest == b'\x05\x39\x07\x2d\x08\x04test' b'\x02 \x47\x75\x6f\x21\xfe\x0e\xe2\x65\x14\x9a\xa2\xbe\x3c\x63\xc5\x38' b'\xa7\x23\x78\xe9\xb0\xa5\x8b\x39\xc5\x91\x63\x67\xd3\x5b\xda\x10' b'\x08\x03ndn' b'\x0c\x02\x0f\xa0\x24\x04\x01\x02\x03\x04')
def make_irdel_cmd(self, prefix, dataname, rawpacket: BinaryStr = None) -> (str, Any): """ make irdel command :param prefix: ir_prefix :type prefix: str :param dataname: dataname :type dataname: str :param rawpacket: raw interest packet :type bytes: :return: command, interest_param, app_param """ # make a irmod command name with args command = prefix + "/" + PSKCmd.commands["CMD_MD"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_4 # make app_param for Infomation Registry (raw interest packet) str_rawpacket = rawpacket.decode('utf-8') param = PSKParameters(rawpacket=str_rawpacket) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def make_pubdata_cmd(self, prefix, dataname, seq, pubdatainfo: PubDataInfo = None) -> (str, Any): """ make pubdata command :param prefix: network_prefix :type prefix: str :param dataname: dataname for publishing data :type dataname: str :param seq: sequence no. :type seq: int :param pubed_data: pubed data :type pubed_data: any :return: command, interest_param, app_param """ # make a pubdata command name with args command = prefix + "/" + PSKCmd.commands[ "CMD_PD"] + dataname + '/' + str(seq) # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_4 param = PSKParameters(pubdatainfo=pubdatainfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def make_subtopic_cmd(self, prefix, dataname, subinfo: SubInfo = None) -> (str, Any): """ make subtopic command :param prefix: network_prefix or topicrn_prefix :type prefix: str :param dataname: topic name :type dataname: str :param subinfo: subscription information :type subinfo: SubInfo :return: command, interest_param, app_param """ # make a subtopic command name with args command = prefix + "/" + PSKCmd.commands["CMD_ST"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 # make a app_params for subscription param = PSKParameters(subinfo=subinfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def test_signed_interest(): name = '/local/ndn/prefix' app_param = b'\x01\x02\x03\x04' int_param = InterestParam() int_param.nonce = 0x6c211166 interest = make_interest(name, int_param, app_param, signer=DigestSha256Signer()) assert (interest == b'\x05\x6f\x07\x36\x08\x05local\x08\x03ndn\x08\x06prefix' b'\x02 \x8e\x6e\x36\xd7\xea\xbc\xde\x43\x75\x61\x40\xc9\x0b\xda\x09\xd5' b'\x00\xd2\xa5\x77\xf2\xf5\x33\xb5\x69\xf0\x44\x1d\xf0\xa7\xf9\xe2' b'\x0a\x04\x6c\x21\x11\x66\x0c\x02\x0f\xa0' b'\x24\x04\x01\x02\x03\x04' b'\x2c\x03\x1b\x01\x00' b'\x2e \xea\xa8\xf0\x99\x08\x63\x78\x95\x1d\xe0\x5f\xf1\xde\xbb\xc1\x18' b'\xb5\x21\x8b\x2f\xca\xa0\xb5\x1d\x18\xfa\xbc\x29\xf5\x4d\x58\xff') interest = make_interest(name, int_param, signer=DigestSha256Signer()) assert (interest == b'\x05\x6b\x07\x36\x08\x05local\x08\x03ndn\x08\x06prefix' b'\x02 \x40\x77\xa5\x70\x49\xd8\x38\x48\xb5\x25\xa4\x23\xab\x97\x8e\x64' b'\x80\xf9\x6d\x5c\xa3\x8a\x80\xa5\xe2\xd6\xe2\x50\xa6\x17\xbe\x4f' b'\x0a\x04\x6c\x21\x11\x66\x0c\x02\x0f\xa0' b'\x24\x00' b'\x2c\x03\x1b\x01\x00' b'\x2e \x09\x4e\x00\x9d\x74\x59\x82\x5c\xa0\x2d\xaa\xb7\xad\x60\x48\x30' b'\x39\x19\xd8\x99\x80\x25\xbe\xff\xa6\xf9\x96\x79\xd6\x5e\x9f\x62')
def make_pubadv_cmd(self, prefix: str, dataname: str, pubadvinfo: PubAdvInfo = None, irinfo: IRInfo = None, rninfo: RNInfo = None) -> (str, Any): """ make pubadv command :param prefix: network_prefix or broker_prefix :type prefix: str :param dataname: dataname for publishing data :type dataname: str :param pubinfo: pubadvinfo :type pubinfo: PubAdvInfo :param irinfo: irinfo :type irinfo: IRInfo :param rninfo: rninfo :type rninfo: RNInfo :return: command, interest_param, app_param """ # make a pubadv command name with args #command = Name.to_str(prefix + "/" + CMD_PUBADV + dataname) command = prefix + "/" + PSKCmd.commands["CMD_PA"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 param = PSKParameters(pubadvinfo=pubadvinfo, irinfo=irinfo, rninfo=rninfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def make_generic_cmd(self, command: str, prefix: str, dataname: str = "/_", pubadvinfo: PubAdvInfo = None, irinfo: IRInfo = None, rninfo: RNInfo = None, **kwargs) -> (str, Any): """ make generic command :param prefix: network_prefix or broker_prefix :type prefix: str :param dataname: dataname for publishing data :type dataname: str :param pubinfo: pubadvinfo :type pubinfo: PubAdvInfo :param irinfo: irinfo :type irinfo: IRInfo :param rninfo: rninfo :type rninfo: RNInfo :return: command, interest_param, app_param """ command = prefix + "/" + command + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 param = PSKParameters(pubadvinfo=pubadvinfo, irinfo=irinfo, rninfo=rninfo, **kwargs) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
async def _process_notify_interest(self, int_name, int_param, app_param): """ Async helper for ``_on_notify_interest()``. """ logging.debug(f'received notify interest: {Name.to_str(int_name)}') topic = int_name[:-2] # remove digest and `notify` # parse notify interest app_param = NotifyAppParam.parse(app_param) publisher_prefix = app_param.publisher_prefix notify_nonce = app_param.notify_nonce publisher_fwd_hint = app_param.publisher_fwd_hint int_param = InterestParam() if publisher_fwd_hint: # support only 1 forwarding hint now int_param.forwarding_hint = [(0x0, publisher_fwd_hint.name)] # send msg interest, retransmit 3 times msg_int_name = publisher_prefix + ['msg'] + topic + [ Component.from_bytes(notify_nonce) ] n_retries = 3 # de-duplicate notify interests of the same nonce if notify_nonce in self.nonce_processed: logging.info( f'Received duplicate notify interest for nonce {notify_nonce}') return self.nonce_processed.add(notify_nonce) aio.ensure_future(self._erase_subsciber_state_after(notify_nonce, 60)) while n_retries > 0: try: logging.debug( f'sending msg interest: {Name.to_str(msg_int_name)}') data_name, meta_info, msg = await self.app.express_interest( msg_int_name, int_param=int_param) break except InterestNack as e: logging.debug(f'Nacked with reason: {e.reason}') await aio.sleep(1) n_retries -= 1 except InterestTimeout: logging.debug(f'Timeout') n_retries -= 1 if msg == None: return # pass msg to application logging.info(f'received subscribed msg: {Name.to_str(msg_int_name)}') self.topic_to_cb[topic](bytes(msg)) # acknowledge notify interest with an empty data packet logging.debug(f'acknowledging notify interest {Name.to_str(int_name)}') self.app.put_data(int_name, None)
def test_default(): name = Name.from_str('/local/ndn/prefix') interest = make_interest(name, InterestParam()) assert interest == b'\x05\x1a\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix\x0c\x02\x0f\xa0' name = Name.encode(name) interest = make_interest(name, InterestParam()) assert interest == b'\x05\x1a\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix\x0c\x02\x0f\xa0' name = '/local/ndn/prefix' interest = make_interest(name, InterestParam()) assert interest == b'\x05\x1a\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix\x0c\x02\x0f\xa0'
def test_forwarding_hint(): name = '/local/ndn/prefix' int_param = InterestParam() int_param.nonce = 0x01020304 int_param.forwarding_hint = [(0x87, '/name/A'), (0x02, Name.from_str('/ndn/B')), (0x12, b'\x07\x0d\x08\x0bshekkuenseu')] interest = make_interest(name, int_param) assert (interest == b'\x05\x55\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix' b'\x1e\x33' b'\x1f\x0e\x1e\x01\x87\x07\x09\x08\x04name\x08\x01A' b'\x1f\x0d\x1e\x01\x02\x07\x08\x08\x03ndn\x08\x01B' b'\x1f\x12\x1e\x01\x12\x07\r\x08\x0bshekkuenseu' b'\x0a\x04\x01\x02\x03\x04\x0c\x02\x0f\xa0')
def test2(): interest = make_interest( '/localhost/nfd/faces/events', InterestParam(must_be_fresh=True, can_be_prefix=True)) lp_packet = make_network_nack(interest, NackReason.NO_ROUTE) assert lp_packet == ( b"\x64\x36\xfd\x03\x20\x05\xfd\x03\x21\x01\x96" b"\x50\x2b\x05\x29\x07\x1f\x08\tlocalhost\x08\x03nfd\x08\x05faces\x08\x06events" b"\x21\x00\x12\x00\x0c\x02\x0f\xa0")
async def _process_notify_interest(self, int_name, int_param, app_param): """ Async helper for ``_on_notify_interest()``. """ logging.debug(f'received notify interest: {Name.to_str(int_name)}') topic = int_name[:-2] # remove digest and `notify` # parse notify interest app_param = PubSub.NotifyAppParam.parse(app_param) publisher_prefix = app_param.publisher_prefix nonce = app_param.nonce publisher_fwd_hint = app_param.publisher_fwd_hint int_param = InterestParam() if publisher_fwd_hint: int_param.forwarding_hint = publisher_fwd_hint # send msg interest, retransmit 3 times msg_int_name = publisher_prefix + ['msg', str(nonce)] n_retries = 3 while n_retries > 0: try: logging.debug( f'sending msg interest: {Name.to_str(msg_int_name)}') data_name, meta_info, msg = await self.app.express_interest( msg_int_name, int_param=int_param) break except InterestNack as e: logging.debug(f'Nacked with reason: {e.reason}') await aio.sleep(1) except InterestTimeout: logging.debug(f'Timeout') if msg == None: return # pass msg to application logging.info(f'received subscribed msg: {Name.to_str(msg_int_name)}') self.topic_to_cb[topic](bytes(msg)) # acknowledge notify interest with an empty data packet logging.debug(f'acknowledging notify interest {Name.to_str(int_name)}') self.app.put_data(int_name, None)
def test_interest_params(): name = '/local/ndn/prefix' int_param = InterestParam() int_param.can_be_prefix = True int_param.must_be_fresh = True int_param.hop_limit = 1 int_param.nonce = 0 int_param.lifetime = 10 interest = make_interest(name, int_param) assert (interest == b'\x05\x26\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix' b'\x21\x00\x12\x00\x0a\x04\x00\x00\x00\x00\x0c\x01\x0a\x22\x01\x01')
def make_pubunadv_cmd(self, prefix, dataname, pubadvinfo: PubAdvInfo = None) -> (str, Any): """ make pubunadv command :param prefix: network_prefix or broker_prefix :type prefix: str :param dataname: dataname for unpublishing data :type dataname: str :param pubadvinfo: pub information :type pubadvinfo: :return: command, interest_param, app_param """ # make a pubunadv command name with args command = prefix + "/" + PSKCmd.commands["CMD_PU"] + dataname # set interest parameter i_param = InterestParam() i_param.must_be_fresh = True i_param.nonce = gen_nonce() i_param.lifetime = INT_LT_10 param = PSKParameters(pubadvinfo=pubadvinfo) str_app_param = json.dumps(param, default=serialize) return command, i_param, bytes(str_app_param, 'utf-8')
def test_throws(): with pytest.raises(ValueError): make_interest("/invalid%%name", InterestParam()) with pytest.raises(TypeError): make_interest("/ndn", InterestParam(lifetime=0.5)) with pytest.raises(TypeError): make_interest("/ndn", InterestParam(forwarding_hint=[1, 2, 3])) with pytest.raises(ValueError): make_interest("/ndn", InterestParam(hop_limit=300)) with pytest.raises(ValueError): make_interest("/params-sha256=4077", InterestParam()) with pytest.raises(ValueError): make_interest("/params-sha256=4077", InterestParam(), b'')
from dataclasses_json import dataclass_json from flask import Flask, Response, request from ndn.encoding import InterestParam, make_interest from ndn.encoding.name import Name from ndn.encoding.ndn_format_0_3 import parse_data from h3client import H3Client app = Flask(__name__) ORIGIN = "https://health.ndn-quic-gateway.invalid" MTU = 1200 CONNECT_TIMEOUT = 2.0 INTEREST_TIMEOUT = 4.0 INTEREST_TIMEOUT_STEP = 0.05 INTEREST_PARAMS = InterestParam(must_be_fresh=True, hop_limit=64) @dataclass class ProbeNameResult: ok: bool rtt: T.Optional[float] = None error: T.Optional[str] = None @dataclass_json @dataclass class ProbeResult: connected: bool = False connectError: T.Optional[str] = None probes: T.Optional[T.List[ProbeNameResult]] = None
def test_mixed_name(): name = ['local', Component.from_str('ndn'), 'prefix'] interest = make_interest(name, InterestParam()) assert interest == b'\x05\x1a\x07\x14\x08\x05local\x08\x03ndn\x08\x06prefix\x0c\x02\x0f\xa0'
def express_interest( self, name: NonStrictName, app_param: Optional[BinaryStr] = None, validator: Optional[Validator] = None, need_raw_packet: bool = False, **kwargs ) -> Coroutine[Any, None, Tuple[FormalName, MetaInfo, Optional[BinaryStr]]]: r""" Express an Interest packet. The Interest packet is sent immediately and a coroutine used to get the result is returned. Awaiting on what is returned will block until the Data is received and return that Data. An exception is raised if unable to receive the Data. :param name: the Name. :type name: :any:`NonStrictName` :param app_param: the ApplicationParameters. :type app_param: Optional[:any:`BinaryStr`] :param validator: the Validator used to verify the Data received. :type validator: Optional[:any:`Validator`] :param need_raw_packet: if True, return the raw Data packet with TL. :type need_raw_packet: bool :param kwargs: :ref:`label-keyword-arguments`. :return: A tuple of (Name, MetaInfo, Content) after ``await``. If need_raw_packet is True, return a tuple (Name, MetaInfo, Content, RawPacket). :rtype: Coroutine[Any, None, Tuple[:any:`FormalName`, :any:`MetaInfo`, Optional[:any:`BinaryStr`]]] The following exception is raised by ``express_interest``: :raises NetworkError: the face to NFD is down before sending this Interest. The following exceptions are raised by the coroutine returned: :raises InterestNack: an NetworkNack is received. :raises InterestTimeout: time out. :raises ValidationFailure: unable to validate the Data packet. :raises InterestCanceled: the face to NFD is shut down after sending this Interest. """ if not self.face.running: raise NetworkError('cannot send packet before connected') if 'signer' in kwargs: signer = kwargs['signer'] elif app_param is not None: signer = self.keychain.get_signer(kwargs) else: signer = None if 'interest_param' in kwargs: interest_param = kwargs['interest_param'] else: if 'nonce' not in kwargs: kwargs['nonce'] = gen_nonce() interest_param = InterestParam.from_dict(kwargs) interest, final_name = make_interest(name, interest_param, app_param, signer=signer, need_final_name=True) future = aio.get_event_loop().create_future() node = self._int_tree.setdefault(final_name, InterestTreeNode()) node.append_interest(future, interest_param) self.face.send(interest) return self._wait_for_data(future, interest_param.lifetime, final_name, node, validator, need_raw_packet)