Otherwise, we may get dependency conflicts, depending on the order in
which we install the modules and requirements file with pip.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
As discussed in #215.
Note: The basis of this code has been AI-generated using Claude Sonnet 4,
but it was reviewed line-by-line and heavily refactored.
Prompts:
- "Create a new integration test in `test/integration` that tests the
newly-introduced status report feature. The test should send a bundle with
a set report-to EID, which may be the (local) sender. The created status
report should then be received and checked that it contains the
correct data."
- There is an issue in `_wait_for_status_report`: `sub_client.receive_msg`
can block indefinitely and there is no possibility to specify a timeout.
However, you could make the test async which allows aborting the receive
function. There is an async AAP2 client and an example for a test based
on it in `test_aap2_async_client.py`.
- I updated the test file. Adapt it so it passes the flake8 check which
gives the following errors: (pasted line-length issues)
- Extend the check of the received status report in the test by parsing it
as valid BPv7 (RFC 9171) status report. An implementation that can be
used for serializing status reports can be found in lines 525-566 of
`pyd3tn/bundle7.py`. The status report is in CBOR format. We use the
`cbor2` library in the project. The BPv7 spec can be found here:
https://www.rfc-editor.org/rfc/rfc9171.html#name-bundle-status-reports
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This introduces a JSON contact configuration format for the
deterministic first-contact forwarding (DFCF) implementation as a modern
alternative to our homebrewn configuration messages. For now, it is only
supported in the external DFCF BDM, but integration into the "router
agent" is planned.
Example JSON configuration string (from our tests):
```
{
"command": "ADD",
"node_id": "dtn://ud3tn2.dtn/",
"cla_addr": "mtcp:127.0.0.1:4223",
"reachable_eids": [
"ipn:1.0"
],
"contact_list": [
{
"start": 1401519306972,
"end": 1401519316972,
"data_rate": 2400,
"reachable_eids": [
"dtn://66553/",
"dtn://89326/"
]
},
{
"start": 1401519506972,
"end": 1401519516972,
"data_rate": 1200,
"reachable_eids": [
"dtn://12349/",
"dtn://89326/"
]
}
]
}
```
Closes: #15
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This adds a test for the new JSON-based query feature of the BDM. The
test is only enabled in the debug integration test for the external
dispatcher and does not run by default, as it does not specify an AAP
2.0 secret and also does not work with the built-in DFCF forwarding
module.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This makes µD3TN behave the same as v0.13.0 when executed without an
additional commandline argument. A new commandline argument `-d` /
`--external-dispatch` is added, which enables the use of external BDMs.
The default forwarding implementation is now again provided using the
v0.13 code, extracted from e1621765a4 and
adapted to the new agent-based forwarding implementation.
Central changes to the old code include:
- A new "Routing Agent" that handles incoming configuration commands,
FIB updates, and BDM dispatch requests.
- The use of the BDM authorization flag to authorize contact
configuration commands.
- The Contact Manager now only triggers the creation and removal of
links / FIB entries; bundle dispatch is triggered through the FIB and
BDM callback functions of the Routing Agent.
- The fragmentation logic is adapted to store the original bundle along
with an offset and length value, instead of pre-creating and storing
the fragments.
- The bundle re-scheduling logic integrated into the Routing Agent is
simplified and does not support changing the fragmentation parameters.
A new function is added to the Router that searches for a new route
for such fragments that were already scheduled at some point,
considering them as un-fragmentable bundle with overridden fragment
offset and length.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
The main reason here is to not initialize a CLA that has a hard limit on
the maximum bundle size (TCPSPP) by default. TCPSPP is rarely used anyway,
so we can disable it and save some memory in the default configuration.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
Since the last update of the cbor[^1] library was in 2016 and the
repository no longer even exists, the cbor2[^2] python library is now
used instead.
[^1]: https://pypi.org/project/cbor/
[^2]: https://pypi.org/project/cbor2/
Signed-off-by: Maximilian Nitsch <maximilian.nitsch@d3tn.com>
CLAs such as SMTCP and TCPSPP do not support any addresses, however, we
were providing some identification after the CLA string. This can
confuse BDMs that evaluate the CLA address in FIB updates to properly
schedule bundles. As there is only one link for these CLAs, we use the
same address (only containing the CLA name and a colon) now.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
We tested this, but just for subscriber sockets. RPC sockets should be
closed by uD3TN if a keepalive value is configured and the client sends
nothing for twice the configured time.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This enables a clean termination of all agent connections on program
exit without memory leaks that might previously occur due to the "pipe
queue" still holding some data (pointer to allocated memory) when
close() is called on the pipe. For that purpose, the "pipe queue" is
replaced by our standard hal_queue implementation, which also has a
higher performance as it does not require a syscall on every read/write
operation.
As hal_queue does not support poll() (it does not provide a fd), we
cannot check whether the socket has been closed by a subscribing AAP2
client while concurrently waiting for the internal queue. As an
alternative, this implements a liveliness check, which checks the sub.
connection opportunistically from the agent manager: When a new
registration is requested, existing registrations are first
"health-checked" and removed if down, so the new connection can take
over if an old one is down and this was not detected previously.
Based on the new infrastructure, a clean termination routine is
implemented that terminates all tasks transitively by terminating the
listener.
An AAP2 connection handler ("comm task") can terminate in two ways:
1. During runtime, when the connection is closed, it must clean up its own
resources.
2. On program termination, all connections must be cleanly closed and
all outstanding mesages handled.
For 1., we keep using detached threads and allow them to release all the
resources. This commit mainly introduces a mechanism for 2.: A list
tracking all comm. tasks is added that can be used to terminate and wait
for all of them on program termination. A "termination flag" indicates
whether tasks should clean up by themselves or the listener task takes
it over. Everything needs to be protected by mutexes for safe
concurrency.
There is specific handling for macOS, which does not signal other
threads clocking on a socket that the socket has been closed when
calling shutdown() but only when calling close() - thus, close() is
executed earlier on macOS. Also, macOS does not unblock poll() when the
socket is close()d, so we do not use it anymore to wait for data on an
RPC connection, but rather set SO_RCVTIMEO for active-client (RPC)
connections to enforce the keepalive timeout.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This generates a payload randomly and checks it upon reception so we
ensure we got the correct bundle.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This adds an asynchronous implementation of the AAP 2.0 client classes
so they can be used with asyncio.
Note that only some functions are concurrency-safe:
If we access the AAP2AsyncClient from multiple places concurrently, the
calls to `send()` and `receive_response()` may overlap. When it is not
intended to use multiple connections, an `asyncio.Lock` together with
functions to send and receive the response directly in sequence now ensure
that this cannot happen. The new `_rpc` functions are provided for that
purpose. Which functions are concurrency-safe is also indicated in the
docstrings.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
- Implement management of FIB and BDM agents:
* add administrative secret which is required for registering FIB and
BDM agents
* allow registering reverse-direction agents for TX/RX of ADUs when
passing the admin secret
* add cmdline option to pass the admin secret via an env variable
* make administrative secret optional in debug builds
- Register agents by number, as FIB and BDM agents may not have a sink
ID. Numbers are allocated by the agent_register function.
- Remove global state, add function to de-allocate everything.
- Add comprehensive unit tests.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This tests various expectations around the AAPv2 connection handling,
e.g., enforcement of acknowledgments and the keepalive mechanism.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This cares for properly delivering the metadata of the created bundle to
the AAPv2 client and adds a test for it.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
We specify AAP 2.0 to be an RPC protocol whereas the direction of calls
can be switched during configuration. Each call needs to be answered.
This change adds the answer for bundle reception by a client.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This increases time limit to 100sm at `test_aap_send_receive.py` so that integration test doesn't fail during execution under valgrind which slows down the program.
Signed-off-by: Oleksandr Nazymko <oleksandr.nazymko@d3tn.com>
This is basically an extended `aap_test.py` as part of the integration
tests, which verifies the received AAP messages and also checks the
returned bundle ID if it contains a well-formed timestamp and sequence
number.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This adds some tolerance for the bundle age check, such that it does not
have to be within a fractional millisecond bound.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This ensures the next test's config is not received (via another CLA)
before the deletion has been processed.
Unfortunately, we have no way to determine whether a command has been
processed by uD3TN (there is no operation to query it), so we have to
rely on a simple timeout. This will change with the new forwarding
interface, see the corresponding Milestone.
Fixes: #110
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
Former releases of uD3TN have included support for STM32/FreeRTOS.
Having this support from the first moment on was a good thing in
order to optimize for platforms with limited resources. As this
platform is not used in current uD3TN setups and as it results in quite
some maintenance work, it is removed with this commit. The removed parts
cover the implementation itself, tests, tools, documentation, parts of
the build/make scripts as well as licensing information.
Signed-off-by: Marius Feldmann <marius.feldmann@d3tn.com>
ud3tn is available under multiple licenses and we want to reflect this in
our source code. But which license information should appear first and how
can we manage this efficiently in the future? The Linux Kernel uses SPDX
expressions instead of boilerplate sections. This seems to be a great
approach, so we do the same here.
Signed-off-by: Georg Alexander Murzik <georg.murzik@d3tn.com>
-> https://datatracker.ietf.org/doc/html/draft-ietf-dtn-bpbis-31#section-4.2.5
The previous validation methods were not sufficient to check validity of
dtn as well as ipn EIDs. This adds further functions to easily detect
the EID scheme and validate dtn plus ipn EIDs. Tests for the most common
cases where validity checks should be successful and where they might
fail are added as well.
Due to this change the default EID of uD3TN gets a slash appended, as
dtn EIDs always have to contain the name delimiter '/'.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
In order to verify the correctness of bundle-age block processing, an
integration test between pyd3tn and ud3tn is added.
Signed-off-by: Maximilian Nitsch <maximilian.nitsch@d3tn.com>
To distribute the pyD3TN DTN protocol implementations as well as the
uD3TN python utilities on PyPi, the Python code is organized in separate
directories and the PyPi packaging guideline is applied. The
restructuring also requires an adjustment of the imports in the scripts
in tools/ and test/.
Signed-off-by: Maximilian Nitsch <maximilian.nitsch@d3tn.com>
This changes the core component name as well as the output binary names
(including the library and test binaries) from "upcn" to "ud3tn".
Additionally, the default configuration for the created socket and the
used EID is adapted.
Signed-off-by: Felix Walter <felix.walter@d3tn.com>
This is the initial commit for uD3TN. uD3TN is a fork of uPCN v0.8.0,
which will be developed and maintained in a public Git repository.
For questions concerning the history of and code provided with uPCN,
please get in touch with us via: contact <at> d3tn <dot> com
Signed-off-by: Felix Walter <felix.walter@d3tn.com>