1. BPv6 vs. BPv7

ION now supports both Bundle Protocol v6 (RFC 5050) and Bundle Protocol v7 (RFC 9171), but not simultaneously. At compile time, the user specifies whether ION will be built to support BPv6 or BPv7. Much in the same manner, pyion can also support BPv6 or BPv7, but its version must match the version that ION was built with. The environment variable PYION_BP_VERSION must be set prior to installing pyion to indicate which version of BP is being used.

2. Interface with the Bundle Protocol (BP)

pyion provides two main abstractions to send/receive data through BP:

  • BpProxy: Proxy to ION engine for a given node (identified by a node number). You should only ever have one proxy per bundle node. To ensure that this is the case, do not create Proxies manually. Instead, use pyion.get_bp_proxy.

  • Endpoint: Endpoint to send/receive data using BP. Do not open/close/interrupt/delete endpoints manually, always do it through the proxy (note that all Endpoints reference the Proxy that created them).

While sending data through ION’s BP, several properties can be specified (e.g., time-to-live, required reports, reporting endpoint, etc). These can be defined as inherent to the endpoint (i.e., all bundles send through this endpoint will have a give TTL), in which case they must be specified while calling bp_open in the BpProxy object, or as one-of properties for a specific bundle (in which case they must be specified while calling bp_send in the Endpoint object).

Not all features available in ION are currently supported. For instance, while you can request BP reports while using pyion (and provide a reporting endpoint), reception of the reports is for now left in binary format and it is thus up to the user to decode them. Similarly, bundles cannot specify advanced class of service properties (ancillary data). Finally, pyion does not provide any flow control mechanisms when sending data over an endpoint. This means that if you overflow the SDR memory, a Python MemoryError exception will be raised and it is up to the user to handle it.

2.1. Endpoints as Python Context Managers

Endpoint objects can be used as context managers since they should always be openend and closed, just like file descriptors or sockets. The following example shows how to use endpoints as context managers

Example 1.a: BP Transmitter

1import pyion
2
3# Create a proxy to node 1 and attach to ION
4proxy = pyion.get_bp_proxy(1)
5
6# Open endpoint 'ipn:1.1' and send data to 'ipn:2.1'
7with proxy.bp_open('ipn:1.1') as eid:
8    eid.bp_send('ipn:2.1', b'hello')

Example 1.b: BP Receiver

 1python
 2import pyion
 3
 4# Create a proxy to node 2 and attach to it
 5proxy = pyion.get_bp_proxy(2)
 6
 7# Listen to 'ipn:2.1' for incoming data
 8with proxy.bp_open('ipn:2.1') as eid:
 9    while eid.is_open:
10        try:
11            # This is a blocking call.
12            print('Received:', eid.bp_receive())
13        except InterruptedError:
14            # User has triggered interruption with Ctrl+C
15            break

Note that the endpoint is opened from the proxy. The same is true for closing and interrupting and endpoint. Therefore, the only operations that can be triggered directly from the endpoint are send and receive (some additional convencience operations are also available, e.g., send a file).

2.2. Endpoints as Class Instances

Endpoints can also be used as class instances that are manually opened and closed by the user. The later is actually not necessary since endpoints will be closed automatically when they are garbage collected.

Here is a more complicated example of a transmitter and receiver that exchange data. At the receiver, the amount of data exchanged is measured, as well as the data rate at which the connection is running. Additionally, this example also demonstrates that typical bundle properties can be provided to an endpoint as a way to configure the BP operation.

Example 2.a: BP Transmitter

 1from datetime import datetime
 2from threading import Thread
 3import time
 4
 5# Import module
 6import pyion
 7from pyion import BpCustodyEnum, BpPriorityEnum, BpReportsEnum
 8
 9# =================================================================
10# === Define global variables
11# =================================================================
12
13# ION node number
14node_nbr = 1
15
16# Originating and destination endpoints
17orig_eid = 'ipn:1.1'
18dest_eid = 'ipn:2.1'
19rept_eid = 'ipn:1.2'
20
21# Define endpoint properties
22ept_props = {
23    'TTL':          3600,   # [sec]
24    'custody':      BpCustodyEnum.SOURCE_CUSTODY_REQUIRED,
25    'priority':     BpPriorityEnum.BP_EXPEDITED_PRIORITY,
26    'report_eid':   rept_eid,
27    'report_flags': BpReportsEnum.BP_RECEIVED_RPT
28    #'report_flags': BpReportsEnum.BP_RECEIVED_RPT | BpReportsEnum.BP_CUSTODY_RPT,
29}
30
31# Create a proxy to ION
32proxy = pyion.get_bp_proxy(node_nbr)
33
34# =================================================================
35# === Acquire reports
36# =================================================================
37
38# Open endpoint to get reports
39rpt_eid = proxy.bp_open(rept_eid)
40
41def print_reports():
42    while True:
43        try:
44            data = rpt_eid.bp_receive()
45            print(data)
46        except InterruptedError:
47            break
48
49# Start monitoring thread
50th = Thread(target=print_reports, daemon=True)
51th.start()
52
53# =================================================================
54# === MAIN
55# =================================================================
56
57# Open a endpoint and set its properties. Then send file
58with proxy.bp_open(orig_eid, **ept_props) as eid:
59    for i in range(50):
60        eid.bp_send(dest_eid, str(datetime.now()) + ' - ' + 'a'*1000)
61
62# Sleep for a while and stop the monitoring thread
63time.sleep(2)
64proxy.bp_interrupt(rept_eid)
65th.join()

Example 2.b: BP Receiver

 1from datetime import datetime
 2import sys
 3import time
 4
 5# Import module
 6import pyion
 7
 8# =================================================================
 9# === Define global variables
10# =================================================================
11
12# ION node number
13node_nbr = 2
14
15# Endpoint to listen to
16EID = 'ipn:2.1'
17
18# =================================================================
19# === MAIN
20# =================================================================
21
22# Create a proxy to ION's BP
23proxy = pyion.get_bp_proxy(node_nbr)
24
25# Open a proxy to receive data
26with proxy.bp_open(EID) as eid:
27    # You are now ready to received
28    print('{} ready to receive'.format(eid))
29
30    nbnd, nbytes, elapsed = 0, 0, 0
31
32    # Receive
33    while eid.is_open:
34        try:
35            # This is a blocking call
36            data = eid.bp_receive()
37
38            try:
39                data = data.decode('utf-8')
40
41                if nbnd == 0: tic = time.time()
42
43                # Separate timestamp and data
44                ts, msg = data.split(' - ')
45
46                # Convert timestamp
47                ts = datetime.strptime(ts, '%Y-%m-%d %H:%M:%S.%f')
48
49                # Get the time it took for data to arrive
50                dt = (datetime.now()-ts).total_seconds()
51
52                # Report statistics
53                nbnd += 1
54                nbytes += sys.getsizeof(data)
55                elapsed = (time.time() - tic)
56                print('{}) Total bytes {} / {:.3f} seconds = {:.3f} bytes/sec'.format(nbnd, nbytes, elapsed, nbytes/elapsed))
57            except UnicodeDecodeError:
58                print(data)
59        except InterruptedError:
60            break

2.3. Updates from Previous Versions

The following is a non-comprehensive list of updates included in pyion: - BpProxies attach to ION automatically upon creation. It is no longer needed for the user to manually call bp_attach. Similarly, BpProxies detach from ION automatically upon deletion. - If ION and pyion are run with BPv6, bundles can be sent with a retransmission timer. Use the retx_timer property of bp_send to control how often bundles should be retransmitted. - While receiving, Endpoint objects can be given a timeout that will stop the reception process if no bundle arrives within a given timeframe. - The size of the data sent or received via an Endpoint should not exceed 2^32-1 bits.