Skip to content

Commit

Permalink
app: Write a new design for NDNApp (v2).
Browse files Browse the repository at this point in the history
Add support for PIT Token.
Add SignedInterest support for NFD mgmt command Interests.

Ref: named-data#48
  • Loading branch information
zjkmxy committed Jul 26, 2022
1 parent 1b97e94 commit b9e0dfe
Show file tree
Hide file tree
Showing 10 changed files with 1,206 additions and 27 deletions.
58 changes: 58 additions & 0 deletions examples/appv2/consumer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# -----------------------------------------------------------------------------
# Copyright (C) 2019-2022 The python-ndn authors
#
# This file is part of python-ndn.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
import logging
from ndn import utils, appv2, types
from ndn import encoding as enc


logging.basicConfig(format='[{asctime}]{levelname}:{message}',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.INFO,
style='{')


app = appv2.NDNApp()


async def main():
try:
timestamp = utils.timestamp()
name = enc.Name.from_str('/example/testApp/randomData') + [enc.Component.from_timestamp(timestamp)]
print(f'Sending Interest {enc.Name.to_str(name)}, {enc.InterestParam(must_be_fresh=True, lifetime=6000)}')
# TODO: Write a better validator
data_name, content, pkt_context = await app.express(
name, validator=appv2.pass_all,
must_be_fresh=True, can_be_prefix=False, lifetime=6000)

print(f'Received Data Name: {enc.Name.to_str(data_name)}')
print(pkt_context['meta_info'])
print(bytes(content) if content else None)
except types.InterestNack as e:
print(f'Nacked with reason={e.reason}')
except types.InterestTimeout:
print(f'Timeout')
except types.InterestCanceled:
print(f'Canceled')
except types.ValidationFailure:
print(f'Data failed to validate')
finally:
app.shutdown()


if __name__ == '__main__':
app.run_forever(after_start=main())
48 changes: 48 additions & 0 deletions examples/appv2/producer.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
# -----------------------------------------------------------------------------
# Copyright (C) 2019-2022 The python-ndn authors
#
# This file is part of python-ndn.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# -----------------------------------------------------------------------------
import typing
import logging
from ndn import appv2
from ndn import encoding as enc


logging.basicConfig(format='[{asctime}]{levelname}:{message}',
datefmt='%Y-%m-%d %H:%M:%S',
level=logging.INFO,
style='{')


app = appv2.NDNApp()
keychain = app.default_keychain()


@app.route('/example/testApp')
def on_interest(name: enc.FormalName, _app_param: typing.Optional[enc.BinaryStr],
reply: appv2.ReplyFunc, context: appv2.PktContext):
print(f'>> I: {enc.Name.to_str(name)}, {context["int_param"]}')
content = "Hello, world!".encode()
reply(app.make_data(name, content=content, signer=keychain.get_signer({}),
freshness_period=10000))
print(f'<< D: {enc.Name.to_str(name)}')
print(enc.MetaInfo(freshness_period=10000))
print(f'Content: (size: {len(content)})')
print('')


if __name__ == '__main__':
app.run_forever()
2 changes: 1 addition & 1 deletion src/ndn/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ async def _wait_for_data(self, future: aio.Future, lifetime: int, node_name: For
else:
return data_name, meta_info, content
else:
raise ValidationFailure(data_name, meta_info, content)
raise ValidationFailure(data_name, meta_info, content, sig)

async def main_loop(self, after_start: Awaitable = None) -> bool:
"""
Expand Down
47 changes: 29 additions & 18 deletions src/ndn/app_support/nfd_mgmt.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ class GeneralStatus(TlvModel):
n_out_nacks = UintField(0x98)
n_satisfied_interests = UintField(0x99)
n_unsatisfied_interests = UintField(0x9a)
# The following comes from DNMP's extension to NFD mgmt protocol:
# https://github.com/pollere/DNMP-v2/blob/c4359ae1af03824ec1ee8cd27a7d52c9151fa813/formats/forwarder-status.proto
# It does not show up in the standard protocol:
# https://redmine.named-data.net/projects/nfd/wiki/ForwarderStatus
n_fragmentation_errors = UintField(0xc8)
n_out_over_mtu = UintField(0xc9)
n_in_lp_invalid = UintField(0xca)
Expand Down Expand Up @@ -228,25 +232,8 @@ class CsInfo(TlvModel):


def make_command(module, command, face: Optional[Face] = None, **kwargs):
local = face.isLocalFace() if face else True

if local:
ret = Name.from_str(f"/localhost/nfd/{module}/{command}")
else:
ret = Name.from_str(f"/localhop/nfd/{module}/{command}")
# Command parameters
cp = ControlParameters()
cp.cp = ControlParametersValue()
for k, v in kwargs.items():
if k == 'strategy':
cp.cp.strategy = Strategy()
cp.cp.strategy.name = v
else:
setattr(cp.cp, k, v)
ret.append(Component.from_bytes(cp.encode()))
ret = make_command_v2(module, command, face, **kwargs)

# Note: when shifting from command Interest to signed Interest, remove all following lines
# and add ``app_param=b'', digest_sha256=True`` to app.express_interest
# Timestamp and nonce
ret.append(Component.from_bytes(struct.pack('!Q', timestamp())))
ret.append(Component.from_bytes(struct.pack('!Q', gen_nonce_64())))
Expand All @@ -270,6 +257,30 @@ def make_command(module, command, face: Optional[Face] = None, **kwargs):
return ret


def make_command_v2(module, command, face: Optional[Face] = None, **kwargs):
# V2 returns the Command Interest name for the NDNv3 signed Interest
# Note: this behavior is supported by NFD and YaNFD but has not been documented yet (on 06/26/2022):
# https://redmine.named-data.net/projects/nfd/wiki/ControlCommand
# Add ``app_param=b'', signer=sec.DigestSha256Signer(for_interest=True)`` to app.express when using this.
local = face.isLocalFace() if face else True

if local:
ret = Name.from_str(f"/localhost/nfd/{module}/{command}")
else:
ret = Name.from_str(f"/localhop/nfd/{module}/{command}")
# Command parameters
cp = ControlParameters()
cp.cp = ControlParametersValue()
for k, v in kwargs.items():
if k == 'strategy':
cp.cp.strategy = Strategy()
cp.cp.strategy.name = v
else:
setattr(cp.cp, k, v)
ret.append(Component.from_bytes(cp.encode()))
return ret


def parse_response(buf):
buf = parse_and_check_tl(memoryview(buf), 0x65)
cr = ControlResponse.parse(buf)
Expand Down
Loading

0 comments on commit b9e0dfe

Please sign in to comment.