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
Endpointsreference theProxythat 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.