mirror of
https://github.com/markqvist/Reticulum.git
synced 2026-06-22 20:12:37 -07:00
Compare commits
105 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 0ff51fed44 | |||
| 6e25f96024 | |||
| ad228fb3b3 | |||
| a61b20a066 | |||
| a49b04af21 | |||
| f030cf6f22 | |||
| 9e7641d2d3 | |||
| c909871fb7 | |||
| 47f60b0320 | |||
| 6797909d90 | |||
| fd6d8ffff8 | |||
| 06de7f4a3d | |||
| 7221becd35 | |||
| a51f5f2eaf | |||
| 9e8d71ddaf | |||
| 9bc55a9047 | |||
| 3e7ab5136e | |||
| d2cf3c2a7e | |||
| 77519f1a0c | |||
| e869b3cac9 | |||
| a2878f1722 | |||
| 748a7290a9 | |||
| 6e80a553c8 | |||
| ec7aa44a17 | |||
| 4fa335639c | |||
| 67195c0b14 | |||
| ad1e6a41ee | |||
| a56d93fc1e | |||
| b8aa6a3e44 | |||
| 1709cd929a | |||
| 4f4961257c | |||
| 1b48f43a0d | |||
| e5d446a54e | |||
| 0af768e742 | |||
| 1a7d20a8d6 | |||
| ec4f4d5a83 | |||
| 8cefa4b2a9 | |||
| 2331f1ea3e | |||
| be7dafa30c | |||
| 3e20cb1b67 | |||
| 097e136662 | |||
| e3a716224d | |||
| 80dc567a53 | |||
| c6576d6504 | |||
| 89d5d9517d | |||
| dc315653c0 | |||
| 746b403890 | |||
| fc619460f0 | |||
| cd0f82d9ad | |||
| 330c2aacac | |||
| 63da084bbe | |||
| cbbd8221ee | |||
| 1d18d53052 | |||
| ceccf3153b | |||
| bde33e7d84 | |||
| 93330d96a0 | |||
| d93ce62878 | |||
| eafa4aefbb | |||
| 53df2fa5e0 | |||
| abc657806d | |||
| a0f219f7f4 | |||
| 47eba03a4b | |||
| 3289cd1299 | |||
| ab5fcd7a5b | |||
| 45494f21aa | |||
| 5d677d2fb7 | |||
| 808082e300 | |||
| 97cfdfd023 | |||
| 9b15cf2295 | |||
| eaa68c2d04 | |||
| ac5ca78c77 | |||
| 5b17dbdfd6 | |||
| d4ed20c7d5 | |||
| a5093ea8f0 | |||
| f5cf438abd | |||
| bf6e73e163 | |||
| 503f475ca5 | |||
| 8506118aee | |||
| dfa295a90a | |||
| 3ace1583da | |||
| c62b66195d | |||
| b724836d2b | |||
| 1e1b9dc79e | |||
| c668a51e39 | |||
| 09b34d34c6 | |||
| 54e18e41c5 | |||
| 5550bca040 | |||
| f7a02351d4 | |||
| 3125b99043 | |||
| 158765abb7 | |||
| 81aa9ac5b6 | |||
| 55f5842587 | |||
| 38dd63a99a | |||
| 558cd6c4a7 | |||
| 15e6a1bfde | |||
| c1087e62fd | |||
| 9d924dcd6d | |||
| 163d2ed157 | |||
| 68f07ddd38 | |||
| d956b93c13 | |||
| 3036305662 | |||
| ee603ce68e | |||
| 989513cb46 | |||
| 7e52c37580 | |||
| 0984f92fa2 |
@@ -12,10 +12,14 @@ Before creating a bug report on this issue tracker, you **must** read the [Contr
|
||||
|
||||
- The issue tracker is used by developers of this project. **Do not use it to ask general questions, or for support requests**.
|
||||
- Ideas and feature requests can be made on the [Discussions](https://github.com/markqvist/Reticulum/discussions). **Only** feature requests accepted by maintainers and developers are tracked and included on the issue tracker. **Do not post feature requests here**.
|
||||
- After reading the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md), delete this section from your bug report.
|
||||
- After reading the [Contribution Guidelines](https://github.com/markqvist/Reticulum/blob/master/Contributing.md), **delete this section only** (*"Read the Contribution Guidelines"*) from your bug report, **and fill in all the other sections**.
|
||||
|
||||
**Describe the Bug**
|
||||
A clear and concise description of what the bug is.
|
||||
First of all: Is this really a bug? Is it reproducible?
|
||||
|
||||
If this is a request for help because something is not working as you expected, stop right here, and go to the [discussions](https://github.com/markqvist/Reticulum/discussions) instead, where you can post your questions and get help from other users.
|
||||
|
||||
If this really is a bug or issue with the software, remove this section of the template, and provide **a clear and concise description of what the bug is**.
|
||||
|
||||
**To Reproduce**
|
||||
Describe in detail how to reproduce the bug.
|
||||
@@ -24,7 +28,7 @@ Describe in detail how to reproduce the bug.
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
**Logs & Screenshots**
|
||||
Please include any relevant log output. If applicable, also add screenshots to help explain your problem.
|
||||
Please include any relevant log output. If applicable, also add screenshots to help explain your problem. In most cases, without any relevant log output, we will not be able to determine the cause of the bug, or reproduce it.
|
||||
|
||||
**System Information**
|
||||
- OS and version
|
||||
|
||||
@@ -87,7 +87,7 @@ jobs:
|
||||
- uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
files: |
|
||||
.artifacts/package/**.whl
|
||||
# .artifacts/package/**.whl
|
||||
# .artifacts/documentation/latex/reticulumnetworkstack.pdf
|
||||
# .artifacts/documentation/epub/ReticulumNetworkStack.epub
|
||||
draft: true
|
||||
|
||||
+102
@@ -1,3 +1,105 @@
|
||||
### 2025-01-19: RNS β 0.9.2
|
||||
|
||||
This maintenance release fixes a number of bugs.
|
||||
|
||||
**Changes**
|
||||
- Fixed missing RX/TX bytes statistics assignment
|
||||
- Fixed potential daemon thread IO buffer deadlock on externally mediated shutdown signal
|
||||
- Fixed missing check for path announce emission timestamp in lower hop-count announce processing
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
068eb4408b332ea6eec1a58fb4644fba3531c9ca10dcd79ecf893aaaf40e720d rns-0.9.2-py3-none-any.whl
|
||||
1e7c123d244cc14c287568f3a99953cc11ffc1e79a72a029aa1be72fa8eff24e rnspure-0.9.2-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2025-01-19: RNS β 0.9.1
|
||||
|
||||
This maintenance release adds reject signalling mechanism to resource transfers, fixes inconsistencies in the code examples, and improves thread configuration in the transport core.
|
||||
|
||||
**Changes**
|
||||
- Added resource reject signalling
|
||||
- Added error reporting on configured radio parameter mismatch on Android
|
||||
- Improved thread configuration for transport core threads
|
||||
- Updated examples
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
49288a562ad6d4b5647c3afec051a6bb6497b75e3f165a972436134d4a93ad76 rns-0.9.1-py3-none-any.whl
|
||||
abd6c4bdead2fc25d0b9b2cda5708586e8cb776b088f2a901a5f262e2ed901ae rnspure-0.9.1-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2025-01-17: RNS β 0.9.0
|
||||
|
||||
This release lays the groundwork for future performance and resource utilisation optimisations. Most importantly, this release adds **link MTU autodiscovery**, which allow established links to use much higher MTUs than the base MTU of 500 bytes.
|
||||
|
||||
**Please note!** To actually use link MTU discovery, all transport nodes along the path must be upgraded to at least version `0.9.0`. Since this is the first release to add support for this feature, *it is currently **not** activated by default*, and no clients or applications will use it yet. Using link MTU autodiscovery by default will be enabled by default in RNS version `0.9.1`. Please upgrade your nodes!
|
||||
|
||||
Additionally, this release adds several new features, performance improvements and bug fixes, as well as support for RNodes running firmware version `1.81`.
|
||||
|
||||
**Changes**
|
||||
- Added MTU autoconfiguration on interfaces that support higher MTUs
|
||||
- Added link MTU autodiscovery and path clamping
|
||||
- Added dynamic SDU calculations based on link MTU to `Resource`, `Channel` and `Buffer`
|
||||
- Added resource EIFR continuity to split resource handling
|
||||
- Added interference status to `RNodeInterface`
|
||||
- Fixed a display bug in `rnstatus`
|
||||
- Added live traffic stats to `rnstatus`
|
||||
- Added T3S3 support to `rnodeconf`
|
||||
- Added Heltec T114 support to `rnodeconf`
|
||||
- Added LilyGO T-Echo support to `rnodeconf`
|
||||
- Added option to print device configuration to `rnodeconf`
|
||||
- Improved CPU utilisation and memory consumption
|
||||
- Improved `rnsd` restart time on systems with many interfaces
|
||||
- Improved `rncp` status output
|
||||
- Improved packet filter performance
|
||||
- Improved interface detachment handling
|
||||
- Improved resource transfer timing and performance
|
||||
- Improved Transport core efficiency
|
||||
- Improved reliability of ratchet reloads if I/O conflicts occur
|
||||
- Improved logging
|
||||
- Improved built-in profiler
|
||||
- Fixed a potential deadlock in logging
|
||||
- Fixed time formatters not handling negative times
|
||||
- Updated example code
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
1ee60634cf0627c45b93f4e6c9adaf1fcdf9c1a8dfd4dd3dcd499e029554ab4f rns-0.9.0-py3-none-any.whl
|
||||
b67eec583fdb224ba8174b317e66b8f7344e338e93760ed1a90f0bafea8cf09e rnspure-0.9.0-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2025-01-09: RNS β 0.8.9
|
||||
|
||||
This maintenance release adds a number of configuration options to `rnodeconf`.
|
||||
|
||||
**Changes**
|
||||
- Added noise floor output to `rnstatus` for supported interfaces
|
||||
- Added channel noise floor and CSMA parameter reporting to `RNodeInterface`
|
||||
- Added ability to set display rotation in `rnodeconf`
|
||||
- Added ability to configure interference avoidance to `rnodeconf`
|
||||
- Fixed missing console image install on Heltec V3 in `rnodeconf`
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
b54fe8bc296f83a3a70569c9d1e9db3096249789c18f8d0217671479fa6881a1 rns-0.8.9-py3-none-any.whl
|
||||
52fd992e5f9478d5a1f61f8f37dc0ee2d268fdd0b8a4e6656d33d632490afc5a rnspure-0.8.9-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2024-12-11: RNS β 0.8.8
|
||||
|
||||
This maintenance release adds a single API function and fixes a bug.
|
||||
|
||||
**Changes**
|
||||
- Allow announce handlers to receive announce packet hash
|
||||
- Fix packet RSSI/SNR/Q cache not being available on standalone instances
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
9c1755a81049c67b051ecb9fe4b2c5f7d98bf09d20ed52d6ce6a410298b0527b rns-0.8.8-py3-none-any.whl
|
||||
d8871d69cde4b0a0b99b383f324d651dc77a2f44ec9641be828902c778a8d128 rnspure-0.8.8-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2024-12-09: RNS β 0.8.7
|
||||
|
||||
This maintenance release adds support for OpenWRT packaging, and brings several minor improvements and bugfixes.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
import argparse
|
||||
import random
|
||||
import sys
|
||||
import RNS
|
||||
|
||||
# Let's define an app name. We'll use this for all
|
||||
@@ -168,4 +169,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
@@ -118,4 +118,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
+3
-4
@@ -157,7 +157,7 @@ def client(destination_hexhash, configpath):
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -254,9 +254,8 @@ def link_closed(link):
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
# When the buffer has new data, read it and write it to the terminal.
|
||||
def client_buffer_ready(ready_bytes: int):
|
||||
@@ -320,4 +319,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
+5
-6
@@ -124,7 +124,7 @@ def server(configpath):
|
||||
def server_loop(destination):
|
||||
# Let the user know that everything is ready
|
||||
RNS.log(
|
||||
"Link example "+
|
||||
"Channel example "+
|
||||
RNS.prettyhexrep(destination.hash)+
|
||||
" running, waiting for a connection."
|
||||
)
|
||||
@@ -212,7 +212,7 @@ def client(destination_hexhash, configpath):
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -276,7 +276,7 @@ def client_loop():
|
||||
packed_size = len(message.pack())
|
||||
channel = server_link.get_channel()
|
||||
if channel.is_ready_to_send():
|
||||
if packed_size <= channel.MDU:
|
||||
if packed_size <= channel.mdu:
|
||||
channel.send(message)
|
||||
else:
|
||||
RNS.log(
|
||||
@@ -321,9 +321,8 @@ def link_closed(link):
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
# When a packet is received over the channel, we
|
||||
# simply print out the data.
|
||||
@@ -387,4 +386,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
+3
-2
@@ -6,6 +6,7 @@
|
||||
##########################################################
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import RNS
|
||||
|
||||
# Let's define an app name. We'll use this for all
|
||||
@@ -130,7 +131,7 @@ def client(destination_hexhash, configpath, timeout=None):
|
||||
except Exception as e:
|
||||
RNS.log("Invalid destination entered. Check your input!")
|
||||
RNS.log(str(e)+"\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -328,4 +329,4 @@ if __name__ == "__main__":
|
||||
client(args.destination, configarg, timeout=timeoutarg)
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
@@ -224,7 +224,7 @@ def client(destination_hexhash, configpath):
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -462,7 +462,7 @@ def filelist_timeout_job():
|
||||
global server_files
|
||||
if len(server_files) == 0:
|
||||
RNS.log("Timed out waiting for filelist, exiting")
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
# When a link is closed, we'll inform the
|
||||
@@ -475,9 +475,8 @@ def link_closed(link):
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
# When RNS detects that the download has
|
||||
# started, we'll update our menu state
|
||||
@@ -601,4 +600,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
@@ -133,7 +133,7 @@ def client(destination_hexhash, configpath):
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -245,9 +245,8 @@ def link_closed(link):
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
# When a packet is received over the link, we
|
||||
# simply print out the data.
|
||||
@@ -311,4 +310,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
+3
-4
@@ -119,7 +119,7 @@ def client(destination_hexhash, configpath):
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -222,9 +222,8 @@ def link_closed(link):
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
# When a packet is received over the link, we
|
||||
# simply print out the data.
|
||||
@@ -288,4 +287,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
+2
-1
@@ -5,6 +5,7 @@
|
||||
##########################################################
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import RNS
|
||||
|
||||
# Let's define an app name. We'll use this for all
|
||||
@@ -98,4 +99,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
@@ -5,6 +5,7 @@
|
||||
##########################################################
|
||||
|
||||
import argparse
|
||||
import sys
|
||||
import RNS
|
||||
|
||||
# Let's define an app name. We'll use this for all
|
||||
@@ -25,9 +26,6 @@ def server(configpath):
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
# TODO: Remove
|
||||
RNS.loglevel = RNS.LOG_DEBUG
|
||||
|
||||
# Randomly create a new identity for our echo server
|
||||
server_identity = RNS.Identity()
|
||||
@@ -141,7 +139,7 @@ def client(destination_hexhash, configpath, timeout=None):
|
||||
except Exception as e:
|
||||
RNS.log("Invalid destination entered. Check your input!")
|
||||
RNS.log(str(e)+"\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -340,4 +338,4 @@ if __name__ == "__main__":
|
||||
client(args.destination, configarg, timeout=timeoutarg)
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
+3
-4
@@ -119,7 +119,7 @@ def client(destination_hexhash, configpath):
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -226,9 +226,8 @@ def link_closed(link):
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
##########################################################
|
||||
@@ -284,4 +283,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
+10
-20
@@ -149,8 +149,6 @@ def server_packet_received(message, packet):
|
||||
time.sleep(0.2)
|
||||
rc = 0
|
||||
received_data = 0
|
||||
# latest_client_link.teardown()
|
||||
# os._exit(0)
|
||||
|
||||
|
||||
##########################################################
|
||||
@@ -159,6 +157,7 @@ def server_packet_received(message, packet):
|
||||
|
||||
# A reference to the server link
|
||||
server_link = None
|
||||
should_quit = False
|
||||
|
||||
# This initialisation is executed when the users chooses
|
||||
# to run as a client
|
||||
@@ -175,7 +174,7 @@ def client(destination_hexhash, configpath):
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
@@ -216,7 +215,7 @@ def client(destination_hexhash, configpath):
|
||||
client_loop()
|
||||
|
||||
def client_loop():
|
||||
global server_link
|
||||
global server_link, should_quit
|
||||
|
||||
# Wait for the link to become active
|
||||
while not server_link:
|
||||
@@ -224,16 +223,7 @@ def client_loop():
|
||||
|
||||
should_quit = False
|
||||
while not should_quit:
|
||||
try:
|
||||
text = input()
|
||||
|
||||
# Check if we should quit the example
|
||||
if text == "quit" or text == "q" or text == "exit":
|
||||
should_quit = True
|
||||
server_link.teardown()
|
||||
|
||||
except Exception as e:
|
||||
raise e
|
||||
time.sleep(0.2)
|
||||
|
||||
# This function is called when a link
|
||||
# has been established with the server
|
||||
@@ -246,8 +236,8 @@ def link_established(link):
|
||||
|
||||
# Inform the user that the server is
|
||||
# connected
|
||||
RNS.log("Link established with server,sending...")
|
||||
rd = os.urandom(RNS.Link.MDU)
|
||||
RNS.log("Link established with server, sending...")
|
||||
rd = os.urandom(link.mdu)
|
||||
started = time.time()
|
||||
while link.status == RNS.Link.ACTIVE and data_sent < data_cap*1.25:
|
||||
RNS.Packet(server_link, rd, create_receipt=False).send()
|
||||
@@ -276,17 +266,17 @@ def link_established(link):
|
||||
# When a link is closed, we'll inform the
|
||||
# user, and exit the program
|
||||
def link_closed(link):
|
||||
global should_quit
|
||||
if link.teardown_reason == RNS.Link.TIMEOUT:
|
||||
RNS.log("The link timed out, exiting now")
|
||||
elif link.teardown_reason == RNS.Link.DESTINATION_CLOSED:
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
|
||||
should_quit = True
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
sys.exit(0)
|
||||
|
||||
def client_packet_received(message, packet):
|
||||
pass
|
||||
@@ -344,4 +334,4 @@ if __name__ == "__main__":
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
sys.exit(0)
|
||||
|
||||
+3
-1
@@ -45,7 +45,8 @@ class StreamDataMessage(MessageBase):
|
||||
The stream id is limited to 2 bytes - 2 bit
|
||||
"""
|
||||
|
||||
MAX_DATA_LEN = RNS.Link.MDU - 2 - 6 # 2 for stream data message header, 6 for channel envelope
|
||||
OVERHEAD = 2 + 6 # 2 for stream data message header, 6 for channel envelope
|
||||
MAX_DATA_LEN = RNS.Link.MDU - OVERHEAD
|
||||
"""
|
||||
When the Buffer package is imported, this value is
|
||||
calculcated based on the value of OVERHEAD
|
||||
@@ -215,6 +216,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager):
|
||||
self._stream_id = stream_id
|
||||
self._channel = channel
|
||||
self._eof = False
|
||||
self._mdu = channel.mdu - StreamDataMessage.OVERHEAD
|
||||
|
||||
def write(self, __b: bytes) -> int | None:
|
||||
try:
|
||||
|
||||
+6
-3
@@ -602,7 +602,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
return envelope
|
||||
|
||||
@property
|
||||
def MDU(self):
|
||||
def mdu(self):
|
||||
"""
|
||||
Maximum Data Unit: the number of bytes available
|
||||
for a message to consume in a single send. This
|
||||
@@ -611,7 +611,10 @@ class Channel(contextlib.AbstractContextManager):
|
||||
|
||||
:return: number of bytes available
|
||||
"""
|
||||
return self._outlet.mdu - 6 # sizeof(msgtype) + sizeof(length) + sizeof(sequence)
|
||||
mdu = self._outlet.mdu - 6 # sizeof(msgtype) + sizeof(length) + sizeof(sequence)
|
||||
if mdu > 0xFFFF:
|
||||
mdu = 0xFFFF
|
||||
return mdu
|
||||
|
||||
|
||||
class LinkChannelOutlet(ChannelOutletBase):
|
||||
@@ -639,7 +642,7 @@ class LinkChannelOutlet(ChannelOutletBase):
|
||||
|
||||
@property
|
||||
def mdu(self):
|
||||
return self.link.MDU
|
||||
return self.link.mdu
|
||||
|
||||
@property
|
||||
def rtt(self):
|
||||
|
||||
@@ -48,7 +48,7 @@ def hkdf(length=None, derive_from=None, salt=None, context=None):
|
||||
derived = b""
|
||||
|
||||
for i in range(ceil(length / hash_len)):
|
||||
block = hmac_sha256(pseudorandom_key, block + context + bytes([i + 1]))
|
||||
block = hmac_sha256(pseudorandom_key, block + context + bytes([(i + 1)%(0xFF+1)]))
|
||||
derived += block
|
||||
|
||||
return derived[:length]
|
||||
|
||||
+13
-1
@@ -424,7 +424,7 @@ class Destination:
|
||||
def _reload_ratchets(self, ratchets_path):
|
||||
if os.path.isfile(ratchets_path):
|
||||
with self.ratchet_file_lock:
|
||||
try:
|
||||
def load_attempt():
|
||||
ratchets_file = open(ratchets_path, "rb")
|
||||
persisted_data = umsgpack.unpackb(ratchets_file.read())
|
||||
if "signature" in persisted_data and "ratchets" in persisted_data:
|
||||
@@ -433,10 +433,22 @@ class Destination:
|
||||
self.ratchets_path = ratchets_path
|
||||
else:
|
||||
raise KeyError("Invalid ratchet file signature")
|
||||
|
||||
try:
|
||||
try:
|
||||
load_attempt()
|
||||
|
||||
except Exception as e:
|
||||
RNS.trace_exception(e)
|
||||
RNS.log(f"First ratchet reload attempt for {self} failed. Possible I/O conflict. Retrying in 500ms.", RNS.LOG_ERROR)
|
||||
time.sleep(0.5)
|
||||
load_attempt()
|
||||
RNS.log(f"Ratchet reload retry succeeded", RNS.LOG_DEBUG)
|
||||
|
||||
except Exception as e:
|
||||
self.ratchets = None
|
||||
self.ratchets_path = None
|
||||
RNS.trace_exception(e)
|
||||
raise OSError("Could not read ratchet file contents for "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
else:
|
||||
RNS.log("No existing ratchet data found, initialising new ratchet file for "+str(self), RNS.LOG_DEBUG)
|
||||
|
||||
+23
-19
@@ -266,30 +266,34 @@ class Identity:
|
||||
|
||||
@staticmethod
|
||||
def _remember_ratchet(destination_hash, ratchet):
|
||||
# TODO: Remove at some point, and only log new ratchets
|
||||
RNS.log(f"Remembering ratchet {RNS.prettyhexrep(Identity._get_ratchet_id(ratchet))} for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_EXTREME)
|
||||
try:
|
||||
Identity.known_ratchets[destination_hash] = ratchet
|
||||
if destination_hash in Identity.known_ratchets and Identity.known_ratchets[destination_hash] == ratchet:
|
||||
ratchet_exists = True
|
||||
else:
|
||||
ratchet_exists = False
|
||||
|
||||
if not RNS.Transport.owner.is_connected_to_shared_instance:
|
||||
def persist_job():
|
||||
with Identity.ratchet_persist_lock:
|
||||
hexhash = RNS.hexrep(destination_hash, delimit=False)
|
||||
ratchet_data = {"ratchet": ratchet, "received": time.time()}
|
||||
if not ratchet_exists:
|
||||
RNS.log(f"Remembering ratchet {RNS.prettyhexrep(Identity._get_ratchet_id(ratchet))} for {RNS.prettyhexrep(destination_hash)}", RNS.LOG_EXTREME)
|
||||
Identity.known_ratchets[destination_hash] = ratchet
|
||||
if not RNS.Transport.owner.is_connected_to_shared_instance:
|
||||
def persist_job():
|
||||
with Identity.ratchet_persist_lock:
|
||||
hexhash = RNS.hexrep(destination_hash, delimit=False)
|
||||
ratchet_data = {"ratchet": ratchet, "received": time.time()}
|
||||
|
||||
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
||||
|
||||
if not os.path.isdir(ratchetdir):
|
||||
os.makedirs(ratchetdir)
|
||||
ratchetdir = RNS.Reticulum.storagepath+"/ratchets"
|
||||
|
||||
if not os.path.isdir(ratchetdir):
|
||||
os.makedirs(ratchetdir)
|
||||
|
||||
outpath = f"{ratchetdir}/{hexhash}.out"
|
||||
finalpath = f"{ratchetdir}/{hexhash}"
|
||||
with open(outpath, "wb") as ratchet_file:
|
||||
ratchet_file.write(umsgpack.packb(ratchet_data))
|
||||
os.replace(outpath, finalpath)
|
||||
outpath = f"{ratchetdir}/{hexhash}.out"
|
||||
finalpath = f"{ratchetdir}/{hexhash}"
|
||||
with open(outpath, "wb") as ratchet_file:
|
||||
ratchet_file.write(umsgpack.packb(ratchet_data))
|
||||
os.replace(outpath, finalpath)
|
||||
|
||||
|
||||
threading.Thread(target=persist_job, daemon=True).start()
|
||||
|
||||
threading.Thread(target=persist_job, daemon=True).start()
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Could not persist ratchet for {RNS.prettyhexrep(destination_hash)} to storage.", RNS.LOG_ERROR)
|
||||
|
||||
@@ -64,6 +64,7 @@ class KISS():
|
||||
CMD_STAT_CHTM = 0x25
|
||||
CMD_STAT_PHYPRM = 0x26
|
||||
CMD_STAT_BAT = 0x27
|
||||
CMD_STAT_CSMA = 0x28
|
||||
CMD_BLINK = 0x30
|
||||
CMD_RANDOM = 0x40
|
||||
CMD_FB_EXT = 0x41
|
||||
@@ -84,15 +85,16 @@ class KISS():
|
||||
RADIO_STATE_ON = 0x01
|
||||
RADIO_STATE_ASK = 0xFF
|
||||
|
||||
CMD_ERROR = 0x90
|
||||
ERROR_INITRADIO = 0x01
|
||||
ERROR_TXFAILED = 0x02
|
||||
ERROR_EEPROM_LOCKED = 0x03
|
||||
ERROR_QUEUE_FULL = 0x04
|
||||
ERROR_MEMORY_LOW = 0x05
|
||||
ERROR_MODEM_TIMEOUT = 0x06
|
||||
CMD_ERROR = 0x90
|
||||
ERROR_INITRADIO = 0x01
|
||||
ERROR_TXFAILED = 0x02
|
||||
ERROR_EEPROM_LOCKED = 0x03
|
||||
ERROR_QUEUE_FULL = 0x04
|
||||
ERROR_MEMORY_LOW = 0x05
|
||||
ERROR_MODEM_TIMEOUT = 0x06
|
||||
ERROR_INVALID_FIRMWARE = 0x10
|
||||
ERROR_INVALID_BLE_MTU = 0x20
|
||||
ERROR_INVALID_CONFIG = 0x40
|
||||
|
||||
PLATFORM_AVR = 0x90
|
||||
PLATFORM_ESP32 = 0x80
|
||||
@@ -242,7 +244,7 @@ class RNodeInterface(Interface):
|
||||
DEFAULT_IFAC_SIZE = 8
|
||||
|
||||
FREQ_MIN = 137000000
|
||||
FREQ_MAX = 1020000000
|
||||
FREQ_MAX = 3000000000
|
||||
|
||||
RSSI_OFFSET = 157
|
||||
|
||||
@@ -465,10 +467,18 @@ class RNodeInterface(Interface):
|
||||
self.r_airtime_long = 0.0
|
||||
self.r_channel_load_short = 0.0
|
||||
self.r_channel_load_long = 0.0
|
||||
self.r_symbol_time_ms = None
|
||||
self.r_symbol_rate = None
|
||||
self.r_preamble_symbols = None
|
||||
self.r_premable_time_ms = None
|
||||
self.r_symbol_time_ms = None
|
||||
self.r_symbol_rate = None
|
||||
self.r_preamble_symbols = None
|
||||
self.r_premable_time_ms = None
|
||||
self.r_csma_slot_time_ms = None
|
||||
self.r_csma_difs_ms = None
|
||||
self.r_csma_cw_band = None
|
||||
self.r_csma_cw_min = None
|
||||
self.r_csma_cw_max = None
|
||||
self.r_current_rssi = None
|
||||
self.r_noise_floor = None
|
||||
|
||||
self.r_battery_state = RNodeInterface.BATTERY_STATE_UNKNOWN
|
||||
self.r_battery_percent = 0
|
||||
self.r_framebuffer = b""
|
||||
@@ -715,6 +725,7 @@ class RNodeInterface(Interface):
|
||||
RNS.log("After configuring "+str(self)+", the reported radio parameters did not match your configuration.", RNS.LOG_ERROR)
|
||||
RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
|
||||
RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
|
||||
self.hw_errors.append({"error": KISS.ERROR_INVALID_CONFIG, "description": "The configuration parameters were not validated by the device. Make sure that the device actually supports the TX power, frequency, bandwidth, spreading factor and coding rate you configured."})
|
||||
|
||||
if self.serial != None:
|
||||
self.serial.close()
|
||||
@@ -1238,16 +1249,31 @@ class RNodeInterface(Interface):
|
||||
byte = KISS.FESC
|
||||
escape = False
|
||||
command_buffer = command_buffer+bytes([byte])
|
||||
if (len(command_buffer) == 8):
|
||||
if (len(command_buffer) == 11):
|
||||
ats = command_buffer[0] << 8 | command_buffer[1]
|
||||
atl = command_buffer[2] << 8 | command_buffer[3]
|
||||
cus = command_buffer[4] << 8 | command_buffer[5]
|
||||
cul = command_buffer[6] << 8 | command_buffer[7]
|
||||
crs = command_buffer[8]
|
||||
nfl = command_buffer[9]
|
||||
ntf = command_buffer[10]
|
||||
|
||||
self.r_airtime_short = ats/100.0
|
||||
self.r_airtime_long = atl/100.0
|
||||
self.r_channel_load_short = cus/100.0
|
||||
self.r_channel_load_long = cul/100.0
|
||||
self.r_current_rssi = crs-RNodeInterface.RSSI_OFFSET
|
||||
self.r_noise_floor = nfl-RNodeInterface.RSSI_OFFSET
|
||||
if ntf == 0xFF:
|
||||
self.r_interference = None
|
||||
else:
|
||||
self.r_interference = ntf-RNodeInterface.RSSI_OFFSET
|
||||
|
||||
if self.r_interference != None:
|
||||
RNS.log(f"{self} Radio detected interference at {self.r_interference} dBm", RNS.LOG_DEBUG)
|
||||
|
||||
# TODO: Remove debug
|
||||
# RNS.log(f"RSSI: {self.r_current_rssi}, Noise floor: {self.r_noise_floor}, Interference: {self.r_interference}", RNS.LOG_EXTREME)
|
||||
elif (command == KISS.CMD_STAT_PHYPRM):
|
||||
if (byte == KISS.FESC):
|
||||
escape = True
|
||||
@@ -1259,22 +1285,49 @@ class RNodeInterface(Interface):
|
||||
byte = KISS.FESC
|
||||
escape = False
|
||||
command_buffer = command_buffer+bytes([byte])
|
||||
if (len(command_buffer) == 10):
|
||||
if (len(command_buffer) == 12):
|
||||
lst = (command_buffer[0] << 8 | command_buffer[1])/1000.0
|
||||
lsr = command_buffer[2] << 8 | command_buffer[3]
|
||||
prs = command_buffer[4] << 8 | command_buffer[5]
|
||||
prt = command_buffer[6] << 8 | command_buffer[7]
|
||||
cst = command_buffer[8] << 8 | command_buffer[9]
|
||||
dft = command_buffer[10] << 8 | command_buffer[11]
|
||||
|
||||
if lst != self.r_symbol_time_ms or lsr != self.r_symbol_rate or prs != self.r_preamble_symbols or prt != self.r_premable_time_ms or cst != self.r_csma_slot_time_ms:
|
||||
if lst != self.r_symbol_time_ms or lsr != self.r_symbol_rate or prs != self.r_preamble_symbols or prt != self.r_premable_time_ms or cst != self.r_csma_slot_time_ms or dft != self.r_csma_difs_ms:
|
||||
self.r_symbol_time_ms = lst
|
||||
self.r_symbol_rate = lsr
|
||||
self.r_preamble_symbols = prs
|
||||
self.r_premable_time_ms = prt
|
||||
self.r_csma_slot_time_ms = cst
|
||||
RNS.log(str(self)+" Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms (at "+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG)
|
||||
RNS.log(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG)
|
||||
RNS.log(str(self)+" Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG)
|
||||
self.r_csma_difs_ms = dft
|
||||
RNS.log(f"{self} Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms ("+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG)
|
||||
RNS.log(f"{self} Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG)
|
||||
RNS.log(f"{self} Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG)
|
||||
RNS.log(f"{self} Radio reporting DIFS time is "+str(self.r_csma_difs_ms)+"ms", RNS.LOG_DEBUG)
|
||||
elif (command == KISS.CMD_STAT_CSMA):
|
||||
if (byte == KISS.FESC):
|
||||
escape = True
|
||||
else:
|
||||
if (escape):
|
||||
if (byte == KISS.TFEND):
|
||||
byte = KISS.FEND
|
||||
if (byte == KISS.TFESC):
|
||||
byte = KISS.FESC
|
||||
escape = False
|
||||
command_buffer = command_buffer+bytes([byte])
|
||||
if (len(command_buffer) == 3):
|
||||
cbw = command_buffer[0]
|
||||
cbl = command_buffer[1]
|
||||
cbh = command_buffer[2]
|
||||
|
||||
if cbw != self.r_csma_cw_band or cbl != self.r_csma_cw_min or cbh != self.r_csma_cw_max:
|
||||
self.r_csma_cw_band = cbw
|
||||
self.r_csma_cw_min = cbl
|
||||
self.r_csma_cw_max = cbh
|
||||
# TODO: Remove debug
|
||||
# RNS.log(f"{self} Radio reporting contention window band is {self.r_csma_cw_band}", RNS.LOG_EXTREME)
|
||||
# RNS.log(f"{self} Radio reporting minimum contention window is {self.r_csma_cw_min}", RNS.LOG_EXTREME)
|
||||
# RNS.log(f"{self} Radio reporting maximum contention window is {self.r_csma_cw_max}", RNS.LOG_EXTREME)
|
||||
elif (command == KISS.CMD_STAT_BAT):
|
||||
if (byte == KISS.FESC):
|
||||
escape = True
|
||||
|
||||
@@ -456,21 +456,23 @@ class AutoInterface(Interface):
|
||||
self.peers[addr][1] = time.time()
|
||||
|
||||
def process_incoming(self, data):
|
||||
data_hash = RNS.Identity.full_hash(data)
|
||||
deque_hit = False
|
||||
if data_hash in self.mif_deque:
|
||||
for te in self.mif_deque_times:
|
||||
if te[0] == data_hash and time.time() < te[1]+AutoInterface.MULTI_IF_DEQUE_TTL:
|
||||
deque_hit = True
|
||||
break
|
||||
if self.online:
|
||||
data_hash = RNS.Identity.full_hash(data)
|
||||
deque_hit = False
|
||||
if data_hash in self.mif_deque:
|
||||
for te in self.mif_deque_times:
|
||||
if te[0] == data_hash and time.time() < te[1]+AutoInterface.MULTI_IF_DEQUE_TTL:
|
||||
deque_hit = True
|
||||
break
|
||||
|
||||
if not deque_hit:
|
||||
self.mif_deque.append(data_hash)
|
||||
self.mif_deque_times.append([data_hash, time.time()])
|
||||
self.rxb += len(data)
|
||||
self.owner.inbound(data, self)
|
||||
if not deque_hit:
|
||||
self.mif_deque.append(data_hash)
|
||||
self.mif_deque_times.append([data_hash, time.time()])
|
||||
self.rxb += len(data)
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
def process_outgoing(self,data):
|
||||
if self.online:
|
||||
for peer in self.peers:
|
||||
try:
|
||||
if self.outbound_udp_socket == None:
|
||||
@@ -492,6 +494,9 @@ class AutoInterface(Interface):
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def detach(self):
|
||||
self.online = False
|
||||
|
||||
def __str__(self):
|
||||
return "AutoInterface["+self.name+"]"
|
||||
|
||||
|
||||
@@ -64,12 +64,16 @@ class Interface:
|
||||
IC_BURST_PENALTY = 5*60
|
||||
IC_HELD_RELEASE_INTERVAL = 30
|
||||
|
||||
AUTOCONFIGURE_MTU = False
|
||||
|
||||
def __init__(self):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
self.created = time.time()
|
||||
self.online = False
|
||||
self.bitrate = 1e6
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
self.created = time.time()
|
||||
self.detached = False
|
||||
self.online = False
|
||||
self.bitrate = 62500
|
||||
self.HW_MTU = None
|
||||
|
||||
self.ingress_control = True
|
||||
self.ic_max_held_announces = Interface.MAX_HELD_ANNOUNCES
|
||||
@@ -117,6 +121,31 @@ class Interface:
|
||||
else:
|
||||
return False
|
||||
|
||||
def optimise_mtu(self):
|
||||
if self.AUTOCONFIGURE_MTU:
|
||||
if self.bitrate > 16_000_000:
|
||||
self.HW_MTU = 262144
|
||||
elif self.bitrate > 8_000_000:
|
||||
self.HW_MTU = 131072
|
||||
elif self.bitrate > 4_000_000:
|
||||
self.HW_MTU = 65536
|
||||
elif self.bitrate > 2_000_000:
|
||||
self.HW_MTU = 32768
|
||||
elif self.bitrate > 1_000_000:
|
||||
self.HW_MTU = 16384
|
||||
elif self.bitrate > 500_000:
|
||||
self.HW_MTU = 8192
|
||||
elif self.bitrate > 250_000:
|
||||
self.HW_MTU = 4096
|
||||
elif self.bitrate > 125_000:
|
||||
self.HW_MTU = 2048
|
||||
elif self.bitrate > 62_500:
|
||||
self.HW_MTU = 1024
|
||||
else:
|
||||
self.HW_MTU = None
|
||||
|
||||
RNS.log(f"{self} hardware MTU set to {self.HW_MTU}", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
|
||||
def age(self):
|
||||
return time.time()-self.created
|
||||
|
||||
|
||||
@@ -52,14 +52,12 @@ class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
|
||||
class LocalClientInterface(Interface):
|
||||
RECONNECT_WAIT = 8
|
||||
AUTOCONFIGURE_MTU = True
|
||||
|
||||
def __init__(self, owner, name, target_port = None, connected_socket=None):
|
||||
super().__init__()
|
||||
|
||||
# TODO: Remove at some point
|
||||
# self.rxptime = 0
|
||||
|
||||
self.HW_MTU = 1064
|
||||
self.HW_MTU = 262144
|
||||
|
||||
self.online = False
|
||||
|
||||
@@ -89,7 +87,7 @@ class LocalClientInterface(Interface):
|
||||
self.connect()
|
||||
|
||||
self.owner = owner
|
||||
self.bitrate = 1000*1000*1000
|
||||
self.bitrate = 1_000_000_000
|
||||
self.online = True
|
||||
self.writing = False
|
||||
|
||||
@@ -157,14 +155,11 @@ class LocalClientInterface(Interface):
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||
self.parent_interface.rxb += len(data)
|
||||
|
||||
# TODO: Remove at some point
|
||||
# processing_start = time.time()
|
||||
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
# TODO: Remove at some point
|
||||
# duration = time.time() - processing_start
|
||||
# self.rxptime += duration
|
||||
try:
|
||||
self.owner.inbound(data, self)
|
||||
except Exception as e:
|
||||
RNS.log(f"An error in the processing of an incoming frame for {self}: {e}", RNS.LOG_ERROR)
|
||||
RNS.trace_exception(e)
|
||||
|
||||
def process_outgoing(self, data):
|
||||
if self.online:
|
||||
@@ -190,6 +185,7 @@ class LocalClientInterface(Interface):
|
||||
except Exception as e:
|
||||
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR)
|
||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
RNS.trace_exception(e)
|
||||
self.teardown()
|
||||
|
||||
|
||||
@@ -197,32 +193,31 @@ class LocalClientInterface(Interface):
|
||||
try:
|
||||
in_frame = False
|
||||
escape = False
|
||||
frame_buffer = b""
|
||||
data_in = b""
|
||||
data_buffer = b""
|
||||
|
||||
while True:
|
||||
data_in = self.socket.recv(4096)
|
||||
if len(data_in) > 0:
|
||||
pointer = 0
|
||||
while pointer < len(data_in):
|
||||
byte = data_in[pointer]
|
||||
pointer += 1
|
||||
if (in_frame and byte == HDLC.FLAG):
|
||||
in_frame = False
|
||||
self.process_incoming(data_buffer)
|
||||
elif (byte == HDLC.FLAG):
|
||||
in_frame = True
|
||||
data_buffer = b""
|
||||
elif (in_frame and len(data_buffer) < self.HW_MTU):
|
||||
if (byte == HDLC.ESC):
|
||||
escape = True
|
||||
frame_buffer += data_in
|
||||
flags_remaining = True
|
||||
while flags_remaining:
|
||||
frame_start = frame_buffer.find(HDLC.FLAG)
|
||||
if frame_start != -1:
|
||||
frame_end = frame_buffer.find(HDLC.FLAG, frame_start+1)
|
||||
if frame_end != -1:
|
||||
frame = frame_buffer[frame_start+1:frame_end]
|
||||
frame = frame.replace(bytes([HDLC.ESC, HDLC.FLAG ^ HDLC.ESC_MASK]), bytes([HDLC.FLAG]))
|
||||
frame = frame.replace(bytes([HDLC.ESC, HDLC.ESC ^ HDLC.ESC_MASK]), bytes([HDLC.ESC]))
|
||||
if len(frame) > RNS.Reticulum.HEADER_MINSIZE:
|
||||
self.process_incoming(frame)
|
||||
frame_buffer = frame_buffer[frame_end:]
|
||||
else:
|
||||
if (escape):
|
||||
if (byte == HDLC.FLAG ^ HDLC.ESC_MASK):
|
||||
byte = HDLC.FLAG
|
||||
if (byte == HDLC.ESC ^ HDLC.ESC_MASK):
|
||||
byte = HDLC.ESC
|
||||
escape = False
|
||||
data_buffer = data_buffer+bytes([byte])
|
||||
flags_remaining = False
|
||||
else:
|
||||
flags_remaining = False
|
||||
|
||||
else:
|
||||
self.online = False
|
||||
if self.is_connected_to_shared_instance and not self.detached:
|
||||
@@ -249,12 +244,14 @@ class LocalClientInterface(Interface):
|
||||
self.detached = True
|
||||
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
if self.socket != None:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except Exception as e:
|
||||
RNS.log("Error while shutting down socket for "+str(self)+": "+str(e))
|
||||
|
||||
try:
|
||||
self.socket.close()
|
||||
if self.socket != None:
|
||||
self.socket.close()
|
||||
except Exception as e:
|
||||
RNS.log("Error while closing socket for "+str(self)+": "+str(e))
|
||||
|
||||
@@ -292,6 +289,7 @@ class LocalClientInterface(Interface):
|
||||
|
||||
|
||||
class LocalServerInterface(Interface):
|
||||
AUTOCONFIGURE_MTU = True
|
||||
|
||||
def __init__(self, owner, bindport=None):
|
||||
super().__init__()
|
||||
@@ -319,6 +317,7 @@ class LocalServerInterface(Interface):
|
||||
address = (self.bind_ip, self.bind_port)
|
||||
|
||||
self.server = ThreadingTCPServer(address, handlerFactory(self.incoming_connection))
|
||||
self.server.daemon_threads = True
|
||||
|
||||
thread = threading.Thread(target=self.server.serve_forever)
|
||||
thread.daemon = True
|
||||
|
||||
@@ -55,6 +55,7 @@ class KISS():
|
||||
CMD_STAT_CHTM = 0x25
|
||||
CMD_STAT_PHYPRM = 0x26
|
||||
CMD_STAT_BAT = 0x27
|
||||
CMD_STAT_CSMA = 0x28
|
||||
CMD_BLINK = 0x30
|
||||
CMD_RANDOM = 0x40
|
||||
CMD_FB_EXT = 0x41
|
||||
@@ -184,6 +185,7 @@ class RNodeInterface(Interface):
|
||||
self.online = False
|
||||
self.detached = False
|
||||
self.reconnecting= False
|
||||
self.hw_errors = []
|
||||
|
||||
self.use_ble = False
|
||||
self.ble_name = ble_name
|
||||
@@ -233,10 +235,18 @@ class RNodeInterface(Interface):
|
||||
self.r_airtime_long = 0.0
|
||||
self.r_channel_load_short = 0.0
|
||||
self.r_channel_load_long = 0.0
|
||||
self.r_symbol_time_ms = None
|
||||
self.r_symbol_rate = None
|
||||
self.r_preamble_symbols = None
|
||||
self.r_premable_time_ms = None
|
||||
self.r_symbol_time_ms = None
|
||||
self.r_symbol_rate = None
|
||||
self.r_preamble_symbols = None
|
||||
self.r_premable_time_ms = None
|
||||
self.r_csma_slot_time_ms = None
|
||||
self.r_csma_difs_ms = None
|
||||
self.r_csma_cw_band = None
|
||||
self.r_csma_cw_min = None
|
||||
self.r_csma_cw_max = None
|
||||
self.r_current_rssi = None
|
||||
self.r_noise_floor = None
|
||||
|
||||
self.r_battery_state = RNodeInterface.BATTERY_STATE_UNKNOWN
|
||||
self.r_battery_percent = 0
|
||||
self.r_framebuffer = b""
|
||||
@@ -246,7 +256,7 @@ class RNodeInterface(Interface):
|
||||
self.r_disp_readtime = 0
|
||||
self.r_disp_latency = 0
|
||||
|
||||
self.should_read_display = False
|
||||
self.should_read_display = False
|
||||
self.read_display_interval = RNodeInterface.DISPLAY_READ_INTERVAL
|
||||
|
||||
self.packet_queue = []
|
||||
@@ -869,16 +879,31 @@ class RNodeInterface(Interface):
|
||||
byte = KISS.FESC
|
||||
escape = False
|
||||
command_buffer = command_buffer+bytes([byte])
|
||||
if (len(command_buffer) == 8):
|
||||
if (len(command_buffer) == 11):
|
||||
ats = command_buffer[0] << 8 | command_buffer[1]
|
||||
atl = command_buffer[2] << 8 | command_buffer[3]
|
||||
cus = command_buffer[4] << 8 | command_buffer[5]
|
||||
cul = command_buffer[6] << 8 | command_buffer[7]
|
||||
crs = command_buffer[8]
|
||||
nfl = command_buffer[9]
|
||||
ntf = command_buffer[10]
|
||||
|
||||
self.r_airtime_short = ats/100.0
|
||||
self.r_airtime_long = atl/100.0
|
||||
self.r_channel_load_short = cus/100.0
|
||||
self.r_channel_load_long = cul/100.0
|
||||
self.r_current_rssi = crs-RNodeInterface.RSSI_OFFSET
|
||||
self.r_noise_floor = nfl-RNodeInterface.RSSI_OFFSET
|
||||
if ntf == 0xFF:
|
||||
self.r_interference = None
|
||||
else:
|
||||
self.r_interference = ntf-RNodeInterface.RSSI_OFFSET
|
||||
|
||||
if self.r_interference != None:
|
||||
RNS.log(f"{self} Radio detected interference at {self.r_interference} dBm", RNS.LOG_DEBUG)
|
||||
|
||||
# TODO: Remove debug
|
||||
# RNS.log(f"RSSI: {self.r_current_rssi}, Noise floor: {self.r_noise_floor}, Interference: {self.r_interference}", RNS.LOG_EXTREME)
|
||||
elif (command == KISS.CMD_STAT_PHYPRM):
|
||||
if (byte == KISS.FESC):
|
||||
escape = True
|
||||
@@ -890,22 +915,49 @@ class RNodeInterface(Interface):
|
||||
byte = KISS.FESC
|
||||
escape = False
|
||||
command_buffer = command_buffer+bytes([byte])
|
||||
if (len(command_buffer) == 10):
|
||||
if (len(command_buffer) == 12):
|
||||
lst = (command_buffer[0] << 8 | command_buffer[1])/1000.0
|
||||
lsr = command_buffer[2] << 8 | command_buffer[3]
|
||||
prs = command_buffer[4] << 8 | command_buffer[5]
|
||||
prt = command_buffer[6] << 8 | command_buffer[7]
|
||||
cst = command_buffer[8] << 8 | command_buffer[9]
|
||||
dft = command_buffer[10] << 8 | command_buffer[11]
|
||||
|
||||
if lst != self.r_symbol_time_ms or lsr != self.r_symbol_rate or prs != self.r_preamble_symbols or prt != self.r_premable_time_ms or cst != self.r_csma_slot_time_ms:
|
||||
if lst != self.r_symbol_time_ms or lsr != self.r_symbol_rate or prs != self.r_preamble_symbols or prt != self.r_premable_time_ms or cst != self.r_csma_slot_time_ms or dft != self.r_csma_difs_ms:
|
||||
self.r_symbol_time_ms = lst
|
||||
self.r_symbol_rate = lsr
|
||||
self.r_preamble_symbols = prs
|
||||
self.r_premable_time_ms = prt
|
||||
self.r_csma_slot_time_ms = cst
|
||||
RNS.log(str(self)+" Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms (at "+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG)
|
||||
RNS.log(str(self)+" Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG)
|
||||
RNS.log(str(self)+" Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG)
|
||||
self.r_csma_difs_ms = dft
|
||||
RNS.log(f"{self} Radio reporting symbol time is "+str(round(self.r_symbol_time_ms,2))+"ms ("+str(self.r_symbol_rate)+" baud)", RNS.LOG_DEBUG)
|
||||
RNS.log(f"{self} Radio reporting preamble is "+str(self.r_preamble_symbols)+" symbols ("+str(self.r_premable_time_ms)+"ms)", RNS.LOG_DEBUG)
|
||||
RNS.log(f"{self} Radio reporting CSMA slot time is "+str(self.r_csma_slot_time_ms)+"ms", RNS.LOG_DEBUG)
|
||||
RNS.log(f"{self} Radio reporting DIFS time is "+str(self.r_csma_difs_ms)+"ms", RNS.LOG_DEBUG)
|
||||
elif (command == KISS.CMD_STAT_CSMA):
|
||||
if (byte == KISS.FESC):
|
||||
escape = True
|
||||
else:
|
||||
if (escape):
|
||||
if (byte == KISS.TFEND):
|
||||
byte = KISS.FEND
|
||||
if (byte == KISS.TFESC):
|
||||
byte = KISS.FESC
|
||||
escape = False
|
||||
command_buffer = command_buffer+bytes([byte])
|
||||
if (len(command_buffer) == 3):
|
||||
cbw = command_buffer[0]
|
||||
cbl = command_buffer[1]
|
||||
cbh = command_buffer[2]
|
||||
|
||||
if cbw != self.r_csma_cw_band or cbl != self.r_csma_cw_min or cbh != self.r_csma_cw_max:
|
||||
self.r_csma_cw_band = cbw
|
||||
self.r_csma_cw_min = cbl
|
||||
self.r_csma_cw_max = cbh
|
||||
# TODO: Remove debug
|
||||
# RNS.log(f"{self} Radio reporting contention window band is {self.r_csma_cw_band}", RNS.LOG_EXTREME)
|
||||
# RNS.log(f"{self} Radio reporting minimum contention window is {self.r_csma_cw_min}", RNS.LOG_EXTREME)
|
||||
# RNS.log(f"{self} Radio reporting maximum contention window is {self.r_csma_cw_max}", RNS.LOG_EXTREME)
|
||||
elif (command == KISS.CMD_STAT_BAT):
|
||||
if (byte == KISS.FESC):
|
||||
escape = True
|
||||
|
||||
@@ -30,6 +30,9 @@ import sys
|
||||
import os
|
||||
import RNS
|
||||
|
||||
class TCPInterface():
|
||||
HW_MTU = 262144
|
||||
|
||||
class HDLC():
|
||||
FLAG = 0x7E
|
||||
ESC = 0x7D
|
||||
@@ -64,6 +67,7 @@ class ThreadingTCP6Server(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
class TCPClientInterface(Interface):
|
||||
BITRATE_GUESS = 10*1000*1000
|
||||
DEFAULT_IFAC_SIZE = 16
|
||||
AUTOCONFIGURE_MTU = True
|
||||
|
||||
RECONNECT_WAIT = 5
|
||||
RECONNECT_MAX_TRIES = None
|
||||
@@ -96,8 +100,7 @@ class TCPClientInterface(Interface):
|
||||
connect_timeout = c.as_int("connect_timeout") if "connect_timeout" in c else None
|
||||
max_reconnect_tries = c.as_int("max_reconnect_tries") if "max_reconnect_tries" in c else None
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
self.HW_MTU = TCPInterface.HW_MTU
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.socket = None
|
||||
@@ -192,19 +195,21 @@ class TCPClientInterface(Interface):
|
||||
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.I2P_PROBE_AFTER))
|
||||
|
||||
def detach(self):
|
||||
self.online = False
|
||||
if self.socket != None:
|
||||
if hasattr(self.socket, "close"):
|
||||
if callable(self.socket.close):
|
||||
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG)
|
||||
self.detached = True
|
||||
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
if self.socket != None:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except Exception as e:
|
||||
RNS.log("Error while shutting down socket for "+str(self)+": "+str(e))
|
||||
|
||||
try:
|
||||
self.socket.close()
|
||||
if self.socket != None:
|
||||
self.socket.close()
|
||||
except Exception as e:
|
||||
RNS.log("Error while closing socket for "+str(self)+": "+str(e))
|
||||
|
||||
@@ -285,14 +290,15 @@ class TCPClientInterface(Interface):
|
||||
raise IOError("Attempt to reconnect on a non-initiator TCP interface")
|
||||
|
||||
def process_incoming(self, data):
|
||||
self.rxb += len(data)
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||
self.parent_interface.rxb += len(data)
|
||||
|
||||
self.owner.inbound(data, self)
|
||||
if self.online and not self.detached:
|
||||
self.rxb += len(data)
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||
self.parent_interface.rxb += len(data)
|
||||
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
def process_outgoing(self, data):
|
||||
if self.online:
|
||||
if self.online and not self.detached:
|
||||
# while self.writing:
|
||||
# time.sleep(0.01)
|
||||
|
||||
@@ -320,19 +326,19 @@ class TCPClientInterface(Interface):
|
||||
try:
|
||||
in_frame = False
|
||||
escape = False
|
||||
frame_buffer = b""
|
||||
data_in = b""
|
||||
data_buffer = b""
|
||||
command = KISS.CMD_UNKNOWN
|
||||
|
||||
while True:
|
||||
data_in = self.socket.recv(4096)
|
||||
if len(data_in) > 0:
|
||||
pointer = 0
|
||||
while pointer < len(data_in):
|
||||
byte = data_in[pointer]
|
||||
pointer += 1
|
||||
|
||||
if self.kiss_framing:
|
||||
# Read loop for KISS framing
|
||||
if self.kiss_framing:
|
||||
# Read loop for KISS framing
|
||||
pointer = 0
|
||||
while pointer < len(data_in):
|
||||
byte = data_in[pointer]
|
||||
pointer += 1
|
||||
if (in_frame and byte == KISS.FEND and command == KISS.CMD_DATA):
|
||||
in_frame = False
|
||||
self.process_incoming(data_buffer)
|
||||
@@ -358,25 +364,26 @@ class TCPClientInterface(Interface):
|
||||
escape = False
|
||||
data_buffer = data_buffer+bytes([byte])
|
||||
|
||||
else:
|
||||
# Read loop for HDLC framing
|
||||
if (in_frame and byte == HDLC.FLAG):
|
||||
in_frame = False
|
||||
self.process_incoming(data_buffer)
|
||||
elif (byte == HDLC.FLAG):
|
||||
in_frame = True
|
||||
data_buffer = b""
|
||||
elif (in_frame and len(data_buffer) < self.HW_MTU):
|
||||
if (byte == HDLC.ESC):
|
||||
escape = True
|
||||
else:
|
||||
# Read loop for standard HDLC framing
|
||||
frame_buffer += data_in
|
||||
flags_remaining = True
|
||||
while flags_remaining:
|
||||
frame_start = frame_buffer.find(HDLC.FLAG)
|
||||
if frame_start != -1:
|
||||
frame_end = frame_buffer.find(HDLC.FLAG, frame_start+1)
|
||||
if frame_end != -1:
|
||||
frame = frame_buffer[frame_start+1:frame_end]
|
||||
frame = frame.replace(bytes([HDLC.ESC, HDLC.FLAG ^ HDLC.ESC_MASK]), bytes([HDLC.FLAG]))
|
||||
frame = frame.replace(bytes([HDLC.ESC, HDLC.ESC ^ HDLC.ESC_MASK]), bytes([HDLC.ESC]))
|
||||
if len(frame) > RNS.Reticulum.HEADER_MINSIZE:
|
||||
self.process_incoming(frame)
|
||||
frame_buffer = frame_buffer[frame_end:]
|
||||
else:
|
||||
if (escape):
|
||||
if (byte == HDLC.FLAG ^ HDLC.ESC_MASK):
|
||||
byte = HDLC.FLAG
|
||||
if (byte == HDLC.ESC ^ HDLC.ESC_MASK):
|
||||
byte = HDLC.ESC
|
||||
escape = False
|
||||
data_buffer = data_buffer+bytes([byte])
|
||||
flags_remaining = False
|
||||
else:
|
||||
flags_remaining = False
|
||||
|
||||
else:
|
||||
self.online = False
|
||||
if self.initiator and not self.detached:
|
||||
@@ -431,8 +438,9 @@ class TCPClientInterface(Interface):
|
||||
|
||||
|
||||
class TCPServerInterface(Interface):
|
||||
BITRATE_GUESS = 10*1000*1000
|
||||
BITRATE_GUESS = 10_000_000
|
||||
DEFAULT_IFAC_SIZE = 16
|
||||
AUTOCONFIGURE_MTU = True
|
||||
|
||||
@staticmethod
|
||||
def get_address_for_if(name, bind_port, prefer_ipv6=False):
|
||||
@@ -484,7 +492,7 @@ class TCPServerInterface(Interface):
|
||||
if port != None:
|
||||
bindport = port
|
||||
|
||||
self.HW_MTU = 1064
|
||||
self.HW_MTU = TCPInterface.HW_MTU
|
||||
|
||||
self.online = False
|
||||
self.spawned_interfaces = []
|
||||
@@ -531,6 +539,7 @@ class TCPServerInterface(Interface):
|
||||
else:
|
||||
ThreadingTCPServer.allow_reuse_address = True
|
||||
self.server = ThreadingTCPServer(bind_address, handlerFactory(self.incoming_connection))
|
||||
self.server.daemon_threads = True
|
||||
|
||||
self.bitrate = TCPServerInterface.BITRATE_GUESS
|
||||
|
||||
@@ -553,6 +562,7 @@ class TCPServerInterface(Interface):
|
||||
spawned_interface.target_port = str(handler.client_address[1])
|
||||
spawned_interface.parent_interface = self
|
||||
spawned_interface.bitrate = self.bitrate
|
||||
spawned_interface.optimise_mtu()
|
||||
|
||||
spawned_interface.ifac_size = self.ifac_size
|
||||
spawned_interface.ifac_netname = self.ifac_netname
|
||||
@@ -596,15 +606,16 @@ class TCPServerInterface(Interface):
|
||||
def process_outgoing(self, data):
|
||||
pass
|
||||
|
||||
|
||||
def detach(self):
|
||||
self.detached = True
|
||||
self.online = False
|
||||
if self.server != None:
|
||||
if hasattr(self.server, "shutdown"):
|
||||
if callable(self.server.shutdown):
|
||||
try:
|
||||
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG)
|
||||
self.server.shutdown()
|
||||
self.detached = True
|
||||
self.server.server_close()
|
||||
self.server = None
|
||||
|
||||
except Exception as e:
|
||||
|
||||
+100
-14
@@ -28,6 +28,7 @@ from time import sleep
|
||||
from .vendor import umsgpack as umsgpack
|
||||
import threading
|
||||
import inspect
|
||||
import struct
|
||||
import math
|
||||
import time
|
||||
import RNS
|
||||
@@ -68,8 +69,9 @@ class Link:
|
||||
Timeout for link establishment in seconds per hop to destination.
|
||||
"""
|
||||
|
||||
TRAFFIC_TIMEOUT_MIN_MS = 5
|
||||
TRAFFIC_TIMEOUT_FACTOR = 6
|
||||
LINK_MTU_SIZE = 3
|
||||
TRAFFIC_TIMEOUT_MIN_MS = 5
|
||||
TRAFFIC_TIMEOUT_FACTOR = 6
|
||||
KEEPALIVE_TIMEOUT_FACTOR = 4
|
||||
"""
|
||||
RTT timeout factor used in link timeout calculation.
|
||||
@@ -106,16 +108,46 @@ class Link:
|
||||
ACCEPT_ALL = 0x02
|
||||
resource_strategies = [ACCEPT_NONE, ACCEPT_APP, ACCEPT_ALL]
|
||||
|
||||
@staticmethod
|
||||
def mtu_bytes(mtu):
|
||||
return struct.pack(">I", mtu & 0xFFFFFF)[1:]
|
||||
|
||||
@staticmethod
|
||||
def mtu_from_lr_packet(packet):
|
||||
if len(packet.data) == Link.ECPUBSIZE+Link.LINK_MTU_SIZE:
|
||||
return (packet.data[Link.ECPUBSIZE] << 16) + (packet.data[Link.ECPUBSIZE+1] << 8) + (packet.data[Link.ECPUBSIZE+2])
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def mtu_from_lp_packet(packet):
|
||||
if len(packet.data) == RNS.Identity.SIGLENGTH//8+Link.ECPUBSIZE//2+Link.LINK_MTU_SIZE:
|
||||
mtu_bytes = packet.data[RNS.Identity.SIGLENGTH//8+Link.ECPUBSIZE//2:RNS.Identity.SIGLENGTH//8+Link.ECPUBSIZE//2+Link.LINK_MTU_SIZE]
|
||||
return (mtu_bytes[0] << 16) + (mtu_bytes[1] << 8) + (mtu_bytes[2])
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def validate_request(owner, data, packet):
|
||||
if len(data) == (Link.ECPUBSIZE):
|
||||
if len(data) == Link.ECPUBSIZE or len(data) == Link.ECPUBSIZE+Link.LINK_MTU_SIZE:
|
||||
try:
|
||||
link = Link(owner = owner, peer_pub_bytes=data[:Link.ECPUBSIZE//2], peer_sig_pub_bytes=data[Link.ECPUBSIZE//2:Link.ECPUBSIZE])
|
||||
link.set_link_id(packet)
|
||||
|
||||
if len(data) == Link.ECPUBSIZE+Link.LINK_MTU_SIZE:
|
||||
RNS.log("Link request includes MTU signalling", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
try:
|
||||
link.mtu = Link.mtu_from_lr_packet(packet) or Reticulum.MTU
|
||||
except Exception as e:
|
||||
RNS.trace_exception(e)
|
||||
link.mtu = RNS.Reticulum.MTU
|
||||
|
||||
link.update_mdu()
|
||||
link.destination = packet.destination
|
||||
link.establishment_timeout = Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, packet.hops) + Link.KEEPALIVE
|
||||
link.establishment_cost += len(packet.raw)
|
||||
RNS.log("Validating link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_VERBOSE)
|
||||
RNS.log(f"Validating link request {RNS.prettyhexrep(link.link_id)}", RNS.LOG_DEBUG)
|
||||
RNS.log(f"Link MTU configured to {RNS.prettysize(link.mtu)}", RNS.LOG_EXTREME)
|
||||
RNS.log(f"Establishment timeout is {RNS.prettytime(link.establishment_timeout)} for incoming link request "+RNS.prettyhexrep(link.link_id), RNS.LOG_EXTREME)
|
||||
link.handshake()
|
||||
link.attached_interface = packet.receiving_interface
|
||||
@@ -134,7 +166,7 @@ class Link:
|
||||
return None
|
||||
|
||||
else:
|
||||
RNS.log("Invalid link request payload size, dropping request", RNS.LOG_DEBUG)
|
||||
RNS.log(f"Invalid link request payload size of {len(data)} bytes, dropping request", RNS.LOG_DEBUG)
|
||||
return None
|
||||
|
||||
|
||||
@@ -142,10 +174,13 @@ class Link:
|
||||
if destination != None and destination.type != RNS.Destination.SINGLE:
|
||||
raise TypeError("Links can only be established to the \"single\" destination type")
|
||||
self.rtt = None
|
||||
self.mtu = RNS.Reticulum.MTU
|
||||
self.establishment_cost = 0
|
||||
self.establishment_rate = None
|
||||
self.callbacks = LinkCallbacks()
|
||||
self.resource_strategy = Link.ACCEPT_NONE
|
||||
self.last_resource_window = None
|
||||
self.last_resource_eifr = None
|
||||
self.outgoing_resources = []
|
||||
self.incoming_resources = []
|
||||
self.pending_requests = []
|
||||
@@ -208,8 +243,13 @@ class Link:
|
||||
if closed_callback != None:
|
||||
self.set_link_closed_callback(closed_callback)
|
||||
|
||||
if (self.initiator):
|
||||
self.request_data = self.pub_bytes+self.sig_pub_bytes
|
||||
if self.initiator:
|
||||
link_mtu = b""
|
||||
nh_hw_mtu = RNS.Transport.next_hop_interface_hw_mtu(destination.hash)
|
||||
if RNS.Reticulum.link_mtu_discovery() and nh_hw_mtu:
|
||||
link_mtu = Link.mtu_bytes(nh_hw_mtu)
|
||||
RNS.log(f"Signalling link MTU of {RNS.prettysize(nh_hw_mtu)} for link", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
self.request_data = self.pub_bytes+self.sig_pub_bytes+link_mtu
|
||||
self.packet = RNS.Packet(destination, self.request_data, packet_type=RNS.Packet.LINKREQUEST)
|
||||
self.packet.pack()
|
||||
self.establishment_cost += len(self.packet.raw)
|
||||
@@ -233,8 +273,17 @@ class Link:
|
||||
if not hasattr(self.peer_pub, "curve"):
|
||||
self.peer_pub.curve = Link.CURVE
|
||||
|
||||
@staticmethod
|
||||
def link_id_from_lr_packet(packet):
|
||||
hashable_part = packet.get_hashable_part()
|
||||
if len(packet.data) > Link.ECPUBSIZE:
|
||||
diff = len(packet.data) - Link.ECPUBSIZE
|
||||
hashable_part = hashable_part[:-diff]
|
||||
|
||||
return RNS.Identity.truncated_hash(hashable_part)
|
||||
|
||||
def set_link_id(self, packet):
|
||||
self.link_id = packet.getTruncatedHash()
|
||||
self.link_id = Link.link_id_from_lr_packet(packet)
|
||||
self.hash = self.link_id
|
||||
|
||||
def handshake(self):
|
||||
@@ -253,10 +302,14 @@ class Link:
|
||||
|
||||
|
||||
def prove(self):
|
||||
signed_data = self.link_id+self.pub_bytes+self.sig_pub_bytes
|
||||
mtu_bytes = b""
|
||||
if self.mtu != RNS.Reticulum.MTU:
|
||||
mtu_bytes = Link.mtu_bytes(self.mtu)
|
||||
|
||||
signed_data = self.link_id+self.pub_bytes+self.sig_pub_bytes+mtu_bytes
|
||||
signature = self.owner.identity.sign(signed_data)
|
||||
|
||||
proof_data = signature+self.pub_bytes
|
||||
proof_data = signature+self.pub_bytes+mtu_bytes
|
||||
proof = RNS.Packet(self, proof_data, packet_type=RNS.Packet.PROOF, context=RNS.Packet.LRPROOF)
|
||||
proof.send()
|
||||
self.establishment_cost += len(proof.raw)
|
||||
@@ -279,6 +332,14 @@ class Link:
|
||||
def validate_proof(self, packet):
|
||||
try:
|
||||
if self.status == Link.PENDING:
|
||||
mtu_bytes = b""
|
||||
confirmed_mtu = None
|
||||
if len(packet.data) == RNS.Identity.SIGLENGTH//8+Link.ECPUBSIZE//2+Link.LINK_MTU_SIZE:
|
||||
confirmed_mtu = Link.mtu_from_lp_packet(packet)
|
||||
mtu_bytes = Link.mtu_bytes(confirmed_mtu)
|
||||
packet.data = packet.data[:RNS.Identity.SIGLENGTH//8+Link.ECPUBSIZE//2]
|
||||
RNS.log(f"Destination confirmed link MTU of {RNS.prettysize(confirmed_mtu)}", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
|
||||
if self.initiator and len(packet.data) == RNS.Identity.SIGLENGTH//8+Link.ECPUBSIZE//2:
|
||||
peer_pub_bytes = packet.data[RNS.Identity.SIGLENGTH//8:RNS.Identity.SIGLENGTH//8+Link.ECPUBSIZE//2]
|
||||
peer_sig_pub_bytes = self.destination.identity.get_public_key()[Link.ECPUBSIZE//2:Link.ECPUBSIZE]
|
||||
@@ -286,7 +347,7 @@ class Link:
|
||||
self.handshake()
|
||||
|
||||
self.establishment_cost += len(packet.raw)
|
||||
signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes
|
||||
signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes+mtu_bytes
|
||||
signature = packet.data[:RNS.Identity.SIGLENGTH//8]
|
||||
|
||||
if self.destination.identity.validate(signature, signed_data):
|
||||
@@ -296,11 +357,13 @@ class Link:
|
||||
self.rtt = time.time() - self.request_time
|
||||
self.attached_interface = packet.receiving_interface
|
||||
self.__remote_identity = self.destination.identity
|
||||
self.mtu = confirmed_mtu or RNS.Reticulum.MTU
|
||||
self.update_mdu()
|
||||
self.status = Link.ACTIVE
|
||||
self.activated_at = time.time()
|
||||
self.last_proof = self.activated_at
|
||||
RNS.Transport.activate_link(self)
|
||||
RNS.log("Link "+str(self)+" established with "+str(self.destination)+", RTT is "+str(round(self.rtt, 3))+"s", RNS.LOG_VERBOSE)
|
||||
RNS.log("Link "+str(self)+" established with "+str(self.destination)+", RTT is "+str(round(self.rtt, 3))+"s", RNS.LOG_DEBUG)
|
||||
|
||||
if self.rtt != None and self.establishment_cost != None and self.rtt > 0 and self.establishment_cost > 0:
|
||||
self.establishment_rate = self.establishment_cost/self.rtt
|
||||
@@ -361,7 +424,7 @@ class Link:
|
||||
if timeout == None:
|
||||
timeout = self.rtt * self.traffic_timeout_factor + RNS.Resource.RESPONSE_MAX_GRACE_TIME*1.125
|
||||
|
||||
if len(packed_request) <= Link.MDU:
|
||||
if len(packed_request) <= self.mdu:
|
||||
request_packet = RNS.Packet(self, packed_request, RNS.Packet.DATA, context = RNS.Packet.REQUEST)
|
||||
packet_receipt = request_packet.send()
|
||||
|
||||
@@ -395,6 +458,10 @@ class Link:
|
||||
)
|
||||
|
||||
|
||||
def update_mdu(self):
|
||||
self.mdu = self.mtu - RNS.Reticulum.HEADER_MAXSIZE - RNS.Reticulum.IFAC_MIN_SIZE
|
||||
self.mdu = math.floor((self.mtu-RNS.Reticulum.IFAC_MIN_SIZE-RNS.Reticulum.HEADER_MINSIZE-RNS.Identity.TOKEN_OVERHEAD)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
|
||||
|
||||
def rtt_packet(self, packet):
|
||||
try:
|
||||
measured_rtt = time.time() - self.request_time
|
||||
@@ -709,7 +776,7 @@ class Link:
|
||||
if response != None:
|
||||
packed_response = umsgpack.packb([request_id, response])
|
||||
|
||||
if len(packed_response) <= Link.MDU:
|
||||
if len(packed_response) <= self.mdu:
|
||||
RNS.Packet(self, packed_response, RNS.Packet.DATA, context = RNS.Packet.RESPONSE).send()
|
||||
else:
|
||||
response_resource = RNS.Resource(packed_response, self, request_id = request_id, is_response = True)
|
||||
@@ -895,6 +962,8 @@ class Link:
|
||||
resource_advertisement.link = self
|
||||
if self.callbacks.resource(resource_advertisement):
|
||||
RNS.Resource.accept(packet, self.callbacks.resource_concluded)
|
||||
else:
|
||||
RNS.Resource.reject(packet)
|
||||
except Exception as e:
|
||||
RNS.log("Error while executing resource accept callback from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
elif self.resource_strategy == Link.ACCEPT_ALL:
|
||||
@@ -940,6 +1009,15 @@ class Link:
|
||||
if resource_hash == resource.hash:
|
||||
resource.cancel()
|
||||
|
||||
elif packet.context == RNS.Packet.RESOURCE_RCL:
|
||||
plaintext = self.decrypt(packet.data)
|
||||
if plaintext != None:
|
||||
self.__update_phy_stats(packet)
|
||||
resource_hash = plaintext[:RNS.Identity.HASHLENGTH//8]
|
||||
for resource in self.outgoing_resources:
|
||||
if resource_hash == resource.hash:
|
||||
resource._rejected()
|
||||
|
||||
elif packet.context == RNS.Packet.KEEPALIVE:
|
||||
if not self.initiator and packet.data == bytes([0xFF]):
|
||||
keepalive_packet = RNS.Packet(self, bytes([0xFE]), context=RNS.Packet.KEEPALIVE)
|
||||
@@ -1076,6 +1154,8 @@ class Link:
|
||||
|
||||
def resource_concluded(self, resource):
|
||||
if resource in self.incoming_resources:
|
||||
self.last_resource_window = resource.window
|
||||
self.last_resource_eifr = resource.eifr
|
||||
self.incoming_resources.remove(resource)
|
||||
if resource in self.outgoing_resources:
|
||||
self.outgoing_resources.remove(resource)
|
||||
@@ -1105,6 +1185,12 @@ class Link:
|
||||
|
||||
return False
|
||||
|
||||
def get_last_resource_window(self):
|
||||
return self.last_resource_window
|
||||
|
||||
def get_last_resource_eifr(self):
|
||||
return self.last_resource_eifr
|
||||
|
||||
def cancel_outgoing_resource(self, resource):
|
||||
if resource in self.outgoing_resources:
|
||||
self.outgoing_resources.remove(resource)
|
||||
|
||||
+9
-1
@@ -137,7 +137,11 @@ class Packet:
|
||||
self.fromPacked = True
|
||||
self.create_receipt = False
|
||||
|
||||
self.MTU = RNS.Reticulum.MTU
|
||||
if destination and destination.type == RNS.Destination.LINK:
|
||||
self.MTU = destination.mtu
|
||||
else:
|
||||
self.MTU = RNS.Reticulum.MTU
|
||||
|
||||
self.sent_at = None
|
||||
self.packet_hash = None
|
||||
self.ratchet_id = None
|
||||
@@ -501,6 +505,10 @@ class PacketReceipt:
|
||||
return False
|
||||
elif len(proof) == PacketReceipt.IMPL_LENGTH:
|
||||
# This is an implicit proof
|
||||
|
||||
if not hasattr(self.destination, "identity"):
|
||||
return False
|
||||
|
||||
if self.destination.identity == None:
|
||||
return False
|
||||
|
||||
|
||||
+86
-24
@@ -141,6 +141,19 @@ class Resource:
|
||||
COMPLETE = 0x06
|
||||
FAILED = 0x07
|
||||
CORRUPT = 0x08
|
||||
REJECTED = 0x00
|
||||
|
||||
@staticmethod
|
||||
def reject(advertisement_packet):
|
||||
try:
|
||||
adv = ResourceAdvertisement.unpack(advertisement_packet.plaintext)
|
||||
resource_hash = adv.h
|
||||
reject_packet = RNS.Packet(advertisement_packet.link, resource_hash, context=RNS.Packet.RESOURCE_RCL)
|
||||
reject_packet.send()
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"An error ocurred while rejecting advertised resource: {e}", RNS.LOG_ERROR)
|
||||
RNS.trace_exception(e)
|
||||
|
||||
@staticmethod
|
||||
def accept(advertisement_packet, callback=None, progress_callback = None, request_id = None):
|
||||
@@ -163,7 +176,7 @@ class Resource:
|
||||
resource.initiator = False
|
||||
resource.callback = callback
|
||||
resource.__progress_callback = progress_callback
|
||||
resource.total_parts = int(math.ceil(resource.size/float(Resource.SDU)))
|
||||
resource.total_parts = int(math.ceil(resource.size/float(resource.sdu)))
|
||||
resource.received_count = 0
|
||||
resource.outstanding_parts = 0
|
||||
resource.parts = [None] * resource.total_parts
|
||||
@@ -186,6 +199,13 @@ class Resource:
|
||||
resource.waiting_for_hmu = False
|
||||
resource.receiving_part = False
|
||||
resource.consecutive_completed_height = -1
|
||||
|
||||
previous_window = resource.link.get_last_resource_window()
|
||||
previous_eifr = resource.link.get_last_resource_eifr()
|
||||
if previous_window:
|
||||
resource.window = previous_window
|
||||
if previous_eifr:
|
||||
resource.previous_eifr = previous_eifr
|
||||
|
||||
if not resource.link.has_incoming_resource(resource):
|
||||
resource.link.register_incoming_resource(resource)
|
||||
@@ -271,6 +291,10 @@ class Resource:
|
||||
|
||||
self.status = Resource.NONE
|
||||
self.link = link
|
||||
if self.link.mtu:
|
||||
self.sdu = self.link.mtu - RNS.Reticulum.HEADER_MAXSIZE - RNS.Reticulum.IFAC_MIN_SIZE
|
||||
else:
|
||||
self.sdu = link.mdu or Resource.SDU
|
||||
self.max_retries = Resource.MAX_RETRIES
|
||||
self.max_adv_retries = Resource.MAX_ADV_RETRIES
|
||||
self.retries_left = self.max_retries
|
||||
@@ -286,10 +310,14 @@ class Resource:
|
||||
self.req_sent = 0
|
||||
self.req_resp_rtt_rate = 0
|
||||
self.rtt_rxd_bytes_at_part_req = 0
|
||||
self.req_data_rtt_rate = 0
|
||||
self.eifr = None
|
||||
self.previous_eifr = None
|
||||
self.fast_rate_rounds = 0
|
||||
self.very_slow_rate_rounds = 0
|
||||
self.request_id = request_id
|
||||
self.is_response = is_response
|
||||
self.auto_compress = auto_compress
|
||||
|
||||
self.req_hashlist = []
|
||||
self.receiver_min_consecutive_height = 0
|
||||
@@ -306,9 +334,9 @@ class Resource:
|
||||
|
||||
compression_began = time.time()
|
||||
if (auto_compress and len(self.uncompressed_data) <= Resource.AUTO_COMPRESS_MAX_SIZE):
|
||||
RNS.log("Compressing resource data...", RNS.LOG_DEBUG)
|
||||
RNS.log("Compressing resource data...", RNS.LOG_EXTREME)
|
||||
self.compressed_data = bz2.compress(self.uncompressed_data)
|
||||
RNS.log("Compression completed in "+str(round(time.time()-compression_began, 3))+" seconds", RNS.LOG_DEBUG)
|
||||
RNS.log("Compression completed in "+str(round(time.time()-compression_began, 3))+" seconds", RNS.LOG_EXTREME)
|
||||
else:
|
||||
self.compressed_data = self.uncompressed_data
|
||||
|
||||
@@ -317,7 +345,7 @@ class Resource:
|
||||
|
||||
if (self.compressed_size < self.uncompressed_size and auto_compress):
|
||||
saved_bytes = len(self.uncompressed_data) - len(self.compressed_data)
|
||||
RNS.log("Compression saved "+str(saved_bytes)+" bytes, sending compressed", RNS.LOG_DEBUG)
|
||||
RNS.log("Compression saved "+str(saved_bytes)+" bytes, sending compressed", RNS.LOG_EXTREME)
|
||||
|
||||
self.data = b""
|
||||
self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE]
|
||||
@@ -335,7 +363,7 @@ class Resource:
|
||||
self.compressed = False
|
||||
self.compressed_data = None
|
||||
if auto_compress:
|
||||
RNS.log("Compression did not decrease size, sending uncompressed", RNS.LOG_DEBUG)
|
||||
RNS.log("Compression did not decrease size, sending uncompressed", RNS.LOG_EXTREME)
|
||||
|
||||
# Resources handle encryption directly to
|
||||
# make optimal use of packet MTU on an entire
|
||||
@@ -346,13 +374,13 @@ class Resource:
|
||||
|
||||
self.size = len(self.data)
|
||||
self.sent_parts = 0
|
||||
hashmap_entries = int(math.ceil(self.size/float(Resource.SDU)))
|
||||
hashmap_entries = int(math.ceil(self.size/float(self.sdu)))
|
||||
self.total_parts = hashmap_entries
|
||||
|
||||
hashmap_ok = False
|
||||
while not hashmap_ok:
|
||||
hashmap_computation_began = time.time()
|
||||
RNS.log("Starting resource hashmap computation with "+str(hashmap_entries)+" entries...", RNS.LOG_DEBUG)
|
||||
RNS.log("Starting resource hashmap computation with "+str(hashmap_entries)+" entries...", RNS.LOG_EXTREME)
|
||||
|
||||
self.random_hash = RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE]
|
||||
self.hash = RNS.Identity.full_hash(data+self.random_hash)
|
||||
@@ -368,11 +396,11 @@ class Resource:
|
||||
self.hashmap = b""
|
||||
collision_guard_list = []
|
||||
for i in range(0,hashmap_entries):
|
||||
data = self.data[i*Resource.SDU:(i+1)*Resource.SDU]
|
||||
data = self.data[i*self.sdu:(i+1)*self.sdu]
|
||||
map_hash = self.get_map_hash(data)
|
||||
|
||||
if map_hash in collision_guard_list:
|
||||
RNS.log("Found hash collision in resource map, remapping...", RNS.LOG_VERBOSE)
|
||||
RNS.log("Found hash collision in resource map, remapping...", RNS.LOG_DEBUG)
|
||||
hashmap_ok = False
|
||||
break
|
||||
else:
|
||||
@@ -388,7 +416,7 @@ class Resource:
|
||||
self.hashmap += part.map_hash
|
||||
self.parts.append(part)
|
||||
|
||||
RNS.log("Hashmap computation concluded in "+str(round(time.time()-hashmap_computation_began, 3))+" seconds", RNS.LOG_DEBUG)
|
||||
RNS.log("Hashmap computation concluded in "+str(round(time.time()-hashmap_computation_began, 3))+" seconds", RNS.LOG_EXTREME)
|
||||
|
||||
if advertise:
|
||||
self.advertise()
|
||||
@@ -447,7 +475,7 @@ class Resource:
|
||||
self.status = Resource.ADVERTISED
|
||||
self.retries_left = self.max_adv_retries
|
||||
self.link.register_outgoing_resource(self)
|
||||
RNS.log("Sent resource advertisement for "+RNS.prettyhexrep(self.hash), RNS.LOG_DEBUG)
|
||||
RNS.log("Sent resource advertisement for "+RNS.prettyhexrep(self.hash), RNS.LOG_EXTREME)
|
||||
except Exception as e:
|
||||
RNS.log("Could not advertise resource, the contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
self.cancel()
|
||||
@@ -455,6 +483,22 @@ class Resource:
|
||||
|
||||
self.watchdog_job()
|
||||
|
||||
def update_eifr(self):
|
||||
if self.rtt == None:
|
||||
rtt = self.link.rtt
|
||||
else:
|
||||
rtt = self.rtt
|
||||
|
||||
if self.req_data_rtt_rate != 0:
|
||||
expected_inflight_rate = self.req_data_rtt_rate*8
|
||||
else:
|
||||
if self.previous_eifr != None:
|
||||
expected_inflight_rate = self.previous_eifr
|
||||
else:
|
||||
expected_inflight_rate = self.link.establishment_cost*8 / rtt
|
||||
|
||||
self.eifr = expected_inflight_rate
|
||||
|
||||
def watchdog_job(self):
|
||||
thread = threading.Thread(target=self.__watchdog_job)
|
||||
thread.daemon = True
|
||||
@@ -469,7 +513,6 @@ class Resource:
|
||||
sleep(0.025)
|
||||
|
||||
sleep_time = None
|
||||
|
||||
if self.status == Resource.ADVERTISED:
|
||||
sleep_time = (self.adv_sent+self.timeout+Resource.PROCESSING_GRACE)-time.time()
|
||||
if sleep_time < 0:
|
||||
@@ -493,17 +536,19 @@ class Resource:
|
||||
|
||||
elif self.status == Resource.TRANSFERRING:
|
||||
if not self.initiator:
|
||||
|
||||
if self.rtt == None:
|
||||
rtt = self.link.rtt
|
||||
else:
|
||||
rtt = self.rtt
|
||||
|
||||
window_remaining = self.outstanding_parts
|
||||
|
||||
retries_used = self.max_retries - self.retries_left
|
||||
extra_wait = retries_used * Resource.PER_RETRY_DELAY
|
||||
sleep_time = self.last_activity + (rtt*(self.part_timeout_factor+window_remaining)) + Resource.RETRY_GRACE_TIME + extra_wait - time.time()
|
||||
|
||||
self.update_eifr()
|
||||
expected_tof_remaining = (self.outstanding_parts*self.sdu*8)/self.eifr
|
||||
|
||||
if self.req_resp_rtt_rate != 0:
|
||||
sleep_time = self.last_activity + self.part_timeout_factor*expected_tof_remaining + Resource.RETRY_GRACE_TIME + extra_wait - time.time()
|
||||
else:
|
||||
sleep_time = self.last_activity + self.part_timeout_factor*((3*self.sdu)/self.eifr) + Resource.RETRY_GRACE_TIME + extra_wait - time.time()
|
||||
|
||||
# RNS.log(f"EIFR {RNS.prettyspeed(self.eifr)}, ETOF {RNS.prettyshorttime(expected_tof_remaining)} ", RNS.LOG_DEBUG, pt=True)
|
||||
# RNS.log(f"Resource ST {RNS.prettyshorttime(sleep_time)}, RTT {RNS.prettyshorttime(self.rtt or self.link.rtt)}, {self.outstanding_parts} left", RNS.LOG_DEBUG, pt=True)
|
||||
|
||||
if sleep_time < 0:
|
||||
if self.retries_left > 0:
|
||||
@@ -553,8 +598,11 @@ class Resource:
|
||||
self.last_part_sent = time.time()
|
||||
sleep_time = 0.001
|
||||
|
||||
elif self.status == Resource.REJECTED:
|
||||
sleep_time = 0.001
|
||||
|
||||
if sleep_time == 0:
|
||||
RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_WARNING)
|
||||
RNS.log("Warning! Link watchdog sleep time of 0!", RNS.LOG_DEBUG)
|
||||
if sleep_time == None or sleep_time < 0:
|
||||
RNS.log("Timing error, cancelling resource transfer.", RNS.LOG_ERROR)
|
||||
self.cancel()
|
||||
@@ -647,6 +695,7 @@ class Resource:
|
||||
request_id = self.request_id,
|
||||
is_response = self.is_response,
|
||||
advertise = False,
|
||||
auto_compress = self.auto_compress,
|
||||
)
|
||||
|
||||
def validate_proof(self, proof_data):
|
||||
@@ -770,6 +819,7 @@ class Resource:
|
||||
|
||||
if rtt != 0:
|
||||
self.req_data_rtt_rate = req_transferred/rtt
|
||||
self.update_eifr()
|
||||
self.rtt_rxd_bytes_at_part_req = self.rtt_rxd_bytes
|
||||
|
||||
if self.req_data_rtt_rate > Resource.RATE_FAST and self.fast_rate_rounds < Resource.FAST_RATE_THRESHOLD:
|
||||
@@ -957,6 +1007,18 @@ class Resource:
|
||||
except Exception as e:
|
||||
RNS.log("Error while executing callbacks on resource cancel from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
def _rejected(self):
|
||||
if self.status < Resource.COMPLETE:
|
||||
if self.initiator:
|
||||
self.status = Resource.REJECTED
|
||||
self.link.cancel_outgoing_resource(self)
|
||||
if self.callback != None:
|
||||
try:
|
||||
self.link.resource_concluded(self)
|
||||
self.callback(self)
|
||||
except Exception as e:
|
||||
RNS.log("Error while executing callbacks on resource reject from "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
def set_callback(self, callback):
|
||||
self.callback = callback
|
||||
|
||||
@@ -981,7 +1043,7 @@ class Resource:
|
||||
processed_segments = self.segment_index-1
|
||||
|
||||
current_segment_parts = self.total_parts
|
||||
max_parts_per_segment = math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
|
||||
max_parts_per_segment = math.ceil(Resource.MAX_EFFICIENT_SIZE/self.sdu)
|
||||
|
||||
previously_processed_parts = processed_segments*max_parts_per_segment
|
||||
|
||||
@@ -1004,7 +1066,7 @@ class Resource:
|
||||
processed_segments = self.segment_index-1
|
||||
|
||||
current_segment_parts = self.total_parts
|
||||
max_parts_per_segment = math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
|
||||
max_parts_per_segment = math.ceil(Resource.MAX_EFFICIENT_SIZE/self.sdu)
|
||||
|
||||
previously_processed_parts = processed_segments*max_parts_per_segment
|
||||
|
||||
|
||||
+81
-9
@@ -39,8 +39,9 @@ else:
|
||||
from RNS.vendor.configobj import ConfigObj
|
||||
import configparser
|
||||
import multiprocessing.connection
|
||||
import signal
|
||||
import importlib
|
||||
import threading
|
||||
import signal
|
||||
import atexit
|
||||
import struct
|
||||
import array
|
||||
@@ -89,6 +90,16 @@ class Reticulum:
|
||||
the default value.
|
||||
"""
|
||||
|
||||
LINK_MTU_DISCOVERY = False
|
||||
"""
|
||||
Whether automatic link MTU discovery is enabled by default in this
|
||||
release. Link MTU discovery significantly increases throughput over
|
||||
fast links, but requires all intermediary hops to also support it.
|
||||
Support for this feature was added in RNS version 0.9.0. This option
|
||||
will become enabled by default in the near future. Please update your
|
||||
RNS instances.
|
||||
"""
|
||||
|
||||
MAX_QUEUED_ANNOUNCES = 16384
|
||||
QUEUED_ANNOUNCE_LIFE = 60*60*24
|
||||
|
||||
@@ -151,32 +162,38 @@ class Reticulum:
|
||||
interfacepath = ""
|
||||
|
||||
__instance = None
|
||||
|
||||
|
||||
__interface_detach_ran = False
|
||||
__exit_handler_ran = False
|
||||
@staticmethod
|
||||
def exit_handler():
|
||||
# This exit handler is called whenever Reticulum is asked to
|
||||
# shut down, and will in turn call exit handlers in other
|
||||
# classes, saving necessary information to disk and carrying
|
||||
# out cleanup operations.
|
||||
if not Reticulum.__exit_handler_ran:
|
||||
if not Reticulum.__interface_detach_ran:
|
||||
RNS.Transport.detach_interfaces()
|
||||
RNS.Transport.exit_handler()
|
||||
RNS.Identity.exit_handler()
|
||||
|
||||
RNS.Transport.exit_handler()
|
||||
RNS.Identity.exit_handler()
|
||||
if RNS.Profiler.ran():
|
||||
RNS.Profiler.results()
|
||||
|
||||
if RNS.profiler_ran:
|
||||
RNS.profiler_results()
|
||||
RNS.loglevel = -1
|
||||
|
||||
@staticmethod
|
||||
def sigint_handler(signal, frame):
|
||||
RNS.Transport.detach_interfaces()
|
||||
Reticulum.__interface_detach_ran = True
|
||||
RNS.exit()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def sigterm_handler(signal, frame):
|
||||
RNS.Transport.detach_interfaces()
|
||||
Reticulum.__interface_detach_ran = True
|
||||
RNS.exit()
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_instance():
|
||||
"""
|
||||
@@ -225,6 +242,7 @@ class Reticulum:
|
||||
Reticulum.interfacepath = Reticulum.configdir+"/interfaces"
|
||||
|
||||
Reticulum.__transport_enabled = False
|
||||
Reticulum.__link_mtu_discovery = Reticulum.LINK_MTU_DISCOVERY
|
||||
Reticulum.__remote_management_enabled = False
|
||||
Reticulum.__use_implicit_proof = True
|
||||
Reticulum.__allow_probes = False
|
||||
@@ -250,6 +268,7 @@ class Reticulum:
|
||||
RNS.loglevel = self.requested_loglevel
|
||||
|
||||
self.is_shared_instance = False
|
||||
self.shared_instance_interface = None
|
||||
self.require_shared = require_shared_instance
|
||||
self.is_connected_to_shared_instance = False
|
||||
self.is_standalone_instance = False
|
||||
@@ -286,7 +305,7 @@ class Reticulum:
|
||||
time.sleep(1.5)
|
||||
|
||||
self.__apply_config()
|
||||
RNS.log(f"Utilising cryptography backend \"{RNS.Cryptography.Provider.backend()}\"", RNS.LOG_VERBOSE)
|
||||
RNS.log(f"Utilising cryptography backend \"{RNS.Cryptography.Provider.backend()}\"", RNS.LOG_DEBUG)
|
||||
RNS.log(f"Configuration loaded from {self.configpath}", RNS.LOG_VERBOSE)
|
||||
|
||||
RNS.Identity.load_known_destinations()
|
||||
@@ -339,6 +358,7 @@ class Reticulum:
|
||||
interface.bitrate = Reticulum._force_shared_instance_bitrate
|
||||
interface._force_bitrate = Reticulum._force_shared_instance_bitrate
|
||||
RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING)
|
||||
interface.optimise_mtu()
|
||||
|
||||
if self.require_shared == True:
|
||||
interface.detach()
|
||||
@@ -347,6 +367,7 @@ class Reticulum:
|
||||
|
||||
else:
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
self.shared_instance_interface = interface
|
||||
self.is_shared_instance = True
|
||||
RNS.log("Started shared instance interface: "+str(interface), RNS.LOG_DEBUG)
|
||||
self.__start_jobs()
|
||||
@@ -363,6 +384,7 @@ class Reticulum:
|
||||
interface.bitrate = Reticulum._force_shared_instance_bitrate
|
||||
interface._force_bitrate = True
|
||||
RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING)
|
||||
interface.optimise_mtu()
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
self.is_shared_instance = False
|
||||
self.is_standalone_instance = False
|
||||
@@ -423,6 +445,10 @@ class Reticulum:
|
||||
v = self.config["reticulum"].as_bool(option)
|
||||
if v == True:
|
||||
Reticulum.__transport_enabled = True
|
||||
if option == "link_mtu_discovery":
|
||||
v = self.config["reticulum"].as_bool(option)
|
||||
if v == True:
|
||||
Reticulum.__link_mtu_discovery = True
|
||||
if option == "enable_remote_management":
|
||||
v = self.config["reticulum"].as_bool(option)
|
||||
if v == True:
|
||||
@@ -580,6 +606,7 @@ class Reticulum:
|
||||
interface.announce_cap = announce_cap
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
interface.optimise_mtu()
|
||||
if ifac_size != None:
|
||||
interface.ifac_size = ifac_size
|
||||
else:
|
||||
@@ -742,6 +769,7 @@ class Reticulum:
|
||||
|
||||
if configured_bitrate:
|
||||
interface.bitrate = configured_bitrate
|
||||
interface.optimise_mtu()
|
||||
|
||||
if ifac_size != None:
|
||||
interface.ifac_size = ifac_size
|
||||
@@ -939,6 +967,9 @@ class Reticulum:
|
||||
if hasattr(interface, "r_channel_load_long"):
|
||||
ifstats["channel_load_long"] = interface.r_channel_load_long
|
||||
|
||||
if hasattr(interface, "r_noise_floor"):
|
||||
ifstats["noise_floor"] = interface.r_noise_floor
|
||||
|
||||
if hasattr(interface, "r_battery_state"):
|
||||
if interface.r_battery_state != 0x00:
|
||||
ifstats["battery_state"] = interface.get_battery_state_string()
|
||||
@@ -952,6 +983,22 @@ class Reticulum:
|
||||
else:
|
||||
ifstats["bitrate"] = None
|
||||
|
||||
if hasattr(interface, "current_rx_speed"):
|
||||
if interface.current_rx_speed != None:
|
||||
ifstats["rxs"] = interface.current_rx_speed
|
||||
else:
|
||||
ifstats["rxs"] = 0
|
||||
else:
|
||||
ifstats["rxs"] = 0
|
||||
|
||||
if hasattr(interface, "current_tx_speed"):
|
||||
if interface.current_tx_speed != None:
|
||||
ifstats["txs"] = interface.current_tx_speed
|
||||
else:
|
||||
ifstats["txs"] = 0
|
||||
else:
|
||||
ifstats["txs"] = 0
|
||||
|
||||
if hasattr(interface, "peers"):
|
||||
if interface.peers != None:
|
||||
ifstats["peers"] = len(interface.peers)
|
||||
@@ -989,6 +1036,10 @@ class Reticulum:
|
||||
|
||||
stats = {}
|
||||
stats["interfaces"] = interfaces
|
||||
stats["rxb"] = RNS.Transport.traffic_rxb
|
||||
stats["txb"] = RNS.Transport.traffic_txb
|
||||
stats["rxs"] = RNS.Transport.speed_rx
|
||||
stats["txs"] = RNS.Transport.speed_tx
|
||||
if Reticulum.transport_enabled():
|
||||
stats["transport_id"] = RNS.Transport.identity.hash
|
||||
stats["transport_uptime"] = time.time()-RNS.Transport.start_time
|
||||
@@ -997,6 +1048,13 @@ class Reticulum:
|
||||
else:
|
||||
stats["probe_responder"] = None
|
||||
|
||||
if importlib.util.find_spec('psutil') != None:
|
||||
import psutil
|
||||
process = psutil.Process()
|
||||
stats["rss"] = process.memory_info().rss
|
||||
else:
|
||||
stats["rss"] = None
|
||||
|
||||
return stats
|
||||
|
||||
def get_path_table(self, max_hops=None):
|
||||
@@ -1209,6 +1267,20 @@ class Reticulum:
|
||||
"""
|
||||
return Reticulum.__transport_enabled
|
||||
|
||||
@staticmethod
|
||||
def link_mtu_discovery():
|
||||
"""
|
||||
Returns whether link MTU discovery is enabled for the running
|
||||
instance.
|
||||
|
||||
When link MTU discovery is enabled, Reticulum will
|
||||
automatically upgrade link MTUs to the highest supported
|
||||
value, increasing transfer speed and efficiency.
|
||||
|
||||
:returns: True if link MTU discovery is enabled, False if not.
|
||||
"""
|
||||
return Reticulum.__link_mtu_discovery
|
||||
|
||||
@staticmethod
|
||||
def remote_management_enabled():
|
||||
"""
|
||||
|
||||
+193
-50
@@ -25,6 +25,7 @@ import RNS
|
||||
import time
|
||||
import math
|
||||
import struct
|
||||
import inspect
|
||||
import threading
|
||||
from time import sleep
|
||||
from .vendor import umsgpack as umsgpack
|
||||
@@ -84,7 +85,8 @@ class Transport:
|
||||
destinations = [] # All active destinations
|
||||
pending_links = [] # Links that are being established
|
||||
active_links = [] # Links that are active
|
||||
packet_hashlist = [] # A list of packet hashes for duplicate detection
|
||||
packet_hashlist = set() # A list of packet hashes for duplicate detection
|
||||
packet_hashlist_prev = set()
|
||||
receipts = [] # Receipts of all outgoing packets for proof processing
|
||||
|
||||
# TODO: "destination_table" should really be renamed to "path_table"
|
||||
@@ -102,9 +104,9 @@ class Transport:
|
||||
path_requests = {} # A table for storing path request timestamps
|
||||
path_states = {} # A table for keeping track of path states
|
||||
|
||||
discovery_path_requests = {} # A table for keeping track of path requests on behalf of other nodes
|
||||
discovery_pr_tags = [] # A table for keeping track of tagged path requests
|
||||
max_pr_tags = 32000 # Maximum amount of unique path request tags to remember
|
||||
discovery_path_requests = {} # A table for keeping track of path requests on behalf of other nodes
|
||||
discovery_pr_tags = [] # A table for keeping track of tagged path requests
|
||||
max_pr_tags = 32000 # Maximum amount of unique path request tags to remember
|
||||
|
||||
# Transport control destinations are used
|
||||
# for control purposes like path requests
|
||||
@@ -140,6 +142,12 @@ class Transport:
|
||||
interface_last_jobs = 0.0
|
||||
interface_jobs_interval = 5.0
|
||||
|
||||
traffic_rxb = 0
|
||||
traffic_txb = 0
|
||||
speed_rx = 0
|
||||
speed_tx = 0
|
||||
traffic_captured = None
|
||||
|
||||
identity = None
|
||||
|
||||
@staticmethod
|
||||
@@ -164,7 +172,8 @@ class Transport:
|
||||
if os.path.isfile(packet_hashlist_path):
|
||||
try:
|
||||
file = open(packet_hashlist_path, "rb")
|
||||
Transport.packet_hashlist = umsgpack.unpackb(file.read())
|
||||
hashlist_data = umsgpack.unpackb(file.read())
|
||||
Transport.packet_hashlist = set(hashlist_data)
|
||||
file.close()
|
||||
except Exception as e:
|
||||
RNS.log("Could not load packet hashlist from storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
@@ -192,6 +201,9 @@ class Transport:
|
||||
thread = threading.Thread(target=Transport.jobloop, daemon=True)
|
||||
thread.start()
|
||||
|
||||
thread = threading.Thread(target=Transport.count_traffic_loop, daemon=True)
|
||||
thread.start()
|
||||
|
||||
if RNS.Reticulum.transport_enabled():
|
||||
destination_table_path = RNS.Reticulum.storagepath+"/destination_table"
|
||||
tunnel_table_path = RNS.Reticulum.storagepath+"/tunnels"
|
||||
@@ -318,6 +330,40 @@ class Transport:
|
||||
except Exception as e:
|
||||
RNS.log(f"Could not prioritize interfaces according to bitrate. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
@staticmethod
|
||||
def count_traffic_loop():
|
||||
while True:
|
||||
time.sleep(1)
|
||||
try:
|
||||
rxb = 0; txb = 0;
|
||||
rxs = 0; txs = 0;
|
||||
for interface in Transport.interfaces:
|
||||
if not hasattr(interface, "parent_interface") or interface.parent_interface == None:
|
||||
if hasattr(interface, "transport_traffic_counter"):
|
||||
now = time.time(); irxb = interface.rxb; itxb = interface.txb
|
||||
tc = interface.transport_traffic_counter
|
||||
rx_diff = irxb - tc["rxb"]
|
||||
tx_diff = itxb - tc["txb"]
|
||||
ts_diff = now - tc["ts"]
|
||||
rxb += rx_diff; crxs = (rx_diff*8)/ts_diff
|
||||
txb += tx_diff; ctxs = (tx_diff*8)/ts_diff
|
||||
interface.current_rx_speed = crxs; rxs += crxs
|
||||
interface.current_tx_speed = ctxs; txs += ctxs
|
||||
tc["rxb"] = irxb;
|
||||
tc["txb"] = itxb;
|
||||
tc["ts"] = now;
|
||||
|
||||
else:
|
||||
interface.transport_traffic_counter = {"ts": time.time(), "rxb": interface.rxb, "txb": interface.txb}
|
||||
|
||||
Transport.traffic_rxb += rxb
|
||||
Transport.traffic_txb += txb
|
||||
Transport.speed_rx = rxs
|
||||
Transport.speed_tx = txs
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"An error occurred while counting interface traffic: {e}", RNS.LOG_ERROR)
|
||||
|
||||
@staticmethod
|
||||
def jobloop():
|
||||
while (True):
|
||||
@@ -445,8 +491,9 @@ class Transport:
|
||||
|
||||
|
||||
# Cull the packet hashlist if it has reached its max size
|
||||
if len(Transport.packet_hashlist) > Transport.hashlist_maxsize:
|
||||
Transport.packet_hashlist = Transport.packet_hashlist[len(Transport.packet_hashlist)-Transport.hashlist_maxsize:len(Transport.packet_hashlist)-1]
|
||||
if len(Transport.packet_hashlist) > Transport.hashlist_maxsize//2:
|
||||
Transport.packet_hashlist_prev = Transport.packet_hashlist
|
||||
Transport.packet_hashlist = set()
|
||||
|
||||
# Cull the path request tags list if it has reached its max size
|
||||
if len(Transport.discovery_pr_tags) > Transport.max_pr_tags:
|
||||
@@ -982,10 +1029,10 @@ class Transport:
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
if should_transmit:
|
||||
if not stored_hash:
|
||||
Transport.packet_hashlist.append(packet.packet_hash)
|
||||
Transport.packet_hashlist.add(packet.packet_hash)
|
||||
stored_hash = True
|
||||
|
||||
# TODO: Re-evaluate potential for blocking
|
||||
@@ -1051,7 +1098,7 @@ class Transport:
|
||||
RNS.log("Dropped invalid GROUP announce packet", RNS.LOG_DEBUG)
|
||||
return False
|
||||
|
||||
if not packet.packet_hash in Transport.packet_hashlist:
|
||||
if not packet.packet_hash in Transport.packet_hashlist and not packet.packet_hash in Transport.packet_hashlist_prev:
|
||||
return True
|
||||
else:
|
||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||
@@ -1149,29 +1196,23 @@ class Transport:
|
||||
if hasattr(interface, "r_stat_rssi"):
|
||||
if interface.r_stat_rssi != None:
|
||||
packet.rssi = interface.r_stat_rssi
|
||||
if len(Transport.local_client_interfaces) > 0:
|
||||
Transport.local_client_rssi_cache.append([packet.packet_hash, packet.rssi])
|
||||
|
||||
while len(Transport.local_client_rssi_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
|
||||
Transport.local_client_rssi_cache.pop(0)
|
||||
Transport.local_client_rssi_cache.append([packet.packet_hash, packet.rssi])
|
||||
while len(Transport.local_client_rssi_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
|
||||
Transport.local_client_rssi_cache.pop(0)
|
||||
|
||||
if hasattr(interface, "r_stat_snr"):
|
||||
if interface.r_stat_rssi != None:
|
||||
packet.snr = interface.r_stat_snr
|
||||
if len(Transport.local_client_interfaces) > 0:
|
||||
Transport.local_client_snr_cache.append([packet.packet_hash, packet.snr])
|
||||
|
||||
while len(Transport.local_client_snr_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
|
||||
Transport.local_client_snr_cache.pop(0)
|
||||
Transport.local_client_snr_cache.append([packet.packet_hash, packet.snr])
|
||||
while len(Transport.local_client_snr_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
|
||||
Transport.local_client_snr_cache.pop(0)
|
||||
|
||||
if hasattr(interface, "r_stat_q"):
|
||||
if interface.r_stat_q != None:
|
||||
packet.q = interface.r_stat_q
|
||||
if len(Transport.local_client_interfaces) > 0:
|
||||
Transport.local_client_q_cache.append([packet.packet_hash, packet.q])
|
||||
|
||||
while len(Transport.local_client_q_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
|
||||
Transport.local_client_q_cache.pop(0)
|
||||
Transport.local_client_q_cache.append([packet.packet_hash, packet.q])
|
||||
while len(Transport.local_client_q_cache) > Transport.LOCAL_CLIENT_CACHE_MAXSIZE:
|
||||
Transport.local_client_q_cache.pop(0)
|
||||
|
||||
if len(Transport.local_client_interfaces) > 0:
|
||||
if Transport.is_local_client_interface(interface):
|
||||
@@ -1202,7 +1243,7 @@ class Transport:
|
||||
remember_packet_hash = False
|
||||
|
||||
if remember_packet_hash:
|
||||
Transport.packet_hashlist.append(packet.packet_hash)
|
||||
Transport.packet_hashlist.add(packet.packet_hash)
|
||||
# TODO: Enable when caching has been redesigned
|
||||
# Transport.cache(packet)
|
||||
|
||||
@@ -1287,6 +1328,24 @@ class Transport:
|
||||
now = time.time()
|
||||
proof_timeout = Transport.extra_link_proof_timeout(packet.receiving_interface)
|
||||
proof_timeout += now + RNS.Link.ESTABLISHMENT_TIMEOUT_PER_HOP * max(1, remaining_hops)
|
||||
|
||||
path_mtu = RNS.Link.mtu_from_lr_packet(packet)
|
||||
nh_mtu = outbound_interface.HW_MTU
|
||||
if path_mtu:
|
||||
if outbound_interface.HW_MTU == None:
|
||||
RNS.log(f"No next-hop HW MTU, disabling link MTU upgrade", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
path_mtu = None
|
||||
new_raw = new_raw[:-RNS.Link.LINK_MTU_SIZE]
|
||||
elif not outbound_interface.AUTOCONFIGURE_MTU:
|
||||
RNS.log(f"Outbound interface doesn't support MTU autoconfiguration, disabling link MTU upgrade", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
path_mtu = None
|
||||
new_raw = new_raw[:-RNS.Link.LINK_MTU_SIZE]
|
||||
else:
|
||||
if nh_mtu < path_mtu:
|
||||
path_mtu = nh_mtu
|
||||
clamped_mtu = RNS.Link.mtu_bytes(path_mtu)
|
||||
RNS.log(f"Clamping link MTU to {RNS.prettysize(nh_mtu)}", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
new_raw = new_raw[:-RNS.Link.LINK_MTU_SIZE]+clamped_mtu
|
||||
|
||||
# Entry format is
|
||||
link_entry = [ now, # 0: Timestamp,
|
||||
@@ -1299,7 +1358,7 @@ class Transport:
|
||||
False, # 7: Validated
|
||||
proof_timeout] # 8: Proof timeout timestamp
|
||||
|
||||
Transport.link_table[packet.getTruncatedHash()] = link_entry
|
||||
Transport.link_table[RNS.Link.link_id_from_lr_packet(packet)] = link_entry
|
||||
|
||||
else:
|
||||
# Entry format is
|
||||
@@ -1349,7 +1408,7 @@ class Transport:
|
||||
# Add this packet to the filter hashlist if we
|
||||
# have determined that it's actually our turn
|
||||
# to process it.
|
||||
Transport.packet_hashlist.append(packet.packet_hash)
|
||||
Transport.packet_hashlist.add(packet.packet_hash)
|
||||
|
||||
new_raw = packet.raw[0:1]
|
||||
new_raw += struct.pack("!B", packet.hops)
|
||||
@@ -1402,7 +1461,8 @@ class Transport:
|
||||
now = time.time()
|
||||
if now < announce_entry[1]:
|
||||
RNS.log("Rebroadcasted announce for "+RNS.prettyhexrep(packet.destination_hash)+" has been passed on to another node, no further tries needed", RNS.LOG_DEBUG)
|
||||
Transport.announce_table.pop(packet.destination_hash)
|
||||
if packet.destination_hash in Transport.announce_table:
|
||||
Transport.announce_table.pop(packet.destination_hash)
|
||||
|
||||
else:
|
||||
received_from = packet.destination_hash
|
||||
@@ -1430,7 +1490,8 @@ class Transport:
|
||||
# replayed to forge paths.
|
||||
# TODO: Check whether this approach works
|
||||
# under all circumstances
|
||||
if not random_blob in random_blobs:
|
||||
path_timebase = Transport.timebase_from_random_blobs(random_blobs)
|
||||
if not random_blob in random_blobs and announce_emitted > path_timebase:
|
||||
Transport.mark_path_unknown_state(packet.destination_hash)
|
||||
should_add = True
|
||||
else:
|
||||
@@ -1713,11 +1774,20 @@ class Transport:
|
||||
execute_callback = False
|
||||
|
||||
if execute_callback:
|
||||
handler.received_announce(
|
||||
destination_hash=packet.destination_hash,
|
||||
announced_identity=announce_identity,
|
||||
app_data=RNS.Identity.recall_app_data(packet.destination_hash)
|
||||
)
|
||||
|
||||
if len(inspect.signature(handler.received_announce).parameters) == 3:
|
||||
handler.received_announce(destination_hash=packet.destination_hash,
|
||||
announced_identity=announce_identity,
|
||||
app_data=RNS.Identity.recall_app_data(packet.destination_hash))
|
||||
|
||||
elif len(inspect.signature(handler.received_announce).parameters) == 4:
|
||||
handler.received_announce(destination_hash=packet.destination_hash,
|
||||
announced_identity=announce_identity,
|
||||
app_data=RNS.Identity.recall_app_data(packet.destination_hash),
|
||||
announce_packet_hash = packet.packet_hash)
|
||||
else:
|
||||
raise TypeError("Invalid signature for announce handler callback")
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Error while processing external announce callback.", RNS.LOG_ERROR)
|
||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
@@ -1728,6 +1798,24 @@ class Transport:
|
||||
if packet.transport_id == None or packet.transport_id == Transport.identity.hash:
|
||||
for destination in Transport.destinations:
|
||||
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
|
||||
path_mtu = RNS.Link.mtu_from_lr_packet(packet)
|
||||
if packet.receiving_interface.AUTOCONFIGURE_MTU:
|
||||
nh_mtu = packet.receiving_interface.HW_MTU
|
||||
else:
|
||||
nh_mtu = RNS.Reticulum.MTU
|
||||
|
||||
if path_mtu:
|
||||
if packet.receiving_interface.HW_MTU == None:
|
||||
RNS.log(f"No next-hop HW MTU, disabling link MTU upgrade", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
path_mtu = None
|
||||
packet.data = packet.data[:-RNS.Link.LINK_MTU_SIZE]
|
||||
else:
|
||||
if nh_mtu < path_mtu:
|
||||
path_mtu = nh_mtu
|
||||
clamped_mtu = RNS.Link.mtu_bytes(path_mtu)
|
||||
RNS.log(f"Clamping link MTU to {RNS.prettysize(nh_mtu)}", RNS.LOG_DEBUG) # TODO: Remove debug
|
||||
packet.data = packet.data[:-RNS.Link.LINK_MTU_SIZE]+clamped_mtu
|
||||
|
||||
packet.destination = destination
|
||||
destination.receive(packet)
|
||||
|
||||
@@ -1785,12 +1873,16 @@ class Transport:
|
||||
if packet.hops == link_entry[3]:
|
||||
if packet.receiving_interface == link_entry[2]:
|
||||
try:
|
||||
if len(packet.data) == RNS.Identity.SIGLENGTH//8+RNS.Link.ECPUBSIZE//2:
|
||||
if len(packet.data) == RNS.Identity.SIGLENGTH//8+RNS.Link.ECPUBSIZE//2 or len(packet.data) == RNS.Identity.SIGLENGTH//8+RNS.Link.ECPUBSIZE//2+RNS.Link.LINK_MTU_SIZE:
|
||||
mtu_bytes = b""
|
||||
if len(packet.data) == RNS.Identity.SIGLENGTH//8+RNS.Link.ECPUBSIZE//2+RNS.Link.LINK_MTU_SIZE:
|
||||
mtu_bytes = RNS.Link.mtu_bytes(RNS.Link.mtu_from_lp_packet(packet))
|
||||
|
||||
peer_pub_bytes = packet.data[RNS.Identity.SIGLENGTH//8:RNS.Identity.SIGLENGTH//8+RNS.Link.ECPUBSIZE//2]
|
||||
peer_identity = RNS.Identity.recall(link_entry[6])
|
||||
peer_sig_pub_bytes = peer_identity.get_public_key()[RNS.Link.ECPUBSIZE//2:RNS.Link.ECPUBSIZE]
|
||||
|
||||
signed_data = packet.destination_hash+peer_pub_bytes+peer_sig_pub_bytes
|
||||
signed_data = packet.destination_hash+peer_pub_bytes+peer_sig_pub_bytes+mtu_bytes
|
||||
signature = packet.data[:RNS.Identity.SIGLENGTH//8]
|
||||
|
||||
if peer_identity.validate(signature, signed_data):
|
||||
@@ -1832,7 +1924,7 @@ class Transport:
|
||||
# Add this packet to the filter hashlist if we
|
||||
# have determined that it's actually destined
|
||||
# for this system, and then validate the proof
|
||||
Transport.packet_hashlist.append(packet.packet_hash)
|
||||
Transport.packet_hashlist.add(packet.packet_hash)
|
||||
link.validate_proof(packet)
|
||||
|
||||
elif packet.context == RNS.Packet.RESOURCE_PRF:
|
||||
@@ -2021,8 +2113,9 @@ class Transport:
|
||||
Registers an announce handler.
|
||||
|
||||
:param handler: Must be an object with an *aspect_filter* attribute and a *received_announce(destination_hash, announced_identity, app_data)*
|
||||
callable. Can optionally have a *receive_path_responses* attribute set to ``True``, to also receive all path responses, in addition to live
|
||||
announces. See the :ref:`Announce Example<example-announce>` for more info.
|
||||
or *received_announce(destination_hash, announced_identity, app_data, announce_packet_hash)* callable. Can optionally have a
|
||||
*receive_path_responses* attribute set to ``True``, to also receive all path responses, in addition to live announces. See
|
||||
the :ref:`Announce Example<example-announce>` for more info.
|
||||
"""
|
||||
if hasattr(handler, "received_announce") and callable(handler.received_announce):
|
||||
if hasattr(handler, "aspect_filter"):
|
||||
@@ -2183,6 +2276,17 @@ class Transport:
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def next_hop_interface_hw_mtu(destination_hash):
|
||||
next_hop_interface = Transport.next_hop_interface(destination_hash)
|
||||
if next_hop_interface != None:
|
||||
if next_hop_interface.AUTOCONFIGURE_MTU:
|
||||
return next_hop_interface.HW_MTU
|
||||
else:
|
||||
return None
|
||||
else:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def next_hop_per_bit_latency(destination_hash):
|
||||
next_hop_interface_bitrate = Transport.next_hop_interface_bitrate(destination_hash)
|
||||
@@ -2559,7 +2663,7 @@ class Transport:
|
||||
# Currently no rules are being applied
|
||||
# here, and all interfaces will be sent
|
||||
# the detach call on RNS teardown.
|
||||
if True:
|
||||
if not interface.detached:
|
||||
detachable_interfaces.append(interface)
|
||||
else:
|
||||
pass
|
||||
@@ -2568,17 +2672,45 @@ class Transport:
|
||||
# Currently no rules are being applied
|
||||
# here, and all interfaces will be sent
|
||||
# the detach call on RNS teardown.
|
||||
if True:
|
||||
if not interface.detached:
|
||||
detachable_interfaces.append(interface)
|
||||
else:
|
||||
pass
|
||||
|
||||
shared_instance_master = None
|
||||
local_interfaces = []
|
||||
detach_threads = []
|
||||
RNS.log("Detaching interfaces", RNS.LOG_DEBUG)
|
||||
for interface in detachable_interfaces:
|
||||
try:
|
||||
interface.detach()
|
||||
if type(interface) == RNS.Interfaces.LocalInterface.LocalServerInterface:
|
||||
shared_instance_master = interface
|
||||
elif type(interface) == RNS.Interfaces.LocalInterface.LocalClientInterface:
|
||||
local_interfaces.append(interface)
|
||||
else:
|
||||
def detach_job():
|
||||
RNS.log(f"Detaching {interface}", RNS.LOG_EXTREME)
|
||||
interface.detach()
|
||||
dt = threading.Thread(target=detach_job, daemon=False)
|
||||
dt.start()
|
||||
detach_threads.append(dt)
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("An error occurred while detaching "+str(interface)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
for dt in detach_threads:
|
||||
dt.join()
|
||||
|
||||
RNS.log("Detaching local clients", RNS.LOG_DEBUG)
|
||||
for li in local_interfaces:
|
||||
li.detach()
|
||||
|
||||
RNS.log("Detaching shared instance", RNS.LOG_DEBUG)
|
||||
if shared_instance_master != None:
|
||||
shared_instance_master.detach()
|
||||
|
||||
RNS.log("All interfaces detached", RNS.LOG_DEBUG)
|
||||
|
||||
@staticmethod
|
||||
def shared_connection_disappeared():
|
||||
for link in Transport.active_links:
|
||||
@@ -2618,15 +2750,26 @@ class Transport:
|
||||
interface.announce_queue = []
|
||||
RNS.log("Dropped "+na_str+" on "+str(interface), RNS.LOG_VERBOSE)
|
||||
|
||||
@staticmethod
|
||||
def timebase_from_random_blob(random_blob):
|
||||
return int.from_bytes(random_blob[5:10], "big")
|
||||
|
||||
@staticmethod
|
||||
def timebase_from_random_blobs(random_blobs):
|
||||
timebase = 0
|
||||
for random_blob in random_blobs:
|
||||
emitted = Transport.timebase_from_random_blob(random_blob)
|
||||
if emitted > timebase: timebase = emitted
|
||||
|
||||
return timebase
|
||||
|
||||
@staticmethod
|
||||
def announce_emitted(packet):
|
||||
random_blob = packet.data[RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8+10]
|
||||
announce_emitted = int.from_bytes(random_blob[5:10], "big")
|
||||
announce_emitted = Transport.timebase_from_random_blob(random_blob)
|
||||
|
||||
return announce_emitted
|
||||
|
||||
|
||||
@staticmethod
|
||||
def save_packet_hashlist():
|
||||
if not Transport.owner.is_connected_to_shared_instance:
|
||||
@@ -2645,13 +2788,13 @@ class Transport:
|
||||
save_start = time.time()
|
||||
|
||||
if not RNS.Reticulum.transport_enabled():
|
||||
Transport.packet_hashlist = []
|
||||
Transport.packet_hashlist = set()
|
||||
else:
|
||||
RNS.log("Saving packet hashlist to storage...", RNS.LOG_DEBUG)
|
||||
|
||||
packet_hashlist_path = RNS.Reticulum.storagepath+"/packet_hashlist"
|
||||
file = open(packet_hashlist_path, "wb")
|
||||
file.write(umsgpack.packb(Transport.packet_hashlist))
|
||||
file.write(umsgpack.packb(list(Transport.packet_hashlist.copy())))
|
||||
file.close()
|
||||
|
||||
save_time = time.time() - save_start
|
||||
@@ -2686,7 +2829,7 @@ class Transport:
|
||||
RNS.log("Saving path table to storage...", RNS.LOG_DEBUG)
|
||||
|
||||
serialised_destinations = []
|
||||
for destination_hash in Transport.destination_table:
|
||||
for destination_hash in Transport.destination_table.copy():
|
||||
# Get the destination entry from the destination table
|
||||
de = Transport.destination_table[destination_hash]
|
||||
interface_hash = de[5].get_hash()
|
||||
@@ -2756,10 +2899,10 @@ class Transport:
|
||||
RNS.log("Saving tunnel table to storage...", RNS.LOG_DEBUG)
|
||||
|
||||
serialised_tunnels = []
|
||||
for tunnel_id in Transport.tunnels:
|
||||
for tunnel_id in Transport.tunnels.copy():
|
||||
te = Transport.tunnels[tunnel_id]
|
||||
interface = te[1]
|
||||
tunnel_paths = te[2]
|
||||
tunnel_paths = te[2].copy()
|
||||
expires = te[3]
|
||||
|
||||
if interface != None:
|
||||
|
||||
+18
-5
@@ -294,9 +294,10 @@ current_resource = None
|
||||
stats = []
|
||||
speed = 0.0
|
||||
phy_speed = 0.0
|
||||
phy_got_total = 0
|
||||
def sender_progress(resource):
|
||||
stats_max = 32
|
||||
global current_resource, stats, speed, phy_speed, resource_done
|
||||
global current_resource, stats, speed, phy_speed, phy_got_total, resource_done
|
||||
current_resource = resource
|
||||
|
||||
now = time.time()
|
||||
@@ -321,6 +322,7 @@ def sender_progress(resource):
|
||||
phy_diff = phy_got - stats[0][2]
|
||||
if phy_diff > 0:
|
||||
phy_speed = phy_diff/span
|
||||
# phy_got_total += phy_diff
|
||||
|
||||
if resource.status < RNS.Resource.COMPLETE:
|
||||
resource_done = False
|
||||
@@ -581,8 +583,8 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
|
||||
exit(0)
|
||||
|
||||
|
||||
def send(configdir, verbosity = 0, quietness = 0, destination = None, file = None, timeout = RNS.Transport.PATH_REQUEST_TIMEOUT, silent=False, phy_rates=False):
|
||||
global current_resource, resource_done, link, speed, show_phy_rates
|
||||
def send(configdir, verbosity = 0, quietness = 0, destination = None, file = None, timeout = RNS.Transport.PATH_REQUEST_TIMEOUT, silent=False, phy_rates=False, no_compress=False):
|
||||
global current_resource, resource_done, link, speed, show_phy_rates, phy_got_total, phy_speed
|
||||
from tempfile import TemporaryFile
|
||||
targetloglevel = 3+verbosity-quietness
|
||||
show_phy_rates = phy_rates
|
||||
@@ -705,7 +707,10 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
print(f"{erase_str}Advertising file resource ", end=es)
|
||||
|
||||
link.identify(identity)
|
||||
resource = RNS.Resource(temp_file, link, callback = sender_progress, progress_callback = sender_progress)
|
||||
auto_compress = True
|
||||
if no_compress:
|
||||
auto_compress = False
|
||||
resource = RNS.Resource(temp_file, link, callback = sender_progress, progress_callback = sender_progress, auto_compress = auto_compress)
|
||||
current_resource = resource
|
||||
|
||||
while resource.status < RNS.Resource.TRANSFERRING:
|
||||
@@ -715,6 +720,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
resource_started_at = time.time()
|
||||
|
||||
if resource.status > RNS.Resource.COMPLETE:
|
||||
if silent:
|
||||
@@ -732,7 +738,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
time.sleep(0.1)
|
||||
prg = current_resource.get_progress()
|
||||
percent = round(prg * 100.0, 1)
|
||||
if show_phy_rates:
|
||||
if show_phy_rates and not resource_done:
|
||||
pss = size_str(phy_speed, "b")
|
||||
phy_str = f" ({pss}ps at physical layer)"
|
||||
else:
|
||||
@@ -754,6 +760,11 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
if not silent:
|
||||
i = progress_update(i)
|
||||
|
||||
resource_concluded_at = time.time()
|
||||
transfer_time = resource_concluded_at - resource_started_at
|
||||
speed = current_resource.total_size/transfer_time
|
||||
# phy_speed = phy_got_total/transfer_time
|
||||
|
||||
if not silent:
|
||||
i = progress_update(i, done=True)
|
||||
|
||||
@@ -784,6 +795,7 @@ def main():
|
||||
parser.add_argument('-q', '--quiet', action='count', default=0, help="decrease verbosity")
|
||||
parser.add_argument("-S", '--silent', action='store_true', default=False, help="disable transfer progress output")
|
||||
parser.add_argument("-l", '--listen', action='store_true', default=False, help="listen for incoming transfer requests")
|
||||
parser.add_argument("-C", '--no-compress', action='store_true', default=False, help="disable automatic compression")
|
||||
parser.add_argument("-F", '--allow-fetch', action='store_true', default=False, help="allow authenticated clients to fetch files")
|
||||
parser.add_argument("-f", '--fetch', action='store_true', default=False, help="fetch file from remote listener instead of sending")
|
||||
parser.add_argument("-j", "--jail", metavar="path", action="store", default=None, help="restrict fetch requests to specified path", type=str)
|
||||
@@ -842,6 +854,7 @@ def main():
|
||||
timeout = args.w,
|
||||
silent = args.silent,
|
||||
phy_rates = args.phy_rates,
|
||||
no_compress = args.no_compress,
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
+293
-93
@@ -2,7 +2,7 @@
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2018-2022 Mark Qvist - unsigned.io/rnode
|
||||
# Copyright (c) 2018-2025 Mark Qvist
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -41,7 +41,7 @@ import RNS
|
||||
RNS.logtimefmt = "%H:%M:%S"
|
||||
RNS.compact_log_fmt = True
|
||||
|
||||
program_version = "2.2.0"
|
||||
program_version = "2.4.0"
|
||||
eth_addr = "0xFDabC71AC4c0C78C95aDDDe3B4FA19d6273c5E73"
|
||||
btc_addr = "35G9uWVzrpJJibzUwpNUQGQNFzLirhrYAH"
|
||||
xmr_addr = "87HcDx6jRSkMQ9nPRd5K9hGGpZLn2s7vWETjMaVM5KfV4TD36NcYa8J8WSxhTSvBzzFpqDwp2fg5GX2moZ7VAP9QMZCZGET"
|
||||
@@ -84,8 +84,11 @@ class KISS():
|
||||
CMD_NP_INT = 0x65
|
||||
CMD_DISP_ADR = 0x63
|
||||
CMD_DISP_BLNK = 0x64
|
||||
CMD_DISP_ROT = 0x67
|
||||
CMD_DISP_RCND = 0x68
|
||||
CMD_BT_CTRL = 0x46
|
||||
CMD_BT_PIN = 0x62
|
||||
CMD_DIS_IA = 0x69
|
||||
CMD_BOARD = 0x47
|
||||
CMD_PLATFORM = 0x48
|
||||
CMD_MCU = 0x49
|
||||
@@ -121,76 +124,80 @@ class KISS():
|
||||
return data
|
||||
|
||||
class ROM():
|
||||
PLATFORM_AVR = 0x90
|
||||
PLATFORM_ESP32 = 0x80
|
||||
PLATFORM_NRF52 = 0x70
|
||||
PLATFORM_AVR = 0x90
|
||||
PLATFORM_ESP32 = 0x80
|
||||
PLATFORM_NRF52 = 0x70
|
||||
|
||||
MCU_1284P = 0x91
|
||||
MCU_2560 = 0x92
|
||||
MCU_ESP32 = 0x81
|
||||
MCU_NRF52 = 0x71
|
||||
MCU_1284P = 0x91
|
||||
MCU_2560 = 0x92
|
||||
MCU_ESP32 = 0x81
|
||||
MCU_NRF52 = 0x71
|
||||
|
||||
PRODUCT_RNODE = 0x03
|
||||
MODEL_A1 = 0xA1
|
||||
MODEL_A6 = 0xA6
|
||||
MODEL_A4 = 0xA4
|
||||
MODEL_A9 = 0xA9
|
||||
MODEL_A3 = 0xA3
|
||||
MODEL_A8 = 0xA8
|
||||
MODEL_A2 = 0xA2
|
||||
MODEL_A7 = 0xA7
|
||||
MODEL_A5 = 0xA5
|
||||
MODEL_AA = 0xAA
|
||||
PRODUCT_RNODE = 0x03
|
||||
MODEL_A1 = 0xA1
|
||||
MODEL_A6 = 0xA6
|
||||
MODEL_A4 = 0xA4
|
||||
MODEL_A9 = 0xA9
|
||||
MODEL_A3 = 0xA3
|
||||
MODEL_A8 = 0xA8
|
||||
MODEL_A2 = 0xA2
|
||||
MODEL_A7 = 0xA7
|
||||
MODEL_A5 = 0xA5
|
||||
MODEL_AA = 0xAA
|
||||
MODEL_AC = 0xAC
|
||||
|
||||
PRODUCT_T32_10 = 0xB2
|
||||
MODEL_BA = 0xBA
|
||||
MODEL_BB = 0xBB
|
||||
PRODUCT_T32_10 = 0xB2
|
||||
MODEL_BA = 0xBA
|
||||
MODEL_BB = 0xBB
|
||||
|
||||
PRODUCT_T32_20 = 0xB0
|
||||
MODEL_B3 = 0xB3
|
||||
MODEL_B8 = 0xB8
|
||||
PRODUCT_T32_20 = 0xB0
|
||||
MODEL_B3 = 0xB3
|
||||
MODEL_B8 = 0xB8
|
||||
|
||||
PRODUCT_T32_21 = 0xB1
|
||||
MODEL_B4 = 0xB4
|
||||
MODEL_B9 = 0xB9
|
||||
MODEL_B4_TCXO = 0x04 # The TCXO model codes are only used here to select the
|
||||
MODEL_B9_TCXO = 0x09 # correct firmware, actual model codes in firmware is
|
||||
# still 0xB4 and 0xB9.
|
||||
PRODUCT_T32_21 = 0xB1
|
||||
MODEL_B4 = 0xB4
|
||||
MODEL_B9 = 0xB9
|
||||
MODEL_B4_TCXO = 0x04 # The TCXO model codes are only used here to select the correct firmware,
|
||||
MODEL_B9_TCXO = 0x09 # actual model codes in firmware is still 0xB4 and 0xB9.
|
||||
PRODUCT_H32_V2 = 0xC0
|
||||
MODEL_C4 = 0xC4
|
||||
MODEL_C9 = 0xC9
|
||||
|
||||
PRODUCT_H32_V2 = 0xC0
|
||||
MODEL_C4 = 0xC4
|
||||
MODEL_C9 = 0xC9
|
||||
PRODUCT_H32_V3 = 0xC1
|
||||
MODEL_C5 = 0xC5
|
||||
MODEL_CA = 0xCA
|
||||
|
||||
PRODUCT_H32_V3 = 0xC1
|
||||
MODEL_C5 = 0xC5
|
||||
MODEL_CA = 0xCA
|
||||
PRODUCT_TBEAM = 0xE0
|
||||
MODEL_E4 = 0xE4
|
||||
MODEL_E9 = 0xE9
|
||||
MODEL_E3 = 0xE3
|
||||
MODEL_E8 = 0xE8
|
||||
|
||||
PRODUCT_TBEAM = 0xE0
|
||||
MODEL_E4 = 0xE4
|
||||
MODEL_E9 = 0xE9
|
||||
MODEL_E3 = 0xE3
|
||||
MODEL_E8 = 0xE8
|
||||
PRODUCT_TBEAM_S_V1 = 0xEA
|
||||
MODEL_DB = 0xDB
|
||||
MODEL_DC = 0xDC
|
||||
|
||||
PRODUCT_TBEAM_S_V1= 0xEA
|
||||
MODEL_DB = 0xDB
|
||||
MODEL_DC = 0xDC
|
||||
PRODUCT_TDECK = 0xD0
|
||||
MODEL_D4 = 0xD4
|
||||
MODEL_D9 = 0xD9
|
||||
|
||||
PRODUCT_TDECK = 0xD0
|
||||
MODEL_D4 = 0xD4
|
||||
MODEL_D9 = 0xD9
|
||||
PRODUCT_RAK4631 = 0x10
|
||||
MODEL_11 = 0x11
|
||||
MODEL_12 = 0x12
|
||||
MODEL_13 = 0x13
|
||||
MODEL_14 = 0x14
|
||||
|
||||
PRODUCT_RAK4631 = 0x10
|
||||
MODEL_11 = 0x11
|
||||
MODEL_12 = 0x12
|
||||
MODEL_13 = 0x13
|
||||
MODEL_14 = 0x14
|
||||
PRODUCT_OPENCOM_XL = 0x20
|
||||
MODEL_21 = 0x21
|
||||
PRODUCT_OPENCOM_XL = 0x20
|
||||
MODEL_21 = 0x21
|
||||
|
||||
PRODUCT_TECHO = 0x15
|
||||
MODEL_16 = 0x16
|
||||
MODEL_17 = 0x17
|
||||
|
||||
PRODUCT_TECHO = 0x15
|
||||
MODEL_T4 = 0x16
|
||||
MODEL_T9 = 0x17
|
||||
PRODUCT_HELTEC_T114 = 0xC2
|
||||
BOARD_HELTEC_T114 = 0x3C
|
||||
MODEL_C6 = 0xC6 # Heltec Mesh Node T114, 470-510 MHz (HT-n5262-LF)
|
||||
MODEL_C7 = 0xC7 # Heltec Mesh Node T114, 863-928 MHz (HT-n5262-HF)
|
||||
|
||||
PRODUCT_HMBRW = 0xF0
|
||||
MODEL_FF = 0xFF
|
||||
@@ -211,6 +218,17 @@ class ROM():
|
||||
ADDR_CONF_FREQ = 0xA3
|
||||
ADDR_CONF_OK = 0xA7
|
||||
|
||||
ADDR_CONF_BT = 0xB0
|
||||
ADDR_CONF_DSET = 0xB1
|
||||
ADDR_CONF_DINT = 0xB2
|
||||
ADDR_CONF_DADR = 0xB3
|
||||
ADDR_CONF_DBLK = 0xB4
|
||||
ADDR_CONF_DROT = 0xB8
|
||||
ADDR_CONF_PSET = 0xB5
|
||||
ADDR_CONF_PINT = 0xB6
|
||||
ADDR_CONF_BSET = 0xB7
|
||||
ADDR_CONF_DIA = 0xB9
|
||||
|
||||
INFO_LOCK_BYTE = 0x73
|
||||
CONF_OK_BYTE = 0x73
|
||||
|
||||
@@ -242,6 +260,7 @@ products = {
|
||||
ROM.PRODUCT_TECHO: "LilyGO T-Echo",
|
||||
ROM.PRODUCT_RAK4631: "RAK4631",
|
||||
ROM.PRODUCT_OPENCOM_XL: "openCom XL",
|
||||
ROM.PRODUCT_HELTEC_T114: "Heltec Mesh Node T114",
|
||||
}
|
||||
|
||||
platforms = {
|
||||
@@ -264,6 +283,7 @@ models = {
|
||||
0xA6: [820000000, 1020000000, 22, "820 - 960 MHz", "rnode_firmware_t3s3.zip", "SX1262"],
|
||||
0xA5: [410000000, 525000000, 17, "410 - 525 MHz", "rnode_firmware_t3s3_sx127x.zip", "SX1278"],
|
||||
0xAA: [820000000, 1020000000, 17, "820 - 960 MHz", "rnode_firmware_t3s3_sx127x.zip", "SX1276"],
|
||||
0xAC: [2400000000, 2500000000, 20, "2.4 - 2.5 GHz", "rnode_firmware_t3s3_sx1280_pa.zip", "SX1280"],
|
||||
0xA2: [410000000, 525000000, 17, "410 - 525 MHz", "rnode_firmware_ng21.zip", "SX1278"],
|
||||
0xA7: [820000000, 1020000000, 17, "820 - 1020 MHz", "rnode_firmware_ng21.zip", "SX1276"],
|
||||
0xA3: [410000000, 525000000, 17, "410 - 525 MHz", "rnode_firmware_ng20.zip", "SX1278"],
|
||||
@@ -278,8 +298,10 @@ models = {
|
||||
0xBB: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_lora32v10.zip", "SX1276"],
|
||||
0xC4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_heltec32v2.zip", "SX1278"],
|
||||
0xC9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_heltec32v2.zip", "SX1276"],
|
||||
0xC5: [420000000, 520000000, 21, "420 - 520 MHz", "rnode_firmware_heltec32v3.zip", "SX1262"],
|
||||
0xCA: [850000000, 950000000, 21, "850 - 950 MHz", "rnode_firmware_heltec32v3.zip", "SX1262"],
|
||||
0xC5: [420000000, 520000000, 22, "420 - 520 MHz", "rnode_firmware_heltec32v3.zip", "SX1268"],
|
||||
0xCA: [850000000, 950000000, 22, "850 - 950 MHz", "rnode_firmware_heltec32v3.zip", "SX1262"],
|
||||
0xC6: [420000000, 520000000, 22, "420 - 520 MHz", "rnode_firmware_heltec_t114.zip", "SX1268"],
|
||||
0xC7: [850000000, 950000000, 22, "850 - 950 MHz", "rnode_firmware_heltec_t114.zip", "SX1262"],
|
||||
0xE4: [420000000, 520000000, 17, "420 - 520 MHz", "rnode_firmware_tbeam.zip", "SX1278"],
|
||||
0xE9: [850000000, 950000000, 17, "850 - 950 MHz", "rnode_firmware_tbeam.zip", "SX1276"],
|
||||
0xD4: [420000000, 520000000, 22, "420 - 520 MHz", "rnode_firmware_tdeck.zip", "SX1268"],
|
||||
@@ -665,6 +687,30 @@ class RNode():
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while sending display blanking timeout command to device")
|
||||
|
||||
def set_display_rotation(self, rotation):
|
||||
data = bytes([rotation & 0xFF])
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_ROT])+data+bytes([KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while sending display rotation command to device")
|
||||
|
||||
def recondition_display(self):
|
||||
data = bytes([0x01])
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_RCND])+data+bytes([KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while sending display recondition command to device")
|
||||
|
||||
def set_disable_interference_avoidance(self, ia_disabled):
|
||||
if ia_disabled:
|
||||
data = bytes([0x01])
|
||||
else:
|
||||
data = bytes([0x00])
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DIS_IA])+data+bytes([KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while sending interference avoidance configuration command to device")
|
||||
|
||||
def set_neopixel_intensity(self, intensity):
|
||||
data = bytes([intensity & 0xFF])
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_NP_INT])+data+bytes([KISS.FEND])
|
||||
@@ -1148,9 +1194,10 @@ def ensure_firmware_file(fw_filename):
|
||||
RNS.log("The selected firmware for this board is version "+selected_version)
|
||||
|
||||
else:
|
||||
RNS.log("Online firmware version check was disabled, but no firmware version specified for install.")
|
||||
RNS.log("use the --fw-version option to manually specify a version.")
|
||||
graceful_exit(98)
|
||||
if selected_version == None:
|
||||
RNS.log("Online firmware version check was disabled, but no firmware version specified for install.")
|
||||
RNS.log("use the --fw-version option to manually specify a version.")
|
||||
graceful_exit(98)
|
||||
|
||||
# if custom firmware url, use it
|
||||
if fw_url != None:
|
||||
@@ -1298,7 +1345,9 @@ def main():
|
||||
|
||||
parser.add_argument("-D", "--display", action="store", metavar="i", type=int, default=None, help="Set display intensity (0-255)")
|
||||
parser.add_argument("-t", "--timeout", action="store", metavar="s", type=int, default=None, help="Set display timeout in seconds, 0 to disable")
|
||||
parser.add_argument("-R", "--rotation", action="store", metavar="rotation", type=int, default=None, help="Set display rotation, valid values are 0 through 3")
|
||||
parser.add_argument("--display-addr", action="store", metavar="byte", type=str, default=None, help="Set display address as hex byte (00 - FF)")
|
||||
parser.add_argument("--recondition-display", action="store_true", help="Start display reconditioning")
|
||||
|
||||
parser.add_argument("--np", action="store", metavar="i", type=int, default=None, help="Set NeoPixel intensity (0-255)")
|
||||
|
||||
@@ -1308,6 +1357,11 @@ def main():
|
||||
parser.add_argument("--sf", action="store", metavar="factor", type=int, default=None, help="Spreading factor for TNC mode (7 - 12)")
|
||||
parser.add_argument("--cr", action="store", metavar="rate", type=int, default=None, help="Coding rate for TNC mode (5 - 8)")
|
||||
|
||||
parser.add_argument("-x", "--ia-enable", action="store_true", help="Enable interference avoidance")
|
||||
parser.add_argument("-X", "--ia-disable", action="store_true", help="Disable interference avoidance")
|
||||
|
||||
parser.add_argument("-c", "--config", action="store_true", help="Print device configuration")
|
||||
|
||||
parser.add_argument("--eeprom-backup", action="store_true", help="Backup EEPROM to file")
|
||||
parser.add_argument("--eeprom-dump", action="store_true", help="Dump EEPROM to console")
|
||||
parser.add_argument("--eeprom-wipe", action="store_true", help="Unlock and wipe EEPROM")
|
||||
@@ -1321,7 +1375,7 @@ def main():
|
||||
parser.add_argument("-r", "--rom", action="store_true", help="Bootstrap EEPROM without flashing firmware")
|
||||
parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") #
|
||||
parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key")
|
||||
parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash")
|
||||
parser.add_argument("-H", "--firmware-hash", action="store", help="Set installed firmware hash")
|
||||
parser.add_argument("-K", "--get-target-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get target firmware hash from device
|
||||
parser.add_argument("-L", "--get-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get calculated firmware hash from device
|
||||
parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap")
|
||||
@@ -1641,30 +1695,31 @@ def main():
|
||||
|
||||
print("")
|
||||
print("What kind of device is this?\n")
|
||||
print("[1] A specific kind of RNode")
|
||||
print(" .")
|
||||
print(" / \\ Select this option if you have an RNode of a specific")
|
||||
print(" | type, built from a recipe or bought from a vendor.")
|
||||
print(" | Select this option if you have an RNode of a specific")
|
||||
print(" \\ / type, built from a recipe or bought from a vendor.")
|
||||
print(" '")
|
||||
print("[1] A specific kind of RNode")
|
||||
print("")
|
||||
print("[2] Homebrew RNode")
|
||||
print(" .")
|
||||
print(" / \\ Select this option if you have put toghether an RNode")
|
||||
print(" | of your own design, or if you are prototyping one.")
|
||||
print(" | Select this option if you have put toghether an RNode")
|
||||
print(" \\ / of your own design, or if you are prototyping one.")
|
||||
print(" '")
|
||||
print("[2] Homebrew RNode")
|
||||
print("")
|
||||
print("[3] LilyGO LoRa32 v2.1 (aka T3 v1.6 / T3 v1.6.1)")
|
||||
print("[4] LilyGO LoRa32 v2.0")
|
||||
print("[5] LilyGO LoRa32 v1.0")
|
||||
print("[6] LilyGO T-Beam")
|
||||
print("[7] Heltec LoRa32 v2")
|
||||
print("[8] Heltec LoRa32 v3")
|
||||
print("[9] LilyGO LoRa T3S3")
|
||||
print(" | Select one of these options if you want to easily turn")
|
||||
print(" \\ / a supported development board into an RNode.")
|
||||
print(" '")
|
||||
print("[3] LilyGO LoRa32 v2.1 (aka T3 v1.6 / T3 v1.6.1)")
|
||||
print("[4] LilyGO LoRa32 v2.0")
|
||||
print("[5] LilyGO LoRa32 v1.0")
|
||||
print("[6] LilyGO T-Beam")
|
||||
print("[7] Heltec LoRa32 v2")
|
||||
print("[8] Heltec LoRa32 v3")
|
||||
print("[9] LilyGO LoRa T3S3")
|
||||
print("[10] RAK4631")
|
||||
print("[11] LilyGo T-Echo")
|
||||
print("[12] LilyGO T-Beam Supreme")
|
||||
print("[13] LilyGO T-Deck")
|
||||
print(" .")
|
||||
print(" / \\ Select one of these options if you want to easily turn")
|
||||
print(" | a supported development board into an RNode.")
|
||||
print("[14] Heltec T114")
|
||||
print("")
|
||||
print("---------------------------------------------------------------------------")
|
||||
print("\nEnter the number that matches your device type:\n? ", end="")
|
||||
@@ -1673,7 +1728,7 @@ def main():
|
||||
try:
|
||||
c_dev = int(input())
|
||||
c_mod = False
|
||||
if c_dev < 1 or c_dev > 13:
|
||||
if c_dev < 1 or c_dev > 14:
|
||||
raise ValueError()
|
||||
elif c_dev == 1:
|
||||
selected_product = ROM.PRODUCT_RNODE
|
||||
@@ -1856,6 +1911,20 @@ def main():
|
||||
print("who would like to experiment with it. Hit enter to continue.")
|
||||
print("---------------------------------------------------------------------------")
|
||||
input()
|
||||
elif c_dev == 14:
|
||||
selected_product = ROM.PRODUCT_HELTEC_T114
|
||||
clear()
|
||||
print("")
|
||||
print("---------------------------------------------------------------------------")
|
||||
print(" Heltec T114 RNode Installer")
|
||||
print("")
|
||||
print("Important! Using RNode firmware on Heltec T114 devices should currently be")
|
||||
print("considered experimental. It is not intended for production or critical use.")
|
||||
print("The currently supplied firmware is provided AS-IS as a courtesey to those")
|
||||
print("who would like to experiment with it. Hit enter to continue.")
|
||||
print("---------------------------------------------------------------------------")
|
||||
input()
|
||||
|
||||
except Exception as e:
|
||||
print("That device type does not exist, exiting now.")
|
||||
graceful_exit()
|
||||
@@ -1964,10 +2033,12 @@ def main():
|
||||
print("");
|
||||
print("[3] 433 MHz (with SX1268 chip)")
|
||||
print("[4] 868/915/923 MHz (with SX1262 chip)")
|
||||
print("");
|
||||
print("[5] 2.4 GHz (with SX1280 chip and PA)")
|
||||
print("\n? ", end="")
|
||||
try:
|
||||
c_model = int(input())
|
||||
if c_model < 1 or c_model > 4:
|
||||
if c_model < 1 or c_model > 5:
|
||||
raise ValueError()
|
||||
elif c_model == 1:
|
||||
selected_model = ROM.MODEL_A5
|
||||
@@ -1985,6 +2056,10 @@ def main():
|
||||
selected_model = ROM.MODEL_A6
|
||||
selected_mcu = ROM.MCU_ESP32
|
||||
selected_platform = ROM.PLATFORM_ESP32
|
||||
elif c_model == 5:
|
||||
selected_model = ROM.MODEL_AC
|
||||
selected_mcu = ROM.MCU_ESP32
|
||||
selected_platform = ROM.PLATFORM_ESP32
|
||||
except Exception as e:
|
||||
print("That model does not exist, exiting now.")
|
||||
graceful_exit()
|
||||
@@ -2172,6 +2247,28 @@ def main():
|
||||
except Exception as e:
|
||||
print("That band does not exist, exiting now.")
|
||||
exit()
|
||||
|
||||
elif selected_product == ROM.PRODUCT_HELTEC_T114:
|
||||
selected_mcu = ROM.MCU_NRF52
|
||||
print("\nWhat band is this Heltec T114 for?\n")
|
||||
print("[1] 433 MHz")
|
||||
print("[2] 868 MHz")
|
||||
print("[3] 915 MHz")
|
||||
print("[4] 923 MHz")
|
||||
try:
|
||||
c_model = int(input())
|
||||
if c_model < 1 or c_model > 4:
|
||||
raise ValueError()
|
||||
elif c_model == 1:
|
||||
selected_model = ROM.MODEL_C6
|
||||
selected_platform = ROM.PLATFORM_NRF52
|
||||
elif c_model > 1:
|
||||
selected_model = ROM.MODEL_C7
|
||||
selected_platform = ROM.PLATFORM_NRF52
|
||||
except Exception as e:
|
||||
print("That band does not exist, exiting now.")
|
||||
exit()
|
||||
|
||||
elif selected_product == ROM.PRODUCT_RAK4631:
|
||||
selected_mcu = ROM.MCU_NRF52
|
||||
print("\nWhat band is this RAK4631 for?\n")
|
||||
@@ -2203,13 +2300,13 @@ def main():
|
||||
print("\n? ", end="")
|
||||
try:
|
||||
c_model = int(input())
|
||||
if c_model < 1 or c_model > 1:
|
||||
if c_model < 1 or c_model > 4:
|
||||
raise ValueError()
|
||||
elif c_model == 1:
|
||||
selected_model = ROM.MODEL_T4
|
||||
selected_model = ROM.MODEL_16
|
||||
selected_platform = ROM.PLATFORM_NRF52
|
||||
elif c_model > 1:
|
||||
selected_model = ROM.MODEL_T9
|
||||
selected_model = ROM.MODEL_17
|
||||
selected_platform = ROM.PLATFORM_NRF52
|
||||
except Exception as e:
|
||||
print("That band does not exist, exiting now.")
|
||||
@@ -2726,6 +2823,7 @@ def main():
|
||||
"0xe000", UPD_DIR+"/"+selected_version+"/rnode_firmware_heltec32v3.boot_app0",
|
||||
"0x0", UPD_DIR+"/"+selected_version+"/rnode_firmware_heltec32v3.bootloader",
|
||||
"0x10000", UPD_DIR+"/"+selected_version+"/rnode_firmware_heltec32v3.bin",
|
||||
"0x210000",UPD_DIR+"/"+selected_version+"/console_image.bin",
|
||||
"0x8000", UPD_DIR+"/"+selected_version+"/rnode_firmware_heltec32v3.partitions",
|
||||
]
|
||||
elif fw_filename == "rnode_firmware_featheresp32.zip":
|
||||
@@ -2908,6 +3006,24 @@ def main():
|
||||
"0x210000",UPD_DIR+"/"+selected_version+"/console_image.bin",
|
||||
"0x8000", UPD_DIR+"/"+selected_version+"/rnode_firmware_t3s3_sx127x.partitions",
|
||||
]
|
||||
elif fw_filename == "rnode_firmware_t3s3_sx1280_pa.zip":
|
||||
return [
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32s3",
|
||||
"--port", args.port,
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
"--flash_mode", "dio",
|
||||
"--flash_freq", "80m",
|
||||
"--flash_size", "4MB",
|
||||
"0xe000", UPD_DIR+"/"+selected_version+"/rnode_firmware_t3s3_sx1280_pa.boot_app0",
|
||||
"0x0", UPD_DIR+"/"+selected_version+"/rnode_firmware_t3s3_sx1280_pa.bootloader",
|
||||
"0x10000", UPD_DIR+"/"+selected_version+"/rnode_firmware_t3s3_sx1280_pa.bin",
|
||||
"0x210000",UPD_DIR+"/"+selected_version+"/console_image.bin",
|
||||
"0x8000", UPD_DIR+"/"+selected_version+"/rnode_firmware_t3s3_sx1280_pa.partitions",
|
||||
]
|
||||
elif fw_filename == "rnode_firmware_tbeam_supreme.zip":
|
||||
return [
|
||||
sys.executable, flasher,
|
||||
@@ -3057,12 +3173,12 @@ def main():
|
||||
if args.platform == ROM.PLATFORM_ESP32:
|
||||
wants_fw_provision = True
|
||||
RNS.log("Waiting for ESP32 reset...")
|
||||
time.sleep(7)
|
||||
time.sleep(8)
|
||||
if args.platform == ROM.PLATFORM_NRF52:
|
||||
wants_fw_provision = True
|
||||
RNS.log("Waiting for NRF52 reset...")
|
||||
# Don't need to wait as long this time.
|
||||
time.sleep(5)
|
||||
time.sleep(6)
|
||||
else:
|
||||
RNS.log("Error from flasher ("+str(flash_status)+") while writing.")
|
||||
RNS.log("Some boards have trouble flashing at high speeds, and you can")
|
||||
@@ -3314,6 +3430,63 @@ def main():
|
||||
RNS.log("Firmware update file not found")
|
||||
graceful_exit()
|
||||
|
||||
if args.config:
|
||||
eeprom_reserved = 200
|
||||
if rnode.platform == ROM.PLATFORM_ESP32:
|
||||
eeprom_size = 296
|
||||
elif rnode.platform == ROM.PLATFORM_NRF52:
|
||||
eeprom_size = 296
|
||||
else:
|
||||
eeprom_size = 4096
|
||||
|
||||
eeprom_offset = eeprom_size-eeprom_reserved
|
||||
def ea(a):
|
||||
return a+eeprom_offset
|
||||
ec_bt = rnode.eeprom[ROM.ADDR_CONF_BT]
|
||||
ec_dint = rnode.eeprom[ROM.ADDR_CONF_DINT]
|
||||
ec_dadr = rnode.eeprom[ROM.ADDR_CONF_DADR]
|
||||
ec_dblk = rnode.eeprom[ROM.ADDR_CONF_DBLK]
|
||||
ec_drot = rnode.eeprom[ROM.ADDR_CONF_DROT]
|
||||
ec_pset = rnode.eeprom[ROM.ADDR_CONF_PSET]
|
||||
ec_pint = rnode.eeprom[ROM.ADDR_CONF_PINT]
|
||||
ec_bset = rnode.eeprom[ROM.ADDR_CONF_BSET]
|
||||
ec_dia = rnode.eeprom[ROM.ADDR_CONF_DIA]
|
||||
print("\nDevice configuration:")
|
||||
if ec_bt == 0x73:
|
||||
print(f" Bluetooth : Enabled")
|
||||
else:
|
||||
print(f" Bluetooth : Disabled")
|
||||
if ec_dia == 0x00:
|
||||
print(f" Interference avoidance : Enabled")
|
||||
else:
|
||||
print(f" Interference avoidance : Disabled")
|
||||
print( f" Display brightness : {ec_dint}")
|
||||
if ec_dadr == 0xFF:
|
||||
print(f" Display address : Default")
|
||||
else:
|
||||
print(f" Display address : {RNS.hexrep(ec_dadr, delimit=False)}")
|
||||
if ec_bset == 0x73 and ec_dblk != 0x00:
|
||||
print(f" Display blanking : {ec_dblk}s")
|
||||
else:
|
||||
print(f" Display blanking : Disabled")
|
||||
if ec_drot != 0xFF:
|
||||
if ec_drot == 0x00:
|
||||
rstr = "Landscape"
|
||||
if ec_drot == 0x01:
|
||||
rstr = "Portrait"
|
||||
if ec_drot == 0x02:
|
||||
rstr = "Landscape 180"
|
||||
if ec_drot == 0x03:
|
||||
rstr = "Portrait 180"
|
||||
print(f" Display rotation : {rstr}")
|
||||
else:
|
||||
print(f" Display rotation : Default")
|
||||
if ec_pset == 0x73:
|
||||
print(f" Neopixel Intensity : {ec_pint}")
|
||||
print("")
|
||||
|
||||
graceful_exit()
|
||||
|
||||
if args.eeprom_dump:
|
||||
RNS.log("EEPROM contents:")
|
||||
RNS.log(RNS.hexrep(rnode.eeprom))
|
||||
@@ -3354,6 +3527,31 @@ def main():
|
||||
RNS.log("Setting display timeout to "+str(di))
|
||||
rnode.set_display_blanking(di)
|
||||
|
||||
if isinstance(args.rotation, int):
|
||||
dr = args.rotation
|
||||
if dr < 0:
|
||||
dr = 0
|
||||
if dr > 3:
|
||||
dr = 3
|
||||
|
||||
RNS.log("Setting display rotation to "+str(dr))
|
||||
rnode.set_display_rotation(dr)
|
||||
|
||||
if isinstance(args.recondition_display, bool):
|
||||
if args.recondition_display:
|
||||
RNS.log("Starting display reconditioning")
|
||||
rnode.recondition_display()
|
||||
|
||||
if isinstance(args.ia_enable, bool):
|
||||
if args.ia_enable:
|
||||
RNS.log("Enabling interference avoidance")
|
||||
rnode.set_disable_interference_avoidance(False)
|
||||
|
||||
if isinstance(args.ia_disable, bool):
|
||||
if args.ia_disable:
|
||||
RNS.log("Disabling interference avoidance")
|
||||
rnode.set_disable_interference_avoidance(True)
|
||||
|
||||
if isinstance(args.np, int):
|
||||
di = args.np
|
||||
if di < 0:
|
||||
@@ -3475,7 +3673,7 @@ def main():
|
||||
elif rnode.platform == ROM.PLATFORM_NRF52:
|
||||
rnode_serial.close()
|
||||
RNS.log("Waiting for NRF52 reset...")
|
||||
time.sleep(14)
|
||||
time.sleep(18)
|
||||
selected_port = None
|
||||
ports = list_ports.comports()
|
||||
for port in ports:
|
||||
@@ -3686,7 +3884,9 @@ def main():
|
||||
if rnode.platform == ROM.PLATFORM_ESP32:
|
||||
rnode.hard_reset()
|
||||
RNS.log("Waiting for ESP32 reset...")
|
||||
time.sleep(6.5)
|
||||
time.sleep(7)
|
||||
if selected_model in [ROM.MODEL_AC, ROM.MODEL_A6, ROM.MODEL_A1, ROM.MODEL_AA, ROM.MODEL_A5]:
|
||||
time.sleep(5)
|
||||
|
||||
elif rnode.platform == ROM.PLATFORM_NRF52:
|
||||
# Wait a few seconds before hard resetting.
|
||||
@@ -3705,7 +3905,7 @@ def main():
|
||||
|
||||
# Give plenty of time for to allow for
|
||||
# potential e-ink display refresh too.
|
||||
time.sleep(14)
|
||||
time.sleep(20)
|
||||
|
||||
# After the hard reset, the port number will
|
||||
# change. We need to find the new port number,
|
||||
|
||||
@@ -42,6 +42,8 @@ def program_setup(configdir, verbosity = 0, quietness = 0, service = False):
|
||||
if reticulum.is_connected_to_shared_instance:
|
||||
RNS.log("Started rnsd version {version} connected to another shared local instance, this is probably NOT what you want!".format(version=__version__), RNS.LOG_WARNING)
|
||||
else:
|
||||
if RNS.Reticulum.get_instance().shared_instance_interface:
|
||||
RNS.Reticulum.get_instance().shared_instance_interface.server.daemon_threads = True
|
||||
RNS.log("Started rnsd version {version}".format(version=__version__), RNS.LOG_NOTICE)
|
||||
|
||||
while True:
|
||||
|
||||
@@ -135,7 +135,7 @@ def get_remote_status(destination_hash, include_lstats, identity, no_output=Fals
|
||||
|
||||
def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False,
|
||||
lstats=False, sorting=None, sort_reverse=False, remote=None, management_identity=None,
|
||||
remote_timeout=RNS.Transport.PATH_REQUEST_TIMEOUT, must_exit=True, rns_instance=None):
|
||||
remote_timeout=RNS.Transport.PATH_REQUEST_TIMEOUT, must_exit=True, rns_instance=None, traffic_totals=False):
|
||||
|
||||
if remote:
|
||||
require_shared = False
|
||||
@@ -228,6 +228,10 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
interfaces.sort(key=lambda i: i["rxb"], reverse=not sort_reverse)
|
||||
if sorting == "tx":
|
||||
interfaces.sort(key=lambda i: i["txb"], reverse=not sort_reverse)
|
||||
if sorting == "rxs":
|
||||
interfaces.sort(key=lambda i: i["rxs"], reverse=not sort_reverse)
|
||||
if sorting == "txs":
|
||||
interfaces.sort(key=lambda i: i["txs"], reverse=not sort_reverse)
|
||||
if sorting == "traffic":
|
||||
interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse)
|
||||
if sorting == "announces" or sorting == "announce":
|
||||
@@ -316,6 +320,12 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
if "bitrate" in ifstat and ifstat["bitrate"] != None:
|
||||
print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"])))
|
||||
|
||||
if "noise_floor" in ifstat:
|
||||
if ifstat["noise_floor"] != None:
|
||||
print(" Noise Fl. : {nfl} dBm".format(nfl=str(ifstat["noise_floor"])))
|
||||
else:
|
||||
print(" Noise Fl. : Unknown")
|
||||
|
||||
if "battery_percent" in ifstat and ifstat["battery_percent"] != None:
|
||||
try:
|
||||
bpi = int(ifstat["battery_percent"])
|
||||
@@ -328,8 +338,8 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
print(" Airtime : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["airtime_short"]),atl=str(ifstat["airtime_long"])))
|
||||
|
||||
if "channel_load_short" in ifstat and "channel_load_long" in ifstat:
|
||||
print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
|
||||
|
||||
print(" Ch. Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
|
||||
|
||||
if "peers" in ifstat and ifstat["peers"] != None:
|
||||
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
||||
|
||||
@@ -361,7 +371,21 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
print(" Announces : {iaf}↑".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
|
||||
print(" {iaf}↓".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))
|
||||
|
||||
print(" Traffic : {txb}↑\n {rxb}↓".format(rxb=size_str(ifstat["rxb"]), txb=size_str(ifstat["txb"])))
|
||||
rxb_str = "↓"+RNS.prettysize(ifstat["rxb"])
|
||||
txb_str = "↑"+RNS.prettysize(ifstat["txb"])
|
||||
strdiff = len(rxb_str)-len(txb_str)
|
||||
if strdiff > 0:
|
||||
txb_str += " "*strdiff
|
||||
elif strdiff < 0:
|
||||
rxb_str += " "*-strdiff
|
||||
|
||||
rxstat = rxb_str
|
||||
txstat = txb_str
|
||||
if "rxs" in ifstat and "txs" in ifstat:
|
||||
rxstat += " "+RNS.prettyspeed(ifstat["rxs"])
|
||||
txstat += " "+RNS.prettyspeed(ifstat["txs"])
|
||||
|
||||
print(f" Traffic : {txstat}\n {rxstat}")
|
||||
|
||||
lstr = ""
|
||||
if link_count != None and lstats:
|
||||
@@ -371,6 +395,19 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
else:
|
||||
lstr = f" {link_count} entr{ms} in link table"
|
||||
|
||||
if traffic_totals:
|
||||
rxb_str = "↓"+RNS.prettysize(stats["rxb"])
|
||||
txb_str = "↑"+RNS.prettysize(stats["txb"])
|
||||
strdiff = len(rxb_str)-len(txb_str)
|
||||
if strdiff > 0:
|
||||
txb_str += " "*strdiff
|
||||
elif strdiff < 0:
|
||||
rxb_str += " "*-strdiff
|
||||
|
||||
rxstat = rxb_str+" "+RNS.prettyspeed(stats["rxs"])
|
||||
txstat = txb_str+" "+RNS.prettyspeed(stats["txs"])
|
||||
print(f"\n Totals : {txstat}\n {rxstat}")
|
||||
|
||||
if "transport_id" in stats and stats["transport_id"] != None:
|
||||
print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running")
|
||||
if "probe_responder" in stats and stats["probe_responder"] != None:
|
||||
@@ -423,11 +460,19 @@ def main(must_exit=True, rns_instance=None):
|
||||
default=False,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-t",
|
||||
"--totals",
|
||||
action="store_true",
|
||||
help="display traffic totals",
|
||||
default=False,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--sort",
|
||||
action="store",
|
||||
help="sort interfaces by [rate, traffic, rx, tx, announces, arx, atx, held]",
|
||||
help="sort interfaces by [rate, traffic, rx, tx, rxs, txs, announces, arx, atx, held]",
|
||||
default=None,
|
||||
type=str
|
||||
)
|
||||
@@ -501,6 +546,7 @@ def main(must_exit=True, rns_instance=None):
|
||||
remote_timeout=args.w,
|
||||
must_exit=must_exit,
|
||||
rns_instance=rns_instance,
|
||||
traffic_totals=args.totals,
|
||||
)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
|
||||
+215
-125
@@ -24,6 +24,7 @@ import os
|
||||
import sys
|
||||
import glob
|
||||
import time
|
||||
import datetime
|
||||
import random
|
||||
import threading
|
||||
|
||||
@@ -68,6 +69,7 @@ logfile = None
|
||||
logdest = LOG_STDOUT
|
||||
logcall = None
|
||||
logtimefmt = "%Y-%m-%d %H:%M:%S"
|
||||
logtimefmt_p = "%H:%M:%S.%f"
|
||||
compact_log_fmt = False
|
||||
|
||||
instance_random = random.Random()
|
||||
@@ -79,21 +81,21 @@ logging_lock = threading.Lock()
|
||||
|
||||
def loglevelname(level):
|
||||
if (level == LOG_CRITICAL):
|
||||
return "Critical"
|
||||
return "[Critical]"
|
||||
if (level == LOG_ERROR):
|
||||
return "Error"
|
||||
return "[Error] "
|
||||
if (level == LOG_WARNING):
|
||||
return "Warning"
|
||||
return "[Warning] "
|
||||
if (level == LOG_NOTICE):
|
||||
return "Notice"
|
||||
return "[Notice] "
|
||||
if (level == LOG_INFO):
|
||||
return "Info"
|
||||
return "[Info] "
|
||||
if (level == LOG_VERBOSE):
|
||||
return "Verbose"
|
||||
return "[Verbose] "
|
||||
if (level == LOG_DEBUG):
|
||||
return "Debug"
|
||||
return "[Debug] "
|
||||
if (level == LOG_EXTREME):
|
||||
return "Extra"
|
||||
return "[Extra] "
|
||||
|
||||
return "Unknown"
|
||||
|
||||
@@ -108,51 +110,51 @@ def timestamp_str(time_s):
|
||||
timestamp = time.localtime(time_s)
|
||||
return time.strftime(logtimefmt, timestamp)
|
||||
|
||||
def log(msg, level=3, _override_destination = False):
|
||||
def precise_timestamp_str(time_s):
|
||||
return datetime.datetime.now().strftime(logtimefmt_p)[:-3]
|
||||
|
||||
def log(msg, level=3, _override_destination = False, pt=False):
|
||||
global _always_override_destination, compact_log_fmt
|
||||
msg = str(msg)
|
||||
if loglevel >= level:
|
||||
if not compact_log_fmt:
|
||||
logstring = "["+timestamp_str(time.time())+"] ["+loglevelname(level)+"] "+msg
|
||||
if pt:
|
||||
logstring = "["+precise_timestamp_str(time.time())+"] "+loglevelname(level)+" "+msg
|
||||
else:
|
||||
logstring = "["+timestamp_str(time.time())+"] "+msg
|
||||
if not compact_log_fmt:
|
||||
logstring = "["+timestamp_str(time.time())+"] "+loglevelname(level)+" "+msg
|
||||
else:
|
||||
logstring = "["+timestamp_str(time.time())+" "+msg
|
||||
|
||||
logging_lock.acquire()
|
||||
with logging_lock:
|
||||
if (logdest == LOG_STDOUT or _always_override_destination or _override_destination):
|
||||
print(logstring)
|
||||
|
||||
if (logdest == LOG_STDOUT or _always_override_destination or _override_destination):
|
||||
print(logstring)
|
||||
logging_lock.release()
|
||||
elif (logdest == LOG_FILE and logfile != None):
|
||||
try:
|
||||
file = open(logfile, "a")
|
||||
file.write(logstring+"\n")
|
||||
file.close()
|
||||
|
||||
if os.path.getsize(logfile) > LOG_MAXSIZE:
|
||||
prevfile = logfile+".1"
|
||||
if os.path.isfile(prevfile):
|
||||
os.unlink(prevfile)
|
||||
os.rename(logfile, prevfile)
|
||||
|
||||
elif (logdest == LOG_FILE and logfile != None):
|
||||
try:
|
||||
file = open(logfile, "a")
|
||||
file.write(logstring+"\n")
|
||||
file.close()
|
||||
|
||||
if os.path.getsize(logfile) > LOG_MAXSIZE:
|
||||
prevfile = logfile+".1"
|
||||
if os.path.isfile(prevfile):
|
||||
os.unlink(prevfile)
|
||||
os.rename(logfile, prevfile)
|
||||
except Exception as e:
|
||||
_always_override_destination = True
|
||||
log("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL)
|
||||
log("Dumping future log events to console!", LOG_CRITICAL)
|
||||
log(msg, level)
|
||||
|
||||
logging_lock.release()
|
||||
except Exception as e:
|
||||
logging_lock.release()
|
||||
_always_override_destination = True
|
||||
log("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL)
|
||||
log("Dumping future log events to console!", LOG_CRITICAL)
|
||||
log(msg, level)
|
||||
|
||||
elif logdest == LOG_CALLBACK:
|
||||
try:
|
||||
logcall(logstring)
|
||||
logging_lock.release()
|
||||
except Exception as e:
|
||||
logging_lock.release()
|
||||
_always_override_destination = True
|
||||
log("Exception occurred while calling external log handler: "+str(e), LOG_CRITICAL)
|
||||
log("Dumping future log events to console!", LOG_CRITICAL)
|
||||
log(msg, level)
|
||||
elif logdest == LOG_CALLBACK:
|
||||
try:
|
||||
logcall(logstring)
|
||||
except Exception as e:
|
||||
_always_override_destination = True
|
||||
log("Exception occurred while calling external log handler: "+str(e), LOG_CRITICAL)
|
||||
log("Dumping future log events to console!", LOG_CRITICAL)
|
||||
log(msg, level)
|
||||
|
||||
|
||||
def rand():
|
||||
@@ -233,6 +235,11 @@ def prettydistance(m, suffix="m"):
|
||||
return "%.2f %s%s" % (num, last_unit, suffix)
|
||||
|
||||
def prettytime(time, verbose=False, compact=False):
|
||||
neg = False
|
||||
if time < 0:
|
||||
time = abs(time)
|
||||
neg = True
|
||||
|
||||
days = int(time // (24 * 3600))
|
||||
time = time % (24 * 3600)
|
||||
hours = int(time // 3600)
|
||||
@@ -283,10 +290,17 @@ def prettytime(time, verbose=False, compact=False):
|
||||
if tstr == "":
|
||||
return "0s"
|
||||
else:
|
||||
return tstr
|
||||
if not neg:
|
||||
return tstr
|
||||
else:
|
||||
return f"-{tstr}"
|
||||
|
||||
def prettyshorttime(time, verbose=False, compact=False):
|
||||
neg = False
|
||||
time = time*1e6
|
||||
if time < 0:
|
||||
time = abs(time)
|
||||
neg = True
|
||||
|
||||
seconds = int(time // 1e6); time %= 1e6
|
||||
milliseconds = int(time // 1e3); time %= 1e3
|
||||
@@ -330,7 +344,10 @@ def prettyshorttime(time, verbose=False, compact=False):
|
||||
if tstr == "":
|
||||
return "0us"
|
||||
else:
|
||||
return tstr
|
||||
if not neg:
|
||||
return tstr
|
||||
else:
|
||||
return f"-{tstr}"
|
||||
|
||||
def phyparams():
|
||||
print("Required Physical Layer MTU : "+str(Reticulum.MTU)+" bytes")
|
||||
@@ -344,97 +361,170 @@ def phyparams():
|
||||
def panic():
|
||||
os._exit(255)
|
||||
|
||||
exit_called = False
|
||||
def exit():
|
||||
print("")
|
||||
sys.exit(0)
|
||||
global exit_called
|
||||
if not exit_called:
|
||||
exit_called = True
|
||||
print("")
|
||||
Reticulum.exit_handler()
|
||||
os._exit(0)
|
||||
|
||||
class Profiler:
|
||||
_ran = False
|
||||
profilers = {}
|
||||
tags = {}
|
||||
|
||||
profiler_ran = False
|
||||
profiler_tags = {}
|
||||
def profiler(tag=None, capture=False, super_tag=None):
|
||||
global profiler_ran, profiler_tags
|
||||
try:
|
||||
thread_ident = threading.get_ident()
|
||||
|
||||
if capture:
|
||||
end = time.perf_counter()
|
||||
if tag in profiler_tags and thread_ident in profiler_tags[tag]["threads"]:
|
||||
if profiler_tags[tag]["threads"][thread_ident]["current_start"] != None:
|
||||
begin = profiler_tags[tag]["threads"][thread_ident]["current_start"]
|
||||
profiler_tags[tag]["threads"][thread_ident]["current_start"] = None
|
||||
profiler_tags[tag]["threads"][thread_ident]["captures"].append(end-begin)
|
||||
if not profiler_ran:
|
||||
profiler_ran = True
|
||||
|
||||
@staticmethod
|
||||
def get_profiler(tag=None, super_tag=None):
|
||||
if tag in Profiler.profilers:
|
||||
return Profiler.profilers[tag]
|
||||
else:
|
||||
if not tag in profiler_tags:
|
||||
profiler_tags[tag] = {"threads": {}, "super": super_tag}
|
||||
if not thread_ident in profiler_tags[tag]["threads"]:
|
||||
profiler_tags[tag]["threads"][thread_ident] = {"current_start": None, "captures": []}
|
||||
profiler = Profiler(tag, super_tag)
|
||||
Profiler.profilers[tag] = profiler
|
||||
return profiler
|
||||
|
||||
profiler_tags[tag]["threads"][thread_ident]["current_start"] = time.perf_counter()
|
||||
def __init__(self, tag=None, super_tag=None):
|
||||
self.paused = False
|
||||
self.pause_time = 0
|
||||
self.pause_started = None
|
||||
self.tag = tag
|
||||
self.super_tag = super_tag
|
||||
if self.super_tag in Profiler.profilers:
|
||||
self.super_profiler = Profiler.profilers[self.super_tag]
|
||||
self.pause_super = self.super_profiler.pause
|
||||
self.resume_super = self.super_profiler.resume
|
||||
else:
|
||||
def noop(self=None):
|
||||
pass
|
||||
self.super_profiler = None
|
||||
self.pause_super = noop
|
||||
self.resume_super = noop
|
||||
|
||||
except Exception as e:
|
||||
trace_exception(e)
|
||||
def __enter__(self):
|
||||
self.pause_super()
|
||||
tag = self.tag
|
||||
super_tag = self.super_tag
|
||||
thread_ident = threading.get_ident()
|
||||
if not tag in Profiler.tags:
|
||||
Profiler.tags[tag] = {"threads": {}, "super": super_tag}
|
||||
if not thread_ident in Profiler.tags[tag]["threads"]:
|
||||
Profiler.tags[tag]["threads"][thread_ident] = {"current_start": None, "captures": []}
|
||||
|
||||
def profiler_results():
|
||||
from statistics import mean, median, stdev
|
||||
results = {}
|
||||
|
||||
for tag in profiler_tags:
|
||||
tag_captures = []
|
||||
tag_entry = profiler_tags[tag]
|
||||
Profiler.tags[tag]["threads"][thread_ident]["current_start"] = time.perf_counter()
|
||||
self.resume_super()
|
||||
|
||||
def __exit__(self, exc_type, exc_value, traceback):
|
||||
self.pause_super()
|
||||
tag = self.tag
|
||||
super_tag = self.super_tag
|
||||
end = time.perf_counter() - self.pause_time
|
||||
self.pause_time = 0
|
||||
thread_ident = threading.get_ident()
|
||||
if tag in Profiler.tags and thread_ident in Profiler.tags[tag]["threads"]:
|
||||
if Profiler.tags[tag]["threads"][thread_ident]["current_start"] != None:
|
||||
begin = Profiler.tags[tag]["threads"][thread_ident]["current_start"]
|
||||
Profiler.tags[tag]["threads"][thread_ident]["current_start"] = None
|
||||
Profiler.tags[tag]["threads"][thread_ident]["captures"].append(end-begin)
|
||||
if not Profiler._ran:
|
||||
Profiler._ran = True
|
||||
self.resume_super()
|
||||
|
||||
def pause(self, pause_started=None):
|
||||
if not self.paused:
|
||||
self.paused = True
|
||||
self.pause_started = pause_started or time.perf_counter()
|
||||
self.pause_super(self.pause_started)
|
||||
|
||||
def resume(self):
|
||||
if self.paused:
|
||||
self.pause_time += time.perf_counter() - self.pause_started
|
||||
self.paused = False
|
||||
self.resume_super()
|
||||
|
||||
@staticmethod
|
||||
def ran():
|
||||
return Profiler._ran
|
||||
|
||||
@staticmethod
|
||||
def results():
|
||||
from statistics import mean, median, stdev
|
||||
results = {}
|
||||
|
||||
for thread_ident in tag_entry["threads"]:
|
||||
thread_entry = tag_entry["threads"][thread_ident]
|
||||
thread_captures = thread_entry["captures"]
|
||||
sample_count = len(thread_captures)
|
||||
for tag in Profiler.tags:
|
||||
tag_captures = []
|
||||
tag_entry = Profiler.tags[tag]
|
||||
|
||||
if sample_count > 2:
|
||||
thread_results = {
|
||||
"count": sample_count,
|
||||
"mean": mean(thread_captures),
|
||||
"median": median(thread_captures),
|
||||
"stdev": stdev(thread_captures)
|
||||
for thread_ident in tag_entry["threads"]:
|
||||
thread_entry = tag_entry["threads"][thread_ident]
|
||||
thread_captures = thread_entry["captures"]
|
||||
sample_count = len(thread_captures)
|
||||
|
||||
if sample_count > 1:
|
||||
thread_results = {
|
||||
"count": sample_count,
|
||||
"mean": mean(thread_captures),
|
||||
"median": median(thread_captures),
|
||||
"stdev": stdev(thread_captures)
|
||||
}
|
||||
elif sample_count == 1:
|
||||
thread_results = {
|
||||
"count": sample_count,
|
||||
"mean": mean(thread_captures),
|
||||
"median": median(thread_captures),
|
||||
"stdev": None
|
||||
}
|
||||
|
||||
tag_captures.extend(thread_captures)
|
||||
|
||||
sample_count = len(tag_captures)
|
||||
if sample_count > 1:
|
||||
tag_results = {
|
||||
"name": tag,
|
||||
"super": tag_entry["super"],
|
||||
"count": len(tag_captures),
|
||||
"mean": mean(tag_captures),
|
||||
"median": median(tag_captures),
|
||||
"stdev": stdev(tag_captures)
|
||||
}
|
||||
elif sample_count == 1:
|
||||
tag_results = {
|
||||
"name": tag,
|
||||
"super": tag_entry["super"],
|
||||
"count": len(tag_captures),
|
||||
"mean": mean(tag_captures),
|
||||
"median": median(tag_captures),
|
||||
"stdev": None
|
||||
}
|
||||
|
||||
tag_captures.extend(thread_captures)
|
||||
|
||||
sample_count = len(tag_captures)
|
||||
if sample_count > 2:
|
||||
tag_results = {
|
||||
"name": tag,
|
||||
"super": tag_entry["super"],
|
||||
"count": len(tag_captures),
|
||||
"mean": mean(tag_captures),
|
||||
"median": median(tag_captures),
|
||||
"stdev": stdev(tag_captures)
|
||||
}
|
||||
|
||||
results[tag] = tag_results
|
||||
|
||||
def print_results_recursive(tag, results, level=0):
|
||||
print_tag_results(tag, level+1)
|
||||
def print_results_recursive(tag, results, level=0):
|
||||
print_tag_results(tag, level+1)
|
||||
|
||||
for tag_name in results:
|
||||
sub_tag = results[tag_name]
|
||||
if sub_tag["super"] == tag["name"]:
|
||||
print_results_recursive(sub_tag, results, level=level+1)
|
||||
|
||||
|
||||
def print_tag_results(tag, level):
|
||||
ind = " "*level
|
||||
name = tag["name"]; count = tag["count"]
|
||||
mean = tag["mean"]; median = tag["median"]; stdev = tag["stdev"]
|
||||
print( f"{ind}{name}")
|
||||
print( f"{ind} Samples : {count}")
|
||||
if stdev != None:
|
||||
print(f"{ind} Mean : {prettyshorttime(mean)}")
|
||||
print(f"{ind} Median : {prettyshorttime(median)}")
|
||||
print(f"{ind} St.dev. : {prettyshorttime(stdev)}")
|
||||
print( f"{ind} Total : {prettyshorttime(mean*count)}")
|
||||
print("")
|
||||
|
||||
print("\nProfiler results:\n")
|
||||
for tag_name in results:
|
||||
sub_tag = results[tag_name]
|
||||
if sub_tag["super"] == tag["name"]:
|
||||
print_results_recursive(sub_tag, results, level=level+1)
|
||||
tag = results[tag_name]
|
||||
if tag["super"] == None:
|
||||
print_results_recursive(tag, results)
|
||||
|
||||
|
||||
def print_tag_results(tag, level):
|
||||
ind = " "*level
|
||||
name = tag["name"]; count = tag["count"]
|
||||
mean = tag["mean"]; tag["median"]; stdev = tag["stdev"]
|
||||
print(f"{ind}{name}")
|
||||
print(f"{ind} Samples : {count}")
|
||||
print(f"{ind} Mean : {prettyshorttime(mean)}")
|
||||
print(f"{ind} Median : {prettyshorttime(median)}")
|
||||
print(f"{ind} St.dev. : {prettyshorttime(stdev)}")
|
||||
print("")
|
||||
|
||||
print("\nProfiler results:\n")
|
||||
for tag_name in results:
|
||||
tag = results[tag_name]
|
||||
if tag["super"] == None:
|
||||
print_results_recursive(tag, results)
|
||||
profile = Profiler.get_profiler
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "0.8.7"
|
||||
__version__ = "0.9.2"
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,4 +1,4 @@
|
||||
# Sphinx build info version 1
|
||||
# This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
|
||||
config: 15adafd4c6c385e9e28ce0d62286dd42
|
||||
config: 137f4f4730a0df8f9714240ecb465598
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
|
||||
VERSION: '0.8.7 beta',
|
||||
VERSION: '0.9.2 beta',
|
||||
LANGUAGE: 'en',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
+32
-35
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Support Reticulum" href="support.html" /><link rel="prev" title="Building Networks" href="networks.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Code Examples - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Code Examples - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -238,6 +238,7 @@ program.</p>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="kn">import</span> <span class="nn">sys</span>
|
||||
<span class="kn">import</span> <span class="nn">RNS</span>
|
||||
|
||||
<span class="c1"># Let's define an app name. We'll use this for all</span>
|
||||
@@ -331,7 +332,7 @@ program.</p>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Minimal.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Minimal.py</a>.</p>
|
||||
@@ -349,6 +350,7 @@ notifications about announces from relevant destinations.</p>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="kn">import</span> <span class="nn">random</span>
|
||||
<span class="kn">import</span> <span class="nn">sys</span>
|
||||
<span class="kn">import</span> <span class="nn">RNS</span>
|
||||
|
||||
<span class="c1"># Let's define an app name. We'll use this for all</span>
|
||||
@@ -511,7 +513,7 @@ notifications about announces from relevant destinations.</p>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Announce.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Announce.py</a>.</p>
|
||||
@@ -640,7 +642,7 @@ over the network.</p>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Broadcast.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Broadcast.py</a>.</p>
|
||||
@@ -657,6 +659,7 @@ the Packet interface.</p>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="kn">import</span> <span class="nn">sys</span>
|
||||
<span class="kn">import</span> <span class="nn">RNS</span>
|
||||
|
||||
<span class="c1"># Let's define an app name. We'll use this for all</span>
|
||||
@@ -781,7 +784,7 @@ the Packet interface.</p>
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!"</span><span class="p">)</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">)</span><span class="o">+</span><span class="s2">"</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
@@ -979,7 +982,7 @@ the Packet interface.</p>
|
||||
<span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="n">timeoutarg</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Echo.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Echo.py</a>.</p>
|
||||
@@ -1109,7 +1112,7 @@ destination, and passing traffic back and forth over the link.</p>
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
@@ -1212,9 +1215,8 @@ destination, and passing traffic back and forth over the link.</p>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When a packet is received over the link, we</span>
|
||||
<span class="c1"># simply print out the data.</span>
|
||||
@@ -1278,7 +1280,7 @@ destination, and passing traffic back and forth over the link.</p>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py</a>.</p>
|
||||
@@ -1422,7 +1424,7 @@ the link has been established.</p>
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
@@ -1534,9 +1536,8 @@ the link has been established.</p>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When a packet is received over the link, we</span>
|
||||
<span class="c1"># simply print out the data.</span>
|
||||
@@ -1600,7 +1601,7 @@ the link has been established.</p>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py</a>.</p>
|
||||
@@ -1729,7 +1730,7 @@ the link has been established.</p>
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
@@ -1836,9 +1837,8 @@ the link has been established.</p>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c1">##########################################################</span>
|
||||
@@ -1894,7 +1894,7 @@ the link has been established.</p>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py</a>.</p>
|
||||
@@ -2029,7 +2029,7 @@ data between peers of a <code class="docutils literal notranslate"><span class="
|
||||
<span class="k">def</span> <span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span>
|
||||
<span class="c1"># Let the user know that everything is ready</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
|
||||
<span class="s2">"Link example "</span><span class="o">+</span>
|
||||
<span class="s2">"Channel example "</span><span class="o">+</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span>
|
||||
<span class="s2">" running, waiting for a connection."</span>
|
||||
<span class="p">)</span>
|
||||
@@ -2117,7 +2117,7 @@ data between peers of a <code class="docutils literal notranslate"><span class="
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
@@ -2181,7 +2181,7 @@ data between peers of a <code class="docutils literal notranslate"><span class="
|
||||
<span class="n">packed_size</span> <span class="o">=</span> <span class="nb">len</span><span class="p">(</span><span class="n">message</span><span class="o">.</span><span class="n">pack</span><span class="p">())</span>
|
||||
<span class="n">channel</span> <span class="o">=</span> <span class="n">server_link</span><span class="o">.</span><span class="n">get_channel</span><span class="p">()</span>
|
||||
<span class="k">if</span> <span class="n">channel</span><span class="o">.</span><span class="n">is_ready_to_send</span><span class="p">():</span>
|
||||
<span class="k">if</span> <span class="n">packed_size</span> <span class="o"><=</span> <span class="n">channel</span><span class="o">.</span><span class="n">MDU</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="n">packed_size</span> <span class="o"><=</span> <span class="n">channel</span><span class="o">.</span><span class="n">mdu</span><span class="p">:</span>
|
||||
<span class="n">channel</span><span class="o">.</span><span class="n">send</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
|
||||
@@ -2226,9 +2226,8 @@ data between peers of a <code class="docutils literal notranslate"><span class="
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When a packet is received over the channel, we</span>
|
||||
<span class="c1"># simply print out the data.</span>
|
||||
@@ -2292,7 +2291,7 @@ data between peers of a <code class="docutils literal notranslate"><span class="
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Channel.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Channel.py</a>.</p>
|
||||
@@ -2460,7 +2459,7 @@ binary data between peers of a <code class="docutils literal notranslate"><span
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
@@ -2557,9 +2556,8 @@ binary data between peers of a <code class="docutils literal notranslate"><span
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When the buffer has new data, read it and write it to the terminal.</span>
|
||||
<span class="k">def</span> <span class="nf">client_buffer_ready</span><span class="p">(</span><span class="n">ready_bytes</span><span class="p">:</span> <span class="nb">int</span><span class="p">):</span>
|
||||
@@ -2623,7 +2621,7 @@ binary data between peers of a <code class="docutils literal notranslate"><span
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Buffer.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Buffer.py</a>.</p>
|
||||
@@ -2859,7 +2857,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
@@ -3097,7 +3095,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
<span class="k">global</span> <span class="n">server_files</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">server_files</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Timed out waiting for filelist, exiting"</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c1"># When a link is closed, we'll inform the</span>
|
||||
@@ -3110,9 +3108,8 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When RNS detects that the download has</span>
|
||||
<span class="c1"># started, we'll update our menu state</span>
|
||||
@@ -3236,7 +3233,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Filetransfer.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Filetransfer.py</a>.</p>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Index - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Index - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -139,7 +139,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -165,7 +165,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -508,14 +508,18 @@
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Link">Link (class in RNS)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Reticulum.LINK_MTU_DISCOVERY">LINK_MTU_DISCOVERY (RNS.Reticulum attribute)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Reticulum.link_mtu_discovery">link_mtu_discovery() (RNS.Reticulum static method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Destination.load_private_key">load_private_key() (RNS.Destination method)</a>
|
||||
|
||||
<ul>
|
||||
<li><a href="reference.html#RNS.Identity.load_private_key">(RNS.Identity method)</a>
|
||||
</li>
|
||||
</ul></li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Identity.load_public_key">load_public_key() (RNS.Identity method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
@@ -526,7 +530,7 @@
|
||||
<h2>M</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Channel.Channel.MDU">MDU (RNS.Channel.Channel property)</a>
|
||||
<li><a href="reference.html#RNS.Channel.Channel.mdu">mdu (RNS.Channel.Channel property)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.MessageBase">MessageBase (class in RNS)</a>
|
||||
</li>
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Using Reticulum on Your System" href="using.html" /><link rel="prev" title="What is Reticulum?" href="whatis.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Getting Started Fast - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Getting Started Fast - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Configuring Interfaces" href="interfaces.html" /><link rel="prev" title="Understanding Reticulum" href="understanding.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Communications Hardware - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Communications Hardware - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="What is Reticulum?" href="whatis.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="#"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="#"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Building Networks" href="networks.html" /><link rel="prev" title="Communications Hardware" href="hardware.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Configuring Interfaces - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Configuring Interfaces - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Code Examples" href="examples.html" /><link rel="prev" title="Configuring Interfaces" href="interfaces.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Building Networks - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Building Networks - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
Binary file not shown.
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="Support Reticulum" href="support.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>API Reference - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>API Reference - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
@@ -261,6 +261,17 @@ MTU is a prerequisite for peers to communicate in the same network.</p>
|
||||
the default value.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
<dt class="sig sig-object py" id="RNS.Reticulum.LINK_MTU_DISCOVERY">
|
||||
<span class="sig-name descname"><span class="pre">LINK_MTU_DISCOVERY</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">False</span></em><a class="headerlink" href="#RNS.Reticulum.LINK_MTU_DISCOVERY" title="Permalink to this definition">#</a></dt>
|
||||
<dd><p>Whether automatic link MTU discovery is enabled by default in this
|
||||
release. Link MTU discovery significantly increases throughput over
|
||||
fast links, but requires all intermediary hops to also support it.
|
||||
Support for this feature was added in RNS version 0.9.0. This option
|
||||
will become enabled by default in the near future. Please update your
|
||||
RNS instances.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py attribute">
|
||||
<dt class="sig sig-object py" id="RNS.Reticulum.ANNOUNCE_CAP">
|
||||
<span class="sig-name descname"><span class="pre">ANNOUNCE_CAP</span></span><em class="property"><span class="w"> </span><span class="p"><span class="pre">=</span></span><span class="w"> </span><span class="pre">2</span></em><a class="headerlink" href="#RNS.Reticulum.ANNOUNCE_CAP" title="Permalink to this definition">#</a></dt>
|
||||
@@ -319,6 +330,21 @@ and pass announces over the network.</p>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Reticulum.link_mtu_discovery">
|
||||
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">link_mtu_discovery</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Reticulum.link_mtu_discovery" title="Permalink to this definition">#</a></dt>
|
||||
<dd><p>Returns whether link MTU discovery is enabled for the running
|
||||
instance.</p>
|
||||
<p>When link MTU discovery is enabled, Reticulum will
|
||||
automatically upgrade link MTUs to the highest supported
|
||||
value, increasing transfer speed and efficiency.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Returns<span class="colon">:</span></dt>
|
||||
<dd class="field-odd"><p>True if link MTU discovery is enabled, False if not.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Reticulum.remote_management_enabled">
|
||||
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">remote_management_enabled</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Reticulum.remote_management_enabled" title="Permalink to this definition">#</a></dt>
|
||||
@@ -1700,8 +1726,8 @@ returning handler will not be called.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py property">
|
||||
<dt class="sig sig-object py" id="RNS.Channel.Channel.MDU">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">MDU</span></span><a class="headerlink" href="#RNS.Channel.Channel.MDU" title="Permalink to this definition">#</a></dt>
|
||||
<dt class="sig sig-object py" id="RNS.Channel.Channel.mdu">
|
||||
<em class="property"><span class="pre">property</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">mdu</span></span><a class="headerlink" href="#RNS.Channel.Channel.mdu" title="Permalink to this definition">#</a></dt>
|
||||
<dd><p>Maximum Data Unit: the number of bytes available
|
||||
for a message to consume in a single send. This
|
||||
value is adjusted from the <code class="docutils literal notranslate"><span class="pre">Link</span></code> MDU to accommodate
|
||||
@@ -1943,8 +1969,9 @@ Transport system of Reticulum.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters<span class="colon">:</span></dt>
|
||||
<dd class="field-odd"><p><strong>handler</strong> – Must be an object with an <em>aspect_filter</em> attribute and a <em>received_announce(destination_hash, announced_identity, app_data)</em>
|
||||
callable. Can optionally have a <em>receive_path_responses</em> attribute set to <code class="docutils literal notranslate"><span class="pre">True</span></code>, to also receive all path responses, in addition to live
|
||||
announces. See the <a class="reference internal" href="examples.html#example-announce"><span class="std std-ref">Announce Example</span></a> for more info.</p>
|
||||
or <em>received_announce(destination_hash, announced_identity, app_data, announce_packet_hash)</em> callable. Can optionally have a
|
||||
<em>receive_path_responses</em> attribute set to <code class="docutils literal notranslate"><span class="pre">True</span></code>, to also receive all path responses, in addition to live announces. See
|
||||
the <a class="reference internal" href="examples.html#example-announce"><span class="std std-ref">Announce Example</span></a> for more info.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
@@ -2083,11 +2110,13 @@ will announce it.</p>
|
||||
<li><a class="reference internal" href="#">API Reference</a><ul>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum"><code class="docutils literal notranslate"><span class="pre">Reticulum</span></code></a><ul>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.MTU"><code class="docutils literal notranslate"><span class="pre">MTU</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.LINK_MTU_DISCOVERY"><code class="docutils literal notranslate"><span class="pre">LINK_MTU_DISCOVERY</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.ANNOUNCE_CAP"><code class="docutils literal notranslate"><span class="pre">ANNOUNCE_CAP</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.MINIMUM_BITRATE"><code class="docutils literal notranslate"><span class="pre">MINIMUM_BITRATE</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.get_instance"><code class="docutils literal notranslate"><span class="pre">get_instance()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.should_use_implicit_proof"><code class="docutils literal notranslate"><span class="pre">should_use_implicit_proof()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.transport_enabled"><code class="docutils literal notranslate"><span class="pre">transport_enabled()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.link_mtu_discovery"><code class="docutils literal notranslate"><span class="pre">link_mtu_discovery()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Reticulum.remote_management_enabled"><code class="docutils literal notranslate"><span class="pre">remote_management_enabled()</span></code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -2221,7 +2250,7 @@ will announce it.</p>
|
||||
<li><a class="reference internal" href="#RNS.Channel.Channel.remove_message_handler"><code class="docutils literal notranslate"><span class="pre">remove_message_handler()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Channel.Channel.is_ready_to_send"><code class="docutils literal notranslate"><span class="pre">is_ready_to_send()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Channel.Channel.send"><code class="docutils literal notranslate"><span class="pre">send()</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Channel.Channel.MDU"><code class="docutils literal notranslate"><span class="pre">MDU</span></code></a></li>
|
||||
<li><a class="reference internal" href="#RNS.Channel.Channel.mdu"><code class="docutils literal notranslate"><span class="pre">mdu</span></code></a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#RNS.MessageBase"><code class="docutils literal notranslate"><span class="pre">MessageBase</span></code></a><ul>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="#" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Search - Reticulum Network Stack 0.8.7 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Search - Reticulum Network Stack 0.9.2 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
@@ -138,7 +138,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -164,7 +164,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="#" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="API Reference" href="reference.html" /><link rel="prev" title="Code Examples" href="examples.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Support Reticulum - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Support Reticulum - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Communications Hardware" href="hardware.html" /><link rel="prev" title="Using Reticulum on Your System" href="using.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Understanding Reticulum - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Understanding Reticulum - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Understanding Reticulum" href="understanding.html" /><link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>Using Reticulum on Your System - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>Using Reticulum on Your System - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Getting Started Fast" href="gettingstartedfast.html" /><link rel="prev" title="Reticulum Network Stack Manual" href="index.html" />
|
||||
|
||||
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
|
||||
<title>What is Reticulum? - Reticulum Network Stack 0.8.7 beta documentation</title>
|
||||
<title>What is Reticulum? - Reticulum Network Stack 0.9.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.7 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.9.2 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -167,7 +167,7 @@
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.7 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.9.2 beta documentation</span>
|
||||
|
||||
</a><form class="sidebar-search-container" method="get" action="search.html" role="search">
|
||||
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
|
||||
|
||||
+2
-2
@@ -333,7 +333,7 @@ class TestLink(unittest.TestCase):
|
||||
resource_size = 5*1000*1000
|
||||
data = os.urandom(resource_size)
|
||||
print("Sending "+self.size_str(resource_size)+" resource...")
|
||||
resource = RNS.Resource(data, l1, timeout=resource_timeout)
|
||||
resource = RNS.Resource(data, l1, timeout=resource_timeout, auto_compress=False)
|
||||
start = time.time()
|
||||
|
||||
# This is a hack, don't do it. Use the callbacks instead.
|
||||
@@ -380,7 +380,7 @@ class TestLink(unittest.TestCase):
|
||||
resource_size = 50*1000*1000
|
||||
data = os.urandom(resource_size)
|
||||
print("Sending "+self.size_str(resource_size)+" resource...")
|
||||
resource = RNS.Resource(data, l1, timeout=resource_timeout, callback=self.lr_callback)
|
||||
resource = RNS.Resource(data, l1, timeout=resource_timeout, callback=self.lr_callback, auto_compress=False)
|
||||
start = time.time()
|
||||
|
||||
TestLink.large_resource_status = resource.status
|
||||
|
||||
Reference in New Issue
Block a user