mirror of
https://github.com/markqvist/Reticulum.git
synced 2026-06-24 21:04:29 -07:00
Compare commits
130 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5e27a81412 | |||
| 0dcb009579 | |||
| 943f76804b | |||
| 8bbe6ae3ae | |||
| f0d85dd078 | |||
| f85dda1829 | |||
| 91e064cdf1 | |||
| fb4e53f6e3 | |||
| 03340ed091 | |||
| ed424fa0a2 | |||
| 406ab216d1 | |||
| 00d8a2064d | |||
| 38b920e393 | |||
| 1ed000c4d9 | |||
| d360958d10 | |||
| fcdb455d73 | |||
| 575639b721 | |||
| 492573f9fe | |||
| c5d30f8ee6 | |||
| 3c4791a622 | |||
| 803a5736c9 | |||
| 267ffbdf5f | |||
| 52028aa44c | |||
| c5248d53d6 | |||
| 2d2f0947ac | |||
| 4fa616a326 | |||
| 136713eec1 | |||
| 0fd75cb819 | |||
| ea52153969 | |||
| 3854781028 | |||
| ec2805f357 | |||
| b5cb3a65dd | |||
| c79cb3aa20 | |||
| 8bff119691 | |||
| 5e0b2c5b42 | |||
| 8908022b88 | |||
| b0dda0ed86 | |||
| 6ae72d4225 | |||
| 0a188a2d39 | |||
| 036abb28fe | |||
| a732767a28 | |||
| 32a1261d98 | |||
| 27c5af3bbc | |||
| 5872108da3 | |||
| 8f6c6b76de | |||
| 99db625c62 | |||
| fdf6a31cbd | |||
| 75f353d7e2 | |||
| 82f204fb44 | |||
| 8d4492ecfd | |||
| f8a53458d6 | |||
| 4229837170 | |||
| 4be2ae6c70 | |||
| dbdeba2fe0 | |||
| 7e34b61f37 | |||
| bf726ed2c7 | |||
| fa54a2affe | |||
| 62e1d0e554 | |||
| 9c823a038b | |||
| 1e6cd50f46 | |||
| 06716e4873 | |||
| 8e4a1e3ffa | |||
| 0abb3bd4c3 | |||
| 336574daed | |||
| 07938ba111 | |||
| e699eb6d25 | |||
| 3864549752 | |||
| 0b934cd0f6 | |||
| 5bac38a752 | |||
| 72c8d4d3dd | |||
| b8c6ea015e | |||
| ffe1beb7ae | |||
| 21c6dbfce0 | |||
| 70cbb8dc79 | |||
| 334f2a364d | |||
| b477354235 | |||
| 254c966159 | |||
| 7ee9b07d9c | |||
| 839b72469c | |||
| 874d76b343 | |||
| 7497e7aa0c | |||
| efa084fb0f | |||
| 48e4a27054 | |||
| 96cf6a790e | |||
| d7b54ff397 | |||
| 90ab065073 | |||
| b6f0784311 | |||
| e37ec654ee | |||
| b237d51276 | |||
| 155ea24008 | |||
| 8c8affc800 | |||
| 481062fca1 | |||
| ffcc5560dc | |||
| 09e146ef0b | |||
| 4c6b04ff69 | |||
| 9889b479d1 | |||
| 95dec00c76 | |||
| cff268926d | |||
| 6fa88f4e4a | |||
| ab8e6791fe | |||
| 13c45cc59a | |||
| 67c468884f | |||
| f028d44609 | |||
| 18b952e612 | |||
| 25178d8f50 | |||
| 1c0b7c00fd | |||
| 2439761529 | |||
| 8803dd5b65 | |||
| d15d04eae5 | |||
| bf40f74a4a | |||
| c0339c0f46 | |||
| b64bb166c0 | |||
| 31d30030dc | |||
| 556e111a98 | |||
| 70b0dd621b | |||
| f7d3212651 | |||
| 0a29f0cfa1 | |||
| 97153ad59d | |||
| bc8378fb60 | |||
| 3320cf8da8 | |||
| bb53bd3f27 | |||
| 73eed59fab | |||
| 91ede52634 | |||
| 93f13a98b2 | |||
| c87c5c9709 | |||
| b0c6c53430 | |||
| 94a5222390 | |||
| 98bb304060 | |||
| 08bfd923ea | |||
| ae28f04ce4 |
+108
@@ -1,3 +1,111 @@
|
||||
### 2023-10-01: RNS β 0.6.1
|
||||
|
||||
This release brings a number of bugfixes, along with useful new mechanisms for ensuring network stability under high, non-constructive and unusual announce load situation.
|
||||
|
||||
**Changes**
|
||||
- Added announce ingress rate control for new and unknown destinations
|
||||
- Added per-interface announce frequency monitoring to the transport engine
|
||||
- Added per-interface announce burst hold queues
|
||||
- Added announce frequency statistics to `rnstatus`
|
||||
- Added option to sort `rnstatus` output according to various metrics
|
||||
- Added timeout options to `rnprobe`
|
||||
- Added ability to drop all paths via a specific transport instance to `rnpath`
|
||||
- Added new options and features to documentation and manual
|
||||
|
||||
**Bugfixes**
|
||||
- Fixed announce queue not clearing all announces with exceeded retry limit at the same time
|
||||
- Fixed a bug that caused local packet RSSI and SNR cache to get stuck
|
||||
- Fixed output formatting in `rncp`
|
||||
- Fixed `rnid` not allowing single-aspect destination names
|
||||
- Fixed a number of typos in the documentation
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
461e5cafa7560dcd3ec047141d10f0f48f151c36e1af1d65ec6c65f732cea46a rns-0.6.1-py3-none-any.whl
|
||||
be6a4a6069f2d050e21582f2cf9d3bb59ed4040a0f07761a540bd752d90ea591 rnspure-0.6.1-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2023-09-21: RNS β 0.6.0
|
||||
|
||||
This release brings a few performance improvements, additions to the included utilities, and fixes a number of bugs.
|
||||
|
||||
**Changes**
|
||||
- Added ability to run automatic probe responder on Transport Instances
|
||||
- Improved `rnprobe` utility
|
||||
- Improved AutoInterface peering on Android devices
|
||||
- Improved Transport performance
|
||||
- Improved path re-discovery when local nodes roam to other network segments
|
||||
- Updated various parts of the documentation
|
||||
|
||||
**Bugfixes**
|
||||
- Fixed missing timeout check in `rncp`
|
||||
- Fixed missing link status check on `Identify()` call, which could lead to an unnecessary exception
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
88a26b1593e82a628dab96dbe8820548aea0159235f730fa992bf1833db59246 rns-0.6.0-py3-none-any.whl
|
||||
bcee416e4fb52346d01f6e0c46b1cebf84b127cc516603367fc2ae00a4149fa2 rnspure-0.6.0-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2023-09-19: RNS β 0.5.9
|
||||
|
||||
This release brings major efficiency improvements to `Channel` and `Buffer` classes, adds a range of usability improvements to the included utilities and fixes a number of bugs.
|
||||
|
||||
**Changes**
|
||||
- Improved `Channel` sequencing, retries and transfer efficiency
|
||||
- Added adaptive compression to `Buffer` class
|
||||
- Added `rnid` examples and documentation to manual
|
||||
- Added silent mode to `rncp`
|
||||
- Added remote fetch mode to `rncp`
|
||||
- Added allowed_identities file support to `rncp`
|
||||
- Added Transport Instance uptime to `rnstatus` output
|
||||
- Added channel CSMA parameter stats to RNode Interface `rnstatus` output
|
||||
- Added ability to set custom RNode OLED display address with rnodeconf
|
||||
|
||||
**Bugfixes**
|
||||
- Fixed inadverdent AutoInterface multi-IF deque hit for resource transfer retries
|
||||
- Fixed invalid path for firmware hash generation while using extracted firmware to autoinstall in `rnodeconf`
|
||||
- Fixed various minor missing error checks
|
||||
- Fixed `rnid` status output bug
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
207ab20bd68bab16b417fbd41a4ecdbcf1e2f6fa553d48df6c8fc181b6e84dac rns-0.5.9-py3-none-any.whl
|
||||
93f0965567dfc2c43f3d703481fe1a7d7b1b8d0b3837ad41c37f28a8af5c1acc rnspure-0.5.9-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2023-09-14: RNS β 0.5.8
|
||||
|
||||
This maintenance release contains a number of usability improvements to Reticulum and related tools.
|
||||
|
||||
**Changes**
|
||||
- Various documentation updates
|
||||
- Improved path-resolution in mixed networks with roaming-mode nodes
|
||||
- Added channel load and airtime stats to `rnstatus` output
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
27ba5cdc4724fc8c7211c3b504f097f6adf47f7b80775e6297e4c4e621ef6348 rns-0.5.8-py3-none-any.whl
|
||||
1ea1c949763c9478ec48f064f7f7864d9f859101ab91b44400879371f490800f rnspure-0.5.8-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2023-08-14: RNS β 0.5.7
|
||||
|
||||
This maintenance release contains a number of bugfixes and quality improvements to Reticulum and related tools.
|
||||
|
||||
**Changes**
|
||||
- Added bytes input to destination hash convenience functions
|
||||
- Fixed possible invalid comparison in link watchdog job
|
||||
- Add option to `rnodeconf` to set baud rate when flashing
|
||||
- Added better explanation in `rnodeconf` when flashing fails
|
||||
- Fixed EEPROM dump directory in `rnodeconf`
|
||||
|
||||
**Release Hashes**
|
||||
```
|
||||
867fbb5c73c2a49a75e1f8f3e9f376b507b683328e26c64d4387acd0cc1dbbc7 rns-0.5.7-py3-none-any.whl
|
||||
7bab2865264b32208e023b5c4bbe88c37f51e3176ca4a8cf332d95f59a6d7f2c rnspure-0.5.7-py3-none-any.whl
|
||||
```
|
||||
|
||||
### 2023-07-09: RNS β 0.5.6
|
||||
|
||||
This maintenance release contains a few bugfixes.
|
||||
|
||||
@@ -32,7 +32,7 @@ def program_setup(configpath):
|
||||
# Destinations are endpoints in Reticulum, that can be addressed
|
||||
# and communicated with. Destinations can also announce their
|
||||
# existence, which will let the network know they are reachable
|
||||
# and autoomatically create paths to them, from anywhere else
|
||||
# and automatically create paths to them, from anywhere else
|
||||
# in the network.
|
||||
destination_1 = RNS.Destination(
|
||||
identity,
|
||||
@@ -53,7 +53,7 @@ def program_setup(configpath):
|
||||
)
|
||||
|
||||
# We configure the destinations to automatically prove all
|
||||
# packets adressed to it. By doing this, RNS will automatically
|
||||
# packets addressed to it. By doing this, RNS will automatically
|
||||
# generate a proof for each incoming packet and transmit it
|
||||
# back to the sender of that packet. This will let anyone that
|
||||
# tries to communicate with the destination know whether their
|
||||
|
||||
+1
-1
@@ -46,7 +46,7 @@ def server(configpath):
|
||||
)
|
||||
|
||||
# We configure the destination to automatically prove all
|
||||
# packets adressed to it. By doing this, RNS will automatically
|
||||
# packets addressed to it. By doing this, RNS will automatically
|
||||
# generate a proof for each incoming packet and transmit it
|
||||
# back to the sender of that packet.
|
||||
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
||||
|
||||
+2
-2
@@ -25,7 +25,7 @@ def program_setup(configpath):
|
||||
# Destinations are endpoints in Reticulum, that can be addressed
|
||||
# and communicated with. Destinations can also announce their
|
||||
# existence, which will let the network know they are reachable
|
||||
# and autoomatically create paths to them, from anywhere else
|
||||
# and automatically create paths to them, from anywhere else
|
||||
# in the network.
|
||||
destination = RNS.Destination(
|
||||
identity,
|
||||
@@ -36,7 +36,7 @@ def program_setup(configpath):
|
||||
)
|
||||
|
||||
# We configure the destination to automatically prove all
|
||||
# packets adressed to it. By doing this, RNS will automatically
|
||||
# packets addressed to it. By doing this, RNS will automatically
|
||||
# generate a proof for each incoming packet and transmit it
|
||||
# back to the sender of that packet. This will let anyone that
|
||||
# tries to communicate with the destination know whether their
|
||||
|
||||
@@ -35,7 +35,7 @@ userland, and can run on practically any system that runs Python 3.
|
||||
## Read The Manual
|
||||
The full documentation for Reticulum is available at [markqvist.github.io/Reticulum/manual/](https://markqvist.github.io/Reticulum/manual/).
|
||||
|
||||
You can also [download the Reticulum manual as a PDF](https://github.com/markqvist/Reticulum/raw/master/docs/Reticulum%20Manual.pdf)
|
||||
You can also download the [Reticulum manual as a PDF](https://github.com/markqvist/Reticulum/raw/master/docs/Reticulum%20Manual.pdf) or [as an e-book in EPUB format](https://github.com/markqvist/Reticulum/raw/master/docs/Reticulum%20Manual.epub).
|
||||
|
||||
For more info, see [reticulum.network](https://reticulum.network/)
|
||||
|
||||
@@ -59,11 +59,13 @@ For more info, see [reticulum.network](https://reticulum.network/)
|
||||
- The API is very easy to use, and provides transfer progress
|
||||
- Lightweight, flexible and expandable Request/Response mechanism
|
||||
- Efficient link establishment
|
||||
- Total bandwidth cost of setting up an encrypted link is 3 packets totaling 297 bytes
|
||||
- Total cost of setting up an encrypted and verified link is only 3 packets, totalling 297 bytes
|
||||
- Low cost of keeping links open at only 0.44 bits per second
|
||||
- Reliable sequential delivery with Channel and Buffer mechanisms
|
||||
|
||||
## Roadmap
|
||||
While Reticulum is already a fully featured and functional networking stack, many improvements and additions are actively being worked on, and planned for the future.
|
||||
While Reticulum is already a fully featured and functional networking stack,
|
||||
many improvements and additions are actively being worked on, and planned for the future.
|
||||
|
||||
To learn more about the direction and future of Reticulum, please see the [Development Roadmap](./Roadmap.md).
|
||||
|
||||
@@ -108,14 +110,28 @@ you want to do. For full details and examples, have a look at the
|
||||
[Getting Started Fast](https://markqvist.github.io/Reticulum/manual/gettingstartedfast.html)
|
||||
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
||||
|
||||
To simply install Reticulum and related utilities on your system, the easiest way is via pip:
|
||||
To simply install Reticulum and related utilities on your system, the easiest way is via `pip`.
|
||||
You can then start any program that uses Reticulum, or start Reticulum as a system service with
|
||||
[the rnsd utility](https://markqvist.github.io/Reticulum/manual/using.html#the-rnsd-utility).
|
||||
|
||||
```bash
|
||||
pip install rns
|
||||
```
|
||||
|
||||
You can then start any program that uses Reticulum, or start Reticulum as a
|
||||
system service with [the rnsd utility](https://markqvist.github.io/Reticulum/manual/using.html#the-rnsd-utility).
|
||||
If you are using an operating system that blocks normal user package installation via `pip`,
|
||||
you can return `pip` to normal behaviour by editing the `~/.config/pip/pip.conf` file,
|
||||
and adding the following directive in the `[global]` section:
|
||||
|
||||
```text
|
||||
[global]
|
||||
break-system-packages = true
|
||||
```
|
||||
|
||||
Alternatively, you can use the `pipx` tool to install Reticulum in an isolated environment:
|
||||
|
||||
```bash
|
||||
pipx install rns
|
||||
```
|
||||
|
||||
When first started, Reticulum will create a default configuration file,
|
||||
providing basic connectivity to other Reticulum peers that might be locally
|
||||
@@ -139,12 +155,15 @@ section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/)
|
||||
- An interface status utility called `rnstatus`, that displays information about interfaces
|
||||
- The path lookup and management tool `rnpath` letting you view and modify path tables
|
||||
- A diagnostics tool called `rnprobe` for checking connectivity to destinations
|
||||
- A simple file transfer program called `rncp` making it easy to copy files to remote systems
|
||||
- A simple file transfer program called `rncp` making it easy to transfer files between systems
|
||||
- The identity management and encryption utility `rnid` let's you manage Identities and encrypt/decrypt files
|
||||
- The remote command execution program `rnx` let's you run commands and
|
||||
programs and retrieve output from remote systems
|
||||
|
||||
All tools, including `rnx` and `rncp`, work reliably and well even over very
|
||||
low-bandwidth links like LoRa or Packet Radio.
|
||||
low-bandwidth links like LoRa or Packet Radio. For full-featured remote shells
|
||||
over Reticulum, also have a look at the [rnsh](https://github.com/acehoss/rnsh)
|
||||
program.
|
||||
|
||||
## Supported interface types and devices
|
||||
|
||||
@@ -227,11 +246,11 @@ I2P. Just add one of the following interfaces to your Reticulum configuration
|
||||
file:
|
||||
|
||||
```
|
||||
# TCP/IP interface to the RNS Dublin Hub
|
||||
[[RNS Testnet Dublin]]
|
||||
# TCP/IP interface to the RNS Amsterdam Hub
|
||||
[[RNS Testnet Amsterdam]]
|
||||
type = TCPClientInterface
|
||||
enabled = yes
|
||||
target_host = dublin.connect.reticulum.network
|
||||
target_host = amsterdam.connect.reticulum.network
|
||||
target_port = 4965
|
||||
|
||||
# TCP/IP interface to the BetweenTheBorders Hub (community-provided)
|
||||
@@ -245,7 +264,7 @@ file:
|
||||
[[RNS Testnet I2P Hub]]
|
||||
type = I2PInterface
|
||||
enabled = yes
|
||||
peers = pmlm3l5rpympihoy2o5ago43kluei2jjjzsalcuiuylbve3mwi2a.b32.i2p
|
||||
peers = g3br23bvx3lq5uddcsjii74xgmn6y5q325ovrkq2zw2wbzbqgbuq.b32.i2p
|
||||
```
|
||||
|
||||
The testnet also contains a number of [Nomad Network](https://github.com/markqvist/nomadnet) nodes, and LXMF propagation nodes.
|
||||
|
||||
+58
-13
@@ -1,3 +1,25 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
from __future__ import annotations
|
||||
import bz2
|
||||
import sys
|
||||
@@ -29,7 +51,7 @@ class StreamDataMessage(MessageBase):
|
||||
calculcated based on the value of OVERHEAD
|
||||
"""
|
||||
|
||||
def __init__(self, stream_id: int = None, data: bytes = None, eof: bool = False):
|
||||
def __init__(self, stream_id: int = None, data: bytes = None, eof: bool = False, compressed: bool = False):
|
||||
"""
|
||||
This class is used to encapsulate binary stream
|
||||
data to be sent over a ``Channel``.
|
||||
@@ -42,7 +64,7 @@ class StreamDataMessage(MessageBase):
|
||||
if stream_id is not None and stream_id > self.STREAM_ID_MAX:
|
||||
raise ValueError("stream_id must be 0-16383")
|
||||
self.stream_id = stream_id
|
||||
self.compressed = False
|
||||
self.compressed = compressed
|
||||
self.data = data or bytes()
|
||||
self.eof = eof
|
||||
|
||||
@@ -50,13 +72,6 @@ class StreamDataMessage(MessageBase):
|
||||
if self.stream_id is None:
|
||||
raise ValueError("stream_id")
|
||||
|
||||
compressed_data = bz2.compress(self.data)
|
||||
saved = len(self.data)-len(compressed_data)
|
||||
|
||||
if saved > 0:
|
||||
self.data = compressed_data
|
||||
self.compressed = True
|
||||
|
||||
header_val = (0x3fff & self.stream_id) | (0x8000 if self.eof else 0x0000) | (0x4000 if self.compressed > 0 else 0x0000)
|
||||
return bytes(struct.pack(">H", header_val) + (self.data if self.data else bytes()))
|
||||
|
||||
@@ -133,7 +148,7 @@ class RawChannelReader(RawIOBase, AbstractContextManager):
|
||||
try:
|
||||
threading.Thread(target=listener, name="Message Callback", args=[len(self._buffer)], daemon=True).start()
|
||||
except Exception as ex:
|
||||
RNS.log("Error calling RawChannelReader(" + str(self._stream_id) + ") callback: " + str(ex))
|
||||
RNS.log("Error calling RawChannelReader(" + str(self._stream_id) + ") callback: " + str(ex), RNS.LOG_ERROR)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -186,6 +201,10 @@ class RawChannelWriter(RawIOBase, AbstractContextManager):
|
||||
object, see the Python documentation for
|
||||
``RawIOBase``.
|
||||
"""
|
||||
|
||||
MAX_CHUNK_LEN = 1024*16
|
||||
COMPRESSION_TRIES = 4
|
||||
|
||||
def __init__(self, stream_id: int, channel: Channel):
|
||||
"""
|
||||
Create a raw channel writer.
|
||||
@@ -199,10 +218,36 @@ class RawChannelWriter(RawIOBase, AbstractContextManager):
|
||||
|
||||
def write(self, __b: bytes) -> int | None:
|
||||
try:
|
||||
chunk = bytes(__b[:StreamDataMessage.MAX_DATA_LEN])
|
||||
message = StreamDataMessage(self._stream_id, chunk, self._eof)
|
||||
comp_tries = RawChannelWriter.COMPRESSION_TRIES
|
||||
comp_try = 1
|
||||
comp_success = False
|
||||
chunk_len = len(__b)
|
||||
if chunk_len > RawChannelWriter.MAX_CHUNK_LEN:
|
||||
chunk_len = RawChannelWriter.MAX_CHUNK_LEN
|
||||
__b = __b[:RawChannelWriter.MAX_CHUNK_LEN]
|
||||
chunk_segment = None
|
||||
while chunk_len > 32 and comp_try < comp_tries:
|
||||
chunk_segment_length = int(chunk_len/comp_try)
|
||||
compressed_chunk = bz2.compress(__b[:chunk_segment_length])
|
||||
compressed_length = len(compressed_chunk)
|
||||
if compressed_length < StreamDataMessage.MAX_DATA_LEN and compressed_length < chunk_segment_length:
|
||||
comp_success = True
|
||||
break
|
||||
else:
|
||||
comp_try += 1
|
||||
|
||||
if comp_success:
|
||||
chunk = compressed_chunk
|
||||
processed_length = chunk_segment_length
|
||||
else:
|
||||
chunk = bytes(__b[:StreamDataMessage.MAX_DATA_LEN])
|
||||
processed_length = len(chunk)
|
||||
|
||||
message = StreamDataMessage(self._stream_id, chunk, self._eof, comp_success)
|
||||
|
||||
self._channel.send(message)
|
||||
return len(chunk)
|
||||
return processed_length
|
||||
|
||||
except RNS.Channel.ChannelException as cex:
|
||||
if cex.type != RNS.Channel.CEType.ME_LINK_NOT_READY:
|
||||
raise
|
||||
|
||||
+42
-17
@@ -234,13 +234,16 @@ class Channel(contextlib.AbstractContextManager):
|
||||
WINDOW = 2
|
||||
|
||||
# Absolute minimum window size
|
||||
WINDOW_MIN = 1
|
||||
WINDOW_MIN = 2
|
||||
WINDOW_MIN_LIMIT_SLOW = 2
|
||||
WINDOW_MIN_LIMIT_MEDIUM = 5
|
||||
WINDOW_MIN_LIMIT_FAST = 16
|
||||
|
||||
# The maximum window size for transfers on slow links
|
||||
WINDOW_MAX_SLOW = 5
|
||||
|
||||
# The maximum window size for transfers on mid-speed links
|
||||
WINDOW_MAX_MEDIUM = 16
|
||||
WINDOW_MAX_MEDIUM = 12
|
||||
|
||||
# The maximum window size for transfers on fast links
|
||||
WINDOW_MAX_FAST = 48
|
||||
@@ -255,7 +258,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
|
||||
# If the RTT rate is higher than this value,
|
||||
# the max window size for fast links will be used.
|
||||
RTT_FAST = 0.25
|
||||
RTT_FAST = 0.18
|
||||
RTT_MEDIUM = 0.75
|
||||
RTT_SLOW = 1.45
|
||||
|
||||
@@ -378,16 +381,14 @@ class Channel(contextlib.AbstractContextManager):
|
||||
with self._lock:
|
||||
i = 0
|
||||
|
||||
window_overflow = (self._next_rx_sequence+Channel.WINDOW_MAX) % Channel.SEQ_MODULUS
|
||||
for existing in ring:
|
||||
|
||||
if envelope.sequence == existing.sequence:
|
||||
RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence "+str(envelope.sequence), RNS.LOG_EXTREME)
|
||||
return False
|
||||
|
||||
if envelope.sequence < existing.sequence and not envelope.sequence < window_overflow:
|
||||
if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2):
|
||||
ring.insert(i, envelope)
|
||||
RNS.log("Inserted seq "+str(envelope.sequence)+" at "+str(i), RNS.LOG_DEBUG)
|
||||
|
||||
envelope.tracked = True
|
||||
return True
|
||||
@@ -396,6 +397,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
|
||||
envelope.tracked = True
|
||||
ring.append(envelope)
|
||||
|
||||
return True
|
||||
|
||||
def _run_callbacks(self, message: MessageBase):
|
||||
@@ -429,13 +431,18 @@ class Channel(contextlib.AbstractContextManager):
|
||||
if not is_new:
|
||||
RNS.log("Duplicate message received on channel "+str(self), RNS.LOG_EXTREME)
|
||||
return
|
||||
else:
|
||||
else:
|
||||
with self._lock:
|
||||
contigous = []
|
||||
for e in self._rx_ring:
|
||||
if e.sequence == self._next_rx_sequence:
|
||||
contigous.append(e)
|
||||
self._next_rx_sequence = (self._next_rx_sequence + 1) % Channel.SEQ_MODULUS
|
||||
if self._next_rx_sequence == 0:
|
||||
for e in self._rx_ring:
|
||||
if e.sequence == self._next_rx_sequence:
|
||||
contigous.append(e)
|
||||
self._next_rx_sequence = (self._next_rx_sequence + 1) % Channel.SEQ_MODULUS
|
||||
|
||||
for e in contigous:
|
||||
if not e.unpacked:
|
||||
@@ -474,6 +481,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
with self._lock:
|
||||
envelope = next(filter(lambda e: self._outlet.get_packet_id(e.packet) == self._outlet.get_packet_id(packet),
|
||||
self._tx_ring), None)
|
||||
|
||||
if envelope and op(envelope):
|
||||
envelope.tracked = False
|
||||
if envelope in self._tx_ring:
|
||||
@@ -481,11 +489,9 @@ class Channel(contextlib.AbstractContextManager):
|
||||
|
||||
if self.window < self.window_max:
|
||||
self.window += 1
|
||||
if (self.window - self.window_min) > (self.window_flexibility-1):
|
||||
self.window_min += 1
|
||||
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Increased "+str(self)+" window to "+str(self.window), RNS.LOG_EXTREME)
|
||||
# RNS.log("Increased "+str(self)+" window to "+str(self.window), RNS.LOG_DEBUG)
|
||||
|
||||
if self._outlet.rtt != 0:
|
||||
if self._outlet.rtt > Channel.RTT_FAST:
|
||||
@@ -498,15 +504,20 @@ class Channel(contextlib.AbstractContextManager):
|
||||
self.medium_rate_rounds += 1
|
||||
if self.window_max < Channel.WINDOW_MAX_MEDIUM and self.medium_rate_rounds == Channel.FAST_RATE_THRESHOLD:
|
||||
self.window_max = Channel.WINDOW_MAX_MEDIUM
|
||||
self.window_min = Channel.WINDOW_MIN_LIMIT_MEDIUM
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_EXTREME)
|
||||
# RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG)
|
||||
# RNS.log("Increased "+str(self)+" min window to "+str(self.window_min), RNS.LOG_DEBUG)
|
||||
|
||||
else:
|
||||
self.fast_rate_rounds += 1
|
||||
if self.window_max < Channel.WINDOW_MAX_FAST and self.fast_rate_rounds == Channel.FAST_RATE_THRESHOLD:
|
||||
self.window_max = Channel.WINDOW_MAX_FAST
|
||||
self.window_max = Channel.WINDOW_MAX_FAST
|
||||
self.window_min = Channel.WINDOW_MIN_LIMIT_FAST
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_EXTREME)
|
||||
# RNS.log("Increased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG)
|
||||
# RNS.log("Increased "+str(self)+" min window to "+str(self.window_min), RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
else:
|
||||
RNS.log("Envelope not found in TX ring for "+str(self), RNS.LOG_EXTREME)
|
||||
@@ -516,8 +527,16 @@ class Channel(contextlib.AbstractContextManager):
|
||||
def _packet_delivered(self, packet: TPacket):
|
||||
self._packet_tx_op(packet, lambda env: True)
|
||||
|
||||
def _update_packet_timeouts(self):
|
||||
for envelope in self._tx_ring:
|
||||
updated_timeout = self._get_packet_timeout_time(envelope.tries)
|
||||
if envelope.packet and hasattr(envelope.packet, "receipt") and envelope.packet.receipt and envelope.packet.receipt.timeout:
|
||||
if updated_timeout > envelope.packet.receipt.timeout:
|
||||
envelope.packet.receipt.set_timeout(updated_timeout)
|
||||
|
||||
def _get_packet_timeout_time(self, tries: int) -> float:
|
||||
return pow(2, tries - 1) * max(self._outlet.rtt, 0.01) * 5
|
||||
to = pow(1.5, tries - 1) * max(self._outlet.rtt*2.5, 0.025) * (len(self._tx_ring)+1.5)
|
||||
return to
|
||||
|
||||
def _packet_timeout(self, packet: TPacket):
|
||||
def retry_envelope(envelope: Envelope) -> bool:
|
||||
@@ -526,17 +545,22 @@ class Channel(contextlib.AbstractContextManager):
|
||||
self._shutdown() # start on separate thread?
|
||||
self._outlet.timed_out()
|
||||
return True
|
||||
|
||||
envelope.tries += 1
|
||||
self._outlet.resend(envelope.packet)
|
||||
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
||||
self._outlet.set_packet_timeout_callback(envelope.packet, self._packet_timeout, self._get_packet_timeout_time(envelope.tries))
|
||||
self._update_packet_timeouts()
|
||||
|
||||
if self.window > self.window_min:
|
||||
self.window -= 1
|
||||
if self.window_max > self.window_min:
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Decreased "+str(self)+" window to "+str(self.window), RNS.LOG_DEBUG)
|
||||
|
||||
if self.window_max > (self.window_min+self.window_flexibility):
|
||||
self.window_max -= 1
|
||||
if (self.window_max - self.window) > (self.window_flexibility-1):
|
||||
self.window_max -= 1
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Decreased "+str(self)+" max window to "+str(self.window_max), RNS.LOG_DEBUG)
|
||||
|
||||
# TODO: Remove at some point
|
||||
# RNS.log("Decreased "+str(self)+" window to "+str(self.window), RNS.LOG_EXTREME)
|
||||
@@ -573,6 +597,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
envelope.tries += 1
|
||||
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
||||
self._outlet.set_packet_timeout_callback(envelope.packet, self._packet_timeout, self._get_packet_timeout_time(envelope.tries))
|
||||
self._update_packet_timeouts()
|
||||
|
||||
return envelope
|
||||
|
||||
|
||||
+10
-2
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -99,7 +99,12 @@ class Destination:
|
||||
name_hash = RNS.Identity.full_hash(Destination.expand_name(None, app_name, *aspects).encode("utf-8"))[:(RNS.Identity.NAME_HASH_LENGTH//8)]
|
||||
addr_hash_material = name_hash
|
||||
if identity != None:
|
||||
addr_hash_material += identity.hash
|
||||
if isinstance(identity, RNS.Identity):
|
||||
addr_hash_material += identity.hash
|
||||
elif isinstance(identity, bytes) and len(identity) == RNS.Reticulum.TRUNCATED_HASHLENGTH//8:
|
||||
addr_hash_material += identity
|
||||
else:
|
||||
raise TypeError("Invalid material supplied for destination hash calculation")
|
||||
|
||||
return RNS.Identity.full_hash(addr_hash_material)[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8]
|
||||
|
||||
@@ -176,6 +181,9 @@ class Destination:
|
||||
"""
|
||||
if self.type != Destination.SINGLE:
|
||||
raise TypeError("Only SINGLE destination types can be announced")
|
||||
|
||||
if self.direction != Destination.IN:
|
||||
raise TypeError("Only IN destination types can be announced")
|
||||
|
||||
now = time.time()
|
||||
stale_responses = []
|
||||
|
||||
+6
-2
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -217,7 +217,7 @@ class Identity:
|
||||
return Identity.truncated_hash(os.urandom(Identity.TRUNCATED_HASHLENGTH//8))
|
||||
|
||||
@staticmethod
|
||||
def validate_announce(packet):
|
||||
def validate_announce(packet, only_validate_signature=False):
|
||||
try:
|
||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||
destination_hash = packet.destination_hash
|
||||
@@ -238,6 +238,10 @@ class Identity:
|
||||
announced_identity.load_public_key(public_key)
|
||||
|
||||
if announced_identity.pub != None and announced_identity.validate(signature, signed_data):
|
||||
if only_validate_signature:
|
||||
del announced_identity
|
||||
return True
|
||||
|
||||
hash_material = name_hash+announced_identity.hash
|
||||
expected_hash = RNS.Identity.full_hash(hash_material)[:RNS.Reticulum.TRUNCATED_HASHLENGTH//8]
|
||||
|
||||
|
||||
@@ -77,8 +77,7 @@ class AX25KISSInterface(Interface):
|
||||
RNS.log("You can install one with the command: python3 -m pip install pyserial", RNS.LOG_CRITICAL)
|
||||
RNS.panic()
|
||||
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
@@ -367,5 +366,8 @@ class AX25KISSInterface(Interface):
|
||||
|
||||
RNS.log("Reconnected serial port for "+str(self))
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "AX25KISSInterface["+self.name+"]"
|
||||
@@ -403,5 +403,8 @@ class KISSInterface(Interface):
|
||||
|
||||
RNS.log("Reconnected serial port for "+str(self))
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "KISSInterface["+self.name+"]"
|
||||
@@ -43,21 +43,22 @@ class KISS():
|
||||
CMD_CR = 0x05
|
||||
CMD_RADIO_STATE = 0x06
|
||||
CMD_RADIO_LOCK = 0x07
|
||||
CMD_ST_ALOCK = 0x0B
|
||||
CMD_LT_ALOCK = 0x0C
|
||||
CMD_DETECT = 0x08
|
||||
CMD_IMPLICIT = 0x09
|
||||
CMD_LEAVE = 0x0A
|
||||
CMD_READY = 0x0F
|
||||
CMD_STAT_RX = 0x21
|
||||
CMD_STAT_TX = 0x22
|
||||
CMD_STAT_RSSI = 0x23
|
||||
CMD_STAT_SNR = 0x24
|
||||
CMD_STAT_CHTM = 0x25
|
||||
CMD_STAT_PHYPRM = 0x26
|
||||
CMD_BLINK = 0x30
|
||||
CMD_RANDOM = 0x40
|
||||
CMD_FB_EXT = 0x41
|
||||
CMD_FB_READ = 0x42
|
||||
CMD_FB_WRITE = 0x43
|
||||
CMD_FB_READL = 0x44
|
||||
CMD_BT_CTRL = 0x46
|
||||
CMD_PLATFORM = 0x48
|
||||
CMD_MCU = 0x49
|
||||
CMD_FW_VERSION = 0x50
|
||||
@@ -315,7 +316,7 @@ class RNodeInterface(Interface):
|
||||
self, owner, name, port, frequency = None, bandwidth = None, txpower = None,
|
||||
sf = None, cr = None, flow_control = False, id_interval = None,
|
||||
allow_bluetooth = False, target_device_name = None,
|
||||
target_device_address = None, id_callsign = None):
|
||||
target_device_address = None, id_callsign = None, st_alock = None, lt_alock = None):
|
||||
import importlib
|
||||
if RNS.vendor.platformutils.is_android():
|
||||
self.on_android = True
|
||||
@@ -373,6 +374,8 @@ class RNodeInterface(Interface):
|
||||
self.cr = cr
|
||||
self.state = KISS.RADIO_STATE_OFF
|
||||
self.bitrate = 0
|
||||
self.st_alock = st_alock
|
||||
self.lt_alock = lt_alock
|
||||
self.platform = None
|
||||
self.display = None
|
||||
self.mcu = None
|
||||
@@ -396,7 +399,17 @@ class RNodeInterface(Interface):
|
||||
self.r_stat_tx = None
|
||||
self.r_stat_rssi = None
|
||||
self.r_stat_snr = None
|
||||
self.r_st_alock = None
|
||||
self.r_lt_alock = None
|
||||
self.r_random = None
|
||||
self.r_airtime_short = 0.0
|
||||
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.packet_queue = []
|
||||
self.flow_control = flow_control
|
||||
@@ -427,6 +440,14 @@ class RNodeInterface(Interface):
|
||||
RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR)
|
||||
self.validcfg = False
|
||||
|
||||
if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)):
|
||||
RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR)
|
||||
self.validcfg = False
|
||||
|
||||
if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)):
|
||||
RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR)
|
||||
self.validcfg = False
|
||||
|
||||
if id_interval != None and id_callsign != None:
|
||||
if (len(id_callsign.encode("utf-8")) <= RNodeInterface.CALLSIGN_MAX_LEN):
|
||||
self.should_id = True
|
||||
@@ -616,6 +637,12 @@ class RNodeInterface(Interface):
|
||||
|
||||
self.setCodingRate()
|
||||
time.sleep(0.15)
|
||||
|
||||
self.setSTALock()
|
||||
time.sleep(0.15)
|
||||
|
||||
self.setLTALock()
|
||||
time.sleep(0.15)
|
||||
|
||||
self.setRadioState(KISS.RADIO_STATE_ON)
|
||||
time.sleep(0.15)
|
||||
@@ -741,6 +768,30 @@ class RNodeInterface(Interface):
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while configuring coding rate for "+str(self))
|
||||
|
||||
def setSTALock(self):
|
||||
if self.st_alock != None:
|
||||
at = int(self.st_alock*100)
|
||||
c1 = at >> 8 & 0xFF
|
||||
c2 = at & 0xFF
|
||||
data = KISS.escape(bytes([c1])+bytes([c2]))
|
||||
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND])
|
||||
written = self.write_mux(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self))
|
||||
|
||||
def setLTALock(self):
|
||||
if self.lt_alock != None:
|
||||
at = int(self.lt_alock*100)
|
||||
c1 = at >> 8 & 0xFF
|
||||
c2 = at & 0xFF
|
||||
data = KISS.escape(bytes([c1])+bytes([c2]))
|
||||
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND])
|
||||
written = self.write_mux(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self))
|
||||
|
||||
def setRadioState(self, state):
|
||||
self.state = state
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND])
|
||||
@@ -994,6 +1045,84 @@ class RNodeInterface(Interface):
|
||||
self.r_stat_rssi = byte-RNodeInterface.RSSI_OFFSET
|
||||
elif (command == KISS.CMD_STAT_SNR):
|
||||
self.r_stat_snr = int.from_bytes(bytes([byte]), byteorder="big", signed=True) * 0.25
|
||||
elif (command == KISS.CMD_ST_ALOCK):
|
||||
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) == 2):
|
||||
at = command_buffer[0] << 8 | command_buffer[1]
|
||||
self.r_st_alock = at/100.0
|
||||
RNS.log(str(self)+" Radio reporting short-term airtime limit is "+str(self.r_st_alock)+"%", RNS.LOG_DEBUG)
|
||||
elif (command == KISS.CMD_LT_ALOCK):
|
||||
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) == 2):
|
||||
at = command_buffer[0] << 8 | command_buffer[1]
|
||||
self.r_lt_alock = at/100.0
|
||||
RNS.log(str(self)+" Radio reporting long-term airtime limit is "+str(self.r_lt_alock)+"%", RNS.LOG_DEBUG)
|
||||
elif (command == KISS.CMD_STAT_CHTM):
|
||||
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) == 8):
|
||||
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]
|
||||
|
||||
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
|
||||
elif (command == KISS.CMD_STAT_PHYPRM):
|
||||
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) == 10):
|
||||
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]
|
||||
|
||||
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:
|
||||
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)
|
||||
elif (command == KISS.CMD_RANDOM):
|
||||
self.r_random = byte
|
||||
elif (command == KISS.CMD_PLATFORM):
|
||||
@@ -1105,6 +1234,9 @@ class RNodeInterface(Interface):
|
||||
self.setRadioState(KISS.RADIO_STATE_OFF)
|
||||
self.leave()
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "RNodeInterface["+str(self.name)+"]"
|
||||
|
||||
|
||||
@@ -254,5 +254,8 @@ class SerialInterface(Interface):
|
||||
|
||||
RNS.log("Reconnected serial port for "+str(self))
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "SerialInterface["+self.name+"]"
|
||||
|
||||
@@ -51,7 +51,8 @@ class AutoInterface(Interface):
|
||||
|
||||
BITRATE_GUESS = 10*1000*1000
|
||||
|
||||
MULTI_IF_DEQUE_LEN = 64
|
||||
MULTI_IF_DEQUE_LEN = 48
|
||||
MULTI_IF_DEQUE_TTL = 0.75
|
||||
|
||||
def handler_factory(self, callback):
|
||||
def create_handler(*args, **keys):
|
||||
@@ -75,11 +76,9 @@ class AutoInterface(Interface):
|
||||
|
||||
def __init__(self, owner, name, group_id=None, discovery_scope=None, discovery_port=None, data_port=None, allowed_interfaces=None, ignored_interfaces=None, configured_bitrate=None):
|
||||
from RNS.vendor.ifaddr import niwrapper
|
||||
super().__init__()
|
||||
self.netinfo = niwrapper
|
||||
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
self.IN = True
|
||||
@@ -93,6 +92,7 @@ class AutoInterface(Interface):
|
||||
self.multicast_echoes = {}
|
||||
self.timed_out_interfaces = {}
|
||||
self.mif_deque = deque(maxlen=AutoInterface.MULTI_IF_DEQUE_LEN)
|
||||
self.mif_deque_times = deque(maxlen=AutoInterface.MULTI_IF_DEQUE_LEN)
|
||||
self.carrier_changed = False
|
||||
|
||||
self.outbound_udp_socket = None
|
||||
@@ -103,6 +103,11 @@ class AutoInterface(Interface):
|
||||
self.peering_timeout = AutoInterface.PEERING_TIMEOUT
|
||||
self.multicast_echo_timeout = AutoInterface.PEERING_TIMEOUT/2
|
||||
|
||||
# Increase peering timeout on Android, due to potential
|
||||
# low-power modes implemented on many chipsets.
|
||||
if RNS.vendor.platformutils.is_android():
|
||||
self.peering_timeout *= 3
|
||||
|
||||
if allowed_interfaces == None:
|
||||
self.allowed_interfaces = []
|
||||
else:
|
||||
@@ -396,8 +401,16 @@ class AutoInterface(Interface):
|
||||
|
||||
def processIncoming(self, data):
|
||||
data_hash = RNS.Identity.full_hash(data)
|
||||
if not data_hash in self.mif_deque:
|
||||
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)
|
||||
|
||||
@@ -418,6 +431,11 @@ class AutoInterface(Interface):
|
||||
self.txb += len(data)
|
||||
|
||||
|
||||
# Until per-device sub-interfacing is implemented,
|
||||
# ingress limiting should be disabled on AutoInterface
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "AutoInterface["+self.name+"]"
|
||||
|
||||
|
||||
@@ -390,8 +390,7 @@ class I2PInterfacePeer(Interface):
|
||||
TUNNEL_STATE_STALE = 0x02
|
||||
|
||||
def __init__(self, parent_interface, owner, name, target_i2p_dest=None, connected_socket=None, max_reconnect_tries=None):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
@@ -832,8 +831,7 @@ class I2PInterface(Interface):
|
||||
BITRATE_GUESS = 256*1000
|
||||
|
||||
def __init__(self, owner, name, rns_storagepath, peers, connectable = False, ifac_size = 16, ifac_netname = None, ifac_netkey = None):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
@@ -964,6 +962,12 @@ class I2PInterface(Interface):
|
||||
def processOutgoing(self, data):
|
||||
pass
|
||||
|
||||
def received_announce(self, from_spawned=False):
|
||||
if from_spawned: self.ia_freq_deque.append(time.time())
|
||||
|
||||
def sent_announce(self, from_spawned=False):
|
||||
if from_spawned: self.oa_freq_deque.append(time.time())
|
||||
|
||||
def detach(self):
|
||||
RNS.log("Detaching "+str(self), RNS.LOG_DEBUG)
|
||||
self.i2p.stop()
|
||||
|
||||
+147
-3
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -23,6 +23,7 @@
|
||||
import RNS
|
||||
import time
|
||||
import threading
|
||||
from collections import deque
|
||||
|
||||
class Interface:
|
||||
IN = False
|
||||
@@ -39,18 +40,160 @@ class Interface:
|
||||
MODE_BOUNDARY = 0x05
|
||||
MODE_GATEWAY = 0x06
|
||||
|
||||
# Which interface modes a Transport Node
|
||||
# should actively discover paths for.
|
||||
# Which interface modes a Transport Node should
|
||||
# actively discover paths for.
|
||||
DISCOVER_PATHS_FOR = [MODE_ACCESS_POINT, MODE_GATEWAY]
|
||||
|
||||
# How many samples to use for announce
|
||||
# frequency calculations
|
||||
IA_FREQ_SAMPLES = 6
|
||||
OA_FREQ_SAMPLES = 6
|
||||
|
||||
# Maximum amount of ingress limited announces
|
||||
# to hold at any given time.
|
||||
MAX_HELD_ANNOUNCES = 256
|
||||
|
||||
# How long a spawned interface will be
|
||||
# considered to be newly created. Two
|
||||
# hours by default.
|
||||
IC_NEW_TIME = 2*60*60
|
||||
IC_BURST_FREQ_NEW = 3.5
|
||||
IC_BURST_FREQ = 12
|
||||
IC_BURST_HOLD = 1*60
|
||||
IC_BURST_PENALTY = 5*60
|
||||
IC_HELD_RELEASE_INTERVAL = 30
|
||||
|
||||
def __init__(self):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
self.created = time.time()
|
||||
self.online = False
|
||||
|
||||
self.ingress_control = True
|
||||
self.ic_max_held_announces = Interface.MAX_HELD_ANNOUNCES
|
||||
self.ic_burst_hold = Interface.IC_BURST_HOLD
|
||||
self.ic_burst_active = False
|
||||
self.ic_burst_activated = 0
|
||||
self.ic_held_release = 0
|
||||
self.ic_burst_freq_new = Interface.IC_BURST_FREQ_NEW
|
||||
self.ic_burst_freq = Interface.IC_BURST_FREQ
|
||||
self.ic_new_time = Interface.IC_NEW_TIME
|
||||
self.ic_burst_penalty = Interface.IC_BURST_PENALTY
|
||||
self.ic_held_release_interval = Interface.IC_HELD_RELEASE_INTERVAL
|
||||
self.held_announces = {}
|
||||
|
||||
self.ia_freq_deque = deque(maxlen=Interface.IA_FREQ_SAMPLES)
|
||||
self.oa_freq_deque = deque(maxlen=Interface.OA_FREQ_SAMPLES)
|
||||
|
||||
def get_hash(self):
|
||||
return RNS.Identity.full_hash(str(self).encode("utf-8"))
|
||||
|
||||
# This is a generic function for determining when an interface
|
||||
# should activate ingress limiting. Since this can vary for
|
||||
# different interface types, this function should be overwritten
|
||||
# in case a particular interface requires a different approach.
|
||||
def should_ingress_limit(self):
|
||||
if self.ingress_control:
|
||||
freq_threshold = self.ic_burst_freq_new if self.age() < self.ic_new_time else self.ic_burst_freq
|
||||
ia_freq = self.incoming_announce_frequency()
|
||||
|
||||
if self.ic_burst_active:
|
||||
if ia_freq < freq_threshold and time.time() > self.ic_burst_activated+self.ic_burst_hold:
|
||||
self.ic_burst_active = False
|
||||
self.ic_held_release = time.time() + self.ic_burst_penalty
|
||||
return True
|
||||
|
||||
else:
|
||||
if ia_freq > freq_threshold:
|
||||
self.ic_burst_active = True
|
||||
self.ic_burst_activated = time.time()
|
||||
return True
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
else:
|
||||
return False
|
||||
|
||||
def age(self):
|
||||
return time.time()-self.created
|
||||
|
||||
def hold_announce(self, announce_packet):
|
||||
if announce_packet.destination_hash in self.held_announces:
|
||||
self.held_announces[announce_packet.destination_hash] = announce_packet
|
||||
elif not len(self.held_announces) >= self.ic_max_held_announces:
|
||||
self.held_announces[announce_packet.destination_hash] = announce_packet
|
||||
|
||||
def process_held_announces(self):
|
||||
try:
|
||||
if not self.should_ingress_limit() and len(self.held_announces) > 0 and time.time() > self.ic_held_release:
|
||||
freq_threshold = self.ic_burst_freq_new if self.age() < self.ic_new_time else self.ic_burst_freq
|
||||
ia_freq = self.incoming_announce_frequency()
|
||||
if ia_freq < freq_threshold:
|
||||
selected_announce_packet = None
|
||||
min_hops = RNS.Transport.PATHFINDER_M
|
||||
for destination_hash in self.held_announces:
|
||||
announce_packet = self.held_announces[destination_hash]
|
||||
if announce_packet.hops < min_hops:
|
||||
min_hops = announce_packet.hops
|
||||
selected_announce_packet = announce_packet
|
||||
|
||||
if selected_announce_packet != None:
|
||||
RNS.log("Releasing held announce packet "+str(selected_announce_packet)+" from "+str(self), RNS.LOG_EXTREME)
|
||||
self.ic_held_release = time.time() + self.ic_held_release_interval
|
||||
self.held_announces.pop(selected_announce_packet.destination_hash)
|
||||
def release():
|
||||
RNS.Transport.inbound(selected_announce_packet.raw, selected_announce_packet.receiving_interface)
|
||||
threading.Thread(target=release, daemon=True).start()
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("An error occurred while processing held announces for "+str(self), RNS.LOG_ERROR)
|
||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
def received_announce(self):
|
||||
self.ia_freq_deque.append(time.time())
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||
self.parent_interface.received_announce(from_spawned=True)
|
||||
|
||||
def sent_announce(self):
|
||||
self.oa_freq_deque.append(time.time())
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||
self.parent_interface.sent_announce(from_spawned=True)
|
||||
|
||||
def incoming_announce_frequency(self):
|
||||
if not len(self.ia_freq_deque) > 1:
|
||||
return 0
|
||||
else:
|
||||
dq_len = len(self.ia_freq_deque)
|
||||
delta_sum = 0
|
||||
for i in range(1,dq_len):
|
||||
delta_sum += self.ia_freq_deque[i]-self.ia_freq_deque[i-1]
|
||||
delta_sum += time.time() - self.ia_freq_deque[dq_len-1]
|
||||
|
||||
if delta_sum == 0:
|
||||
avg = 0
|
||||
else:
|
||||
avg = 1/(delta_sum/(dq_len))
|
||||
|
||||
return avg
|
||||
|
||||
def outgoing_announce_frequency(self):
|
||||
if not len(self.oa_freq_deque) > 1:
|
||||
return 0
|
||||
else:
|
||||
dq_len = len(self.oa_freq_deque)
|
||||
delta_sum = 0
|
||||
for i in range(1,dq_len):
|
||||
delta_sum += self.oa_freq_deque[i]-self.oa_freq_deque[i-1]
|
||||
delta_sum += time.time() - self.oa_freq_deque[dq_len-1]
|
||||
|
||||
if delta_sum == 0:
|
||||
avg = 0
|
||||
else:
|
||||
avg = 1/(delta_sum/(dq_len))
|
||||
|
||||
return avg
|
||||
|
||||
def process_announce_queue(self):
|
||||
if not hasattr(self, "announce_cap"):
|
||||
self.announce_cap = RNS.Reticulum.ANNOUNCE_CAP
|
||||
@@ -79,6 +222,7 @@ class Interface:
|
||||
self.announce_allowed_at = now + wait_time
|
||||
|
||||
self.processOutgoing(selected["raw"])
|
||||
self.sent_announce()
|
||||
|
||||
if selected in self.announce_queue:
|
||||
self.announce_queue.remove(selected)
|
||||
|
||||
@@ -70,8 +70,7 @@ class KISSInterface(Interface):
|
||||
RNS.log("You can install one with the command: python3 -m pip install pyserial", RNS.LOG_CRITICAL)
|
||||
RNS.panic()
|
||||
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
@@ -349,5 +348,8 @@ class KISSInterface(Interface):
|
||||
|
||||
RNS.log("Reconnected serial port for "+str(self))
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "KISSInterface["+self.name+"]"
|
||||
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -53,8 +53,7 @@ class LocalClientInterface(Interface):
|
||||
RECONNECT_WAIT = 3
|
||||
|
||||
def __init__(self, owner, name, target_port = None, connected_socket=None):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
# TODO: Remove at some point
|
||||
# self.rxptime = 0
|
||||
@@ -103,6 +102,9 @@ class LocalClientInterface(Interface):
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def connect(self):
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.connect((self.target_ip, self.target_port))
|
||||
@@ -280,8 +282,7 @@ class LocalClientInterface(Interface):
|
||||
class LocalServerInterface(Interface):
|
||||
|
||||
def __init__(self, owner, bindport=None):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
self.online = False
|
||||
self.clients = 0
|
||||
|
||||
@@ -329,7 +330,7 @@ class LocalServerInterface(Interface):
|
||||
spawned_interface.target_port = str(handler.client_address[1])
|
||||
spawned_interface.parent_interface = self
|
||||
spawned_interface.bitrate = self.bitrate
|
||||
RNS.log("Accepting new connection to shared instance: "+str(spawned_interface), RNS.LOG_EXTREME)
|
||||
# RNS.log("Accepting new connection to shared instance: "+str(spawned_interface), RNS.LOG_EXTREME)
|
||||
RNS.Transport.interfaces.append(spawned_interface)
|
||||
RNS.Transport.local_client_interfaces.append(spawned_interface)
|
||||
self.clients += 1
|
||||
@@ -338,6 +339,12 @@ class LocalServerInterface(Interface):
|
||||
def processOutgoing(self, data):
|
||||
pass
|
||||
|
||||
def received_announce(self, from_spawned=False):
|
||||
if from_spawned: self.ia_freq_deque.append(time.time())
|
||||
|
||||
def sent_announce(self, from_spawned=False):
|
||||
if from_spawned: self.oa_freq_deque.append(time.time())
|
||||
|
||||
def __str__(self):
|
||||
return "Shared Instance["+str(self.bind_port)+"]"
|
||||
|
||||
|
||||
@@ -54,8 +54,7 @@ class PipeInterface(Interface):
|
||||
if respawn_delay == None:
|
||||
respawn_delay = 5
|
||||
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -43,6 +43,8 @@ class KISS():
|
||||
CMD_CR = 0x05
|
||||
CMD_RADIO_STATE = 0x06
|
||||
CMD_RADIO_LOCK = 0x07
|
||||
CMD_ST_ALOCK = 0x0B
|
||||
CMD_LT_ALOCK = 0x0C
|
||||
CMD_DETECT = 0x08
|
||||
CMD_LEAVE = 0x0A
|
||||
CMD_READY = 0x0F
|
||||
@@ -50,6 +52,8 @@ class KISS():
|
||||
CMD_STAT_TX = 0x22
|
||||
CMD_STAT_RSSI = 0x23
|
||||
CMD_STAT_SNR = 0x24
|
||||
CMD_STAT_CHTM = 0x25
|
||||
CMD_STAT_PHYPRM = 0x26
|
||||
CMD_BLINK = 0x30
|
||||
CMD_RANDOM = 0x40
|
||||
CMD_FB_EXT = 0x41
|
||||
@@ -98,7 +102,7 @@ class RNodeInterface(Interface):
|
||||
|
||||
RECONNECT_WAIT = 5
|
||||
|
||||
def __init__(self, owner, name, port, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False, id_interval = None, id_callsign = None):
|
||||
def __init__(self, owner, name, port, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False, id_interval = None, id_callsign = None, st_alock = None, lt_alock = None):
|
||||
if RNS.vendor.platformutils.is_android():
|
||||
raise SystemError("Invlaid interface type. The Android-specific RNode interface must be used on Android")
|
||||
|
||||
@@ -110,8 +114,7 @@ class RNodeInterface(Interface):
|
||||
RNS.log("You can install one with the command: python3 -m pip install pyserial", RNS.LOG_CRITICAL)
|
||||
RNS.panic()
|
||||
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 508
|
||||
|
||||
@@ -135,6 +138,8 @@ class RNodeInterface(Interface):
|
||||
self.cr = cr
|
||||
self.state = KISS.RADIO_STATE_OFF
|
||||
self.bitrate = 0
|
||||
self.st_alock = st_alock
|
||||
self.lt_alock = lt_alock
|
||||
self.platform = None
|
||||
self.display = None
|
||||
self.mcu = None
|
||||
@@ -158,7 +163,17 @@ class RNodeInterface(Interface):
|
||||
self.r_stat_tx = None
|
||||
self.r_stat_rssi = None
|
||||
self.r_stat_snr = None
|
||||
self.r_st_alock = None
|
||||
self.r_lt_alock = None
|
||||
self.r_random = None
|
||||
self.r_airtime_short = 0.0
|
||||
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.packet_queue = []
|
||||
self.flow_control = flow_control
|
||||
@@ -186,6 +201,14 @@ class RNodeInterface(Interface):
|
||||
RNS.log("Invalid coding rate configured for "+str(self), RNS.LOG_ERROR)
|
||||
self.validcfg = False
|
||||
|
||||
if (self.st_alock and (self.st_alock < 0.0 or self.st_alock > 100.0)):
|
||||
RNS.log("Invalid short-term airtime limit configured for "+str(self), RNS.LOG_ERROR)
|
||||
self.validcfg = False
|
||||
|
||||
if (self.lt_alock and (self.lt_alock < 0.0 or self.lt_alock > 100.0)):
|
||||
RNS.log("Invalid long-term airtime limit configured for "+str(self), RNS.LOG_ERROR)
|
||||
self.validcfg = False
|
||||
|
||||
if id_interval != None and id_callsign != None:
|
||||
if (len(id_callsign.encode("utf-8")) <= RNodeInterface.CALLSIGN_MAX_LEN):
|
||||
self.should_id = True
|
||||
@@ -281,6 +304,8 @@ class RNodeInterface(Interface):
|
||||
self.setTXPower()
|
||||
self.setSpreadingFactor()
|
||||
self.setCodingRate()
|
||||
self.setSTALock()
|
||||
self.setLTALock()
|
||||
self.setRadioState(KISS.RADIO_STATE_ON)
|
||||
|
||||
def detect(self):
|
||||
@@ -385,6 +410,30 @@ class RNodeInterface(Interface):
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while configuring coding rate for "+str(self))
|
||||
|
||||
def setSTALock(self):
|
||||
if self.st_alock != None:
|
||||
at = int(self.st_alock*100)
|
||||
c1 = at >> 8 & 0xFF
|
||||
c2 = at & 0xFF
|
||||
data = KISS.escape(bytes([c1])+bytes([c2]))
|
||||
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_ST_ALOCK])+data+bytes([KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while configuring short-term airtime limit for "+str(self))
|
||||
|
||||
def setLTALock(self):
|
||||
if self.lt_alock != None:
|
||||
at = int(self.lt_alock*100)
|
||||
c1 = at >> 8 & 0xFF
|
||||
c2 = at & 0xFF
|
||||
data = KISS.escape(bytes([c1])+bytes([c2]))
|
||||
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_LT_ALOCK])+data+bytes([KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while configuring long-term airtime limit for "+str(self))
|
||||
|
||||
def setRadioState(self, state):
|
||||
self.state = state
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_RADIO_STATE])+bytes([state])+bytes([KISS.FEND])
|
||||
@@ -622,6 +671,84 @@ class RNodeInterface(Interface):
|
||||
self.r_stat_rssi = byte-RNodeInterface.RSSI_OFFSET
|
||||
elif (command == KISS.CMD_STAT_SNR):
|
||||
self.r_stat_snr = int.from_bytes(bytes([byte]), byteorder="big", signed=True) * 0.25
|
||||
elif (command == KISS.CMD_ST_ALOCK):
|
||||
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) == 2):
|
||||
at = command_buffer[0] << 8 | command_buffer[1]
|
||||
self.r_st_alock = at/100.0
|
||||
RNS.log(str(self)+" Radio reporting short-term airtime limit is "+str(self.r_st_alock)+"%", RNS.LOG_DEBUG)
|
||||
elif (command == KISS.CMD_LT_ALOCK):
|
||||
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) == 2):
|
||||
at = command_buffer[0] << 8 | command_buffer[1]
|
||||
self.r_lt_alock = at/100.0
|
||||
RNS.log(str(self)+" Radio reporting long-term airtime limit is "+str(self.r_lt_alock)+"%", RNS.LOG_DEBUG)
|
||||
elif (command == KISS.CMD_STAT_CHTM):
|
||||
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) == 8):
|
||||
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]
|
||||
|
||||
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
|
||||
elif (command == KISS.CMD_STAT_PHYPRM):
|
||||
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) == 10):
|
||||
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]
|
||||
|
||||
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:
|
||||
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)
|
||||
elif (command == KISS.CMD_RANDOM):
|
||||
self.r_random = byte
|
||||
elif (command == KISS.CMD_PLATFORM):
|
||||
@@ -710,5 +837,8 @@ class RNodeInterface(Interface):
|
||||
self.setRadioState(KISS.RADIO_STATE_OFF)
|
||||
self.leave()
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "RNodeInterface["+str(self.name)+"]"
|
||||
|
||||
@@ -60,8 +60,7 @@ class SerialInterface(Interface):
|
||||
RNS.log("You can install one with the command: python3 -m pip install pyserial", RNS.LOG_CRITICAL)
|
||||
RNS.panic()
|
||||
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
@@ -201,5 +200,8 @@ class SerialInterface(Interface):
|
||||
|
||||
RNS.log("Reconnected serial port for "+str(self))
|
||||
|
||||
def should_ingress_limit(self):
|
||||
return False
|
||||
|
||||
def __str__(self):
|
||||
return "SerialInterface["+self.name+"]"
|
||||
|
||||
@@ -79,8 +79,7 @@ class TCPClientInterface(Interface):
|
||||
I2P_PROBES = 5
|
||||
|
||||
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None, kiss_framing=False, i2p_tunneled = False, connect_timeout = None):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
@@ -419,8 +418,7 @@ class TCPServerInterface(Interface):
|
||||
return ifaddr[netinfo.AF_INET][0]["broadcast"]
|
||||
|
||||
def __init__(self, owner, name, device=None, bindip=None, bindport=None, i2p_tunneled=False):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
@@ -505,6 +503,12 @@ class TCPServerInterface(Interface):
|
||||
self.clients += 1
|
||||
spawned_interface.read_loop()
|
||||
|
||||
def received_announce(self, from_spawned=False):
|
||||
if from_spawned: self.ia_freq_deque.append(time.time())
|
||||
|
||||
def sent_announce(self, from_spawned=False):
|
||||
if from_spawned: self.oa_freq_deque.append(time.time())
|
||||
|
||||
def processOutgoing(self, data):
|
||||
pass
|
||||
|
||||
|
||||
@@ -45,8 +45,7 @@ class UDPInterface(Interface):
|
||||
return ifaddr[netinfo.AF_INET][0]["broadcast"]
|
||||
|
||||
def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None):
|
||||
self.rxb = 0
|
||||
self.txb = 0
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
|
||||
+7
-3
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -319,7 +319,7 @@ class Link:
|
||||
|
||||
:param identity: An RNS.Identity instance to identify as.
|
||||
"""
|
||||
if self.initiator:
|
||||
if self.initiator and self.status == Link.ACTIVE:
|
||||
signed_data = self.link_id + identity.get_public_key()
|
||||
signature = identity.sign(signed_data)
|
||||
proof_data = identity.get_public_key() + signature
|
||||
@@ -510,7 +510,11 @@ class Link:
|
||||
def __watchdog_job(self):
|
||||
while not self.status == Link.CLOSED:
|
||||
while (self.watchdog_lock):
|
||||
sleep(max(self.rtt, 0.025))
|
||||
rtt_wait = 0.025
|
||||
if hasattr(self, "rtt") and self.rtt:
|
||||
rtt_wait = self.rtt
|
||||
|
||||
sleep(max(rtt_wait, 0.025))
|
||||
|
||||
if not self.status == Link.CLOSED:
|
||||
# Link was initiated, but no response
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -30,7 +30,7 @@ class Packet:
|
||||
"""
|
||||
The Packet class is used to create packet instances that can be sent
|
||||
over a Reticulum network. Packets will automatically be encrypted if
|
||||
they are adressed to a ``RNS.Destination.SINGLE`` destination,
|
||||
they are addressed to a ``RNS.Destination.SINGLE`` destination,
|
||||
``RNS.Destination.GROUP`` destination or a :ref:`RNS.Link<api-link>`.
|
||||
|
||||
For ``RNS.Destination.GROUP`` destinations, Reticulum will use the
|
||||
|
||||
@@ -0,0 +1,27 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
class Resolver:
|
||||
|
||||
@staticmethod
|
||||
def resolve_identity(full_name):
|
||||
pass
|
||||
+5
-2
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -476,7 +476,8 @@ class Resource:
|
||||
|
||||
if sleep_time < 0:
|
||||
if self.retries_left > 0:
|
||||
RNS.log("Timed out waiting for parts, requesting retry", RNS.LOG_DEBUG)
|
||||
ms = "" if self.outstanding_parts == 1 else "s"
|
||||
RNS.log("Timed out waiting for "+str(self.outstanding_parts)+" part"+ms+", requesting retry", RNS.LOG_DEBUG)
|
||||
if self.window > self.window_min:
|
||||
self.window -= 1
|
||||
if self.window_max > self.window_min:
|
||||
@@ -661,6 +662,7 @@ class Resource:
|
||||
for map_hash in self.hashmap[self.consecutive_completed_height:self.consecutive_completed_height+self.window]:
|
||||
if map_hash == part_hash:
|
||||
if self.parts[i] == None:
|
||||
|
||||
# Insert data into parts list
|
||||
self.parts[i] = part_data
|
||||
self.rtt_rxd_bytes += len(part_data)
|
||||
@@ -760,6 +762,7 @@ class Resource:
|
||||
self.req_sent = self.last_activity
|
||||
self.req_sent_bytes = len(request_packet.raw)
|
||||
self.req_resp = None
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Could not send resource request packet, cancelling resource", RNS.LOG_DEBUG)
|
||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_DEBUG)
|
||||
|
||||
+84
-4
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -133,6 +133,7 @@ class Reticulum:
|
||||
JOB_INTERVAL = 5*60
|
||||
CLEAN_INTERVAL = 15*60
|
||||
PERSIST_INTERVAL = 60*60*12
|
||||
GRACIOUS_PERSIST_INTERVAL = 60*5
|
||||
|
||||
router = None
|
||||
config = None
|
||||
@@ -200,6 +201,7 @@ class Reticulum:
|
||||
|
||||
Reticulum.__transport_enabled = False
|
||||
Reticulum.__use_implicit_proof = True
|
||||
Reticulum.__allow_probes = False
|
||||
|
||||
Reticulum.panic_on_interface_error = False
|
||||
|
||||
@@ -288,7 +290,6 @@ class Reticulum:
|
||||
|
||||
if now > self.last_data_persist+Reticulum.PERSIST_INTERVAL:
|
||||
self.__persist_data()
|
||||
self.last_data_persist = time.time()
|
||||
|
||||
time.sleep(Reticulum.JOB_INTERVAL)
|
||||
|
||||
@@ -319,6 +320,7 @@ class Reticulum:
|
||||
self.is_standalone_instance = False
|
||||
self.is_connected_to_shared_instance = True
|
||||
Reticulum.__transport_enabled = False
|
||||
Reticulum.__allow_probes = False
|
||||
RNS.log("Connected to locally available Reticulum instance via: "+str(interface), RNS.LOG_DEBUG)
|
||||
except Exception as e:
|
||||
RNS.log("Local shared instance appears to be running, but it could not be connected", RNS.LOG_ERROR)
|
||||
@@ -361,6 +363,10 @@ class Reticulum:
|
||||
v = self.config["reticulum"].as_bool(option)
|
||||
if v == True:
|
||||
Reticulum.__transport_enabled = True
|
||||
if option == "respond_to_probes":
|
||||
v = self.config["reticulum"].as_bool(option)
|
||||
if v == True:
|
||||
Reticulum.__allow_probes = True
|
||||
if option == "panic_on_interface_error":
|
||||
v = self.config["reticulum"].as_bool(option)
|
||||
if v == True:
|
||||
@@ -441,6 +447,23 @@ class Reticulum:
|
||||
if c["pass_phrase"] != "":
|
||||
ifac_netkey = c["pass_phrase"]
|
||||
|
||||
ingress_control = True
|
||||
if "ingress_control" in c: ingress_control = c.as_bool("ingress_control")
|
||||
ic_max_held_announces = None
|
||||
if "ic_max_held_announces" in c: ic_max_held_announces = c.as_int("ic_max_held_announces")
|
||||
ic_burst_hold = None
|
||||
if "ic_burst_hold" in c: ic_burst_hold = c.as_float("ic_burst_hold")
|
||||
ic_burst_freq_new = None
|
||||
if "ic_burst_freq_new" in c: ic_burst_freq_new = c.as_float("ic_burst_freq_new")
|
||||
ic_burst_freq = None
|
||||
if "ic_burst_freq" in c: ic_burst_freq = c.as_float("ic_burst_freq")
|
||||
ic_new_time = None
|
||||
if "ic_new_time" in c: ic_new_time = c.as_float("ic_new_time")
|
||||
ic_burst_penalty = None
|
||||
if "ic_burst_penalty" in c: ic_burst_penalty = c.as_float("ic_burst_penalty")
|
||||
ic_held_release_interval = None
|
||||
if "ic_held_release_interval" in c: ic_held_release_interval = c.as_float("ic_held_release_interval")
|
||||
|
||||
configured_bitrate = None
|
||||
if "bitrate" in c:
|
||||
if c.as_int("bitrate") >= Reticulum.MINIMUM_BITRATE:
|
||||
@@ -835,6 +858,8 @@ class Reticulum:
|
||||
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
|
||||
id_interval = int(c["id_interval"]) if "id_interval" in c else None
|
||||
id_callsign = c["id_callsign"] if "id_callsign" in c else None
|
||||
st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c else None
|
||||
lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c else None
|
||||
|
||||
port = c["port"] if "port" in c else None
|
||||
|
||||
@@ -852,7 +877,9 @@ class Reticulum:
|
||||
cr = codingrate,
|
||||
flow_control = flow_control,
|
||||
id_interval = id_interval,
|
||||
id_callsign = id_callsign
|
||||
id_callsign = id_callsign,
|
||||
st_alock = st_alock,
|
||||
lt_alock = lt_alock
|
||||
)
|
||||
|
||||
if "outgoing" in c and c.as_bool("outgoing") == False:
|
||||
@@ -874,6 +901,14 @@ class Reticulum:
|
||||
interface.announce_rate_target = announce_rate_target
|
||||
interface.announce_rate_grace = announce_rate_grace
|
||||
interface.announce_rate_penalty = announce_rate_penalty
|
||||
interface.ingress_control = ingress_control
|
||||
if ic_max_held_announces != None: interface.ic_max_held_announces = ic_max_held_announces
|
||||
if ic_burst_hold != None: interface.ic_burst_hold = ic_burst_hold
|
||||
if ic_burst_freq_new != None: interface.ic_burst_freq_new = ic_burst_freq_new
|
||||
if ic_burst_freq != None: interface.ic_burst_freq = ic_burst_freq
|
||||
if ic_new_time != None: interface.ic_new_time = ic_new_time
|
||||
if ic_burst_penalty != None: interface.ic_burst_penalty = ic_burst_penalty
|
||||
if ic_held_release_interval != None: interface.ic_held_release_interval = ic_held_release_interval
|
||||
|
||||
interface.ifac_netname = ifac_netname
|
||||
interface.ifac_netkey = ifac_netkey
|
||||
@@ -960,11 +995,13 @@ class Reticulum:
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
def _should_persist_data(self):
|
||||
self.__persist_data()
|
||||
if time.time() > self.last_data_persist+Reticulum.GRACIOUS_PERSIST_INTERVAL:
|
||||
self.__persist_data()
|
||||
|
||||
def __persist_data(self):
|
||||
RNS.Transport.persist_data()
|
||||
RNS.Identity.persist_data()
|
||||
self.last_data_persist = time.time()
|
||||
|
||||
def __clean_caches(self):
|
||||
RNS.log("Cleaning resource and packet caches...", RNS.LOG_EXTREME)
|
||||
@@ -1040,6 +1077,9 @@ class Reticulum:
|
||||
if path == "path":
|
||||
rpc_connection.send(self.drop_path(call["destination_hash"]))
|
||||
|
||||
if path == "all_via":
|
||||
rpc_connection.send(self.drop_all_via(call["destination_hash"]))
|
||||
|
||||
if path == "announce_queues":
|
||||
rpc_connection.send(self.drop_announce_queues())
|
||||
|
||||
@@ -1089,6 +1129,18 @@ class Reticulum:
|
||||
else:
|
||||
ifstats["tunnelstate"] = None
|
||||
|
||||
if hasattr(interface, "r_airtime_short"):
|
||||
ifstats["airtime_short"] = interface.r_airtime_short
|
||||
|
||||
if hasattr(interface, "r_airtime_long"):
|
||||
ifstats["airtime_long"] = interface.r_airtime_long
|
||||
|
||||
if hasattr(interface, "r_channel_load_short"):
|
||||
ifstats["channel_load_short"] = interface.r_channel_load_short
|
||||
|
||||
if hasattr(interface, "r_channel_load_long"):
|
||||
ifstats["channel_load_long"] = interface.r_channel_load_long
|
||||
|
||||
if hasattr(interface, "bitrate"):
|
||||
if interface.bitrate != None:
|
||||
ifstats["bitrate"] = interface.bitrate
|
||||
@@ -1119,6 +1171,9 @@ class Reticulum:
|
||||
ifstats["name"] = str(interface)
|
||||
ifstats["rxb"] = interface.rxb
|
||||
ifstats["txb"] = interface.txb
|
||||
ifstats["incoming_announce_frequency"] = interface.incoming_announce_frequency()
|
||||
ifstats["outgoing_announce_frequency"] = interface.outgoing_announce_frequency()
|
||||
ifstats["held_announces"] = len(interface.held_announces)
|
||||
ifstats["status"] = interface.online
|
||||
ifstats["mode"] = interface.mode
|
||||
|
||||
@@ -1128,6 +1183,11 @@ class Reticulum:
|
||||
stats["interfaces"] = interfaces
|
||||
if Reticulum.transport_enabled():
|
||||
stats["transport_id"] = RNS.Transport.identity.hash
|
||||
stats["transport_uptime"] = time.time()-RNS.Transport.start_time
|
||||
if Reticulum.probe_destination_enabled():
|
||||
stats["probe_responder"] = RNS.Transport.probe_destination.hash
|
||||
else:
|
||||
stats["probe_responder"] = None
|
||||
|
||||
return stats
|
||||
|
||||
@@ -1184,6 +1244,22 @@ class Reticulum:
|
||||
else:
|
||||
return RNS.Transport.expire_path(destination)
|
||||
|
||||
def drop_all_via(self, transport_hash):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
|
||||
rpc_connection.send({"drop": "all_via", "destination_hash": transport_hash})
|
||||
response = rpc_connection.recv()
|
||||
return response
|
||||
|
||||
else:
|
||||
dropped_count = 0
|
||||
for destination_hash in RNS.Transport.destination_table:
|
||||
if RNS.Transport.destination_table[destination_hash][1] == transport_hash:
|
||||
RNS.Transport.expire_path(destination_hash)
|
||||
dropped_count += 1
|
||||
|
||||
return dropped_count
|
||||
|
||||
def drop_announce_queues(self):
|
||||
if self.is_connected_to_shared_instance:
|
||||
rpc_connection = multiprocessing.connection.Client(self.rpc_addr, authkey=self.rpc_key)
|
||||
@@ -1266,6 +1342,10 @@ class Reticulum:
|
||||
"""
|
||||
return Reticulum.__transport_enabled
|
||||
|
||||
@staticmethod
|
||||
def probe_destination_enabled():
|
||||
return Reticulum.__allow_probes
|
||||
|
||||
# Default configuration file:
|
||||
__default_rns_config__ = '''# This is the default Reticulum config file.
|
||||
# You should probably edit it to include any additional,
|
||||
|
||||
+124
-50
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors.
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -115,9 +115,10 @@ class Transport:
|
||||
|
||||
pending_local_path_requests = {}
|
||||
|
||||
jobs_locked = False
|
||||
jobs_running = False
|
||||
job_interval = 0.250
|
||||
start_time = None
|
||||
jobs_locked = False
|
||||
jobs_running = False
|
||||
job_interval = 0.250
|
||||
links_last_checked = 0.0
|
||||
links_check_interval = 1.0
|
||||
receipts_last_checked = 0.0
|
||||
@@ -127,6 +128,8 @@ class Transport:
|
||||
hashlist_maxsize = 1000000
|
||||
tables_last_culled = 0.0
|
||||
tables_cull_interval = 5.0
|
||||
interface_last_jobs = 0.0
|
||||
interface_jobs_interval = 5.0
|
||||
|
||||
identity = None
|
||||
|
||||
@@ -269,7 +272,17 @@ class Transport:
|
||||
except Exception as e:
|
||||
RNS.log("Could not load tunnel table from storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
if RNS.Reticulum.probe_destination_enabled():
|
||||
Transport.probe_destination = RNS.Destination(Transport.identity, RNS.Destination.IN, RNS.Destination.SINGLE, Transport.APP_NAME, "probe")
|
||||
Transport.probe_destination.accepts_links(False)
|
||||
Transport.probe_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
||||
Transport.probe_destination.announce()
|
||||
RNS.log("Transport Instance will respond to probe requests on "+str(Transport.probe_destination), RNS.LOG_NOTICE)
|
||||
else:
|
||||
Transport.probe_destination = None
|
||||
|
||||
RNS.log("Transport instance "+str(Transport.identity)+" started", RNS.LOG_VERBOSE)
|
||||
Transport.start_time = time.time()
|
||||
|
||||
# Synthesize tunnels for any interfaces wanting it
|
||||
for interface in Transport.interfaces:
|
||||
@@ -341,12 +354,12 @@ class Transport:
|
||||
|
||||
# Process announces needing retransmission
|
||||
if time.time() > Transport.announces_last_checked+Transport.announces_check_interval:
|
||||
completed_announces = []
|
||||
for destination_hash in Transport.announce_table:
|
||||
announce_entry = Transport.announce_table[destination_hash]
|
||||
if announce_entry[2] > Transport.PATHFINDER_R:
|
||||
RNS.log("Completed announce processing for "+RNS.prettyhexrep(destination_hash)+", retry limit reached", RNS.LOG_EXTREME)
|
||||
Transport.announce_table.pop(destination_hash)
|
||||
break
|
||||
completed_announces.append(destination_hash)
|
||||
else:
|
||||
if time.time() > announce_entry[1]:
|
||||
announce_entry[1] = time.time() + Transport.PATHFINDER_G + Transport.PATHFINDER_RW
|
||||
@@ -393,6 +406,10 @@ class Transport:
|
||||
Transport.announce_table[destination_hash] = held_entry
|
||||
RNS.log("Reinserting held announce into table", RNS.LOG_DEBUG)
|
||||
|
||||
for destination_hash in completed_announces:
|
||||
if destination_hash in Transport.announce_table:
|
||||
Transport.announce_table.pop(destination_hash)
|
||||
|
||||
Transport.announces_last_checked = time.time()
|
||||
|
||||
|
||||
@@ -428,12 +445,41 @@ class Transport:
|
||||
if link_entry[6] in Transport.path_requests:
|
||||
last_path_request = Transport.path_requests[link_entry[6]]
|
||||
|
||||
lr_taken_hops = link_entry[5]
|
||||
|
||||
path_request_throttle = time.time() - last_path_request < Transport.PATH_REQUEST_MI
|
||||
path_request_conditions = False
|
||||
|
||||
# If the path has been invalidated between the time of
|
||||
# making the link request and now, try to rediscover it
|
||||
if not Transport.has_path(link_entry[6]):
|
||||
RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and path is now missing", RNS.LOG_DEBUG)
|
||||
path_request_conditions =True
|
||||
|
||||
# If this link request was originated from a local client
|
||||
# attempt to rediscover a path to the destination, if this
|
||||
# has not already happened recently.
|
||||
lr_taken_hops = link_entry[5]
|
||||
if lr_taken_hops == 0 and time.time() - last_path_request > Transport.PATH_REQUEST_MI:
|
||||
elif not path_request_throttle and lr_taken_hops == 0:
|
||||
RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted local client link was never established", RNS.LOG_DEBUG)
|
||||
path_request_conditions = True
|
||||
|
||||
# If the link destination was previously only 1 hop
|
||||
# away, this likely means that it was local to one
|
||||
# of our interfaces, and that it roamed somewhere else.
|
||||
# In that case, try to discover a new path.
|
||||
elif not path_request_throttle and Transport.hops_to(link_entry[6]) == 1:
|
||||
RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and destination was previously local to an interface on this instance", RNS.LOG_DEBUG)
|
||||
path_request_conditions = True
|
||||
|
||||
# If the link destination was previously only 1 hop
|
||||
# away, this likely means that it was local to one
|
||||
# of our interfaces, and that it roamed somewhere else.
|
||||
# In that case, try to discover a new path.
|
||||
elif not path_request_throttle and lr_taken_hops == 1:
|
||||
RNS.log("Trying to rediscover path for "+RNS.prettyhexrep(link_entry[6])+" since an attempted link was never established, and link initiator is local to an interface on this instance", RNS.LOG_DEBUG)
|
||||
path_request_conditions = True
|
||||
|
||||
if path_request_conditions:
|
||||
if not link_entry[6] in path_requests:
|
||||
path_requests.append(link_entry[6])
|
||||
|
||||
@@ -564,6 +610,11 @@ class Transport:
|
||||
|
||||
Transport.tables_last_culled = time.time()
|
||||
|
||||
if time.time() > Transport.interface_last_jobs + Transport.interface_jobs_interval:
|
||||
for interface in Transport.interfaces:
|
||||
interface.process_held_announces()
|
||||
Transport.interface_last_jobs = time.time()
|
||||
|
||||
else:
|
||||
# Transport jobs were locked, do nothing
|
||||
pass
|
||||
@@ -843,6 +894,8 @@ class Transport:
|
||||
# thread.start()
|
||||
|
||||
Transport.transmit(interface, packet.raw)
|
||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||
interface.sent_announce()
|
||||
sent = True
|
||||
|
||||
if sent:
|
||||
@@ -996,6 +1049,7 @@ class Transport:
|
||||
|
||||
packet = RNS.Packet(None, raw)
|
||||
if not packet.unpack():
|
||||
Transport.jobs_locked = False
|
||||
return
|
||||
|
||||
packet.receiving_interface = interface
|
||||
@@ -1009,7 +1063,7 @@ class Transport:
|
||||
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()
|
||||
Transport.local_client_rssi_cache.pop(0)
|
||||
|
||||
if hasattr(interface, "r_stat_snr"):
|
||||
if interface.r_stat_rssi != None:
|
||||
@@ -1018,7 +1072,7 @@ class Transport:
|
||||
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()
|
||||
Transport.local_client_snr_cache.pop(0)
|
||||
|
||||
if len(Transport.local_client_interfaces) > 0:
|
||||
if Transport.is_local_client_interface(interface):
|
||||
@@ -1077,6 +1131,7 @@ class Transport:
|
||||
# normal processing.
|
||||
if packet.context == RNS.Packet.CACHE_REQUEST:
|
||||
if Transport.cache_request_packet(packet):
|
||||
Transport.jobs_locked = False
|
||||
return
|
||||
|
||||
# If the packet is in transport, check whether we
|
||||
@@ -1168,7 +1223,7 @@ class Transport:
|
||||
# Also check that expected hop count matches
|
||||
if packet.hops == link_entry[5]:
|
||||
outbound_interface = link_entry[2]
|
||||
|
||||
|
||||
if outbound_interface != None:
|
||||
new_raw = packet.raw[0:1]
|
||||
new_raw += struct.pack("!B", packet.hops)
|
||||
@@ -1183,8 +1238,21 @@ class Transport:
|
||||
# announces, queueing rebroadcasts of these, and removal
|
||||
# of queued announce rebroadcasts once handed to the next node.
|
||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||
if interface != None and RNS.Identity.validate_announce(packet, only_validate_signature=True):
|
||||
interface.received_announce()
|
||||
|
||||
if not packet.destination_hash in Transport.destination_table:
|
||||
# This is an unknown destination, and we'll apply
|
||||
# potential ingress limiting. Already known
|
||||
# destinations will have re-announces controlled
|
||||
# by normal announce rate limiting.
|
||||
if interface.should_ingress_limit():
|
||||
interface.hold_announce(packet)
|
||||
Transport.jobs_locked = False
|
||||
return
|
||||
|
||||
local_destination = next((d for d in Transport.destinations if d.hash == packet.destination_hash), None)
|
||||
if local_destination == None and RNS.Identity.validate_announce(packet):
|
||||
if local_destination == None and RNS.Identity.validate_announce(packet):
|
||||
if packet.transport_id != None:
|
||||
received_from = packet.transport_id
|
||||
|
||||
@@ -1276,7 +1344,7 @@ class Transport:
|
||||
should_add = True
|
||||
|
||||
if should_add:
|
||||
now = time.time()
|
||||
now = time.time()
|
||||
|
||||
rate_blocked = False
|
||||
if packet.context != RNS.Packet.PATH_RESPONSE and packet.receiving_interface.announce_rate_target != None:
|
||||
@@ -1494,7 +1562,7 @@ class Transport:
|
||||
RNS.log("Error while processing external announce callback.", RNS.LOG_ERROR)
|
||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
# Handling for linkrequests to local destinations
|
||||
# Handling for link requests to local destinations
|
||||
elif packet.packet_type == RNS.Packet.LINKREQUEST:
|
||||
if packet.transport_id == None or packet.transport_id == Transport.identity.hash:
|
||||
for destination in Transport.destinations:
|
||||
@@ -1780,8 +1848,11 @@ class Transport:
|
||||
|
||||
@staticmethod
|
||||
def should_cache(packet):
|
||||
if packet.context == RNS.Packet.RESOURCE_PRF:
|
||||
return True
|
||||
# TODO: Rework the caching system. It's currently
|
||||
# not very useful to even cache Resource proofs,
|
||||
# disabling it for now, until redesigned.
|
||||
# if packet.context == RNS.Packet.RESOURCE_PRF:
|
||||
# return True
|
||||
|
||||
return False
|
||||
|
||||
@@ -1804,8 +1875,7 @@ class Transport:
|
||||
file.close()
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Error writing packet to cache", RNS.LOG_ERROR)
|
||||
RNS.log("The contained exception was: "+str(e))
|
||||
RNS.log("Error writing packet to cache. The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
@staticmethod
|
||||
def get_cached_packet(packet_hash):
|
||||
@@ -2046,41 +2116,45 @@ class Transport:
|
||||
packet = Transport.destination_table[destination_hash][6]
|
||||
next_hop = Transport.destination_table[destination_hash][1]
|
||||
received_from = Transport.destination_table[destination_hash][5]
|
||||
|
||||
if requestor_transport_id != None and next_hop == requestor_transport_id:
|
||||
# TODO: Find a bandwidth efficient way to invalidate our
|
||||
# known path on this signal. The obvious way of signing
|
||||
# path requests with transport instance keys is quite
|
||||
# inefficient. There is probably a better way. Doing
|
||||
# path invalidation here would decrease the network
|
||||
# convergence time. Maybe just drop it?
|
||||
RNS.log("Not answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", since next hop is the requestor", RNS.LOG_DEBUG)
|
||||
|
||||
if attached_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING and attached_interface == received_from:
|
||||
RNS.log("Not answering path request on roaming-mode interface, since next hop is on same roaming-mode interface", RNS.LOG_DEBUG)
|
||||
|
||||
else:
|
||||
RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", path is known", RNS.LOG_DEBUG)
|
||||
|
||||
now = time.time()
|
||||
retries = Transport.PATHFINDER_R
|
||||
local_rebroadcasts = 0
|
||||
block_rebroadcasts = True
|
||||
announce_hops = packet.hops
|
||||
|
||||
if is_from_local_client:
|
||||
retransmit_timeout = now
|
||||
if requestor_transport_id != None and next_hop == requestor_transport_id:
|
||||
# TODO: Find a bandwidth efficient way to invalidate our
|
||||
# known path on this signal. The obvious way of signing
|
||||
# path requests with transport instance keys is quite
|
||||
# inefficient. There is probably a better way. Doing
|
||||
# path invalidation here would decrease the network
|
||||
# convergence time. Maybe just drop it?
|
||||
RNS.log("Not answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", since next hop is the requestor", RNS.LOG_DEBUG)
|
||||
else:
|
||||
# TODO: Look at this timing
|
||||
retransmit_timeout = now + Transport.PATH_REQUEST_GRACE # + (RNS.rand() * Transport.PATHFINDER_RW)
|
||||
RNS.log("Answering path request for "+RNS.prettyhexrep(destination_hash)+interface_str+", path is known", RNS.LOG_DEBUG)
|
||||
|
||||
# This handles an edge case where a peer sends a past
|
||||
# request for a destination just after an announce for
|
||||
# said destination has arrived, but before it has been
|
||||
# rebroadcast locally. In such a case the actual announce
|
||||
# is temporarily held, and then reinserted when the path
|
||||
# request has been served to the peer.
|
||||
if packet.destination_hash in Transport.announce_table:
|
||||
held_entry = Transport.announce_table[packet.destination_hash]
|
||||
Transport.held_announces[packet.destination_hash] = held_entry
|
||||
|
||||
Transport.announce_table[packet.destination_hash] = [now, retransmit_timeout, retries, received_from, announce_hops, packet, local_rebroadcasts, block_rebroadcasts, attached_interface]
|
||||
now = time.time()
|
||||
retries = Transport.PATHFINDER_R
|
||||
local_rebroadcasts = 0
|
||||
block_rebroadcasts = True
|
||||
announce_hops = packet.hops
|
||||
|
||||
if is_from_local_client:
|
||||
retransmit_timeout = now
|
||||
else:
|
||||
# TODO: Look at this timing
|
||||
retransmit_timeout = now + Transport.PATH_REQUEST_GRACE # + (RNS.rand() * Transport.PATHFINDER_RW)
|
||||
|
||||
# This handles an edge case where a peer sends a past
|
||||
# request for a destination just after an announce for
|
||||
# said destination has arrived, but before it has been
|
||||
# rebroadcast locally. In such a case the actual announce
|
||||
# is temporarily held, and then reinserted when the path
|
||||
# request has been served to the peer.
|
||||
if packet.destination_hash in Transport.announce_table:
|
||||
held_entry = Transport.announce_table[packet.destination_hash]
|
||||
Transport.held_announces[packet.destination_hash] = held_entry
|
||||
|
||||
Transport.announce_table[packet.destination_hash] = [now, retransmit_timeout, retries, received_from, announce_hops, packet, local_rebroadcasts, block_rebroadcasts, attached_interface]
|
||||
|
||||
elif is_from_local_client:
|
||||
# Forward path request on all interfaces
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2023 Mark Qvist / unsigned.io
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
# in the Software without restriction, including without limitation the rights
|
||||
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
# copies of the Software, and to permit persons to whom the Software is
|
||||
# furnished to do so, subject to the following conditions:
|
||||
#
|
||||
# The above copyright notice and this permission notice shall be included in all
|
||||
# copies or substantial portions of the Software.
|
||||
#
|
||||
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
# SOFTWARE.
|
||||
|
||||
import RNS
|
||||
import argparse
|
||||
import time
|
||||
|
||||
from RNS._version import __version__
|
||||
|
||||
|
||||
def program_setup(configdir, verbosity = 0, quietness = 0, service = False):
|
||||
targetverbosity = verbosity-quietness
|
||||
|
||||
if service:
|
||||
targetlogdest = RNS.LOG_FILE
|
||||
targetverbosity = None
|
||||
else:
|
||||
targetlogdest = RNS.LOG_STDOUT
|
||||
|
||||
reticulum = RNS.Reticulum(configdir=configdir, verbosity=targetverbosity, logdest=targetlogdest)
|
||||
exit(0)
|
||||
|
||||
def main():
|
||||
try:
|
||||
parser = argparse.ArgumentParser(description="Reticulum Distributed Identity Resolver")
|
||||
parser.add_argument("--config", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||
parser.add_argument('-q', '--quiet', action='count', default=0)
|
||||
parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit")
|
||||
parser.add_argument("--version", action="version", version="ir {version}".format(version=__version__))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.exampleconfig:
|
||||
print(__example_rns_config__)
|
||||
exit()
|
||||
|
||||
if args.config:
|
||||
configarg = args.config
|
||||
else:
|
||||
configarg = None
|
||||
|
||||
program_setup(configdir = configarg, verbosity=args.verbose, quietness=args.quiet)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
exit()
|
||||
|
||||
__example_rns_config__ = '''# This is an example Identity Resolver file.
|
||||
'''
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
+394
-44
@@ -24,6 +24,7 @@
|
||||
|
||||
import RNS
|
||||
import argparse
|
||||
import threading
|
||||
import time
|
||||
import sys
|
||||
import os
|
||||
@@ -34,9 +35,12 @@ APP_NAME = "rncp"
|
||||
allow_all = False
|
||||
allowed_identity_hashes = []
|
||||
|
||||
def receive(configdir, verbosity = 0, quietness = 0, allowed = [], display_identity = False, limit = None, disable_auth = None, disable_announce = False):
|
||||
def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identity = False, limit = None, disable_auth = None, announce = False):
|
||||
global allow_all, allowed_identity_hashes
|
||||
from tempfile import TemporaryFile
|
||||
identity = None
|
||||
if announce < 0:
|
||||
announce = False
|
||||
|
||||
targetloglevel = 3+verbosity-quietness
|
||||
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
|
||||
@@ -54,16 +58,48 @@ def receive(configdir, verbosity = 0, quietness = 0, allowed = [], display_ident
|
||||
|
||||
if display_identity:
|
||||
print("Identity : "+str(identity))
|
||||
print("Receiving on : "+RNS.prettyhexrep(destination.hash))
|
||||
print("Listening on : "+RNS.prettyhexrep(destination.hash))
|
||||
exit(0)
|
||||
|
||||
if disable_auth:
|
||||
allow_all = True
|
||||
else:
|
||||
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||
try:
|
||||
allowed_file_name = "allowed_identities"
|
||||
allowed_file = None
|
||||
if os.path.isfile(os.path.expanduser("/etc/rncp/"+allowed_file_name)):
|
||||
allowed_file = os.path.expanduser("/etc/rncp/"+allowed_file_name)
|
||||
elif os.path.isfile(os.path.expanduser("~/.config/rncp/"+allowed_file_name)):
|
||||
allowed_file = os.path.expanduser("~/.config/rncp/"+allowed_file_name)
|
||||
elif os.path.isfile(os.path.expanduser("~/.rncp/"+allowed_file_name)):
|
||||
allowed_file = os.path.expanduser("~/.rncp/"+allowed_file_name)
|
||||
if allowed_file != None:
|
||||
af = open(allowed_file, "r")
|
||||
al = af.read().replace("\r", "").split("\n")
|
||||
ali = []
|
||||
for a in al:
|
||||
if len(a) == dest_len:
|
||||
ali.append(a)
|
||||
|
||||
if len(ali) > 0:
|
||||
if not allowed:
|
||||
allowed = ali
|
||||
else:
|
||||
allowed.extend(ali)
|
||||
if len(ali) == 1:
|
||||
ms = "y"
|
||||
else:
|
||||
ms = "ies"
|
||||
|
||||
RNS.log("Loaded "+str(len(ali))+" allowed identit"+ms+" from "+str(allowed_file), RNS.LOG_VERBOSE)
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Error while parsing allowed_identities file. The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
if allowed != None:
|
||||
for a in allowed:
|
||||
try:
|
||||
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||
if len(a) != dest_len:
|
||||
raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2))
|
||||
try:
|
||||
@@ -78,16 +114,60 @@ def receive(configdir, verbosity = 0, quietness = 0, allowed = [], display_ident
|
||||
if len(allowed_identity_hashes) < 1 and not disable_auth:
|
||||
print("Warning: No allowed identities configured, rncp will not accept any files!")
|
||||
|
||||
destination.set_link_established_callback(receive_link_established)
|
||||
print("rncp ready to receive on "+RNS.prettyhexrep(destination.hash))
|
||||
def fetch_request(path, data, request_id, link_id, remote_identity, requested_at):
|
||||
target_link = None
|
||||
for link in RNS.Transport.active_links:
|
||||
if link.link_id == link_id:
|
||||
target_link = link
|
||||
|
||||
if not disable_announce:
|
||||
destination.announce()
|
||||
file_path = os.path.expanduser(data)
|
||||
if not os.path.isfile(file_path):
|
||||
RNS.log("Client-requested file not found: "+str(file_path), RNS.LOG_VERBOSE)
|
||||
return False
|
||||
else:
|
||||
if target_link != None:
|
||||
RNS.log("Sending file "+str(file_path)+" to client", RNS.LOG_VERBOSE)
|
||||
|
||||
temp_file = TemporaryFile()
|
||||
real_file = open(file_path, "rb")
|
||||
filename_bytes = os.path.basename(file_path).encode("utf-8")
|
||||
filename_len = len(filename_bytes)
|
||||
|
||||
if filename_len > 0xFFFF:
|
||||
print("Filename exceeds max size, cannot send")
|
||||
exit(1)
|
||||
else:
|
||||
print("Preparing file...", end=" ")
|
||||
|
||||
temp_file.write(filename_len.to_bytes(2, "big"))
|
||||
temp_file.write(filename_bytes)
|
||||
temp_file.write(real_file.read())
|
||||
temp_file.seek(0)
|
||||
|
||||
fetch_resource = RNS.Resource(temp_file, target_link)
|
||||
return True
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
destination.set_link_established_callback(client_link_established)
|
||||
destination.register_request_handler("fetch_file", response_generator=fetch_request, allow=RNS.Destination.ALLOW_LIST, allowed_list=allowed_identity_hashes)
|
||||
print("rncp listening on "+RNS.prettyhexrep(destination.hash))
|
||||
|
||||
if announce >= 0:
|
||||
def job():
|
||||
destination.announce()
|
||||
if announce > 0:
|
||||
while True:
|
||||
time.sleep(announce)
|
||||
destination.announce()
|
||||
|
||||
threading.Thread(target=job, daemon=True).start()
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
def receive_link_established(link):
|
||||
def client_link_established(link):
|
||||
RNS.log("Incoming link established", RNS.LOG_VERBOSE)
|
||||
link.set_remote_identified_callback(receive_sender_identified)
|
||||
link.set_resource_strategy(RNS.Link.ACCEPT_APP)
|
||||
@@ -181,7 +261,221 @@ def sender_progress(resource):
|
||||
resource_done = True
|
||||
|
||||
link = None
|
||||
def send(configdir, verbosity = 0, quietness = 0, destination = None, file = None, timeout = RNS.Transport.PATH_REQUEST_TIMEOUT):
|
||||
def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = None, timeout = RNS.Transport.PATH_REQUEST_TIMEOUT, silent=False):
|
||||
global current_resource, resource_done, link, speed
|
||||
targetloglevel = 3+verbosity-quietness
|
||||
|
||||
try:
|
||||
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||
if len(destination) != dest_len:
|
||||
raise ValueError("Allowed destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2))
|
||||
try:
|
||||
destination_hash = bytes.fromhex(destination)
|
||||
except Exception as e:
|
||||
raise ValueError("Invalid destination entered. Check your input.")
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
exit(1)
|
||||
|
||||
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
|
||||
|
||||
identity_path = RNS.Reticulum.identitypath+"/"+APP_NAME
|
||||
if os.path.isfile(identity_path):
|
||||
identity = RNS.Identity.from_file(identity_path)
|
||||
if identity == None:
|
||||
RNS.log("Could not load identity for rncp. The identity file at \""+str(identity_path)+"\" may be corrupt or unreadable.", RNS.LOG_ERROR)
|
||||
exit(2)
|
||||
else:
|
||||
identity = None
|
||||
|
||||
if identity == None:
|
||||
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
||||
identity = RNS.Identity()
|
||||
identity.to_file(identity_path)
|
||||
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
RNS.Transport.request_path(destination_hash)
|
||||
if silent:
|
||||
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested")
|
||||
else:
|
||||
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
i = 0
|
||||
syms = "⢄⢂⢁⡁⡈⡐⡠"
|
||||
estab_timeout = time.time()+timeout
|
||||
while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout:
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
if silent:
|
||||
print("Path not found")
|
||||
else:
|
||||
print("\r \rPath not found")
|
||||
exit(1)
|
||||
else:
|
||||
if silent:
|
||||
print("Establishing link with "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("\r \rEstablishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=" ")
|
||||
|
||||
listener_identity = RNS.Identity.recall(destination_hash)
|
||||
listener_destination = RNS.Destination(
|
||||
listener_identity,
|
||||
RNS.Destination.OUT,
|
||||
RNS.Destination.SINGLE,
|
||||
APP_NAME,
|
||||
"receive"
|
||||
)
|
||||
|
||||
link = RNS.Link(listener_destination)
|
||||
while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout:
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
if silent:
|
||||
print("Could not establish link with "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("\r \rCould not establish link with "+RNS.prettyhexrep(destination_hash))
|
||||
exit(1)
|
||||
else:
|
||||
if silent:
|
||||
print("Requesting file from remote...")
|
||||
else:
|
||||
print("\r \rRequesting file from remote ", end=" ")
|
||||
|
||||
link.identify(identity)
|
||||
|
||||
request_resolved = False
|
||||
request_status = "unknown"
|
||||
resource_resolved = False
|
||||
resource_status = "unrequested"
|
||||
current_resource = None
|
||||
def request_response(request_receipt):
|
||||
nonlocal request_resolved, request_status
|
||||
if request_receipt.response == False:
|
||||
request_status = "not_found"
|
||||
elif request_receipt.response == None:
|
||||
request_status = "remote_error"
|
||||
else:
|
||||
request_status = "found"
|
||||
|
||||
request_resolved = True
|
||||
|
||||
def request_failed(request_receipt):
|
||||
nonlocal request_resolved, request_status
|
||||
request_status = "unknown"
|
||||
request_resolved = True
|
||||
|
||||
def fetch_resource_started(resource):
|
||||
nonlocal resource_status
|
||||
current_resource = resource
|
||||
current_resource.progress_callback(sender_progress)
|
||||
resource_status = "started"
|
||||
|
||||
def fetch_resource_concluded(resource):
|
||||
nonlocal resource_resolved, resource_status
|
||||
if resource.status == RNS.Resource.COMPLETE:
|
||||
if resource.total_size > 4:
|
||||
filename_len = int.from_bytes(resource.data.read(2), "big")
|
||||
filename = resource.data.read(filename_len).decode("utf-8")
|
||||
|
||||
counter = 0
|
||||
saved_filename = filename
|
||||
while os.path.isfile(saved_filename):
|
||||
counter += 1
|
||||
saved_filename = filename+"."+str(counter)
|
||||
|
||||
file = open(saved_filename, "wb")
|
||||
file.write(resource.data.read())
|
||||
file.close()
|
||||
resource_status = "completed"
|
||||
|
||||
else:
|
||||
print("Invalid data received, ignoring resource")
|
||||
resource_status = "invalid_data"
|
||||
|
||||
else:
|
||||
print("Resource failed")
|
||||
resource_status = "failed"
|
||||
|
||||
resource_resolved = True
|
||||
|
||||
link.set_resource_strategy(RNS.Link.ACCEPT_ALL)
|
||||
link.set_resource_started_callback(fetch_resource_started)
|
||||
link.set_resource_concluded_callback(fetch_resource_concluded)
|
||||
link.request("fetch_file", data=file, response_callback=request_response, failed_callback=request_failed)
|
||||
|
||||
syms = "⢄⢂⢁⡁⡈⡐⡠"
|
||||
while not request_resolved:
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if request_status == "not_found":
|
||||
if not silent: print("\r \r", end="")
|
||||
print("Fetch request failed, the file "+str(file)+" was not found on the remote")
|
||||
link.teardown()
|
||||
time.sleep(1)
|
||||
exit(0)
|
||||
elif request_status == "remote_error":
|
||||
if not silent: print("\r \r", end="")
|
||||
print("Fetch request failed due to an error on the remote system")
|
||||
link.teardown()
|
||||
time.sleep(1)
|
||||
exit(0)
|
||||
elif request_status == "unknown":
|
||||
if not silent: print("\r \r", end="")
|
||||
print("Fetch request failed due to an unknown error (probably not authorised)")
|
||||
link.teardown()
|
||||
time.sleep(1)
|
||||
exit(0)
|
||||
elif request_status == "found":
|
||||
if not silent: print("\r \r", end="")
|
||||
|
||||
while not resource_resolved:
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
if current_resource:
|
||||
prg = current_resource.get_progress()
|
||||
percent = round(prg * 100.0, 1)
|
||||
stat_str = str(percent)+"% - " + size_str(int(prg*current_resource.total_size)) + " of " + size_str(current_resource.total_size) + " - " +size_str(speed, "b")+"ps"
|
||||
print("\r \rTransferring file "+syms[i]+" "+stat_str, end=" ")
|
||||
else:
|
||||
print("\r \rWaiting for transfer to start "+syms[i]+" ", end=" ")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if current_resource.status != RNS.Resource.COMPLETE:
|
||||
if silent:
|
||||
print("The transfer failed")
|
||||
else:
|
||||
print("\r \rThe transfer failed")
|
||||
exit(1)
|
||||
else:
|
||||
if silent:
|
||||
print(str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("\r \r"+str(file)+" fetched from "+RNS.prettyhexrep(destination_hash))
|
||||
link.teardown()
|
||||
time.sleep(0.25)
|
||||
exit(0)
|
||||
|
||||
link.teardown()
|
||||
exit(0)
|
||||
|
||||
|
||||
def send(configdir, verbosity = 0, quietness = 0, destination = None, file = None, timeout = RNS.Transport.PATH_REQUEST_TIMEOUT, silent=False):
|
||||
global current_resource, resource_done, link, speed
|
||||
from tempfile import TemporaryFile
|
||||
targetloglevel = 3+verbosity-quietness
|
||||
@@ -240,23 +534,33 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
RNS.Transport.request_path(destination_hash)
|
||||
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ")
|
||||
if silent:
|
||||
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested")
|
||||
else:
|
||||
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
i = 0
|
||||
syms = "⢄⢂⢁⡁⡈⡐⡠"
|
||||
estab_timeout = time.time()+timeout
|
||||
while not RNS.Transport.has_path(destination_hash) and time.time() < estab_timeout:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
print("\r \rPath not found")
|
||||
if silent:
|
||||
print("Path not found")
|
||||
else:
|
||||
print("\r \rPath not found")
|
||||
exit(1)
|
||||
else:
|
||||
print("\r \rEstablishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=" ")
|
||||
if silent:
|
||||
print("Establishing link with "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("\r \rEstablishing link with "+RNS.prettyhexrep(destination_hash)+" ", end=" ")
|
||||
|
||||
receiver_identity = RNS.Identity.recall(destination_hash)
|
||||
receiver_destination = RNS.Destination(
|
||||
@@ -269,48 +573,75 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
|
||||
link = RNS.Link(receiver_destination)
|
||||
while link.status != RNS.Link.ACTIVE and time.time() < estab_timeout:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
print("\r \rCould not establish link with "+RNS.prettyhexrep(destination_hash))
|
||||
if time.time() > estab_timeout:
|
||||
if silent:
|
||||
print("Link establishment with "+RNS.prettyhexrep(destination_hash)+" timed out")
|
||||
else:
|
||||
print("\r \rLink establishment with "+RNS.prettyhexrep(destination_hash)+" timed out")
|
||||
exit(1)
|
||||
elif not RNS.Transport.has_path(destination_hash):
|
||||
if silent:
|
||||
print("No path found to "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("\r \rNo path found to "+RNS.prettyhexrep(destination_hash))
|
||||
exit(1)
|
||||
else:
|
||||
print("\r \rAdvertising file resource ", end=" ")
|
||||
if silent:
|
||||
print("Advertising file resource...")
|
||||
else:
|
||||
print("\r \rAdvertising file resource ", end=" ")
|
||||
|
||||
link.identify(identity)
|
||||
resource = RNS.Resource(temp_file, link, callback = sender_progress, progress_callback = sender_progress)
|
||||
current_resource = resource
|
||||
|
||||
while resource.status < RNS.Resource.TRANSFERRING:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
|
||||
if resource.status > RNS.Resource.COMPLETE:
|
||||
print("\r \rFile was not accepted by "+RNS.prettyhexrep(destination_hash))
|
||||
if silent:
|
||||
print("File was not accepted by "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("\r \rFile was not accepted by "+RNS.prettyhexrep(destination_hash))
|
||||
exit(1)
|
||||
else:
|
||||
print("\r \rTransferring file ", end=" ")
|
||||
if silent:
|
||||
print("Transferring file...")
|
||||
else:
|
||||
print("\r \rTransferring file ", end=" ")
|
||||
|
||||
while not resource_done:
|
||||
time.sleep(0.1)
|
||||
prg = current_resource.get_progress()
|
||||
percent = round(prg * 100.0, 1)
|
||||
stat_str = str(percent)+"% - " + size_str(int(prg*current_resource.total_size)) + " of " + size_str(current_resource.total_size) + " - " +size_str(speed, "b")+"ps"
|
||||
print("\r \rTransferring file "+syms[i]+" "+stat_str, end=" ")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
if not silent:
|
||||
time.sleep(0.1)
|
||||
prg = current_resource.get_progress()
|
||||
percent = round(prg * 100.0, 1)
|
||||
stat_str = str(percent)+"% - " + size_str(int(prg*current_resource.total_size)) + " of " + size_str(current_resource.total_size) + " - " +size_str(speed, "b")+"ps"
|
||||
print("\r \rTransferring file "+syms[i]+" "+stat_str, end=" ")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if current_resource.status != RNS.Resource.COMPLETE:
|
||||
print("\r \rThe transfer failed")
|
||||
if silent:
|
||||
print("The transfer failed")
|
||||
else:
|
||||
print("\r \rThe transfer failed")
|
||||
exit(1)
|
||||
else:
|
||||
print("\r \r"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash))
|
||||
if silent:
|
||||
print(str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("\r \r"+str(file_path)+" copied to "+RNS.prettyhexrep(destination_hash))
|
||||
link.teardown()
|
||||
time.sleep(0.25)
|
||||
real_file.close()
|
||||
@@ -325,19 +656,21 @@ def main():
|
||||
parser.add_argument("--config", metavar="path", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0, help="increase verbosity")
|
||||
parser.add_argument('-q', '--quiet', action='count', default=0, help="decrease verbosity")
|
||||
parser.add_argument('-p', '--print-identity', action='store_true', default=False, help="print identity and destination info and exit")
|
||||
parser.add_argument("-r", '--receive', action='store_true', default=False, help="wait for incoming files")
|
||||
parser.add_argument("-b", '--no-announce', action='store_true', default=False, help="don't announce at program start")
|
||||
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("-f", '--fetch', action='store_true', default=False, help="fetch file from remote listener instead of sending")
|
||||
parser.add_argument("-b", action='store', metavar="seconds", default=-1, help="announce interval, 0 to only announce at startup", type=int)
|
||||
parser.add_argument('-a', metavar="allowed_hash", dest="allowed", action='append', help="accept from this identity", type=str)
|
||||
parser.add_argument('-n', '--no-auth', action='store_true', default=False, help="accept files from anyone")
|
||||
parser.add_argument('-p', '--print-identity', action='store_true', default=False, help="print identity and destination info and exit")
|
||||
parser.add_argument("-w", action="store", metavar="seconds", type=float, help="sender timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
||||
# parser.add_argument("--limit", action="store", metavar="files", type=float, help="maximum number of files to accept", default=None)
|
||||
parser.add_argument("--version", action="version", version="rncp {version}".format(version=__version__))
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.receive or args.print_identity:
|
||||
receive(
|
||||
if args.listen or args.print_identity:
|
||||
listen(
|
||||
configdir = args.config,
|
||||
verbosity=args.verbose,
|
||||
quietness=args.quiet,
|
||||
@@ -345,9 +678,25 @@ def main():
|
||||
display_identity=args.print_identity,
|
||||
# limit=args.limit,
|
||||
disable_auth=args.no_auth,
|
||||
disable_announce=args.no_announce,
|
||||
announce=args.b,
|
||||
)
|
||||
|
||||
elif args.fetch:
|
||||
if args.destination != None and args.file != None:
|
||||
fetch(
|
||||
configdir = args.config,
|
||||
verbosity = args.verbose,
|
||||
quietness = args.quiet,
|
||||
destination = args.destination,
|
||||
file = args.file,
|
||||
timeout = args.w,
|
||||
silent = args.silent,
|
||||
)
|
||||
else:
|
||||
print("")
|
||||
parser.print_help()
|
||||
print("")
|
||||
|
||||
elif args.destination != None and args.file != None:
|
||||
send(
|
||||
configdir = args.config,
|
||||
@@ -356,6 +705,7 @@ def main():
|
||||
destination = args.destination,
|
||||
file = args.file,
|
||||
timeout = args.w,
|
||||
silent = args.silent,
|
||||
)
|
||||
|
||||
else:
|
||||
|
||||
@@ -166,8 +166,8 @@ def main():
|
||||
RNS.log("Identity request timed out", RNS.LOG_ERROR)
|
||||
exit(6)
|
||||
else:
|
||||
RNS.log("Received Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash)+" from the network")
|
||||
identity = RNS.Identity.recall(destination_hash)
|
||||
RNS.log("Received Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash)+" from the network")
|
||||
|
||||
else:
|
||||
RNS.log("Recalled Identity "+str(identity)+" for destination "+RNS.prettyhexrep(destination_hash))
|
||||
@@ -196,7 +196,7 @@ def main():
|
||||
if args.hash:
|
||||
try:
|
||||
aspects = args.hash.split(".")
|
||||
if not len(aspects) > 1:
|
||||
if not len(aspects) > 0:
|
||||
RNS.log("Invalid destination aspects specified", RNS.LOG_ERROR)
|
||||
exit(32)
|
||||
else:
|
||||
|
||||
Regular → Executable
+68
-29
@@ -41,7 +41,7 @@ import RNS
|
||||
RNS.logtimefmt = "%H:%M:%S"
|
||||
RNS.compact_log_fmt = True
|
||||
|
||||
program_version = "2.1.2"
|
||||
program_version = "2.1.3"
|
||||
eth_addr = "0x81F7B979fEa6134bA9FD5c701b3501A2e61E897a"
|
||||
btc_addr = "3CPmacGm34qYvR6XWLVEJmi2aNe3PZqUuq"
|
||||
xmr_addr = "87HcDx6jRSkMQ9nPRd5K9hGGpZLn2s7vWETjMaVM5KfV4TD36NcYa8J8WSxhTSvBzzFpqDwp2fg5GX2moZ7VAP9QMZCZGET"
|
||||
@@ -80,6 +80,7 @@ class KISS():
|
||||
CMD_BLINK = 0x30
|
||||
CMD_RANDOM = 0x40
|
||||
CMD_DISP_INT = 0x45
|
||||
CMD_DISP_ADR = 0x63
|
||||
CMD_BT_CTRL = 0x46
|
||||
CMD_BT_PIN = 0x62
|
||||
CMD_BOARD = 0x47
|
||||
@@ -237,6 +238,7 @@ try:
|
||||
EXT_DIR = CNF_DIR+"/extracted"
|
||||
RT_PATH = CNF_DIR+"/recovery_esptool.py"
|
||||
TK_DIR = CNF_DIR+"/trusted_keys"
|
||||
ROM_DIR = CNF_DIR+"/eeprom"
|
||||
|
||||
if not os.path.isdir(CNF_DIR):
|
||||
os.makedirs(CNF_DIR)
|
||||
@@ -248,6 +250,8 @@ try:
|
||||
os.makedirs(EXT_DIR)
|
||||
if not os.path.isdir(TK_DIR):
|
||||
os.makedirs(TK_DIR)
|
||||
if not os.path.isdir(ROM_DIR):
|
||||
os.makedirs(ROM_DIR)
|
||||
|
||||
except Exception as e:
|
||||
print("No access to directory "+str(CNF_DIR)+". This utility needs file system access to store firmware and data files. Cannot continue.")
|
||||
@@ -574,7 +578,14 @@ class RNode():
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_INT])+data+bytes([KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while sending bluetooth enable command to device")
|
||||
raise IOError("An IO error occurred while sending display intensity command to device")
|
||||
|
||||
def set_display_address(self, address):
|
||||
data = bytes([address & 0xFF])
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_DISP_ADR])+data+bytes([KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise IOError("An IO error occurred while sending display address command to device")
|
||||
|
||||
def enable_bluetooth(self):
|
||||
kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND])
|
||||
@@ -1131,7 +1142,8 @@ def main():
|
||||
parser.add_argument("-e", "--extract", action="store_true", help="Extract firmware from connected RNode for later use")
|
||||
parser.add_argument("-E", "--use-extracted", action="store_true", help="Use the extracted firmware for autoinstallation or update")
|
||||
parser.add_argument("-C", "--clear-cache", action="store_true", help="Clear locally cached firmware files")
|
||||
|
||||
parser.add_argument("--baud-flash", action="store", metavar="baud_flash", type=str, default="921600", help="Set specific baud rate when flashing device. Default is 921600")
|
||||
|
||||
parser.add_argument("-N", "--normal", action="store_true", help="Switch device to normal mode")
|
||||
parser.add_argument("-T", "--tnc", action="store_true", help="Switch device to TNC mode")
|
||||
|
||||
@@ -1140,6 +1152,7 @@ def main():
|
||||
parser.add_argument("-p", "--bluetooth-pair", action="store_true", help="Put device into bluetooth pairing mode")
|
||||
|
||||
parser.add_argument("-D", "--display", action="store", metavar="i", type=int, default=None, help="Set display intensity (0-255)")
|
||||
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("--freq", action="store", metavar="Hz", type=int, default=None, help="Frequency in Hz for TNC mode")
|
||||
parser.add_argument("--bw", action="store", metavar="Hz", type=int, default=None, help="Bandwidth in Hz for TNC mode")
|
||||
@@ -1348,11 +1361,11 @@ def main():
|
||||
hash_f.close()
|
||||
|
||||
extraction_parts = [
|
||||
("bootloader", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud 921600 --before default_reset --after hard_reset read_flash 0x1000 0x4650 \""+EXT_DIR+"/extracted_rnode_firmware.bootloader\""),
|
||||
("partition table", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud 921600 --before default_reset --after hard_reset read_flash 0x8000 0xC00 \""+EXT_DIR+"/extracted_rnode_firmware.partitions\""),
|
||||
("app boot", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud 921600 --before default_reset --after hard_reset read_flash 0xe000 0x2000 \""+EXT_DIR+"/extracted_rnode_firmware.boot_app0\""),
|
||||
("application image", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud 921600 --before default_reset --after hard_reset read_flash 0x10000 0x200000 \""+EXT_DIR+"/extracted_rnode_firmware.bin\""),
|
||||
("console image", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud 921600 --before default_reset --after hard_reset read_flash 0x210000 0x1F0000 \""+EXT_DIR+"/extracted_console_image.bin\""),
|
||||
("bootloader", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x1000 0x4650 \""+EXT_DIR+"/extracted_rnode_firmware.bootloader\""),
|
||||
("partition table", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x8000 0xC00 \""+EXT_DIR+"/extracted_rnode_firmware.partitions\""),
|
||||
("app boot", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0xe000 0x2000 \""+EXT_DIR+"/extracted_rnode_firmware.boot_app0\""),
|
||||
("application image", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x10000 0x200000 \""+EXT_DIR+"/extracted_rnode_firmware.bin\""),
|
||||
("console image", "python \""+CNF_DIR+"/recovery_esptool.py\" --chip esp32 --port "+port_path+" --baud "+args.baud_flash+" --before default_reset --after hard_reset read_flash 0x210000 0x1F0000 \""+EXT_DIR+"/extracted_console_image.bin\""),
|
||||
]
|
||||
import subprocess, shlex
|
||||
for part, command in extraction_parts:
|
||||
@@ -2055,7 +2068,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2073,7 +2086,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2091,7 +2104,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2109,7 +2122,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2127,7 +2140,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2145,7 +2158,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2163,7 +2176,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2181,7 +2194,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2199,7 +2212,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2217,7 +2230,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2235,7 +2248,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2253,7 +2266,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2271,7 +2284,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2289,7 +2302,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2307,7 +2320,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2325,7 +2338,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2343,7 +2356,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2361,7 +2374,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2378,7 +2391,7 @@ def main():
|
||||
sys.executable, flasher,
|
||||
"--chip", "esp32",
|
||||
"--port", args.port,
|
||||
"--baud", "921600",
|
||||
"--baud", args.baud_flash,
|
||||
"--before", "default_reset",
|
||||
"--after", "hard_reset",
|
||||
"write_flash", "-z",
|
||||
@@ -2466,6 +2479,10 @@ def main():
|
||||
RNS.log("Waiting for ESP32 reset...")
|
||||
time.sleep(7)
|
||||
else:
|
||||
RNS.log("Error from flasher ("+str(flash_status)+") while writing.")
|
||||
RNS.log("Some boards have trouble flashing at high speeds, and you can")
|
||||
RNS.log("try flashing with a lower baud rate, as in this example:")
|
||||
RNS.log("rnodeconf --autoinstall --baud-flash 115200")
|
||||
exit()
|
||||
|
||||
except Exception as e:
|
||||
@@ -2604,7 +2621,11 @@ def main():
|
||||
vf.close()
|
||||
else:
|
||||
partition_filename = fw_filename.replace(".zip", ".bin")
|
||||
partition_hash = get_partition_hash(UPD_DIR+"/"+selected_version+"/"+partition_filename)
|
||||
if fw_filename == "extracted_rnode_firmware.zip":
|
||||
partition_full_path = EXT_DIR+"/extracted_rnode_firmware.bin"
|
||||
else:
|
||||
partition_full_path = UPD_DIR+"/"+selected_version+"/"+partition_filename
|
||||
partition_hash = get_partition_hash(partition_full_path)
|
||||
if partition_hash != None:
|
||||
rnode.set_firmware_hash(partition_hash)
|
||||
rnode.indicate_firmware_update()
|
||||
@@ -2673,7 +2694,7 @@ def main():
|
||||
try:
|
||||
timestamp = time.time()
|
||||
filename = str(time.strftime("%Y-%m-%d_%H-%M-%S"))
|
||||
path = "./eeprom/"+filename+".eeprom"
|
||||
path = ROM_DIR + filename + ".eeprom"
|
||||
file = open(path, "wb")
|
||||
file.write(rnode.eeprom)
|
||||
file.close()
|
||||
@@ -2692,6 +2713,24 @@ def main():
|
||||
RNS.log("Setting display intensity to "+str(di))
|
||||
rnode.set_display_intensity(di)
|
||||
|
||||
if isinstance(args.display_addr, str):
|
||||
set_addr = False
|
||||
try:
|
||||
if args.display_addr.startswith("0x"):
|
||||
args.display_addr = args.display_addr[2:]
|
||||
da = bytes.fromhex(args.display_addr)
|
||||
set_addr = True
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
if set_addr and len(da) == 1:
|
||||
RNS.log("Setting display address to "+RNS.hexrep(da, delimit=False))
|
||||
rnode.set_display_address(ord(da))
|
||||
rnode.hard_reset()
|
||||
exit()
|
||||
else:
|
||||
RNS.log("Invalid display address specified")
|
||||
|
||||
if args.bluetooth_on:
|
||||
RNS.log("Enabling Bluetooth...")
|
||||
rnode.enable_bluetooth()
|
||||
|
||||
+45
-9
@@ -30,7 +30,7 @@ import argparse
|
||||
from RNS._version import __version__
|
||||
|
||||
|
||||
def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, timeout, drop_queues):
|
||||
def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity, timeout, drop_queues, drop_via):
|
||||
if table:
|
||||
destination_hash = None
|
||||
if destination_hexhash != None:
|
||||
@@ -155,6 +155,29 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
elif drop_via:
|
||||
try:
|
||||
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||
if len(destination_hexhash) != dest_len:
|
||||
raise ValueError("Destination length is invalid, must be {hex} hexadecimal characters ({byte} bytes).".format(hex=dest_len, byte=dest_len//2))
|
||||
try:
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except Exception as e:
|
||||
raise ValueError("Invalid destination entered. Check your input.")
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
|
||||
|
||||
if reticulum.drop_all_via(destination_hash):
|
||||
print("Dropped all paths via "+RNS.prettyhexrep(destination_hash))
|
||||
else:
|
||||
print("Unable to drop paths via "+RNS.prettyhexrep(destination_hash)+". Does the transport instance exist?")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
else:
|
||||
try:
|
||||
dest_len = (RNS.Reticulum.TRUNCATED_HASHLENGTH//8)*2
|
||||
@@ -187,15 +210,20 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
||||
|
||||
if RNS.Transport.has_path(destination_hash):
|
||||
hops = RNS.Transport.hops_to(destination_hash)
|
||||
next_hop = RNS.prettyhexrep(reticulum.get_next_hop(destination_hash))
|
||||
next_hop_interface = reticulum.get_next_hop_if_name(destination_hash)
|
||||
|
||||
if hops != 1:
|
||||
ms = "s"
|
||||
next_hop_bytes = reticulum.get_next_hop(destination_hash)
|
||||
if next_hop_bytes == None:
|
||||
print("\r \rError: Invalid path data returned")
|
||||
sys.exit(1)
|
||||
else:
|
||||
ms = ""
|
||||
next_hop = RNS.prettyhexrep(next_hop_bytes)
|
||||
next_hop_interface = reticulum.get_next_hop_if_name(destination_hash)
|
||||
|
||||
print("\rPath found, destination "+RNS.prettyhexrep(destination_hash)+" is "+str(hops)+" hop"+ms+" away via "+next_hop+" on "+next_hop_interface)
|
||||
if hops != 1:
|
||||
ms = "s"
|
||||
else:
|
||||
ms = ""
|
||||
|
||||
print("\rPath found, destination "+RNS.prettyhexrep(destination_hash)+" is "+str(hops)+" hop"+ms+" away via "+next_hop+" on "+next_hop_interface)
|
||||
else:
|
||||
print("\r \rPath not found")
|
||||
sys.exit(1)
|
||||
@@ -251,6 +279,13 @@ def main():
|
||||
default=False
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-x", "--drop-via",
|
||||
action="store_true",
|
||||
help="drop all paths via specified transport instance",
|
||||
default=False
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-w",
|
||||
action="store",
|
||||
@@ -277,7 +312,7 @@ def main():
|
||||
else:
|
||||
configarg = None
|
||||
|
||||
if not args.drop_announces and not args.table and not args.rates and not args.destination:
|
||||
if not args.drop_announces and not args.table and not args.rates and not args.destination and not args.drop_via:
|
||||
print("")
|
||||
parser.print_help()
|
||||
print("")
|
||||
@@ -291,6 +326,7 @@ def main():
|
||||
verbosity = args.verbose,
|
||||
timeout = args.w,
|
||||
drop_queues = args.drop_announces,
|
||||
drop_via = args.drop_via,
|
||||
)
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
+73
-68
@@ -31,8 +31,10 @@ import argparse
|
||||
from RNS._version import __version__
|
||||
|
||||
DEFAULT_PROBE_SIZE = 16
|
||||
DEFAULT_TIMEOUT = 15
|
||||
|
||||
def program_setup(configdir, destination_hexhash, size=DEFAULT_PROBE_SIZE, full_name = None, verbosity = 0):
|
||||
def program_setup(configdir, destination_hexhash, size=None, full_name = None, verbosity = 0, timeout=None):
|
||||
if size == None: size = DEFAULT_PROBE_SIZE
|
||||
if full_name == None:
|
||||
print("The full destination name including application name aspects must be specified for the destination")
|
||||
exit()
|
||||
@@ -71,14 +73,19 @@ def program_setup(configdir, destination_hexhash, size=DEFAULT_PROBE_SIZE, full_
|
||||
print("Path to "+RNS.prettyhexrep(destination_hash)+" requested ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
_timeout = time.time() + (timeout or DEFAULT_TIMEOUT)
|
||||
i = 0
|
||||
syms = "⢄⢂⢁⡁⡈⡐⡠"
|
||||
while not RNS.Transport.has_path(destination_hash):
|
||||
while not RNS.Transport.has_path(destination_hash) and not time.time() > _timeout:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if time.time() > _timeout:
|
||||
print("\r \rPath request timed out")
|
||||
exit(1)
|
||||
|
||||
server_identity = RNS.Identity.recall(destination_hash)
|
||||
|
||||
request_destination = RNS.Destination(
|
||||
@@ -89,66 +96,85 @@ def program_setup(configdir, destination_hexhash, size=DEFAULT_PROBE_SIZE, full_
|
||||
*aspects
|
||||
)
|
||||
|
||||
probe = RNS.Packet(request_destination, os.urandom(size))
|
||||
try:
|
||||
probe = RNS.Packet(request_destination, os.urandom(size))
|
||||
probe.pack()
|
||||
except OSError:
|
||||
print("Error: Probe packet size of "+str(len(probe.raw))+" bytes exceed MTU of "+str(RNS.Reticulum.MTU)+" bytes")
|
||||
exit(3)
|
||||
|
||||
receipt = probe.send()
|
||||
|
||||
if more_output:
|
||||
more = " via "+RNS.prettyhexrep(reticulum.get_next_hop(destination_hash))+" on "+str(reticulum.get_next_hop_if_name(destination_hash))
|
||||
nhd = reticulum.get_next_hop(destination_hash)
|
||||
via_str = " via "+RNS.prettyhexrep(nhd) if nhd != None else ""
|
||||
if_str = " on "+str(reticulum.get_next_hop_if_name(destination_hash)) if reticulum.get_next_hop_if_name(destination_hash) != "None" else ""
|
||||
more = via_str+if_str
|
||||
else:
|
||||
more = ""
|
||||
|
||||
print("\rSent "+str(size)+" byte probe to "+RNS.prettyhexrep(destination_hash)+more+" ", end=" ")
|
||||
|
||||
_timeout = time.time() + (timeout or DEFAULT_TIMEOUT)
|
||||
i = 0
|
||||
while not receipt.status == RNS.PacketReceipt.DELIVERED:
|
||||
while receipt.status == RNS.PacketReceipt.SENT and not time.time() > _timeout:
|
||||
time.sleep(0.1)
|
||||
print(("\b\b"+syms[i]+" "), end="")
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
if time.time() > _timeout:
|
||||
print("\r \rProbe timed out")
|
||||
exit(2)
|
||||
|
||||
print("\b\b ")
|
||||
sys.stdout.flush()
|
||||
|
||||
hops = RNS.Transport.hops_to(destination_hash)
|
||||
if hops != 1:
|
||||
ms = "s"
|
||||
else:
|
||||
ms = ""
|
||||
if receipt.status == RNS.PacketReceipt.DELIVERED:
|
||||
hops = RNS.Transport.hops_to(destination_hash)
|
||||
if hops != 1:
|
||||
ms = "s"
|
||||
else:
|
||||
ms = ""
|
||||
|
||||
rtt = receipt.get_rtt()
|
||||
if (rtt >= 1):
|
||||
rtt = round(rtt, 3)
|
||||
rttstring = str(rtt)+" seconds"
|
||||
else:
|
||||
rtt = round(rtt*1000, 3)
|
||||
rttstring = str(rtt)+" milliseconds"
|
||||
rtt = receipt.get_rtt()
|
||||
if (rtt >= 1):
|
||||
rtt = round(rtt, 3)
|
||||
rttstring = str(rtt)+" seconds"
|
||||
else:
|
||||
rtt = round(rtt*1000, 3)
|
||||
rttstring = str(rtt)+" milliseconds"
|
||||
|
||||
reception_stats = ""
|
||||
if reticulum.is_connected_to_shared_instance:
|
||||
reception_rssi = reticulum.get_packet_rssi(receipt.proof_packet.packet_hash)
|
||||
reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash)
|
||||
reception_stats = ""
|
||||
if reticulum.is_connected_to_shared_instance:
|
||||
reception_rssi = reticulum.get_packet_rssi(receipt.proof_packet.packet_hash)
|
||||
reception_snr = reticulum.get_packet_snr(receipt.proof_packet.packet_hash)
|
||||
|
||||
if reception_rssi != None:
|
||||
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]"
|
||||
|
||||
if reception_snr != None:
|
||||
reception_stats += " [SNR "+str(reception_snr)+" dB]"
|
||||
|
||||
else:
|
||||
if receipt.proof_packet != None:
|
||||
if receipt.proof_packet.rssi != None:
|
||||
reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]"
|
||||
if reception_rssi != None:
|
||||
reception_stats += " [RSSI "+str(reception_rssi)+" dBm]"
|
||||
|
||||
if receipt.proof_packet.snr != None:
|
||||
reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]"
|
||||
if reception_snr != None:
|
||||
reception_stats += " [SNR "+str(reception_snr)+" dB]"
|
||||
|
||||
print(
|
||||
"Valid reply received from "+
|
||||
RNS.prettyhexrep(receipt.destination.hash)+
|
||||
"\nRound-trip time is "+rttstring+
|
||||
" over "+str(hops)+" hop"+ms+
|
||||
reception_stats
|
||||
)
|
||||
else:
|
||||
if receipt.proof_packet != None:
|
||||
if receipt.proof_packet.rssi != None:
|
||||
reception_stats += " [RSSI "+str(receipt.proof_packet.rssi)+" dBm]"
|
||||
|
||||
if receipt.proof_packet.snr != None:
|
||||
reception_stats += " [SNR "+str(receipt.proof_packet.snr)+" dB]"
|
||||
|
||||
print(
|
||||
"Valid reply received from "+
|
||||
RNS.prettyhexrep(receipt.destination.hash)+
|
||||
"\nRound-trip time is "+rttstring+
|
||||
" over "+str(hops)+" hop"+ms+
|
||||
reception_stats
|
||||
)
|
||||
|
||||
else:
|
||||
print("\r \rProbe timed out")
|
||||
exit(2)
|
||||
|
||||
|
||||
|
||||
@@ -156,34 +182,12 @@ def main():
|
||||
try:
|
||||
parser = argparse.ArgumentParser(description="Reticulum Probe Utility")
|
||||
|
||||
parser.add_argument("--config",
|
||||
action="store",
|
||||
default=None,
|
||||
help="path to alternative Reticulum config directory",
|
||||
type=str
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"--version",
|
||||
action="version",
|
||||
version="rnprobe {version}".format(version=__version__)
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"full_name",
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="full destination name in dotted notation",
|
||||
type=str
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"destination_hash",
|
||||
nargs="?",
|
||||
default=None,
|
||||
help="hexadecimal hash of the destination",
|
||||
type=str
|
||||
)
|
||||
parser.add_argument("--config", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
|
||||
parser.add_argument("-s", "--size", action="store", default=None, help="size of probe packet payload in bytes", type=int)
|
||||
parser.add_argument("-t", "--timeout", metavar="seconds", action="store", default=None, help="timeout before giving up", type=float)
|
||||
parser.add_argument("--version", action="version", version="rnprobe {version}".format(version=__version__))
|
||||
parser.add_argument("full_name", nargs="?", default=None, help="full destination name in dotted notation", type=str)
|
||||
parser.add_argument("destination_hash", nargs="?", default=None, help="hexadecimal hash of the destination", type=str)
|
||||
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||
|
||||
@@ -202,6 +206,7 @@ def main():
|
||||
program_setup(
|
||||
configdir = configarg,
|
||||
destination_hexhash = args.destination_hash,
|
||||
size = args.size,
|
||||
full_name = args.full_name,
|
||||
verbosity = args.verbose
|
||||
)
|
||||
|
||||
+13
-1
@@ -87,7 +87,7 @@ __example_rns_config__ = '''# This is an example Reticulum config file.
|
||||
# always-on. This directive is optional and can be removed
|
||||
# for brevity.
|
||||
|
||||
enable_transport = False
|
||||
enable_transport = No
|
||||
|
||||
|
||||
# By default, the first program to launch the Reticulum
|
||||
@@ -111,6 +111,7 @@ share_instance = Yes
|
||||
shared_instance_port = 37428
|
||||
instance_control_port = 37429
|
||||
|
||||
|
||||
# You can configure Reticulum to panic and forcibly close
|
||||
# if an unrecoverable interface error occurs, such as the
|
||||
# hardware device for an interface disappearing. This is
|
||||
@@ -120,6 +121,17 @@ instance_control_port = 37429
|
||||
panic_on_interface_error = No
|
||||
|
||||
|
||||
# When Transport is enabled, it is possible to allow the
|
||||
# Transport Instance to respond to probe requests from
|
||||
# the rnprobe utility. This can be a useful tool to test
|
||||
# connectivity. When this option is enabled, the probe
|
||||
# destination will be generated from the Identity of the
|
||||
# Transport Instance, and printed to the log at startup.
|
||||
# Optional, and disabled by default.
|
||||
|
||||
respond_to_probes = No
|
||||
|
||||
|
||||
[logging]
|
||||
# Valid log levels are 0 through 7:
|
||||
# 0: Log only critical information
|
||||
|
||||
+100
-24
@@ -46,7 +46,7 @@ def size_str(num, suffix='B'):
|
||||
|
||||
return "%.2f%s%s" % (num, last_unit, suffix)
|
||||
|
||||
def program_setup(configdir, dispall=False, verbosity=0, name_filter=None,json=False):
|
||||
def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=False, astats=False, sorting=None, sort_reverse=False):
|
||||
reticulum = RNS.Reticulum(configdir = configdir, loglevel = 3+verbosity)
|
||||
|
||||
stats = None
|
||||
@@ -62,16 +62,38 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None,json=F
|
||||
if isinstance(stats[s], bytes):
|
||||
stats[s] = RNS.hexrep(stats[s], delimit=False)
|
||||
|
||||
for i in stats[s]:
|
||||
if isinstance(i, dict):
|
||||
for k in i:
|
||||
if isinstance(i[k], bytes):
|
||||
i[k] = RNS.hexrep(i[k], delimit=False)
|
||||
if isinstance(stats[s], dict):
|
||||
for i in stats[s]:
|
||||
if isinstance(i, dict):
|
||||
for k in i:
|
||||
if isinstance(i[k], bytes):
|
||||
i[k] = RNS.hexrep(i[k], delimit=False)
|
||||
|
||||
print(json.dumps(stats))
|
||||
exit()
|
||||
|
||||
interfaces = stats["interfaces"]
|
||||
if sorting != None and isinstance(sorting, str):
|
||||
sorting = sorting.lower()
|
||||
if sorting == "rate" or sorting == "bitrate":
|
||||
interfaces.sort(key=lambda i: i["bitrate"], reverse=not sort_reverse)
|
||||
if sorting == "rx":
|
||||
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 == "traffic":
|
||||
interfaces.sort(key=lambda i: i["rxb"]+i["txb"], reverse=not sort_reverse)
|
||||
if sorting == "announces" or sorting == "announce":
|
||||
interfaces.sort(key=lambda i: i["incoming_announce_frequency"]+i["outgoing_announce_frequency"], reverse=not sort_reverse)
|
||||
if sorting == "arx":
|
||||
interfaces.sort(key=lambda i: i["incoming_announce_frequency"], reverse=not sort_reverse)
|
||||
if sorting == "atx":
|
||||
interfaces.sort(key=lambda i: i["outgoing_announce_frequency"], reverse=not sort_reverse)
|
||||
if sorting == "held":
|
||||
interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse)
|
||||
|
||||
|
||||
for ifstat in stats["interfaces"]:
|
||||
for ifstat in interfaces:
|
||||
name = ifstat["name"]
|
||||
|
||||
if dispall or not (
|
||||
@@ -113,7 +135,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None,json=F
|
||||
else:
|
||||
spec_str = " programs"
|
||||
|
||||
clients_string = "Serving : "+str(cnum)+spec_str
|
||||
clients_string = "Serving : "+str(cnum)+spec_str
|
||||
elif name.startswith("I2PInterface["):
|
||||
if "i2p_connectable" in ifstat and ifstat["i2p_connectable"] == True:
|
||||
cnum = clients
|
||||
@@ -122,11 +144,11 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None,json=F
|
||||
else:
|
||||
spec_str = " connected I2P endpoints"
|
||||
|
||||
clients_string = "Peers : "+str(cnum)+spec_str
|
||||
clients_string = "Peers : "+str(cnum)+spec_str
|
||||
else:
|
||||
clients_string = ""
|
||||
else:
|
||||
clients_string = "Clients : "+str(clients)
|
||||
clients_string = "Clients : "+str(clients)
|
||||
|
||||
else:
|
||||
clients = None
|
||||
@@ -134,43 +156,63 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None,json=F
|
||||
print(" {n}".format(n=ifstat["name"]))
|
||||
|
||||
if "ifac_netname" in ifstat and ifstat["ifac_netname"] != None:
|
||||
print(" Network : {nn}".format(nn=ifstat["ifac_netname"]))
|
||||
print(" Network : {nn}".format(nn=ifstat["ifac_netname"]))
|
||||
|
||||
print(" Status : {ss}".format(ss=ss))
|
||||
print(" Status : {ss}".format(ss=ss))
|
||||
|
||||
if clients != None and clients_string != "":
|
||||
print(" "+clients_string)
|
||||
|
||||
if not (name.startswith("Shared Instance[") or name.startswith("TCPInterface[Client") or name.startswith("LocalInterface[")):
|
||||
print(" Mode : {mode}".format(mode=modestr))
|
||||
print(" Mode : {mode}".format(mode=modestr))
|
||||
|
||||
if "bitrate" in ifstat and ifstat["bitrate"] != None:
|
||||
print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"])))
|
||||
print(" Rate : {ss}".format(ss=speed_str(ifstat["bitrate"])))
|
||||
|
||||
if "airtime_short" in ifstat and "airtime_long" in ifstat:
|
||||
print(" Airtime : {atl}% (1h), {ats}% (15s)".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 : {atl}% (1h), {ats}% (15s)".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"]))
|
||||
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
||||
|
||||
if "tunnelstate" in ifstat and ifstat["tunnelstate"] != None:
|
||||
print(" I2P : {ts}".format(ts=ifstat["tunnelstate"]))
|
||||
print(" I2P : {ts}".format(ts=ifstat["tunnelstate"]))
|
||||
|
||||
if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None:
|
||||
sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">"
|
||||
print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))
|
||||
print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))
|
||||
|
||||
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
||||
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
||||
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
||||
|
||||
if "announce_queue" in ifstat and ifstat["announce_queue"] != None and ifstat["announce_queue"] > 0:
|
||||
if astats and "announce_queue" in ifstat and ifstat["announce_queue"] != None and ifstat["announce_queue"] > 0:
|
||||
aqn = ifstat["announce_queue"]
|
||||
if aqn == 1:
|
||||
print(" Queued : {np} announce".format(np=aqn))
|
||||
print(" Queued : {np} announce".format(np=aqn))
|
||||
else:
|
||||
print(" Queued : {np} announces".format(np=aqn))
|
||||
print(" Queued : {np} announces".format(np=aqn))
|
||||
|
||||
print(" Traffic : {txb}↑\n {rxb}↓".format(rxb=size_str(ifstat["rxb"]), txb=size_str(ifstat["txb"])))
|
||||
if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0:
|
||||
aqn = ifstat["held_announces"]
|
||||
if aqn == 1:
|
||||
print(" Held : {np} announce".format(np=aqn))
|
||||
else:
|
||||
print(" Held : {np} announces".format(np=aqn))
|
||||
|
||||
if astats and "incoming_announce_frequency" in ifstat and ifstat["incoming_announce_frequency"] != None:
|
||||
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"])))
|
||||
|
||||
if "transport_id" in stats and stats["transport_id"] != None:
|
||||
print("\n Reticulum Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" is running")
|
||||
print("\n Transport Instance "+RNS.prettyhexrep(stats["transport_id"])+" running")
|
||||
if "probe_responder" in stats and stats["probe_responder"] != None:
|
||||
print(" Probe responder at "+RNS.prettyhexrep(stats["probe_responder"])+ " active")
|
||||
print(" Uptime is "+RNS.prettytime(stats["transport_uptime"]))
|
||||
|
||||
print("")
|
||||
|
||||
@@ -191,6 +233,31 @@ def main():
|
||||
default=False
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-A",
|
||||
"--announce-stats",
|
||||
action="store_true",
|
||||
help="show announce stats",
|
||||
default=False
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--sort",
|
||||
action="store",
|
||||
help="sort interfaces by [rate, traffic, rx, tx, announces, arx, atx, held]",
|
||||
default=None,
|
||||
type=str
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--reverse",
|
||||
action="store_true",
|
||||
help="reverse sorting",
|
||||
default=False,
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--json",
|
||||
@@ -210,7 +277,16 @@ def main():
|
||||
else:
|
||||
configarg = None
|
||||
|
||||
program_setup(configdir = configarg, dispall = args.all, verbosity=args.verbose, name_filter=args.filter, json=args.json)
|
||||
program_setup(
|
||||
configdir = configarg,
|
||||
dispall = args.all,
|
||||
verbosity=args.verbose,
|
||||
name_filter=args.filter,
|
||||
json=args.json,
|
||||
astats=args.announce_stats,
|
||||
sorting=args.sort,
|
||||
sort_reverse=args.reverse,
|
||||
)
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
|
||||
+14
-1
@@ -1,6 +1,6 @@
|
||||
# MIT License
|
||||
#
|
||||
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
||||
# Copyright (c) 2016-2023 Mark Qvist / unsigned.io and contributors
|
||||
#
|
||||
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
# of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -38,6 +38,7 @@ from .Transport import Transport
|
||||
from .Destination import Destination
|
||||
from .Packet import Packet
|
||||
from .Packet import PacketReceipt
|
||||
from .Resolver import Resolver
|
||||
from .Resource import Resource, ResourceAdvertisement
|
||||
from .Cryptography import HKDF
|
||||
from .Cryptography import Hashes
|
||||
@@ -179,6 +180,18 @@ def prettysize(num, suffix='B'):
|
||||
|
||||
return "%.2f%s%s" % (num, last_unit, suffix)
|
||||
|
||||
def prettyfrequency(hz, suffix="Hz"):
|
||||
num = hz*1e6
|
||||
units = ["µ", "m", "", "K","M","G","T","P","E","Z"]
|
||||
last_unit = "Y"
|
||||
|
||||
for unit in units:
|
||||
if abs(num) < 1000.0:
|
||||
return "%.2f %s%s" % (num, unit, suffix)
|
||||
num /= 1000.0
|
||||
|
||||
return "%.2f%s%s" % (num, last_unit, suffix)
|
||||
|
||||
def prettytime(time, verbose=False):
|
||||
days = int(time // (24 * 3600))
|
||||
time = time % (24 * 3600)
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
__version__ = "0.5.6"
|
||||
__version__ = "0.6.1"
|
||||
|
||||
+1
-1
@@ -17,6 +17,7 @@ For each release cycle of Reticulum, improvements and additions from the five [P
|
||||
- The current `0.5.x` release cycle aims at completing
|
||||
- [x] Reach feature-completion of the Reticulum API
|
||||
- [x] Improve performance and efficiency of the `Buffer` and `Channel` API
|
||||
- [x] Add bluetooth pairing code output to rnodeconf
|
||||
- [ ] Overhauling and updating the documentation
|
||||
- [ ] Performance and memory optimisations of the Python reference implementation
|
||||
- [ ] Fixing potential bugs
|
||||
@@ -74,7 +75,6 @@ These efforts aim to expand and improve the core functionality and reliability o
|
||||
### Usability & Utility
|
||||
These effors seek to make Reticulum easier to use and operate, and to expand the utility of the stack on deployed systems.
|
||||
|
||||
- Add bluetooth pairing code output to rnodeconf
|
||||
- Easy way to share interface configurations, see [#19](https://github.com/markqvist/Reticulum/discussions/19)
|
||||
- Transit traffic display in rnstatus
|
||||
- rnsconfig utility
|
||||
|
||||
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: cfbffc4eb01b7de3c908133b7794ac1c
|
||||
config: 5010fe6649ca8583894ff92c81cfc071
|
||||
tags: 645f666f9bcd5a90fca523b33c5a78b7
|
||||
|
||||
@@ -70,7 +70,8 @@ Remote Shell
|
||||
|
||||
The `rnsh <https://github.com/acehoss/rnsh>`_ program lets you establish fully interactive
|
||||
remote shell sessions over Reticulum. It also allows you to pipe any program to or from a
|
||||
remote system, and is similar to how ``ssh`` works.
|
||||
remote system, and is similar to how ``ssh`` works. The ``rnsh`` is very efficient, and
|
||||
can facilitate fully interactive shell sessions, even over extremely low-bandwidth links.
|
||||
|
||||
Nomad Network
|
||||
^^^^^^^^^^^^^
|
||||
@@ -219,11 +220,11 @@ by adding one of the following interfaces to your ``.reticulum/config`` file:
|
||||
|
||||
.. code::
|
||||
|
||||
# TCP/IP interface to the Dublin hub
|
||||
[[RNS Testnet Dublin]]
|
||||
# TCP/IP interface to the RNS Amsterdam Hub
|
||||
[[RNS Testnet Amsterdam]]
|
||||
type = TCPClientInterface
|
||||
enabled = yes
|
||||
target_host = dublin.connect.reticulum.network
|
||||
target_host = amsterdam.connect.reticulum.network
|
||||
target_port = 4965
|
||||
|
||||
# TCP/IP interface to the BetweenTheBorders Hub (community-provided)
|
||||
@@ -233,11 +234,11 @@ by adding one of the following interfaces to your ``.reticulum/config`` file:
|
||||
target_host = betweentheborders.com
|
||||
target_port = 4242
|
||||
|
||||
# Interface to I2P hub A
|
||||
[[RNS Testnet I2P Hub A]]
|
||||
# Interface to Testnet I2P Hub
|
||||
[[RNS Testnet I2P Hub]]
|
||||
type = I2PInterface
|
||||
enabled = yes
|
||||
peers = uxg5kubabakh3jtnvsipingbr5574dle7bubvip7llfvwx2tgrua.b32.i2p
|
||||
peers = g3br23bvx3lq5uddcsjii74xgmn6y5q325ovrkq2zw2wbzbqgbuq.b32.i2p
|
||||
|
||||
Many other Reticulum instances are connecting to this testnet, and you can also join it
|
||||
via other entry points if you know them. There is absolutely no control over the network
|
||||
@@ -281,7 +282,7 @@ started is to install the latest release of Reticulum via pip:
|
||||
|
||||
.. code::
|
||||
|
||||
pip3 install rns
|
||||
pip install rns
|
||||
|
||||
The above command will install Reticulum and dependencies, and you will be
|
||||
ready to import and use RNS in your own programs. The next step will most
|
||||
@@ -291,7 +292,7 @@ For extended functionality, you can install optional dependencies:
|
||||
|
||||
.. code::
|
||||
|
||||
pip3 install pyserial
|
||||
pip install pyserial
|
||||
|
||||
|
||||
Further information can be found in the :ref:`API Reference<api-main>`.
|
||||
@@ -306,7 +307,7 @@ don't use pip, but try this recipe:
|
||||
.. code::
|
||||
|
||||
# Install dependencies
|
||||
pip3 install cryptography pyserial
|
||||
pip install cryptography pyserial
|
||||
|
||||
# Clone repository
|
||||
git clone https://github.com/markqvist/Reticulum.git
|
||||
@@ -316,25 +317,25 @@ don't use pip, but try this recipe:
|
||||
ln -s ../RNS ./Examples/
|
||||
|
||||
# Run an example
|
||||
python3 Examples/Echo.py -s
|
||||
python Examples/Echo.py -s
|
||||
|
||||
# Unless you've manually created a config file, Reticulum will do so now,
|
||||
# and immediately exit. Make any necessary changes to the file:
|
||||
nano ~/.reticulum/config
|
||||
|
||||
# ... and launch the example again.
|
||||
python3 Examples/Echo.py -s
|
||||
python Examples/Echo.py -s
|
||||
|
||||
# You can now repeat the process on another computer,
|
||||
# and run the same example with -h to get command line options.
|
||||
python3 Examples/Echo.py -h
|
||||
python Examples/Echo.py -h
|
||||
|
||||
# Run the example in client mode to "ping" the server.
|
||||
# Replace the hash below with the actual destination hash of your server.
|
||||
python3 Examples/Echo.py 174a64852a75682259ad8b921b8bf416
|
||||
python Examples/Echo.py 174a64852a75682259ad8b921b8bf416
|
||||
|
||||
# Have a look at another example
|
||||
python3 Examples/Filetransfer.py -h
|
||||
python Examples/Filetransfer.py -h
|
||||
|
||||
When you have experimented with the basic examples, it's time to go read the
|
||||
:ref:`Understanding Reticulum<understanding-main>` chapter. Before submitting
|
||||
@@ -446,11 +447,11 @@ detailed in this manual.
|
||||
|
||||
Debian Bookworm
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Debian released after April 2023, it is no longer possible
|
||||
On versions of Debian released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but installation
|
||||
via this method is not fully tested yet.
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -463,14 +464,28 @@ via this method is not fully tested yet.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
|
||||
.. code:: text
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
Please note that the "break-system-packages" directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems.
|
||||
|
||||
|
||||
Ubuntu Lunar
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but installation
|
||||
via this method is not fully tested yet.
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -483,14 +498,24 @@ via this method is not fully tested yet.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
|
||||
.. code:: text
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
Please note that the "break-system-packages" directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this _could_ in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems.
|
||||
|
||||
Pure-Python Reticulum
|
||||
==============================================
|
||||
In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies
|
||||
|
||||
On more unusual systems, and in some rare cases, it might not be possible to
|
||||
install or even compile one or more of the above modules. In such situations,
|
||||
install one or more dependencies. In such situations,
|
||||
you can use the ``rnspure`` package instead of the ``rns`` package, or use ``pip``
|
||||
with the ``--no-dependencies`` command-line option. The ``rnspure``
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
|
||||
@@ -24,11 +24,20 @@ starting from scratch.
|
||||
This chapter will outline a few different sensible starting paths to get
|
||||
real-world functional wireless communications up and running with minimal cost
|
||||
and effort. Two fundamental devices categories will be covered, *RNodes* and
|
||||
*WiFi-based radios*.
|
||||
*WiFi-based radios*. Additionally, other common options will be briefly described.
|
||||
|
||||
Knowing how to employ just a few different types of hardware will make it possible
|
||||
to build a wide range of useful networks with little effort.
|
||||
|
||||
Combining Hardware Types
|
||||
========================
|
||||
|
||||
It is useful to combine different link and hardware types when designing and
|
||||
building a network. One useful design pattern is to employ high-capacity point-to-point
|
||||
links based on WiFi or millimeter-wave radios (with high-gain directional antennas)
|
||||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.
|
||||
|
||||
While there are many other device categories that are useful in building Reticulum
|
||||
networks, knowing how to employ just these two will make it possible to build
|
||||
a wide range of useful networks with little effort.
|
||||
|
||||
.. _rnode-main:
|
||||
|
||||
@@ -190,13 +199,6 @@ such as serial port and on-air parameters. For v2.x firmwares, you just need to
|
||||
the Connection ID of the RNode, and Reticulum will automatically locate and connect to the
|
||||
RNode, using the parameters stored in the RNode itself.
|
||||
|
||||
.. _rnode-suppliers:
|
||||
|
||||
Suppliers
|
||||
^^^^^^^^^
|
||||
Get in touch if you want to have your RNode supplier listed here, or if you want help to
|
||||
get started with producing RNodes.
|
||||
|
||||
|
||||
WiFi-based Hardware
|
||||
===================
|
||||
@@ -231,11 +233,31 @@ that is relatively cheap while providing long range and high capacity for Reticu
|
||||
networks. As in all other cases, it is also possible for Reticulum to co-exist with IP
|
||||
networks running concurrently on such devices.
|
||||
|
||||
Combining Hardware Types
|
||||
========================
|
||||
Ethernet-based Hardware
|
||||
=======================
|
||||
|
||||
It is useful to combine different link and hardware types when designing and
|
||||
building a network. One useful design pattern is to employ high-capacity point-to-point
|
||||
links based on WiFi or millimeter-wave radios (with high-gain directional antennas)
|
||||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.
|
||||
Reticulum can run over any kind of hardware that can provide a switched Ethernet-based
|
||||
medium. This means that anything from a plain Ethernet switch, to fiber-optic systems,
|
||||
to data radios with Ethernet interfaces can be used by Reticulum.
|
||||
|
||||
The Ethernet medium does not need to have any IP infrastructure such as DHCP servers
|
||||
or routing set up, but in case such infrastructure does exist, Reticulum will simply
|
||||
co-exist with.
|
||||
|
||||
To use Reticulum over Ethernet-based mediums, it is generally enough to use the included
|
||||
:ref:`AutoInterface<interfaces-auto>`. This interface also works over any kind of
|
||||
virtual networking adapter, such as ``tun`` and ``tap`` devices in Linux.
|
||||
|
||||
Serial Lines & Devices
|
||||
======================
|
||||
|
||||
Using Reticulum over any kind of raw serial line is also possible with the
|
||||
:ref:`SerialInterface<interfaces-serial>`. This interface type is also useful for
|
||||
using Reticulum over communications hardware that provides a serial port interface.
|
||||
|
||||
Packet Radio Modems
|
||||
===================
|
||||
|
||||
Any packet radio modem that provides a standard KISS interface over USB, serial or TCP
|
||||
can be used with Reticulum. This includes virtual software modems such as
|
||||
`FreeDV TNC <https://github.com/xssfox/freedv-tnc>`_ and `Dire Wolf <https://github.com/wb2osz/direwolf>`_.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
.. _interfaces-main:
|
||||
|
||||
********************
|
||||
Supported Interfaces
|
||||
********************
|
||||
**********************
|
||||
Configuring Interfaces
|
||||
**********************
|
||||
|
||||
Reticulum supports using many kinds of devices as networking interfaces, and
|
||||
allows you to mix and match them in any way you choose. The number of distinct
|
||||
@@ -365,6 +365,7 @@ can be used, and offers full control over LoRa parameters.
|
||||
# out identification on the channel with
|
||||
# a set interval by configuring the
|
||||
# following two parameters.
|
||||
|
||||
# id_callsign = MYCALL-0
|
||||
# id_interval = 600
|
||||
|
||||
@@ -372,7 +373,21 @@ can be used, and offers full control over LoRa parameters.
|
||||
# with low amounts of RAM, using packet
|
||||
# flow control can be useful. By default
|
||||
# it is disabled.
|
||||
flow_control = False
|
||||
|
||||
# flow_control = False
|
||||
|
||||
# It is possible to limit the airtime
|
||||
# utilisation of an RNode by using the
|
||||
# following two configuration options.
|
||||
# The short-term limit is applied in a
|
||||
# window of approximately 15 seconds,
|
||||
# and the long-term limit is enforced
|
||||
# over a rolling 60 minute window. Both
|
||||
# options are specified in percent.
|
||||
|
||||
# airtime_limit_long = 1.5
|
||||
# airtime_limit_short = 33
|
||||
|
||||
|
||||
.. _interfaces-serial:
|
||||
|
||||
@@ -746,3 +761,74 @@ conserve bandwidth, while very fast networks can support applications that
|
||||
need very frequent announces. Reticulum implements these mechanisms to ensure
|
||||
that a large span of network types can seamlessly *co-exist* and interconnect.
|
||||
|
||||
.. _interfaces-ingress-control:
|
||||
|
||||
New Destination Rate Limiting
|
||||
=============================
|
||||
|
||||
On public interfaces, where anyone may connect and announce new destinations,
|
||||
it can be useful to control the rate at which announces for *new* destinations are
|
||||
processed.
|
||||
|
||||
If a large influx of announces for newly created or previously unknown destinations
|
||||
occur within a short amount of time, Reticulum will place these announces on hold,
|
||||
so that announce traffic for known and previously established destinations can
|
||||
continue to be processed without interruptions.
|
||||
|
||||
After the burst subsides, and an additional waiting period has passed, the held
|
||||
announces will be released at a slow rate, until the hold queue is cleared. This
|
||||
also means, that should a node decide to connect to a public interface, announce
|
||||
a large amount of bogus destinations, and then disconnect, these destination will
|
||||
never make it into path tables and waste network bandwidth on retransmitted
|
||||
announces.
|
||||
|
||||
**It's important to note** that the ingress control works at the level of *individual
|
||||
sub-interfaces*. As an example, this means that one client on a :ref:`TCP Server Interface<interfaces-tcps>`
|
||||
cannot disrupt processing of incoming announces for other connected clients on the same
|
||||
:ref:`TCP Server Interface<interfaces-tcps>`. All other clients on the same interface will still have new announces
|
||||
processed without interruption.
|
||||
|
||||
By default, Reticulum will handle this automatically, and ingress announce
|
||||
control will be enabled on interface where it is sensible to do so. It should
|
||||
generally not be neccessary to modify the ingress control configuration,
|
||||
but all the parameters are exposed for configuration if needed.
|
||||
|
||||
* | The ``ingress_control`` option tells Reticulum whether or not
|
||||
to enable announce ingress control on the interface. Defaults to
|
||||
``True``.
|
||||
|
||||
* | The ``ic_new_time`` option configures how long (in seconds) an
|
||||
interface is considered newly spawned. Defaults to ``2*60*60`` seconds. This
|
||||
option is useful on publicly accessible interfaces that spawn new
|
||||
sub-interfaces when a new client connects.
|
||||
|
||||
* | The ``ic_burst_freq_new`` option sets the maximum announce ingress
|
||||
frequency for newly spawned interfaces. Defaults to ``3.5``
|
||||
announces per second.
|
||||
|
||||
* | The ``ic_burst_freq`` option sets the maximum announce ingress
|
||||
frequency for other interfaces. Defaults to ``12`` announces
|
||||
per second.
|
||||
|
||||
*If an interface exceeds its burst frequency, incoming announces
|
||||
for unknown destinations will be temporarily held in a queue, and
|
||||
not processed until later.*
|
||||
|
||||
* | The ``ic_max_held_announces`` option sets the maximum amount of
|
||||
unique announces that will be held in the queue. Any additional
|
||||
unique announces will be dropped. Defaults to ``256`` announces.
|
||||
|
||||
* | The ``ic_burst_hold`` option sets how much time (in seconds) must
|
||||
pass after the burst frequency drops below its threshold, for the
|
||||
announce burst to be considered cleared. Defaults to ``60``
|
||||
seconds.
|
||||
|
||||
* | The ``ic_burst_penalty`` option sets how much time (in seconds) must
|
||||
pass after the burst is considered cleared, before held announces can
|
||||
start being released from the queue. Defaults to ``5*60``
|
||||
seconds.
|
||||
|
||||
* | The ``ic_held_release_interval`` option sets how much time (in seconds)
|
||||
must pass between releasing each held announce from the queue. Defaults
|
||||
to ``30`` seconds.
|
||||
|
||||
|
||||
@@ -108,6 +108,17 @@ configuration file is created. The default configuration looks like this:
|
||||
panic_on_interface_error = No
|
||||
|
||||
|
||||
# When Transport is enabled, it is possible to allow the
|
||||
# Transport Instance to respond to probe requests from
|
||||
# the rnprobe utility. This can be a useful tool to test
|
||||
# connectivity. When this option is enabled, the probe
|
||||
# destination will be generated from the Identity of the
|
||||
# Transport Instance, and printed to the log at startup.
|
||||
# Optional, and disabled by default.
|
||||
|
||||
respond_to_probes = No
|
||||
|
||||
|
||||
[logging]
|
||||
# Valid log levels are 0 through 7:
|
||||
# 0: Log only critical information
|
||||
@@ -145,10 +156,19 @@ configuration file is created. The default configuration looks like this:
|
||||
If Reticulum infrastructure already exists locally, you probably don't need to
|
||||
change anything, and you may already be connected to a wider network. If not,
|
||||
you will probably need to add relevant *interfaces* to the configuration, in
|
||||
order to communicate with other systems. It is a good idea to read the comments
|
||||
and explanations in the above default config. It will teach you the basic
|
||||
concepts you need to understand to configure your network. Once you have done that,
|
||||
take a look at the :ref:`Interfaces<interfaces-main>` chapter of this manual.
|
||||
order to communicate with other systems.
|
||||
|
||||
You can generate a much more verbose configuration example by running the command:
|
||||
|
||||
``rnsd --exampleconfig``
|
||||
|
||||
The output includes examples for most interface types supported
|
||||
by Reticulum, along with additional options and configuration parameters.
|
||||
|
||||
It is a good idea to read the comments and explanations in the above default config.
|
||||
It will teach you the basic concepts you need to understand to configure your network.
|
||||
Once you have done that, take a look at the :ref:`Interfaces<interfaces-main>` chapter
|
||||
of this manual.
|
||||
|
||||
Included Utility Programs
|
||||
-------------------------
|
||||
@@ -170,28 +190,47 @@ When ``rnsd`` is running, it will keep all configured interfaces open, handle tr
|
||||
it is enabled, and allow any other programs to immediately utilise the
|
||||
Reticulum network it is configured for.
|
||||
|
||||
You can even run multiple instances of rnsd with different configurations on
|
||||
You can even run multiple instances of ``rnsd`` with different configurations on
|
||||
the same system.
|
||||
|
||||
.. code:: text
|
||||
**Usage Examples**
|
||||
|
||||
# Install Reticulum
|
||||
pip3 install rns
|
||||
|
||||
# Run rnsd
|
||||
rnsd
|
||||
Run ``rnsd``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
|
||||
$ rnsd
|
||||
|
||||
[2023-08-18 17:59:56] [Notice] Started rnsd version 0.5.8
|
||||
|
||||
Run ``rnsd`` in service mode, ensuring all logging output is sent directly to file:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnsd -s
|
||||
|
||||
Generate a verbose and detailed configuration example, with explanations of all the
|
||||
various configuration options, and interface configuration examples:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnsd --exampleconfig
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnsd.py [-h] [--config CONFIG] [-v] [-q] [-s] [--exampleconfig] [--version]
|
||||
|
||||
Reticulum Network Stack Daemon
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
-s, --service rnsd is running as a service and should log to file
|
||||
--exampleconfig print verbose configuration example to stdout and exit
|
||||
--version show program's version number and exit
|
||||
|
||||
You can easily add ``rnsd`` as an always-on service by :ref:`configuring a service<using-systemd>`.
|
||||
@@ -202,12 +241,14 @@ The rnstatus Utility
|
||||
Using the ``rnstatus`` utility, you can view the status of configured Reticulum
|
||||
interfaces, similar to the ``ifconfig`` program.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Run ``rnstatus``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnstatus
|
||||
rnstatus
|
||||
$ rnstatus
|
||||
|
||||
# Example output
|
||||
Shared Instance[37428]
|
||||
Status : Up
|
||||
Serving : 1 program
|
||||
@@ -240,44 +281,175 @@ interfaces, similar to the ``ifconfig`` program.
|
||||
|
||||
Reticulum Transport Instance <5245a8efe1788c6a1cd36144a270e13b> running
|
||||
|
||||
Filter output to only show some interfaces:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnstatus [-h] [--config CONFIG] [--version] [-a] [-v]
|
||||
$ rnstatus rnode
|
||||
|
||||
RNodeInterface[RNode UHF]
|
||||
Status : Up
|
||||
Mode : Access Point
|
||||
Rate : 1.30 kbps
|
||||
Access : 64-bit IFAC by <…e702c42ba8>
|
||||
Traffic : 8.49 KB↑
|
||||
9.23 KB↓
|
||||
|
||||
Reticulum Transport Instance <5245a8efe1788c6a1cd36144a270e13b> running
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnstatus.py [-h] [--config CONFIG] [--version] [-a] [-A] [-s SORT]
|
||||
[-r] [-j] [-v] [filter]
|
||||
|
||||
Reticulum Network Stack Status
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
-a, --all show all interfaces
|
||||
positional arguments:
|
||||
filter only display interfaces with names including filter
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
-a, --all show all interfaces
|
||||
-A, --announce-stats show announce stats
|
||||
-s SORT, --sort SORT sort interfaces by [rate, traffic, rx, tx, announces, arx, atx, held]
|
||||
-r, --reverse reverse sorting
|
||||
-j, --json output in JSON format
|
||||
-v, --verbose
|
||||
|
||||
|
||||
The rnid Utility
|
||||
====================
|
||||
|
||||
With the ``rnid`` utility, you can generate, manage and view Reticulum Identities.
|
||||
The program can also calculate Destination hashes, and perform encryption and
|
||||
decryption of files.
|
||||
|
||||
Using ``rnid``, it is possible to asymmetrically encrypt files and information for
|
||||
any Reticulum destination hash, and also to create and verify cryptographic signatures.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Generate a new Identity:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -g ./new_identity
|
||||
|
||||
Display Identity key information:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -i ./new_identity -p
|
||||
|
||||
Loaded Identity <984b74a3f768bef236af4371e6f248cd> from new_id
|
||||
Public Key : 0f4259fef4521ab75a3409e353fe9073eb10783b4912a6a9937c57bf44a62c1e
|
||||
Private Key : Hidden
|
||||
|
||||
Encrypt a file for an LXMF user:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -i 8dd57a738226809646089335a6b03695 -e my_file.txt
|
||||
|
||||
Recalled Identity <bc7291552be7a58f361522990465165c> for destination <8dd57a738226809646089335a6b03695>
|
||||
Encrypting my_file.txt
|
||||
File my_file.txt encrypted for <bc7291552be7a58f361522990465165c> to my_file.txt.rfe
|
||||
|
||||
If the Identity for the destination is not already known, you can fetch it from the network by using the ``-R`` command-line option:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -R -i 30602def3b3506a28ed33db6f60cc6c9 -e my_file.txt
|
||||
|
||||
Requesting unknown Identity for <30602def3b3506a28ed33db6f60cc6c9>...
|
||||
Received Identity <2b489d06eaf7c543808c76a5332a447d> for destination <30602def3b3506a28ed33db6f60cc6c9> from the network
|
||||
Encrypting my_file.txt
|
||||
File my_file.txt encrypted for <2b489d06eaf7c543808c76a5332a447d> to my_file.txt.rfe
|
||||
|
||||
Decrypt a file using the Reticulum Identity it was encrypted for:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -i ./my_identity -d my_file.txt.rfe
|
||||
|
||||
Loaded Identity <2225fdeecaf6e2db4556c3c2d7637294> from ./my_identity
|
||||
Decrypting ./my_file.txt.rfe...
|
||||
File ./my_file.txt.rfe decrypted with <2225fdeecaf6e2db4556c3c2d7637294> to ./my_file.txt
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnid.py [-h] [--config path] [-i identity] [-g path] [-v] [-q] [-a aspects]
|
||||
[-H aspects] [-e path] [-d path] [-s path] [-V path] [-r path] [-w path]
|
||||
[-f] [-R] [-t seconds] [-p] [-P] [--version]
|
||||
|
||||
Reticulum Identity & Encryption Utility
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config path path to alternative Reticulum config directory
|
||||
-i identity, --identity identity
|
||||
hexadecimal Reticulum Destination hash or path to Identity file
|
||||
-g path, --generate path
|
||||
generate a new Identity
|
||||
-v, --verbose increase verbosity
|
||||
-q, --quiet decrease verbosity
|
||||
-a aspects, --announce aspects
|
||||
announce a destination based on this Identity
|
||||
-H aspects, --hash aspects
|
||||
show destination hashes for other aspects for this Identity
|
||||
-e path, --encrypt path
|
||||
encrypt file
|
||||
-d path, --decrypt path
|
||||
decrypt file
|
||||
-s path, --sign path sign file
|
||||
-V path, --validate path
|
||||
validate signature
|
||||
-r path, --read path input file path
|
||||
-w path, --write path
|
||||
output file path
|
||||
-f, --force write output even if it overwrites existing files
|
||||
-R, --request request unknown Identities from the network
|
||||
-t seconds identity request timeout before giving up
|
||||
-p, --print-identity print identity info and exit
|
||||
-P, --print-private allow displaying private keys
|
||||
--version show program's version number and exit
|
||||
|
||||
|
||||
The rnpath Utility
|
||||
====================
|
||||
|
||||
With the ``rnpath`` utility, you can look up and view paths for
|
||||
destinations on the Reticulum network.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Resolve path to a destination:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnpath
|
||||
rnpath c89b4da064bf66d280f0e4d8abfd9806
|
||||
$ rnpath c89b4da064bf66d280f0e4d8abfd9806
|
||||
|
||||
# Example output
|
||||
Path found, destination <c89b4da064bf66d280f0e4d8abfd9806> is 4 hops away via <f53a1c4278e0726bb73fcc623d6ce763> on TCPInterface[Testnet/dublin.connect.reticulum.network:4965]
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnpath [-h] [--config CONFIG] [--version] [-t] [-r] [-d] [-D] [-w seconds] [-v] [destination]
|
||||
|
||||
usage: rnpath.py [-h] [--config CONFIG] [--version] [-t] [-r] [-d] [-D]
|
||||
[-x] [-w seconds] [-v] [destination]
|
||||
|
||||
Reticulum Path Discovery Utility
|
||||
|
||||
|
||||
positional arguments:
|
||||
destination hexadecimal hash of the destination
|
||||
|
||||
optional arguments:
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
@@ -285,6 +457,7 @@ destinations on the Reticulum network.
|
||||
-r, --rates show announce rate info
|
||||
-d, --drop remove the path to a destination
|
||||
-D, --drop-announces drop all queued announces
|
||||
-x, --drop-via drop all paths via specified transport instance
|
||||
-w seconds timeout before giving up
|
||||
-v, --verbose
|
||||
|
||||
@@ -295,21 +468,53 @@ The rnprobe Utility
|
||||
The ``rnprobe`` utility lets you probe a destination for connectivity, similar
|
||||
to the ``ping`` program. Please note that probes will only be answered if the
|
||||
specified destination is configured to send proofs for received packets. Many
|
||||
destinations will not have this option enabled, and will not be probable.
|
||||
destinations will not have this option enabled, so most destinations will not
|
||||
be probable.
|
||||
|
||||
You can enable a probe-reply destination on Reticulum Transport Instances by
|
||||
setting the ``respond_to_probes`` configuration directive. Reticulum will then
|
||||
print the probe destination to the log on Transport Instance startup.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Probe a destination:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnprobe
|
||||
rnprobe example_utilities.echo.request 2d03725b327348980d570f739a3a5708
|
||||
$ rnprobe rnstransport.probe 2d03725b327348980d570f739a3a5708
|
||||
|
||||
# Example output
|
||||
Sent 16 byte probe to <2d03725b327348980d570f739a3a5708>
|
||||
Valid reply received from <2d03725b327348980d570f739a3a5708>
|
||||
Round-trip time is 38.469 milliseconds over 2 hops
|
||||
|
||||
Send a larger probe:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnprobe [-h] [--config CONFIG] [--version] [-v] [full_name] [destination_hash]
|
||||
$ rnprobe rnstransport.probe 2d03725b327348980d570f739a3a5708 -s 256
|
||||
|
||||
Sent 16 byte probe to <2d03725b327348980d570f739a3a5708>
|
||||
Valid reply received from <2d03725b327348980d570f739a3a5708>
|
||||
Round-trip time is 38.781 milliseconds over 2 hops
|
||||
|
||||
If the interface that receives the probe replies supports reporting radio
|
||||
parameters such as **RSSI** and **SNR**, the ``rnprobe`` utility will print
|
||||
these as part of the result as well.
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnprobe rnstransport.probe e7536ee90bd4a440e130490b87a25124
|
||||
|
||||
Sent 16 byte probe to <e7536ee90bd4a440e130490b87a25124>
|
||||
Valid reply received from <e7536ee90bd4a440e130490b87a25124>
|
||||
Round-trip time is 1.809 seconds over 1 hop [RSSI -73 dBm] [SNR 12.0 dB]
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnprobe [-h] [--config CONFIG] [--version] [-v] [-s SIZE]
|
||||
[full_name] [destination_hash]
|
||||
|
||||
Reticulum Probe Utility
|
||||
|
||||
@@ -320,6 +525,7 @@ destinations will not have this option enabled, and will not be probable.
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
-s SIZE, --size SIZE size of probe packet payload in bytes
|
||||
--version show program's version number and exit
|
||||
-v, --verbose
|
||||
|
||||
@@ -330,20 +536,39 @@ The rncp Utility
|
||||
The ``rncp`` utility is a simple file transfer tool. Using it, you can transfer
|
||||
files through Reticulum.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Run rncp on the receiving system, specifying which identities are allowed to send files:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rncp on the receiving system, specifying which identities
|
||||
# are allowed to send files
|
||||
rncp --receive -a 1726dbad538775b5bf9b0ea25a4079c8 -a c50cc4e4f7838b6c31f60ab9032cbc62
|
||||
$ rncp --listen -a 1726dbad538775b5bf9b0ea25a4079c8 -a c50cc4e4f7838b6c31f60ab9032cbc62
|
||||
|
||||
# From another system, copy a file to the receiving system
|
||||
rncp ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
|
||||
You can specify as many allowed senders as needed, or complete disable authentication.
|
||||
You can also specify allowed identity hashes (one per line) in the file ~/.rncp/allowed_identities
|
||||
and simply running the program in listener mode:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rncp [-h] [--config path] [-v] [-q] [-p] [-r] [-b] [-a allowed_hash] [-n] [-w seconds] [--version] [file] [destination]
|
||||
$ rncp --listen
|
||||
|
||||
From another system, copy a file to the receiving system:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rncp ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
|
||||
Or fetch a file from the remote system:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rncp --fetch ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rncp.py [-h] [--config path] [-v] [-q] [-S] [-l] [-f] [-b seconds]
|
||||
[-a allowed_hash] [-n] [-p] [-w seconds] [--version] [file] [destination]
|
||||
|
||||
Reticulum File Transfer Utility
|
||||
|
||||
@@ -351,19 +576,20 @@ You can specify as many allowed senders as needed, or complete disable authentic
|
||||
file file to be transferred
|
||||
destination hexadecimal hash of the receiver
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config path path to alternative Reticulum config directory
|
||||
-v, --verbose increase verbosity
|
||||
-q, --quiet decrease verbosity
|
||||
-p, --print-identity print identity and destination info and exit
|
||||
-r, --receive wait for incoming files
|
||||
-b, --no-announce don't announce at program start
|
||||
-S, --silent disable transfer progress output
|
||||
-l, --listen listen for incoming transfer requests
|
||||
-f, --fetch fetch file from remote listener instead of sending
|
||||
-b seconds announce interval, 0 to only announce at startup
|
||||
-a allowed_hash accept from this identity
|
||||
-n, --no-auth accept files from anyone
|
||||
-n, --no-auth accept files and fetches from anyone
|
||||
-p, --print-identity print identity and destination info and exit
|
||||
-w seconds sender timeout before giving up
|
||||
--version show program's version number and exit
|
||||
-v, --verbose
|
||||
|
||||
|
||||
The rnx Utility
|
||||
@@ -371,32 +597,43 @@ The rnx Utility
|
||||
|
||||
The ``rnx`` utility is a basic remote command execution program. It allows you to
|
||||
execute commands on remote systems over Reticulum, and to view returned command
|
||||
output.
|
||||
output. For a fully interactive remote shell solution, be sure to also take a look
|
||||
at the `rnsh <https://github.com/acehoss/rnsh>`_ program.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Run rnx on the listening system, specifying which identities are allowed to execute commands:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnx on the listening system, specifying which identities
|
||||
# are allowed to execute commands
|
||||
rnx --listen -a 941bed5e228775e5a8079fc38b1ccf3f -a 1b03013c25f1c2ca068a4f080b844a10
|
||||
$ rnx --listen -a 941bed5e228775e5a8079fc38b1ccf3f -a 1b03013c25f1c2ca068a4f080b844a10
|
||||
|
||||
# From another system, run a command
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 "cat /proc/cpuinfo"
|
||||
|
||||
# Or enter the interactive mode pseudo-shell
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 -x
|
||||
|
||||
# The default identity file is stored in
|
||||
# ~/.reticulum/identities/rnx, but you can use
|
||||
# another one, which will be created if it does
|
||||
# not already exist
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 -i /path/to/identity -x
|
||||
|
||||
You can specify as many allowed senders as needed, or completely disable authentication.
|
||||
From another system, run a command on the remote:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnx [-h] [--config path] [-v] [-q] [-p] [-l] [-i identity] [-x] [-b] [-a allowed_hash] [-n] [-N] [-d] [-m] [-w seconds] [-W seconds] [--stdin STDIN] [--stdout STDOUT] [--stderr STDERR] [--version]
|
||||
[destination] [command]
|
||||
$ rnx 7a55144adf826958a9529a3bcf08b149 "cat /proc/cpuinfo"
|
||||
|
||||
Or enter the interactive mode pseudo-shell:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnx 7a55144adf826958a9529a3bcf08b149 -x
|
||||
|
||||
The default identity file is stored in ``~/.reticulum/identities/rnx``, but you can use
|
||||
another one, which will be created if it does not already exist
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnx 7a55144adf826958a9529a3bcf08b149 -i /path/to/identity -x
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnx [-h] [--config path] [-v] [-q] [-p] [-l] [-i identity] [-x] [-b] [-n] [-N]
|
||||
[-d] [-m] [-a allowed_hash] [-w seconds] [-W seconds] [--stdin STDIN]
|
||||
[--stdout STDOUT] [--stderr STDERR] [--version] [destination] [command]
|
||||
|
||||
Reticulum Remote Execution Utility
|
||||
|
||||
@@ -433,11 +670,19 @@ The rnodeconf Utility
|
||||
The ``rnodeconf`` utility allows you to inspect and configure existing :ref:`RNodes<rnode-main>`, and
|
||||
to create and provision new :ref:`RNodes<rnode-main>` from any supported hardware devices.
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnodeconf [-h] [-i] [-a] [-u] [-U] [--fw-version version] [--nocheck] [-C] [-N] [-T] [-b] [-B] [-p] [--freq Hz] [--bw Hz] [--txp dBm] [--sf factor] [--cr rate] [--eeprom-backup] [--eeprom-dump] [--eeprom-wipe] [--version] [port]
|
||||
usage: rnodeconf.py [-h] [-i] [-a] [-u] [-U] [--fw-version version] [--nocheck] [-e]
|
||||
[-E] [-C] [--baud-flash baud_flash] [-N] [-T] [-b] [-B] [-p] [-D i]
|
||||
[--freq Hz] [--bw Hz] [--txp dBm] [--sf factor] [--cr rate]
|
||||
[--eeprom-backup] [--eeprom-dump] [--eeprom-wipe] [-P]
|
||||
[--trust-key hexbytes] [--version] [port]
|
||||
|
||||
RNode Configuration and firmware utility. This program allows you to change various settings and startup modes of RNode. It can also install, flash and update the firmware on supported devices.
|
||||
RNode Configuration and firmware utility. This program allows you to change various
|
||||
settings and startup modes of RNode. It can also install, flash and update the firmware
|
||||
on supported devices.
|
||||
|
||||
positional arguments:
|
||||
port serial port where RNode is attached
|
||||
@@ -453,11 +698,14 @@ to create and provision new :ref:`RNodes<rnode-main>` from any supported hardwar
|
||||
-e, --extract Extract firmware from connected RNode for later use
|
||||
-E, --use-extracted Use the extracted firmware for autoinstallation or update
|
||||
-C, --clear-cache Clear locally cached firmware files
|
||||
--baud-flash baud_flash
|
||||
Set specific baud rate when flashing device. Default is 921600
|
||||
-N, --normal Switch device to normal mode
|
||||
-T, --tnc Switch device to TNC mode
|
||||
-b, --bluetooth-on Turn device bluetooth on
|
||||
-B, --bluetooth-off Turn device bluetooth off
|
||||
-p, --bluetooth-pair Put device into bluetooth pairing mode
|
||||
-D i, --display i Set display intensity (0-255)
|
||||
--freq Hz Frequency in Hz for TNC mode
|
||||
--bw Hz Bandwidth in Hz for TNC mode
|
||||
--txp dBm TX power in dBm for TNC mode
|
||||
@@ -466,6 +714,8 @@ to create and provision new :ref:`RNodes<rnode-main>` from any supported hardwar
|
||||
--eeprom-backup Backup EEPROM to file
|
||||
--eeprom-dump Dump EEPROM to console
|
||||
--eeprom-wipe Unlock and wipe EEPROM
|
||||
-P, --public Display public part of signing key
|
||||
--trust-key hexbytes Public key to trust for device verification
|
||||
--version Print program version and exit
|
||||
|
||||
For more information on how to create your own RNodes, please read the :ref:`Creating RNodes<rnode-creating>`
|
||||
|
||||
@@ -21,15 +21,15 @@ networks, without any need for hierarchical or beaureucratic structures to contr
|
||||
or manage them, while ensuring individuals and communities full sovereignty
|
||||
over their own network segments.
|
||||
|
||||
Reticulum is a complete networking stack, and does not need IP or higher
|
||||
Reticulum is a **complete networking stack**, and does not need IP or higher
|
||||
layers, although it is easy to utilise IP (with TCP or UDP) as the underlying
|
||||
carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the
|
||||
Internet or private IP networks. Reticulum is built directly on cryptographic
|
||||
principles, allowing resilience and stable functionality in open and trustless
|
||||
networks.
|
||||
|
||||
No kernel modules or drivers are required. Reticulum runs completely in
|
||||
userland, and can run on practically any system that runs Python 3. Reticulum
|
||||
No kernel modules or drivers are required. Reticulum can run completely in
|
||||
userland, and will run on practically any system that runs Python 3. Reticulum
|
||||
runs well even on small single-board computers like the Pi Zero.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Current Status
|
||||
**Please know!** Reticulum should currently be considered beta software. All core protocol
|
||||
features are implemented and functioning, but additions will probably occur as
|
||||
real-world use is explored. *There will be bugs*. The API and wire-format can be
|
||||
considered stable at the moment, but could change if absolutely warranted.
|
||||
considered complete and stable at the moment, but could change if absolutely warranted.
|
||||
|
||||
|
||||
What does Reticulum Offer?
|
||||
@@ -71,7 +71,7 @@ What does Reticulum Offer?
|
||||
|
||||
* Efficient link establishment
|
||||
|
||||
* Total bandwidth cost of setting up a link is only 3 packets, totalling 297 bytes
|
||||
* Total cost of setting up an encrypted and verified link is only 3 packets, totalling 297 bytes
|
||||
|
||||
* Low cost of keeping links open at only 0.44 bits per second
|
||||
|
||||
|
||||
@@ -1,134 +0,0 @@
|
||||
/*
|
||||
* _sphinx_javascript_frameworks_compat.js
|
||||
* ~~~~~~~~~~
|
||||
*
|
||||
* Compatability shim for jQuery and underscores.js.
|
||||
*
|
||||
* WILL BE REMOVED IN Sphinx 6.0
|
||||
* xref RemovedInSphinx60Warning
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* select a different prefix for underscore
|
||||
*/
|
||||
$u = _.noConflict();
|
||||
|
||||
|
||||
/**
|
||||
* small helper function to urldecode strings
|
||||
*
|
||||
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/decodeURIComponent#Decoding_query_parameters_from_a_URL
|
||||
*/
|
||||
jQuery.urldecode = function(x) {
|
||||
if (!x) {
|
||||
return x
|
||||
}
|
||||
return decodeURIComponent(x.replace(/\+/g, ' '));
|
||||
};
|
||||
|
||||
/**
|
||||
* small helper function to urlencode strings
|
||||
*/
|
||||
jQuery.urlencode = encodeURIComponent;
|
||||
|
||||
/**
|
||||
* This function returns the parsed url parameters of the
|
||||
* current request. Multiple values per key are supported,
|
||||
* it will always return arrays of strings for the value parts.
|
||||
*/
|
||||
jQuery.getQueryParameters = function(s) {
|
||||
if (typeof s === 'undefined')
|
||||
s = document.location.search;
|
||||
var parts = s.substr(s.indexOf('?') + 1).split('&');
|
||||
var result = {};
|
||||
for (var i = 0; i < parts.length; i++) {
|
||||
var tmp = parts[i].split('=', 2);
|
||||
var key = jQuery.urldecode(tmp[0]);
|
||||
var value = jQuery.urldecode(tmp[1]);
|
||||
if (key in result)
|
||||
result[key].push(value);
|
||||
else
|
||||
result[key] = [value];
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/**
|
||||
* highlight a given string on a jquery object by wrapping it in
|
||||
* span elements with the given class name.
|
||||
*/
|
||||
jQuery.fn.highlightText = function(text, className) {
|
||||
function highlight(node, addItems) {
|
||||
if (node.nodeType === 3) {
|
||||
var val = node.nodeValue;
|
||||
var pos = val.toLowerCase().indexOf(text);
|
||||
if (pos >= 0 &&
|
||||
!jQuery(node.parentNode).hasClass(className) &&
|
||||
!jQuery(node.parentNode).hasClass("nohighlight")) {
|
||||
var span;
|
||||
var isInSVG = jQuery(node).closest("body, svg, foreignObject").is("svg");
|
||||
if (isInSVG) {
|
||||
span = document.createElementNS("http://www.w3.org/2000/svg", "tspan");
|
||||
} else {
|
||||
span = document.createElement("span");
|
||||
span.className = className;
|
||||
}
|
||||
span.appendChild(document.createTextNode(val.substr(pos, text.length)));
|
||||
node.parentNode.insertBefore(span, node.parentNode.insertBefore(
|
||||
document.createTextNode(val.substr(pos + text.length)),
|
||||
node.nextSibling));
|
||||
node.nodeValue = val.substr(0, pos);
|
||||
if (isInSVG) {
|
||||
var rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
|
||||
var bbox = node.parentElement.getBBox();
|
||||
rect.x.baseVal.value = bbox.x;
|
||||
rect.y.baseVal.value = bbox.y;
|
||||
rect.width.baseVal.value = bbox.width;
|
||||
rect.height.baseVal.value = bbox.height;
|
||||
rect.setAttribute('class', className);
|
||||
addItems.push({
|
||||
"parent": node.parentNode,
|
||||
"target": rect});
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (!jQuery(node).is("button, select, textarea")) {
|
||||
jQuery.each(node.childNodes, function() {
|
||||
highlight(this, addItems);
|
||||
});
|
||||
}
|
||||
}
|
||||
var addItems = [];
|
||||
var result = this.each(function() {
|
||||
highlight(this, addItems);
|
||||
});
|
||||
for (var i = 0; i < addItems.length; ++i) {
|
||||
jQuery(addItems[i].parent).before(addItems[i].target);
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
/*
|
||||
* backward compatibility for jQuery.browser
|
||||
* This will be supported until firefox bug is fixed.
|
||||
*/
|
||||
if (!jQuery.browser) {
|
||||
jQuery.uaMatch = function(ua) {
|
||||
ua = ua.toLowerCase();
|
||||
|
||||
var match = /(chrome)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(webkit)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(opera)(?:.*version|)[ \/]([\w.]+)/.exec(ua) ||
|
||||
/(msie) ([\w.]+)/.exec(ua) ||
|
||||
ua.indexOf("compatible") < 0 && /(mozilla)(?:.*? rv:([\w.]+)|)/.exec(ua) ||
|
||||
[];
|
||||
|
||||
return {
|
||||
browser: match[ 1 ] || "",
|
||||
version: match[ 2 ] || "0"
|
||||
};
|
||||
};
|
||||
jQuery.browser = {};
|
||||
jQuery.browser[jQuery.uaMatch(navigator.userAgent).browser] = true;
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Sphinx stylesheet -- basic theme.
|
||||
*
|
||||
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
|
||||
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
@@ -324,6 +324,7 @@ aside.sidebar {
|
||||
p.sidebar-title {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
nav.contents,
|
||||
aside.topic,
|
||||
div.admonition, div.topic, blockquote {
|
||||
@@ -331,6 +332,7 @@ div.admonition, div.topic, blockquote {
|
||||
}
|
||||
|
||||
/* -- topics ---------------------------------------------------------------- */
|
||||
|
||||
nav.contents,
|
||||
aside.topic,
|
||||
div.topic {
|
||||
@@ -606,6 +608,7 @@ ol.simple p,
|
||||
ul.simple p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
aside.footnote > span,
|
||||
div.citation > span {
|
||||
float: left;
|
||||
@@ -667,6 +670,16 @@ dd {
|
||||
margin-left: 30px;
|
||||
}
|
||||
|
||||
.sig dd {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.sig dl {
|
||||
margin-top: 0px;
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
dl > dd:last-child,
|
||||
dl > dd:last-child > :last-child {
|
||||
margin-bottom: 0;
|
||||
@@ -735,6 +748,14 @@ abbr, acronym {
|
||||
cursor: help;
|
||||
}
|
||||
|
||||
.translated {
|
||||
background-color: rgba(207, 255, 207, 0.2)
|
||||
}
|
||||
|
||||
.untranslated {
|
||||
background-color: rgba(255, 207, 207, 0.2)
|
||||
}
|
||||
|
||||
/* -- code displays --------------------------------------------------------- */
|
||||
|
||||
pre {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Base JavaScript utilities for all Sphinx HTML documentation.
|
||||
*
|
||||
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
|
||||
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
var DOCUMENTATION_OPTIONS = {
|
||||
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
|
||||
VERSION: '0.5.6 beta',
|
||||
VERSION: '0.6.1 beta',
|
||||
LANGUAGE: 'en',
|
||||
COLLAPSE_INDEX: false,
|
||||
BUILDER: 'html',
|
||||
|
||||
Vendored
-10881
File diff suppressed because it is too large
Load Diff
Vendored
-2
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
* This script contains the language-specific data used by searchtools.js,
|
||||
* namely the list of stopwords, stemmer, scorer and splitter.
|
||||
*
|
||||
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
|
||||
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
.highlight .cs { color: #8f5902; font-style: italic } /* Comment.Special */
|
||||
.highlight .gd { color: #a40000 } /* Generic.Deleted */
|
||||
.highlight .ge { color: #000000; font-style: italic } /* Generic.Emph */
|
||||
.highlight .ges { color: #000000; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
|
||||
.highlight .gr { color: #ef2929 } /* Generic.Error */
|
||||
.highlight .gh { color: #000080; font-weight: bold } /* Generic.Heading */
|
||||
.highlight .gi { color: #00A000 } /* Generic.Inserted */
|
||||
@@ -107,6 +108,7 @@ body[data-theme="dark"] .highlight .c1 { color: #ababab; font-style: italic } /*
|
||||
body[data-theme="dark"] .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */
|
||||
body[data-theme="dark"] .highlight .gd { color: #d22323 } /* Generic.Deleted */
|
||||
body[data-theme="dark"] .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */
|
||||
body[data-theme="dark"] .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
|
||||
body[data-theme="dark"] .highlight .gr { color: #d22323 } /* Generic.Error */
|
||||
body[data-theme="dark"] .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
|
||||
body[data-theme="dark"] .highlight .gi { color: #589819 } /* Generic.Inserted */
|
||||
@@ -192,6 +194,7 @@ body:not([data-theme="light"]) .highlight .c1 { color: #ababab; font-style: ital
|
||||
body:not([data-theme="light"]) .highlight .cs { color: #e50808; font-weight: bold; background-color: #520000 } /* Comment.Special */
|
||||
body:not([data-theme="light"]) .highlight .gd { color: #d22323 } /* Generic.Deleted */
|
||||
body:not([data-theme="light"]) .highlight .ge { color: #d0d0d0; font-style: italic } /* Generic.Emph */
|
||||
body:not([data-theme="light"]) .highlight .ges { color: #d0d0d0; font-weight: bold; font-style: italic } /* Generic.EmphStrong */
|
||||
body:not([data-theme="light"]) .highlight .gr { color: #d22323 } /* Generic.Error */
|
||||
body:not([data-theme="light"]) .highlight .gh { color: #ffffff; font-weight: bold } /* Generic.Heading */
|
||||
body:not([data-theme="light"]) .highlight .gi { color: #589819 } /* Generic.Inserted */
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
*
|
||||
* Sphinx JavaScript utilities for the full-text search.
|
||||
*
|
||||
* :copyright: Copyright 2007-2022 by the Sphinx team, see AUTHORS.
|
||||
* :copyright: Copyright 2007-2023 by the Sphinx team, see AUTHORS.
|
||||
* :license: BSD, see LICENSE for details.
|
||||
*
|
||||
*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
+20
-23
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Code Examples - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -258,7 +258,7 @@ program.</p>
|
||||
<span class="c1"># Destinations are endpoints in Reticulum, that can be addressed</span>
|
||||
<span class="c1"># and communicated with. Destinations can also announce their</span>
|
||||
<span class="c1"># existence, which will let the network know they are reachable</span>
|
||||
<span class="c1"># and autoomatically create paths to them, from anywhere else</span>
|
||||
<span class="c1"># and automatically create paths to them, from anywhere else</span>
|
||||
<span class="c1"># in the network.</span>
|
||||
<span class="n">destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span>
|
||||
<span class="n">identity</span><span class="p">,</span>
|
||||
@@ -269,7 +269,7 @@ program.</p>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># We configure the destination to automatically prove all</span>
|
||||
<span class="c1"># packets adressed to it. By doing this, RNS will automatically</span>
|
||||
<span class="c1"># packets addressed to it. By doing this, RNS will automatically</span>
|
||||
<span class="c1"># generate a proof for each incoming packet and transmit it</span>
|
||||
<span class="c1"># back to the sender of that packet. This will let anyone that</span>
|
||||
<span class="c1"># tries to communicate with the destination know whether their</span>
|
||||
@@ -375,7 +375,7 @@ notifications about announces from relevant destinations.</p>
|
||||
<span class="c1"># Destinations are endpoints in Reticulum, that can be addressed</span>
|
||||
<span class="c1"># and communicated with. Destinations can also announce their</span>
|
||||
<span class="c1"># existence, which will let the network know they are reachable</span>
|
||||
<span class="c1"># and autoomatically create paths to them, from anywhere else</span>
|
||||
<span class="c1"># and automatically create paths to them, from anywhere else</span>
|
||||
<span class="c1"># in the network.</span>
|
||||
<span class="n">destination_1</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span>
|
||||
<span class="n">identity</span><span class="p">,</span>
|
||||
@@ -396,7 +396,7 @@ notifications about announces from relevant destinations.</p>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># We configure the destinations to automatically prove all</span>
|
||||
<span class="c1"># packets adressed to it. By doing this, RNS will automatically</span>
|
||||
<span class="c1"># packets addressed to it. By doing this, RNS will automatically</span>
|
||||
<span class="c1"># generate a proof for each incoming packet and transmit it</span>
|
||||
<span class="c1"># back to the sender of that packet. This will let anyone that</span>
|
||||
<span class="c1"># tries to communicate with the destination know whether their</span>
|
||||
@@ -697,7 +697,7 @@ the Packet interface.</p>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># We configure the destination to automatically prove all</span>
|
||||
<span class="c1"># packets adressed to it. By doing this, RNS will automatically</span>
|
||||
<span class="c1"># packets addressed to it. By doing this, RNS will automatically</span>
|
||||
<span class="c1"># generate a proof for each incoming packet and transmit it</span>
|
||||
<span class="c1"># back to the sender of that packet.</span>
|
||||
<span class="n">echo_destination</span><span class="o">.</span><span class="n">set_proof_strategy</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">PROVE_ALL</span><span class="p">)</span>
|
||||
@@ -3322,14 +3322,11 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+15
-18
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -257,14 +257,11 @@
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+14
-17
@@ -4,12 +4,12 @@
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/><title>Index - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -139,7 +139,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -159,13 +159,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -179,7 +179,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -723,14 +723,11 @@
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Getting Started Fast - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -277,7 +277,8 @@ radio interfaces can then be added later.</p>
|
||||
<h3>Remote Shell<a class="headerlink" href="#remote-shell" title="Permalink to this heading">#</a></h3>
|
||||
<p>The <a class="reference external" href="https://github.com/acehoss/rnsh">rnsh</a> program lets you establish fully interactive
|
||||
remote shell sessions over Reticulum. It also allows you to pipe any program to or from a
|
||||
remote system, and is similar to how <code class="docutils literal notranslate"><span class="pre">ssh</span></code> works.</p>
|
||||
remote system, and is similar to how <code class="docutils literal notranslate"><span class="pre">ssh</span></code> works. The <code class="docutils literal notranslate"><span class="pre">rnsh</span></code> is very efficient, and
|
||||
can facilitate fully interactive shell sessions, even over extremely low-bandwidth links.</p>
|
||||
</section>
|
||||
<section id="nomad-network">
|
||||
<h3>Nomad Network<a class="headerlink" href="#nomad-network" title="Permalink to this heading">#</a></h3>
|
||||
@@ -387,11 +388,11 @@ easier setup, use TCP.</p>
|
||||
<h2>Connect to the Public Testnet<a class="headerlink" href="#connect-to-the-public-testnet" title="Permalink to this heading">#</a></h2>
|
||||
<p>An experimental public testnet has been made accessible over both I2P and TCP. You can join it
|
||||
by adding one of the following interfaces to your <code class="docutils literal notranslate"><span class="pre">.reticulum/config</span></code> file:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># TCP/IP interface to the Dublin hub</span>
|
||||
<span class="p">[[</span><span class="n">RNS</span> <span class="n">Testnet</span> <span class="n">Dublin</span><span class="p">]]</span>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># TCP/IP interface to the RNS Amsterdam Hub</span>
|
||||
<span class="p">[[</span><span class="n">RNS</span> <span class="n">Testnet</span> <span class="n">Amsterdam</span><span class="p">]]</span>
|
||||
<span class="nb">type</span> <span class="o">=</span> <span class="n">TCPClientInterface</span>
|
||||
<span class="n">enabled</span> <span class="o">=</span> <span class="n">yes</span>
|
||||
<span class="n">target_host</span> <span class="o">=</span> <span class="n">dublin</span><span class="o">.</span><span class="n">connect</span><span class="o">.</span><span class="n">reticulum</span><span class="o">.</span><span class="n">network</span>
|
||||
<span class="n">target_host</span> <span class="o">=</span> <span class="n">amsterdam</span><span class="o">.</span><span class="n">connect</span><span class="o">.</span><span class="n">reticulum</span><span class="o">.</span><span class="n">network</span>
|
||||
<span class="n">target_port</span> <span class="o">=</span> <span class="mi">4965</span>
|
||||
|
||||
<span class="c1"># TCP/IP interface to the BetweenTheBorders Hub (community-provided)</span>
|
||||
@@ -401,11 +402,11 @@ by adding one of the following interfaces to your <code class="docutils literal
|
||||
<span class="n">target_host</span> <span class="o">=</span> <span class="n">betweentheborders</span><span class="o">.</span><span class="n">com</span>
|
||||
<span class="n">target_port</span> <span class="o">=</span> <span class="mi">4242</span>
|
||||
|
||||
<span class="c1"># Interface to I2P hub A</span>
|
||||
<span class="p">[[</span><span class="n">RNS</span> <span class="n">Testnet</span> <span class="n">I2P</span> <span class="n">Hub</span> <span class="n">A</span><span class="p">]]</span>
|
||||
<span class="c1"># Interface to Testnet I2P Hub</span>
|
||||
<span class="p">[[</span><span class="n">RNS</span> <span class="n">Testnet</span> <span class="n">I2P</span> <span class="n">Hub</span><span class="p">]]</span>
|
||||
<span class="nb">type</span> <span class="o">=</span> <span class="n">I2PInterface</span>
|
||||
<span class="n">enabled</span> <span class="o">=</span> <span class="n">yes</span>
|
||||
<span class="n">peers</span> <span class="o">=</span> <span class="n">uxg5kubabakh3jtnvsipingbr5574dle7bubvip7llfvwx2tgrua</span><span class="o">.</span><span class="n">b32</span><span class="o">.</span><span class="n">i2p</span>
|
||||
<span class="n">peers</span> <span class="o">=</span> <span class="n">g3br23bvx3lq5uddcsjii74xgmn6y5q325ovrkq2zw2wbzbqgbuq</span><span class="o">.</span><span class="n">b32</span><span class="o">.</span><span class="n">i2p</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Many other Reticulum instances are connecting to this testnet, and you can also join it
|
||||
@@ -426,7 +427,7 @@ digital radio transceiver, that integrates easily with Reticulum.</p>
|
||||
<p>To build one yourself requires installing a custom firmware on a supported LoRa
|
||||
development board with an auto-install script. Please see the <a class="reference internal" href="hardware.html#hardware-main"><span class="std std-ref">Communications Hardware</span></a>
|
||||
chapter for a guide. If you prefer purchasing a ready-made unit, you can refer to the
|
||||
<a class="reference internal" href="hardware.html#rnode-suppliers"><span class="std std-ref">list of suppliers</span></a>. For more information on RNode, you can also
|
||||
<span class="xref std std-ref">list of suppliers</span>. For more information on RNode, you can also
|
||||
refer to these additional external resources:</p>
|
||||
<ul class="simple">
|
||||
<li><p><a class="reference external" href="https://unsigned.io/how-to-make-your-own-rnodes/">How To Make Your Own RNodes</a></p></li>
|
||||
@@ -443,14 +444,14 @@ and propose adding an interface for the hardware.</p>
|
||||
<h2>Develop a Program with Reticulum<a class="headerlink" href="#develop-a-program-with-reticulum" title="Permalink to this heading">#</a></h2>
|
||||
<p>If you want to develop programs that use Reticulum, the easiest way to get
|
||||
started is to install the latest release of Reticulum via pip:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip3</span> <span class="n">install</span> <span class="n">rns</span>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">rns</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The above command will install Reticulum and dependencies, and you will be
|
||||
ready to import and use RNS in your own programs. The next step will most
|
||||
likely be to look at some <a class="reference internal" href="examples.html#examples-main"><span class="std std-ref">Example Programs</span></a>.</p>
|
||||
<p>For extended functionality, you can install optional dependencies:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip3</span> <span class="n">install</span> <span class="n">pyserial</span>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="n">pip</span> <span class="n">install</span> <span class="n">pyserial</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Further information can be found in the <a class="reference internal" href="reference.html#api-main"><span class="std std-ref">API Reference</span></a>.</p>
|
||||
@@ -461,7 +462,7 @@ likely be to look at some <a class="reference internal" href="examples.html#exam
|
||||
utilities, you’ll want to get the latest source from GitHub. In that case,
|
||||
don’t use pip, but try this recipe:</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install dependencies</span>
|
||||
<span class="n">pip3</span> <span class="n">install</span> <span class="n">cryptography</span> <span class="n">pyserial</span>
|
||||
<span class="n">pip</span> <span class="n">install</span> <span class="n">cryptography</span> <span class="n">pyserial</span>
|
||||
|
||||
<span class="c1"># Clone repository</span>
|
||||
<span class="n">git</span> <span class="n">clone</span> <span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">github</span><span class="o">.</span><span class="n">com</span><span class="o">/</span><span class="n">markqvist</span><span class="o">/</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">git</span>
|
||||
@@ -471,25 +472,25 @@ don’t use pip, but try this recipe:</p>
|
||||
<span class="n">ln</span> <span class="o">-</span><span class="n">s</span> <span class="o">../</span><span class="n">RNS</span> <span class="o">./</span><span class="n">Examples</span><span class="o">/</span>
|
||||
|
||||
<span class="c1"># Run an example</span>
|
||||
<span class="n">python3</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">s</span>
|
||||
<span class="n">python</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">s</span>
|
||||
|
||||
<span class="c1"># Unless you've manually created a config file, Reticulum will do so now,</span>
|
||||
<span class="c1"># and immediately exit. Make any necessary changes to the file:</span>
|
||||
<span class="n">nano</span> <span class="o">~/.</span><span class="n">reticulum</span><span class="o">/</span><span class="n">config</span>
|
||||
|
||||
<span class="c1"># ... and launch the example again.</span>
|
||||
<span class="n">python3</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">s</span>
|
||||
<span class="n">python</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">s</span>
|
||||
|
||||
<span class="c1"># You can now repeat the process on another computer,</span>
|
||||
<span class="c1"># and run the same example with -h to get command line options.</span>
|
||||
<span class="n">python3</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">h</span>
|
||||
<span class="n">python</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">h</span>
|
||||
|
||||
<span class="c1"># Run the example in client mode to "ping" the server.</span>
|
||||
<span class="c1"># Replace the hash below with the actual destination hash of your server.</span>
|
||||
<span class="n">python3</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="mi">174</span><span class="n">a64852a75682259ad8b921b8bf416</span>
|
||||
<span class="n">python</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Echo</span><span class="o">.</span><span class="n">py</span> <span class="mi">174</span><span class="n">a64852a75682259ad8b921b8bf416</span>
|
||||
|
||||
<span class="c1"># Have a look at another example</span>
|
||||
<span class="n">python3</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Filetransfer</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">h</span>
|
||||
<span class="n">python</span> <span class="n">Examples</span><span class="o">/</span><span class="n">Filetransfer</span><span class="o">.</span><span class="n">py</span> <span class="o">-</span><span class="n">h</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>When you have experimented with the basic examples, it’s time to go read the
|
||||
@@ -586,11 +587,11 @@ detailed in this manual.</p>
|
||||
</section>
|
||||
<section id="debian-bookworm">
|
||||
<h3>Debian Bookworm<a class="headerlink" href="#debian-bookworm" title="Permalink to this heading">#</a></h3>
|
||||
<p>On versions of Debian released after April 2023, it is no longer possible
|
||||
<p>On versions of Debian released after April 2023, it is no longer possible by default
|
||||
to use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement <code class="docutils literal notranslate"><span class="pre">pipx</span></code> command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but installation
|
||||
via this method is not fully tested yet.</p>
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install pipx</span>
|
||||
<span class="n">sudo</span> <span class="n">apt</span> <span class="n">install</span> <span class="n">pipx</span>
|
||||
|
||||
@@ -601,14 +602,25 @@ via this method is not fully tested yet.</p>
|
||||
<span class="n">pipx</span> <span class="n">install</span> <span class="n">rns</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Alternatively, you can restore normal behaviour to <code class="docutils literal notranslate"><span class="pre">pip</span></code> by creating or editing
|
||||
the configuration file located at <code class="docutils literal notranslate"><span class="pre">~/.config/pip/pip.conf</span></code>, and adding the
|
||||
following section:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>[global]
|
||||
break-system-packages = true
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Please note that the “break-system-packages” directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this <em>could</em> in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems.</p>
|
||||
</section>
|
||||
<section id="ubuntu-lunar">
|
||||
<h3>Ubuntu Lunar<a class="headerlink" href="#ubuntu-lunar" title="Permalink to this heading">#</a></h3>
|
||||
<p>On versions of Ubuntu released after April 2023, it is no longer possible
|
||||
<p>On versions of Ubuntu released after April 2023, it is no longer possible by default
|
||||
to use <code class="docutils literal notranslate"><span class="pre">pip</span></code> to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement <code class="docutils literal notranslate"><span class="pre">pipx</span></code> command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but installation
|
||||
via this method is not fully tested yet.</p>
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Install pipx</span>
|
||||
<span class="n">sudo</span> <span class="n">apt</span> <span class="n">install</span> <span class="n">pipx</span>
|
||||
|
||||
@@ -619,14 +631,23 @@ via this method is not fully tested yet.</p>
|
||||
<span class="n">pipx</span> <span class="n">install</span> <span class="n">rns</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Alternatively, you can restore normal behaviour to <code class="docutils literal notranslate"><span class="pre">pip</span></code> by creating or editing
|
||||
the configuration file located at <code class="docutils literal notranslate"><span class="pre">~/.config/pip/pip.conf</span></code>, and adding the
|
||||
following section:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>[global]
|
||||
break-system-packages = true
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Please note that the “break-system-packages” directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing <code class="docutils literal notranslate"><span class="pre">pip</span></code> packages user- and system-wide. While this _could_ in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="pure-python-reticulum">
|
||||
<h2>Pure-Python Reticulum<a class="headerlink" href="#pure-python-reticulum" title="Permalink to this heading">#</a></h2>
|
||||
<p>In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies</p>
|
||||
<p>On more unusual systems, and in some rare cases, it might not be possible to
|
||||
install or even compile one or more of the above modules. In such situations,
|
||||
install one or more dependencies. In such situations,
|
||||
you can use the <code class="docutils literal notranslate"><span class="pre">rnspure</span></code> package instead of the <code class="docutils literal notranslate"><span class="pre">rns</span></code> package, or use <code class="docutils literal notranslate"><span class="pre">pip</span></code>
|
||||
with the <code class="docutils literal notranslate"><span class="pre">--no-dependencies</span></code> command-line option. The <code class="docutils literal notranslate"><span class="pre">rnspure</span></code>
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
@@ -737,14 +758,11 @@ section of this manual.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+55
-38
@@ -3,15 +3,15 @@
|
||||
<head><meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Supported Interfaces" href="interfaces.html" /><link rel="prev" title="Understanding Reticulum" href="understanding.html" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Communications Hardware - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -240,10 +240,17 @@ starting from scratch.</p>
|
||||
<p>This chapter will outline a few different sensible starting paths to get
|
||||
real-world functional wireless communications up and running with minimal cost
|
||||
and effort. Two fundamental devices categories will be covered, <em>RNodes</em> and
|
||||
<em>WiFi-based radios</em>.</p>
|
||||
<p>While there are many other device categories that are useful in building Reticulum
|
||||
networks, knowing how to employ just these two will make it possible to build
|
||||
a wide range of useful networks with little effort.</p>
|
||||
<em>WiFi-based radios</em>. Additionally, other common options will be briefly described.</p>
|
||||
<p>Knowing how to employ just a few different types of hardware will make it possible
|
||||
to build a wide range of useful networks with little effort.</p>
|
||||
<section id="combining-hardware-types">
|
||||
<h2>Combining Hardware Types<a class="headerlink" href="#combining-hardware-types" title="Permalink to this heading">#</a></h2>
|
||||
<p>It is useful to combine different link and hardware types when designing and
|
||||
building a network. One useful design pattern is to employ high-capacity point-to-point
|
||||
links based on WiFi or millimeter-wave radios (with high-gain directional antennas)
|
||||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.</p>
|
||||
</section>
|
||||
<section id="rnode">
|
||||
<span id="rnode-main"></span><h2>RNode<a class="headerlink" href="#rnode" title="Permalink to this heading">#</a></h2>
|
||||
<p>Reliable and general-purpose long-range digital radio transceiver systems are
|
||||
@@ -373,11 +380,6 @@ such as serial port and on-air parameters. For v2.x firmwares, you just need to
|
||||
the Connection ID of the RNode, and Reticulum will automatically locate and connect to the
|
||||
RNode, using the parameters stored in the RNode itself.</p>
|
||||
</section>
|
||||
<section id="suppliers">
|
||||
<span id="rnode-suppliers"></span><h3>Suppliers<a class="headerlink" href="#suppliers" title="Permalink to this heading">#</a></h3>
|
||||
<p>Get in touch if you want to have your RNode supplier listed here, or if you want help to
|
||||
get started with producing RNodes.</p>
|
||||
</section>
|
||||
</section>
|
||||
<section id="wifi-based-hardware">
|
||||
<h2>WiFi-based Hardware<a class="headerlink" href="#wifi-based-hardware" title="Permalink to this heading">#</a></h2>
|
||||
@@ -403,13 +405,29 @@ that is relatively cheap while providing long range and high capacity for Reticu
|
||||
networks. As in all other cases, it is also possible for Reticulum to co-exist with IP
|
||||
networks running concurrently on such devices.</p>
|
||||
</section>
|
||||
<section id="combining-hardware-types">
|
||||
<h2>Combining Hardware Types<a class="headerlink" href="#combining-hardware-types" title="Permalink to this heading">#</a></h2>
|
||||
<p>It is useful to combine different link and hardware types when designing and
|
||||
building a network. One useful design pattern is to employ high-capacity point-to-point
|
||||
links based on WiFi or millimeter-wave radios (with high-gain directional antennas)
|
||||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.</p>
|
||||
<section id="ethernet-based-hardware">
|
||||
<h2>Ethernet-based Hardware<a class="headerlink" href="#ethernet-based-hardware" title="Permalink to this heading">#</a></h2>
|
||||
<p>Reticulum can run over any kind of hardware that can provide a switched Ethernet-based
|
||||
medium. This means that anything from a plain Ethernet switch, to fiber-optic systems,
|
||||
to data radios with Ethernet interfaces can be used by Reticulum.</p>
|
||||
<p>The Ethernet medium does not need to have any IP infrastructure such as DHCP servers
|
||||
or routing set up, but in case such infrastructure does exist, Reticulum will simply
|
||||
co-exist with.</p>
|
||||
<p>To use Reticulum over Ethernet-based mediums, it is generally enough to use the included
|
||||
<a class="reference internal" href="interfaces.html#interfaces-auto"><span class="std std-ref">AutoInterface</span></a>. This interface also works over any kind of
|
||||
virtual networking adapter, such as <code class="docutils literal notranslate"><span class="pre">tun</span></code> and <code class="docutils literal notranslate"><span class="pre">tap</span></code> devices in Linux.</p>
|
||||
</section>
|
||||
<section id="serial-lines-devices">
|
||||
<h2>Serial Lines & Devices<a class="headerlink" href="#serial-lines-devices" title="Permalink to this heading">#</a></h2>
|
||||
<p>Using Reticulum over any kind of raw serial line is also possible with the
|
||||
<a class="reference internal" href="interfaces.html#interfaces-serial"><span class="std std-ref">SerialInterface</span></a>. This interface type is also useful for
|
||||
using Reticulum over communications hardware that provides a serial port interface.</p>
|
||||
</section>
|
||||
<section id="packet-radio-modems">
|
||||
<h2>Packet Radio Modems<a class="headerlink" href="#packet-radio-modems" title="Permalink to this heading">#</a></h2>
|
||||
<p>Any packet radio modem that provides a standard KISS interface over USB, serial or TCP
|
||||
can be used with Reticulum. This includes virtual software modems such as
|
||||
<a class="reference external" href="https://github.com/xssfox/freedv-tnc">FreeDV TNC</a> and <a class="reference external" href="https://github.com/wb2osz/direwolf">Dire Wolf</a>.</p>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
@@ -423,7 +441,7 @@ connectivity for client devices.</p>
|
||||
<div class="context">
|
||||
<span>Next</span>
|
||||
</div>
|
||||
<div class="title">Supported Interfaces</div>
|
||||
<div class="title">Configuring Interfaces</div>
|
||||
</div>
|
||||
<svg class="furo-related-icon"><use href="#svg-arrow-right"></use></svg>
|
||||
</a>
|
||||
@@ -470,6 +488,7 @@ connectivity for client devices.</p>
|
||||
<div class="toc-tree">
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Communications Hardware</a><ul>
|
||||
<li><a class="reference internal" href="#combining-hardware-types">Combining Hardware Types</a></li>
|
||||
<li><a class="reference internal" href="#rnode">RNode</a><ul>
|
||||
<li><a class="reference internal" href="#creating-rnodes">Creating RNodes</a></li>
|
||||
<li><a class="reference internal" href="#supported-boards">Supported Boards</a><ul>
|
||||
@@ -483,11 +502,12 @@ connectivity for client devices.</p>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#installation">Installation</a></li>
|
||||
<li><a class="reference internal" href="#usage-with-reticulum">Usage with Reticulum</a></li>
|
||||
<li><a class="reference internal" href="#suppliers">Suppliers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a class="reference internal" href="#wifi-based-hardware">WiFi-based Hardware</a></li>
|
||||
<li><a class="reference internal" href="#combining-hardware-types">Combining Hardware Types</a></li>
|
||||
<li><a class="reference internal" href="#ethernet-based-hardware">Ethernet-based Hardware</a></li>
|
||||
<li><a class="reference internal" href="#serial-lines-devices">Serial Lines & Devices</a></li>
|
||||
<li><a class="reference internal" href="#packet-radio-modems">Packet Radio Modems</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -499,14 +519,11 @@ connectivity for client devices.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+22
-21
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="#"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="#"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="#">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="#">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -272,6 +272,7 @@ to participate in the development of Reticulum itself.</p>
|
||||
<li class="toctree-l2"><a class="reference internal" href="using.html#included-utility-programs">Included Utility Programs</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnsd-utility">The rnsd Utility</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnstatus-utility">The rnstatus Utility</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnid-utility">The rnid Utility</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnpath-utility">The rnpath Utility</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rnprobe-utility">The rnprobe Utility</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="using.html#the-rncp-utility">The rncp Utility</a></li>
|
||||
@@ -315,19 +316,21 @@ to participate in the development of Reticulum itself.</p>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="hardware.html#combining-hardware-types">Combining Hardware Types</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="hardware.html#rnode">RNode</a><ul>
|
||||
<li class="toctree-l3"><a class="reference internal" href="hardware.html#creating-rnodes">Creating RNodes</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="hardware.html#supported-boards">Supported Boards</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="hardware.html#installation">Installation</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="hardware.html#usage-with-reticulum">Usage with Reticulum</a></li>
|
||||
<li class="toctree-l3"><a class="reference internal" href="hardware.html#suppliers">Suppliers</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="hardware.html#wifi-based-hardware">WiFi-based Hardware</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="hardware.html#combining-hardware-types">Combining Hardware Types</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="hardware.html#ethernet-based-hardware">Ethernet-based Hardware</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="hardware.html#serial-lines-devices">Serial Lines & Devices</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="hardware.html#packet-radio-modems">Packet Radio Modems</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a><ul>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a><ul>
|
||||
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#auto-interface">Auto Interface</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#i2p-interface">I2P Interface</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#tcp-server-interface">TCP Server Interface</a></li>
|
||||
@@ -341,6 +344,7 @@ to participate in the development of Reticulum itself.</p>
|
||||
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#common-interface-options">Common Interface Options</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#interface-modes">Interface Modes</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#announce-rate-control">Announce Rate Control</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="interfaces.html#new-destination-rate-limiting">New Destination Rate Limiting</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a><ul>
|
||||
@@ -464,14 +468,11 @@ to participate in the development of Reticulum itself.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+119
-22
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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>Supported Interfaces - Reticulum Network Stack 0.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Configuring Interfaces - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -221,8 +221,8 @@
|
||||
</label>
|
||||
</div>
|
||||
<article role="main">
|
||||
<section id="supported-interfaces">
|
||||
<span id="interfaces-main"></span><h1>Supported Interfaces<a class="headerlink" href="#supported-interfaces" title="Permalink to this heading">#</a></h1>
|
||||
<section id="configuring-interfaces">
|
||||
<span id="interfaces-main"></span><h1>Configuring Interfaces<a class="headerlink" href="#configuring-interfaces" title="Permalink to this heading">#</a></h1>
|
||||
<p>Reticulum supports using many kinds of devices as networking interfaces, and
|
||||
allows you to mix and match them in any way you choose. The number of distinct
|
||||
network topologies you can create with Reticulum is more or less endless, but
|
||||
@@ -527,6 +527,7 @@ can be used, and offers full control over LoRa parameters.</p>
|
||||
<span class="c1"># out identification on the channel with</span>
|
||||
<span class="c1"># a set interval by configuring the</span>
|
||||
<span class="c1"># following two parameters.</span>
|
||||
|
||||
<span class="c1"># id_callsign = MYCALL-0</span>
|
||||
<span class="c1"># id_interval = 600</span>
|
||||
|
||||
@@ -534,7 +535,20 @@ can be used, and offers full control over LoRa parameters.</p>
|
||||
<span class="c1"># with low amounts of RAM, using packet</span>
|
||||
<span class="c1"># flow control can be useful. By default</span>
|
||||
<span class="c1"># it is disabled.</span>
|
||||
<span class="n">flow_control</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
|
||||
<span class="c1"># flow_control = False</span>
|
||||
|
||||
<span class="c1"># It is possible to limit the airtime</span>
|
||||
<span class="c1"># utilisation of an RNode by using the</span>
|
||||
<span class="c1"># following two configuration options.</span>
|
||||
<span class="c1"># The short-term limit is applied in a</span>
|
||||
<span class="c1"># window of approximately 15 seconds,</span>
|
||||
<span class="c1"># and the long-term limit is enforced</span>
|
||||
<span class="c1"># over a rolling 60 minute window. Both</span>
|
||||
<span class="c1"># options are specified in percent.</span>
|
||||
|
||||
<span class="c1"># airtime_limit_long = 1.5</span>
|
||||
<span class="c1"># airtime_limit_short = 33</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -923,6 +937,91 @@ conserve bandwidth, while very fast networks can support applications that
|
||||
need very frequent announces. Reticulum implements these mechanisms to ensure
|
||||
that a large span of network types can seamlessly <em>co-exist</em> and interconnect.</p>
|
||||
</section>
|
||||
<section id="new-destination-rate-limiting">
|
||||
<span id="interfaces-ingress-control"></span><h2>New Destination Rate Limiting<a class="headerlink" href="#new-destination-rate-limiting" title="Permalink to this heading">#</a></h2>
|
||||
<p>On public interfaces, where anyone may connect and announce new destinations,
|
||||
it can be useful to control the rate at which announces for <em>new</em> destinations are
|
||||
processed.</p>
|
||||
<p>If a large influx of announces for newly created or previously unknown destinations
|
||||
occur within a short amount of time, Reticulum will place these announces on hold,
|
||||
so that announce traffic for known and previously established destinations can
|
||||
continue to be processed without interruptions.</p>
|
||||
<p>After the burst subsides, and an additional waiting period has passed, the held
|
||||
announces will be released at a slow rate, until the hold queue is cleared. This
|
||||
also means, that should a node decide to connect to a public interface, announce
|
||||
a large amount of bogus destinations, and then disconnect, these destination will
|
||||
never make it into path tables and waste network bandwidth on retransmitted
|
||||
announces.</p>
|
||||
<p><strong>It’s important to note</strong> that the ingress control works at the level of <em>individual
|
||||
sub-interfaces</em>. As an example, this means that one client on a <a class="reference internal" href="#interfaces-tcps"><span class="std std-ref">TCP Server Interface</span></a>
|
||||
cannot disrupt processing of incoming announces for other connected clients on the same
|
||||
<a class="reference internal" href="#interfaces-tcps"><span class="std std-ref">TCP Server Interface</span></a>. All other clients on the same interface will still have new announces
|
||||
processed without interruption.</p>
|
||||
<p>By default, Reticulum will handle this automatically, and ingress announce
|
||||
control will be enabled on interface where it is sensible to do so. It should
|
||||
generally not be neccessary to modify the ingress control configuration,
|
||||
but all the parameters are exposed for configuration if needed.</p>
|
||||
<blockquote>
|
||||
<div><ul>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ingress_control</span></code> option tells Reticulum whether or not
|
||||
to enable announce ingress control on the interface. Defaults to
|
||||
<code class="docutils literal notranslate"><span class="pre">True</span></code>.</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ic_new_time</span></code> option configures how long (in seconds) an
|
||||
interface is considered newly spawned. Defaults to <code class="docutils literal notranslate"><span class="pre">2*60*60</span></code> seconds. This
|
||||
option is useful on publicly accessible interfaces that spawn new
|
||||
sub-interfaces when a new client connects.</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ic_burst_freq_new</span></code> option sets the maximum announce ingress
|
||||
frequency for newly spawned interfaces. Defaults to <code class="docutils literal notranslate"><span class="pre">3.5</span></code>
|
||||
announces per second.</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ic_burst_freq</span></code> option sets the maximum announce ingress
|
||||
frequency for other interfaces. Defaults to <code class="docutils literal notranslate"><span class="pre">12</span></code> announces
|
||||
per second.</div>
|
||||
</div>
|
||||
<blockquote>
|
||||
<div><p><em>If an interface exceeds its burst frequency, incoming announces
|
||||
for unknown destinations will be temporarily held in a queue, and
|
||||
not processed until later.</em></p>
|
||||
</div></blockquote>
|
||||
</li>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ic_max_held_announces</span></code> option sets the maximum amount of
|
||||
unique announces that will be held in the queue. Any additional
|
||||
unique announces will be dropped. Defaults to <code class="docutils literal notranslate"><span class="pre">256</span></code> announces.</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ic_burst_hold</span></code> option sets how much time (in seconds) must
|
||||
pass after the burst frequency drops below its threshold, for the
|
||||
announce burst to be considered cleared. Defaults to <code class="docutils literal notranslate"><span class="pre">60</span></code>
|
||||
seconds.</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ic_burst_penalty</span></code> option sets how much time (in seconds) must
|
||||
pass after the burst is considered cleared, before held announces can
|
||||
start being released from the queue. Defaults to <code class="docutils literal notranslate"><span class="pre">5*60</span></code>
|
||||
seconds.</div>
|
||||
</div>
|
||||
</li>
|
||||
<li><div class="line-block">
|
||||
<div class="line">The <code class="docutils literal notranslate"><span class="pre">ic_held_release_interval</span></code> option sets how much time (in seconds)
|
||||
must pass between releasing each held announce from the queue. Defaults
|
||||
to <code class="docutils literal notranslate"><span class="pre">30</span></code> seconds.</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div></blockquote>
|
||||
</section>
|
||||
</section>
|
||||
|
||||
</article>
|
||||
@@ -981,7 +1080,7 @@ that a large span of network types can seamlessly <em>co-exist</em> and intercon
|
||||
<div class="toc-tree-container">
|
||||
<div class="toc-tree">
|
||||
<ul>
|
||||
<li><a class="reference internal" href="#">Supported Interfaces</a><ul>
|
||||
<li><a class="reference internal" href="#">Configuring Interfaces</a><ul>
|
||||
<li><a class="reference internal" href="#auto-interface">Auto Interface</a></li>
|
||||
<li><a class="reference internal" href="#i2p-interface">I2P Interface</a></li>
|
||||
<li><a class="reference internal" href="#tcp-server-interface">TCP Server Interface</a></li>
|
||||
@@ -995,6 +1094,7 @@ that a large span of network types can seamlessly <em>co-exist</em> and intercon
|
||||
<li><a class="reference internal" href="#common-interface-options">Common Interface Options</a></li>
|
||||
<li><a class="reference internal" href="#interface-modes">Interface Modes</a></li>
|
||||
<li><a class="reference internal" href="#announce-rate-control">Announce Rate Control</a></li>
|
||||
<li><a class="reference internal" href="#new-destination-rate-limiting">New Destination Rate Limiting</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -1006,14 +1106,11 @@ that a large span of network types can seamlessly <em>co-exist</em> and intercon
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+17
-20
@@ -3,15 +3,15 @@
|
||||
<head><meta charset="utf-8"/>
|
||||
<meta name="viewport" content="width=device-width,initial-scale=1"/>
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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="Supported Interfaces" href="interfaces.html" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Building Networks - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -413,7 +413,7 @@ connected outliers are now an integral part of the network.</p>
|
||||
<span>Previous</span>
|
||||
</div>
|
||||
|
||||
<div class="title">Supported Interfaces</div>
|
||||
<div class="title">Configuring Interfaces</div>
|
||||
|
||||
</div>
|
||||
</a>
|
||||
@@ -467,14 +467,11 @@ connected outliers are now an integral part of the network.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
Binary file not shown.
+18
-21
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>API Reference - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -850,7 +850,7 @@ unless other app_data is specified in the <em>announce</em> method.</p>
|
||||
<em class="property"><span class="pre">class</span><span class="w"> </span></em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Packet</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">destination</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">create_receipt</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Packet" title="Permalink to this definition">#</a></dt>
|
||||
<dd><p>The Packet class is used to create packet instances that can be sent
|
||||
over a Reticulum network. Packets will automatically be encrypted if
|
||||
they are adressed to a <code class="docutils literal notranslate"><span class="pre">RNS.Destination.SINGLE</span></code> destination,
|
||||
they are addressed to a <code class="docutils literal notranslate"><span class="pre">RNS.Destination.SINGLE</span></code> destination,
|
||||
<code class="docutils literal notranslate"><span class="pre">RNS.Destination.GROUP</span></code> destination or a <a class="reference internal" href="#api-link"><span class="std std-ref">RNS.Link</span></a>.</p>
|
||||
<p>For <code class="docutils literal notranslate"><span class="pre">RNS.Destination.GROUP</span></code> destinations, Reticulum will use the
|
||||
pre-shared key configured for the destination. All packets to group
|
||||
@@ -1536,7 +1536,7 @@ and <code class="docutils literal notranslate"><span class="pre">BufferedRWPair<
|
||||
<code class="docutils literal notranslate"><span class="pre">RawChannelReader</span></code> and <code class="docutils literal notranslate"><span class="pre">RawChannelWriter</span></code>.</p>
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Buffer.create_reader">
|
||||
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">create_reader</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">stream_id</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">channel</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#RNS.Channel.Channel" title="RNS.Channel.Channel"><span class="pre">Channel</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">ready_callback</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">Callable</span><span class="p"><span class="pre">[</span></span><span class="p"><span class="pre">[</span></span><span class="pre">int</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">None</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">BufferedReader</span></span></span><a class="headerlink" href="#RNS.Buffer.create_reader" title="Permalink to this definition">#</a></dt>
|
||||
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">create_reader</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">stream_id</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">channel</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#RNS.Channel.Channel" title="RNS.Channel.Channel"><span class="pre">Channel</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">ready_callback</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Callable</span><span class="p"><span class="pre">[</span></span><span class="p"><span class="pre">[</span></span><span class="pre">int</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">None</span><span class="p"><span class="pre">]</span></span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">BufferedReader</span></span></span><a class="headerlink" href="#RNS.Buffer.create_reader" title="Permalink to this definition">#</a></dt>
|
||||
<dd><p>Create a buffered reader that reads binary data sent
|
||||
over a <code class="docutils literal notranslate"><span class="pre">Channel</span></code>, with an optional callback when
|
||||
new data is available.</p>
|
||||
@@ -1581,7 +1581,7 @@ of this object, see the Python documentation for
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Buffer.create_bidirectional_buffer">
|
||||
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">create_bidirectional_buffer</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">receive_stream_id</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">send_stream_id</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">channel</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#RNS.Channel.Channel" title="RNS.Channel.Channel"><span class="pre">Channel</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">ready_callback</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Optional</span><span class="p"><span class="pre">[</span></span><span class="pre">Callable</span><span class="p"><span class="pre">[</span></span><span class="p"><span class="pre">[</span></span><span class="pre">int</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">None</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">]</span></span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">BufferedRWPair</span></span></span><a class="headerlink" href="#RNS.Buffer.create_bidirectional_buffer" title="Permalink to this definition">#</a></dt>
|
||||
<em class="property"><span class="pre">static</span><span class="w"> </span></em><span class="sig-name descname"><span class="pre">create_bidirectional_buffer</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">receive_stream_id</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">send_stream_id</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">int</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">channel</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><a class="reference internal" href="#RNS.Channel.Channel" title="RNS.Channel.Channel"><span class="pre">Channel</span></a></span></em>, <em class="sig-param"><span class="n"><span class="pre">ready_callback</span></span><span class="p"><span class="pre">:</span></span><span class="w"> </span><span class="n"><span class="pre">Callable</span><span class="p"><span class="pre">[</span></span><span class="p"><span class="pre">[</span></span><span class="pre">int</span><span class="p"><span class="pre">]</span></span><span class="p"><span class="pre">,</span></span><span class="w"> </span><span class="pre">None</span><span class="p"><span class="pre">]</span></span><span class="w"> </span><span class="p"><span class="pre">|</span></span><span class="w"> </span><span class="pre">None</span></span><span class="w"> </span><span class="o"><span class="pre">=</span></span><span class="w"> </span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span> <span class="sig-return"><span class="sig-return-icon">→</span> <span class="sig-return-typehint"><span class="pre">BufferedRWPair</span></span></span><a class="headerlink" href="#RNS.Buffer.create_bidirectional_buffer" title="Permalink to this definition">#</a></dt>
|
||||
<dd><p>Create a buffered reader/writer pair that reads and
|
||||
writes binary data over a <code class="docutils literal notranslate"><span class="pre">Channel</span></code>, with an
|
||||
optional callback when new data is available.</p>
|
||||
@@ -2013,14 +2013,11 @@ will announce it.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+13
-16
@@ -4,11 +4,11 @@
|
||||
<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.5.6 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/><title>Search - Reticulum Network Stack 0.6.1 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -138,7 +138,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -158,13 +158,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -178,7 +178,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -262,15 +262,12 @@
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
|
||||
<script src="_static/searchtools.js"></script>
|
||||
<script src="_static/language_data.js"></script>
|
||||
|
||||
File diff suppressed because one or more lines are too long
+15
-18
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Support Reticulum - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Support Reticulum</a></li>
|
||||
@@ -330,14 +330,11 @@ report issues, suggest functionality and contribute code to Reticulum.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Understanding Reticulum - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -1196,14 +1196,11 @@ those risks are acceptable to you.</p>
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+271
-83
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>Using Reticulum on Your System - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1 current current-page"><a class="current reference internal" href="#">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -316,6 +316,17 @@ configuration file is created. The default configuration looks like this:</p>
|
||||
<span class="n">panic_on_interface_error</span> <span class="o">=</span> <span class="n">No</span>
|
||||
|
||||
|
||||
<span class="c1"># When Transport is enabled, it is possible to allow the</span>
|
||||
<span class="c1"># Transport Instance to respond to probe requests from</span>
|
||||
<span class="c1"># the rnprobe utility. This can be a useful tool to test</span>
|
||||
<span class="c1"># connectivity. When this option is enabled, the probe</span>
|
||||
<span class="c1"># destination will be generated from the Identity of the</span>
|
||||
<span class="c1"># Transport Instance, and printed to the log at startup.</span>
|
||||
<span class="c1"># Optional, and disabled by default.</span>
|
||||
|
||||
<span class="n">respond_to_probes</span> <span class="o">=</span> <span class="n">No</span>
|
||||
|
||||
|
||||
<span class="p">[</span><span class="n">logging</span><span class="p">]</span>
|
||||
<span class="c1"># Valid log levels are 0 through 7:</span>
|
||||
<span class="c1"># 0: Log only critical information</span>
|
||||
@@ -354,10 +365,15 @@ configuration file is created. The default configuration looks like this:</p>
|
||||
<p>If Reticulum infrastructure already exists locally, you probably don’t need to
|
||||
change anything, and you may already be connected to a wider network. If not,
|
||||
you will probably need to add relevant <em>interfaces</em> to the configuration, in
|
||||
order to communicate with other systems. It is a good idea to read the comments
|
||||
and explanations in the above default config. It will teach you the basic
|
||||
concepts you need to understand to configure your network. Once you have done that,
|
||||
take a look at the <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Interfaces</span></a> chapter of this manual.</p>
|
||||
order to communicate with other systems.</p>
|
||||
<p>You can generate a much more verbose configuration example by running the command:</p>
|
||||
<p><code class="docutils literal notranslate"><span class="pre">rnsd</span> <span class="pre">--exampleconfig</span></code></p>
|
||||
<p>The output includes examples for most interface types supported
|
||||
by Reticulum, along with additional options and configuration parameters.</p>
|
||||
<p>It is a good idea to read the comments and explanations in the above default config.
|
||||
It will teach you the basic concepts you need to understand to configure your network.
|
||||
Once you have done that, take a look at the <a class="reference internal" href="interfaces.html#interfaces-main"><span class="std std-ref">Interfaces</span></a> chapter
|
||||
of this manual.</p>
|
||||
</section>
|
||||
<section id="included-utility-programs">
|
||||
<h2>Included Utility Programs<a class="headerlink" href="#included-utility-programs" title="Permalink to this heading">#</a></h2>
|
||||
@@ -374,24 +390,36 @@ other programs, applications and services can utilise.</p>
|
||||
When <code class="docutils literal notranslate"><span class="pre">rnsd</span></code> is running, it will keep all configured interfaces open, handle transport if
|
||||
it is enabled, and allow any other programs to immediately utilise the
|
||||
Reticulum network it is configured for.</p>
|
||||
<p>You can even run multiple instances of rnsd with different configurations on
|
||||
<p>You can even run multiple instances of <code class="docutils literal notranslate"><span class="pre">rnsd</span></code> with different configurations on
|
||||
the same system.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Install Reticulum
|
||||
pip3 install rns
|
||||
<p><strong>Usage Examples</strong></p>
|
||||
<p>Run <code class="docutils literal notranslate"><span class="pre">rnsd</span></code>:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnsd
|
||||
|
||||
# Run rnsd
|
||||
rnsd
|
||||
[2023-08-18 17:59:56] [Notice] Started rnsd version 0.5.8
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
|
||||
<p>Run <code class="docutils literal notranslate"><span class="pre">rnsd</span></code> in service mode, ensuring all logging output is sent directly to file:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnsd -s
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Generate a verbose and detailed configuration example, with explanations of all the
|
||||
various configuration options, and interface configuration examples:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnsd --exampleconfig
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnsd.py [-h] [--config CONFIG] [-v] [-q] [-s] [--exampleconfig] [--version]
|
||||
|
||||
Reticulum Network Stack Daemon
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
-s, --service rnsd is running as a service and should log to file
|
||||
--exampleconfig print verbose configuration example to stdout and exit
|
||||
--version show program's version number and exit
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -401,10 +429,10 @@ optional arguments:
|
||||
<h3>The rnstatus Utility<a class="headerlink" href="#the-rnstatus-utility" title="Permalink to this heading">#</a></h3>
|
||||
<p>Using the <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code> utility, you can view the status of configured Reticulum
|
||||
interfaces, similar to the <code class="docutils literal notranslate"><span class="pre">ifconfig</span></code> program.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rnstatus
|
||||
rnstatus
|
||||
<p><strong>Usage Examples</strong></p>
|
||||
<p>Run <code class="docutils literal notranslate"><span class="pre">rnstatus</span></code>:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnstatus
|
||||
|
||||
# Example output
|
||||
Shared Instance[37428]
|
||||
Status : Up
|
||||
Serving : 1 program
|
||||
@@ -438,38 +466,147 @@ RNodeInterface[RNode UHF]
|
||||
Reticulum Transport Instance <5245a8efe1788c6a1cd36144a270e13b> running
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnstatus [-h] [--config CONFIG] [--version] [-a] [-v]
|
||||
<p>Filter output to only show some interfaces:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnstatus rnode
|
||||
|
||||
RNodeInterface[RNode UHF]
|
||||
Status : Up
|
||||
Mode : Access Point
|
||||
Rate : 1.30 kbps
|
||||
Access : 64-bit IFAC by <…e702c42ba8>
|
||||
Traffic : 8.49 KB↑
|
||||
9.23 KB↓
|
||||
|
||||
Reticulum Transport Instance <5245a8efe1788c6a1cd36144a270e13b> running
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnstatus.py [-h] [--config CONFIG] [--version] [-a] [-A] [-s SORT]
|
||||
[-r] [-j] [-v] [filter]
|
||||
|
||||
Reticulum Network Stack Status
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
-a, --all show all interfaces
|
||||
positional arguments:
|
||||
filter only display interfaces with names including filter
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
-a, --all show all interfaces
|
||||
-A, --announce-stats show announce stats
|
||||
-s SORT, --sort SORT sort interfaces by [rate, traffic, rx, tx, announces, arx, atx, held]
|
||||
-r, --reverse reverse sorting
|
||||
-j, --json output in JSON format
|
||||
-v, --verbose
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="the-rnid-utility">
|
||||
<h3>The rnid Utility<a class="headerlink" href="#the-rnid-utility" title="Permalink to this heading">#</a></h3>
|
||||
<p>With the <code class="docutils literal notranslate"><span class="pre">rnid</span></code> utility, you can generate, manage and view Reticulum Identities.
|
||||
The program can also calculate Destination hashes, and perform encryption and
|
||||
decryption of files.</p>
|
||||
<p>Using <code class="docutils literal notranslate"><span class="pre">rnid</span></code>, it is possible to asymmetrically encrypt files and information for
|
||||
any Reticulum destination hash, and also to create and verify cryptographic signatures.</p>
|
||||
<p><strong>Usage Examples</strong></p>
|
||||
<p>Generate a new Identity:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnid -g ./new_identity
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Display Identity key information:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnid -i ./new_identity -p
|
||||
|
||||
Loaded Identity <984b74a3f768bef236af4371e6f248cd> from new_id
|
||||
Public Key : 0f4259fef4521ab75a3409e353fe9073eb10783b4912a6a9937c57bf44a62c1e
|
||||
Private Key : Hidden
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Encrypt a file for an LXMF user:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnid -i 8dd57a738226809646089335a6b03695 -e my_file.txt
|
||||
|
||||
Recalled Identity <bc7291552be7a58f361522990465165c> for destination <8dd57a738226809646089335a6b03695>
|
||||
Encrypting my_file.txt
|
||||
File my_file.txt encrypted for <bc7291552be7a58f361522990465165c> to my_file.txt.rfe
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If the Identity for the destination is not already known, you can fetch it from the network by using the <code class="docutils literal notranslate"><span class="pre">-R</span></code> command-line option:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnid -R -i 30602def3b3506a28ed33db6f60cc6c9 -e my_file.txt
|
||||
|
||||
Requesting unknown Identity for <30602def3b3506a28ed33db6f60cc6c9>...
|
||||
Received Identity <2b489d06eaf7c543808c76a5332a447d> for destination <30602def3b3506a28ed33db6f60cc6c9> from the network
|
||||
Encrypting my_file.txt
|
||||
File my_file.txt encrypted for <2b489d06eaf7c543808c76a5332a447d> to my_file.txt.rfe
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Decrypt a file using the Reticulum Identity it was encrypted for:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnid -i ./my_identity -d my_file.txt.rfe
|
||||
|
||||
Loaded Identity <2225fdeecaf6e2db4556c3c2d7637294> from ./my_identity
|
||||
Decrypting ./my_file.txt.rfe...
|
||||
File ./my_file.txt.rfe decrypted with <2225fdeecaf6e2db4556c3c2d7637294> to ./my_file.txt
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnid.py [-h] [--config path] [-i identity] [-g path] [-v] [-q] [-a aspects]
|
||||
[-H aspects] [-e path] [-d path] [-s path] [-V path] [-r path] [-w path]
|
||||
[-f] [-R] [-t seconds] [-p] [-P] [--version]
|
||||
|
||||
Reticulum Identity & Encryption Utility
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config path path to alternative Reticulum config directory
|
||||
-i identity, --identity identity
|
||||
hexadecimal Reticulum Destination hash or path to Identity file
|
||||
-g path, --generate path
|
||||
generate a new Identity
|
||||
-v, --verbose increase verbosity
|
||||
-q, --quiet decrease verbosity
|
||||
-a aspects, --announce aspects
|
||||
announce a destination based on this Identity
|
||||
-H aspects, --hash aspects
|
||||
show destination hashes for other aspects for this Identity
|
||||
-e path, --encrypt path
|
||||
encrypt file
|
||||
-d path, --decrypt path
|
||||
decrypt file
|
||||
-s path, --sign path sign file
|
||||
-V path, --validate path
|
||||
validate signature
|
||||
-r path, --read path input file path
|
||||
-w path, --write path
|
||||
output file path
|
||||
-f, --force write output even if it overwrites existing files
|
||||
-R, --request request unknown Identities from the network
|
||||
-t seconds identity request timeout before giving up
|
||||
-p, --print-identity print identity info and exit
|
||||
-P, --print-private allow displaying private keys
|
||||
--version show program's version number and exit
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
<section id="the-rnpath-utility">
|
||||
<h3>The rnpath Utility<a class="headerlink" href="#the-rnpath-utility" title="Permalink to this heading">#</a></h3>
|
||||
<p>With the <code class="docutils literal notranslate"><span class="pre">rnpath</span></code> utility, you can look up and view paths for
|
||||
destinations on the Reticulum network.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rnpath
|
||||
rnpath c89b4da064bf66d280f0e4d8abfd9806
|
||||
<p><strong>Usage Examples</strong></p>
|
||||
<p>Resolve path to a destination:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnpath c89b4da064bf66d280f0e4d8abfd9806
|
||||
|
||||
# Example output
|
||||
Path found, destination <c89b4da064bf66d280f0e4d8abfd9806> is 4 hops away via <f53a1c4278e0726bb73fcc623d6ce763> on TCPInterface[Testnet/dublin.connect.reticulum.network:4965]
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnpath [-h] [--config CONFIG] [--version] [-t] [-r] [-d] [-D] [-w seconds] [-v] [destination]
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnpath.py [-h] [--config CONFIG] [--version] [-t] [-r] [-d] [-D]
|
||||
[-x] [-w seconds] [-v] [destination]
|
||||
|
||||
Reticulum Path Discovery Utility
|
||||
|
||||
positional arguments:
|
||||
destination hexadecimal hash of the destination
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
@@ -477,6 +614,7 @@ optional arguments:
|
||||
-r, --rates show announce rate info
|
||||
-d, --drop remove the path to a destination
|
||||
-D, --drop-announces drop all queued announces
|
||||
-x, --drop-via drop all paths via specified transport instance
|
||||
-w seconds timeout before giving up
|
||||
-v, --verbose
|
||||
</pre></div>
|
||||
@@ -487,17 +625,41 @@ optional arguments:
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rnprobe</span></code> utility lets you probe a destination for connectivity, similar
|
||||
to the <code class="docutils literal notranslate"><span class="pre">ping</span></code> program. Please note that probes will only be answered if the
|
||||
specified destination is configured to send proofs for received packets. Many
|
||||
destinations will not have this option enabled, and will not be probable.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rnprobe
|
||||
rnprobe example_utilities.echo.request 2d03725b327348980d570f739a3a5708
|
||||
destinations will not have this option enabled, so most destinations will not
|
||||
be probable.</p>
|
||||
<p>You can enable a probe-reply destination on Reticulum Transport Instances by
|
||||
setting the <code class="docutils literal notranslate"><span class="pre">respond_to_probes</span></code> configuration directive. Reticulum will then
|
||||
print the probe destination to the log on Transport Instance startup.</p>
|
||||
<p><strong>Usage Examples</strong></p>
|
||||
<p>Probe a destination:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnprobe rnstransport.probe 2d03725b327348980d570f739a3a5708
|
||||
|
||||
# Example output
|
||||
Sent 16 byte probe to <2d03725b327348980d570f739a3a5708>
|
||||
Valid reply received from <2d03725b327348980d570f739a3a5708>
|
||||
Round-trip time is 38.469 milliseconds over 2 hops
|
||||
</pre></div>
|
||||
</div>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnprobe [-h] [--config CONFIG] [--version] [-v] [full_name] [destination_hash]
|
||||
<p>Send a larger probe:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnprobe rnstransport.probe 2d03725b327348980d570f739a3a5708 -s 256
|
||||
|
||||
Sent 16 byte probe to <2d03725b327348980d570f739a3a5708>
|
||||
Valid reply received from <2d03725b327348980d570f739a3a5708>
|
||||
Round-trip time is 38.781 milliseconds over 2 hops
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>If the interface that receives the probe replies supports reporting radio
|
||||
parameters such as <strong>RSSI</strong> and <strong>SNR</strong>, the <code class="docutils literal notranslate"><span class="pre">rnprobe</span></code> utility will print
|
||||
these as part of the result as well.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnprobe rnstransport.probe e7536ee90bd4a440e130490b87a25124
|
||||
|
||||
Sent 16 byte probe to <e7536ee90bd4a440e130490b87a25124>
|
||||
Valid reply received from <e7536ee90bd4a440e130490b87a25124>
|
||||
Round-trip time is 1.809 seconds over 1 hop [RSSI -73 dBm] [SNR 12.0 dB]
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnprobe [-h] [--config CONFIG] [--version] [-v] [-s SIZE]
|
||||
[full_name] [destination_hash]
|
||||
|
||||
Reticulum Probe Utility
|
||||
|
||||
@@ -508,6 +670,7 @@ positional arguments:
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
-s SIZE, --size SIZE size of probe packet payload in bytes
|
||||
--version show program's version number and exit
|
||||
-v, --verbose
|
||||
</pre></div>
|
||||
@@ -517,16 +680,27 @@ optional arguments:
|
||||
<h3>The rncp Utility<a class="headerlink" href="#the-rncp-utility" title="Permalink to this heading">#</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rncp</span></code> utility is a simple file transfer tool. Using it, you can transfer
|
||||
files through Reticulum.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rncp on the receiving system, specifying which identities
|
||||
# are allowed to send files
|
||||
rncp --receive -a 1726dbad538775b5bf9b0ea25a4079c8 -a c50cc4e4f7838b6c31f60ab9032cbc62
|
||||
|
||||
# From another system, copy a file to the receiving system
|
||||
rncp ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
<p><strong>Usage Examples</strong></p>
|
||||
<p>Run rncp on the receiving system, specifying which identities are allowed to send files:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rncp --listen -a 1726dbad538775b5bf9b0ea25a4079c8 -a c50cc4e4f7838b6c31f60ab9032cbc62
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can specify as many allowed senders as needed, or complete disable authentication.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rncp [-h] [--config path] [-v] [-q] [-p] [-r] [-b] [-a allowed_hash] [-n] [-w seconds] [--version] [file] [destination]
|
||||
<p>You can also specify allowed identity hashes (one per line) in the file ~/.rncp/allowed_identities
|
||||
and simply running the program in listener mode:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rncp --listen
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>From another system, copy a file to the receiving system:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rncp ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or fetch a file from the remote system:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rncp --fetch ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rncp.py [-h] [--config path] [-v] [-q] [-S] [-l] [-f] [-b seconds]
|
||||
[-a allowed_hash] [-n] [-p] [-w seconds] [--version] [file] [destination]
|
||||
|
||||
Reticulum File Transfer Utility
|
||||
|
||||
@@ -534,19 +708,20 @@ positional arguments:
|
||||
file file to be transferred
|
||||
destination hexadecimal hash of the receiver
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config path path to alternative Reticulum config directory
|
||||
-v, --verbose increase verbosity
|
||||
-q, --quiet decrease verbosity
|
||||
-p, --print-identity print identity and destination info and exit
|
||||
-r, --receive wait for incoming files
|
||||
-b, --no-announce don't announce at program start
|
||||
-S, --silent disable transfer progress output
|
||||
-l, --listen listen for incoming transfer requests
|
||||
-f, --fetch fetch file from remote listener instead of sending
|
||||
-b seconds announce interval, 0 to only announce at startup
|
||||
-a allowed_hash accept from this identity
|
||||
-n, --no-auth accept files from anyone
|
||||
-n, --no-auth accept files and fetches from anyone
|
||||
-p, --print-identity print identity and destination info and exit
|
||||
-w seconds sender timeout before giving up
|
||||
--version show program's version number and exit
|
||||
-v, --verbose
|
||||
</pre></div>
|
||||
</div>
|
||||
</section>
|
||||
@@ -554,27 +729,30 @@ optional arguments:
|
||||
<h3>The rnx Utility<a class="headerlink" href="#the-rnx-utility" title="Permalink to this heading">#</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rnx</span></code> utility is a basic remote command execution program. It allows you to
|
||||
execute commands on remote systems over Reticulum, and to view returned command
|
||||
output.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span># Run rnx on the listening system, specifying which identities
|
||||
# are allowed to execute commands
|
||||
rnx --listen -a 941bed5e228775e5a8079fc38b1ccf3f -a 1b03013c25f1c2ca068a4f080b844a10
|
||||
|
||||
# From another system, run a command
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 "cat /proc/cpuinfo"
|
||||
|
||||
# Or enter the interactive mode pseudo-shell
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 -x
|
||||
|
||||
# The default identity file is stored in
|
||||
# ~/.reticulum/identities/rnx, but you can use
|
||||
# another one, which will be created if it does
|
||||
# not already exist
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 -i /path/to/identity -x
|
||||
output. For a fully interactive remote shell solution, be sure to also take a look
|
||||
at the <a class="reference external" href="https://github.com/acehoss/rnsh">rnsh</a> program.</p>
|
||||
<p><strong>Usage Examples</strong></p>
|
||||
<p>Run rnx on the listening system, specifying which identities are allowed to execute commands:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnx --listen -a 941bed5e228775e5a8079fc38b1ccf3f -a 1b03013c25f1c2ca068a4f080b844a10
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>You can specify as many allowed senders as needed, or completely disable authentication.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnx [-h] [--config path] [-v] [-q] [-p] [-l] [-i identity] [-x] [-b] [-a allowed_hash] [-n] [-N] [-d] [-m] [-w seconds] [-W seconds] [--stdin STDIN] [--stdout STDOUT] [--stderr STDERR] [--version]
|
||||
[destination] [command]
|
||||
<p>From another system, run a command on the remote:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnx 7a55144adf826958a9529a3bcf08b149 "cat /proc/cpuinfo"
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>Or enter the interactive mode pseudo-shell:</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnx 7a55144adf826958a9529a3bcf08b149 -x
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>The default identity file is stored in <code class="docutils literal notranslate"><span class="pre">~/.reticulum/identities/rnx</span></code>, but you can use
|
||||
another one, which will be created if it does not already exist</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>$ rnx 7a55144adf826958a9529a3bcf08b149 -i /path/to/identity -x
|
||||
</pre></div>
|
||||
</div>
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnx [-h] [--config path] [-v] [-q] [-p] [-l] [-i identity] [-x] [-b] [-n] [-N]
|
||||
[-d] [-m] [-a allowed_hash] [-w seconds] [-W seconds] [--stdin STDIN]
|
||||
[--stdout STDOUT] [--stderr STDERR] [--version] [destination] [command]
|
||||
|
||||
Reticulum Remote Execution Utility
|
||||
|
||||
@@ -610,9 +788,16 @@ optional arguments:
|
||||
<h3>The rnodeconf Utility<a class="headerlink" href="#the-rnodeconf-utility" title="Permalink to this heading">#</a></h3>
|
||||
<p>The <code class="docutils literal notranslate"><span class="pre">rnodeconf</span></code> utility allows you to inspect and configure existing <a class="reference internal" href="hardware.html#rnode-main"><span class="std std-ref">RNodes</span></a>, and
|
||||
to create and provision new <a class="reference internal" href="hardware.html#rnode-main"><span class="std std-ref">RNodes</span></a> from any supported hardware devices.</p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnodeconf [-h] [-i] [-a] [-u] [-U] [--fw-version version] [--nocheck] [-C] [-N] [-T] [-b] [-B] [-p] [--freq Hz] [--bw Hz] [--txp dBm] [--sf factor] [--cr rate] [--eeprom-backup] [--eeprom-dump] [--eeprom-wipe] [--version] [port]
|
||||
<p><strong>All Command-Line Options</strong></p>
|
||||
<div class="highlight-text notranslate"><div class="highlight"><pre><span></span>usage: rnodeconf.py [-h] [-i] [-a] [-u] [-U] [--fw-version version] [--nocheck] [-e]
|
||||
[-E] [-C] [--baud-flash baud_flash] [-N] [-T] [-b] [-B] [-p] [-D i]
|
||||
[--freq Hz] [--bw Hz] [--txp dBm] [--sf factor] [--cr rate]
|
||||
[--eeprom-backup] [--eeprom-dump] [--eeprom-wipe] [-P]
|
||||
[--trust-key hexbytes] [--version] [port]
|
||||
|
||||
RNode Configuration and firmware utility. This program allows you to change various settings and startup modes of RNode. It can also install, flash and update the firmware on supported devices.
|
||||
RNode Configuration and firmware utility. This program allows you to change various
|
||||
settings and startup modes of RNode. It can also install, flash and update the firmware
|
||||
on supported devices.
|
||||
|
||||
positional arguments:
|
||||
port serial port where RNode is attached
|
||||
@@ -628,11 +813,14 @@ options:
|
||||
-e, --extract Extract firmware from connected RNode for later use
|
||||
-E, --use-extracted Use the extracted firmware for autoinstallation or update
|
||||
-C, --clear-cache Clear locally cached firmware files
|
||||
--baud-flash baud_flash
|
||||
Set specific baud rate when flashing device. Default is 921600
|
||||
-N, --normal Switch device to normal mode
|
||||
-T, --tnc Switch device to TNC mode
|
||||
-b, --bluetooth-on Turn device bluetooth on
|
||||
-B, --bluetooth-off Turn device bluetooth off
|
||||
-p, --bluetooth-pair Put device into bluetooth pairing mode
|
||||
-D i, --display i Set display intensity (0-255)
|
||||
--freq Hz Frequency in Hz for TNC mode
|
||||
--bw Hz Bandwidth in Hz for TNC mode
|
||||
--txp dBm TX power in dBm for TNC mode
|
||||
@@ -641,6 +829,8 @@ options:
|
||||
--eeprom-backup Backup EEPROM to file
|
||||
--eeprom-dump Dump EEPROM to console
|
||||
--eeprom-wipe Unlock and wipe EEPROM
|
||||
-P, --public Display public part of signing key
|
||||
--trust-key hexbytes Public key to trust for device verification
|
||||
--version Print program version and exit
|
||||
</pre></div>
|
||||
</div>
|
||||
@@ -789,6 +979,7 @@ WantedBy=multi-user.target
|
||||
<li><a class="reference internal" href="#included-utility-programs">Included Utility Programs</a><ul>
|
||||
<li><a class="reference internal" href="#the-rnsd-utility">The rnsd Utility</a></li>
|
||||
<li><a class="reference internal" href="#the-rnstatus-utility">The rnstatus Utility</a></li>
|
||||
<li><a class="reference internal" href="#the-rnid-utility">The rnid Utility</a></li>
|
||||
<li><a class="reference internal" href="#the-rnpath-utility">The rnpath Utility</a></li>
|
||||
<li><a class="reference internal" href="#the-rnprobe-utility">The rnprobe Utility</a></li>
|
||||
<li><a class="reference internal" href="#the-rncp-utility">The rncp Utility</a></li>
|
||||
@@ -812,14 +1003,11 @@ WantedBy=multi-user.target
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
+20
-23
@@ -5,13 +5,13 @@
|
||||
<meta name="color-scheme" content="light dark"><meta name="generator" content="Docutils 0.19: https://docutils.sourceforge.io/" />
|
||||
<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.5.6 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<meta name="generator" content="sphinx-7.1.2, furo 2022.09.29.dev1"/>
|
||||
<title>What is Reticulum? - Reticulum Network Stack 0.6.1 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css?v=a746c00c" />
|
||||
<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/copybutton.css?v=76b2166b" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/custom.css?v=bb3cebc5" />
|
||||
|
||||
|
||||
|
||||
@@ -141,7 +141,7 @@
|
||||
</label>
|
||||
</div>
|
||||
<div class="header-center">
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.5.6 beta documentation</div></a>
|
||||
<a href="index.html"><div class="brand">Reticulum Network Stack 0.6.1 beta documentation</div></a>
|
||||
</div>
|
||||
<div class="header-right">
|
||||
<div class="theme-toggle-container theme-toggle-header">
|
||||
@@ -161,13 +161,13 @@
|
||||
<aside class="sidebar-drawer">
|
||||
<div class="sidebar-container">
|
||||
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand centered" href="index.html">
|
||||
<div class="sidebar-sticky"><a class="sidebar-brand" href="index.html">
|
||||
|
||||
<div class="sidebar-logo-container">
|
||||
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
|
||||
</div>
|
||||
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.5.6 beta documentation</span>
|
||||
<span class="sidebar-brand-text">Reticulum Network Stack 0.6.1 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">
|
||||
@@ -181,7 +181,7 @@
|
||||
<li class="toctree-l1"><a class="reference internal" href="using.html">Using Reticulum on Your System</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="understanding.html">Understanding Reticulum</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="hardware.html">Communications Hardware</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Supported Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="interfaces.html">Configuring Interfaces</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="networks.html">Building Networks</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="examples.html">Code Examples</a></li>
|
||||
<li class="toctree-l1"><a class="reference internal" href="support.html">Support Reticulum</a></li>
|
||||
@@ -238,21 +238,21 @@ outside control, manipulation or censorship.</p>
|
||||
networks, without any need for hierarchical or beaureucratic structures to control
|
||||
or manage them, while ensuring individuals and communities full sovereignty
|
||||
over their own network segments.</p>
|
||||
<p>Reticulum is a complete networking stack, and does not need IP or higher
|
||||
<p>Reticulum is a <strong>complete networking stack</strong>, and does not need IP or higher
|
||||
layers, although it is easy to utilise IP (with TCP or UDP) as the underlying
|
||||
carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the
|
||||
Internet or private IP networks. Reticulum is built directly on cryptographic
|
||||
principles, allowing resilience and stable functionality in open and trustless
|
||||
networks.</p>
|
||||
<p>No kernel modules or drivers are required. Reticulum runs completely in
|
||||
userland, and can run on practically any system that runs Python 3. Reticulum
|
||||
<p>No kernel modules or drivers are required. Reticulum can run completely in
|
||||
userland, and will run on practically any system that runs Python 3. Reticulum
|
||||
runs well even on small single-board computers like the Pi Zero.</p>
|
||||
<section id="current-status">
|
||||
<h2>Current Status<a class="headerlink" href="#current-status" title="Permalink to this heading">#</a></h2>
|
||||
<p><strong>Please know!</strong> Reticulum should currently be considered beta software. All core protocol
|
||||
features are implemented and functioning, but additions will probably occur as
|
||||
real-world use is explored. <em>There will be bugs</em>. The API and wire-format can be
|
||||
considered stable at the moment, but could change if absolutely warranted.</p>
|
||||
considered complete and stable at the moment, but could change if absolutely warranted.</p>
|
||||
</section>
|
||||
<section id="what-does-reticulum-offer">
|
||||
<h2>What does Reticulum Offer?<a class="headerlink" href="#what-does-reticulum-offer" title="Permalink to this heading">#</a></h2>
|
||||
@@ -275,7 +275,7 @@ considered stable at the moment, but could change if absolutely warranted.</p>
|
||||
<li><p>An intuitive and developer-friendly API</p></li>
|
||||
<li><p>Efficient link establishment</p>
|
||||
<ul>
|
||||
<li><p>Total bandwidth cost of setting up a link is only 3 packets, totalling 297 bytes</p></li>
|
||||
<li><p>Total cost of setting up an encrypted and verified link is only 3 packets, totalling 297 bytes</p></li>
|
||||
<li><p>Low cost of keeping links open at only 0.44 bits per second</p></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -434,14 +434,11 @@ want to help out with this, or can help sponsor an audit, please do get in touch
|
||||
|
||||
</aside>
|
||||
</div>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js"></script>
|
||||
<script src="_static/jquery.js"></script>
|
||||
<script src="_static/underscore.js"></script>
|
||||
<script src="_static/_sphinx_javascript_frameworks_compat.js"></script>
|
||||
<script src="_static/doctools.js"></script>
|
||||
<script src="_static/sphinx_highlight.js"></script>
|
||||
<script src="_static/scripts/furo.js"></script>
|
||||
<script src="_static/clipboard.min.js"></script>
|
||||
<script src="_static/copybutton.js"></script>
|
||||
</div><script data-url_root="./" id="documentation_options" src="_static/documentation_options.js?v=56280ba4"></script>
|
||||
<script src="_static/doctools.js?v=888ff710"></script>
|
||||
<script src="_static/sphinx_highlight.js?v=4825356b"></script>
|
||||
<script src="_static/scripts/furo.js?v=2c7c1115"></script>
|
||||
<script src="_static/clipboard.min.js?v=a7894cd8"></script>
|
||||
<script src="_static/copybutton.js?v=f281be69"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -70,7 +70,8 @@ Remote Shell
|
||||
|
||||
The `rnsh <https://github.com/acehoss/rnsh>`_ program lets you establish fully interactive
|
||||
remote shell sessions over Reticulum. It also allows you to pipe any program to or from a
|
||||
remote system, and is similar to how ``ssh`` works.
|
||||
remote system, and is similar to how ``ssh`` works. The ``rnsh`` is very efficient, and
|
||||
can facilitate fully interactive shell sessions, even over extremely low-bandwidth links.
|
||||
|
||||
Nomad Network
|
||||
^^^^^^^^^^^^^
|
||||
@@ -219,11 +220,11 @@ by adding one of the following interfaces to your ``.reticulum/config`` file:
|
||||
|
||||
.. code::
|
||||
|
||||
# TCP/IP interface to the Dublin hub
|
||||
[[RNS Testnet Dublin]]
|
||||
# TCP/IP interface to the RNS Amsterdam Hub
|
||||
[[RNS Testnet Amsterdam]]
|
||||
type = TCPClientInterface
|
||||
enabled = yes
|
||||
target_host = dublin.connect.reticulum.network
|
||||
target_host = amsterdam.connect.reticulum.network
|
||||
target_port = 4965
|
||||
|
||||
# TCP/IP interface to the BetweenTheBorders Hub (community-provided)
|
||||
@@ -233,11 +234,11 @@ by adding one of the following interfaces to your ``.reticulum/config`` file:
|
||||
target_host = betweentheborders.com
|
||||
target_port = 4242
|
||||
|
||||
# Interface to I2P hub A
|
||||
[[RNS Testnet I2P Hub A]]
|
||||
# Interface to Testnet I2P Hub
|
||||
[[RNS Testnet I2P Hub]]
|
||||
type = I2PInterface
|
||||
enabled = yes
|
||||
peers = uxg5kubabakh3jtnvsipingbr5574dle7bubvip7llfvwx2tgrua.b32.i2p
|
||||
peers = g3br23bvx3lq5uddcsjii74xgmn6y5q325ovrkq2zw2wbzbqgbuq.b32.i2p
|
||||
|
||||
Many other Reticulum instances are connecting to this testnet, and you can also join it
|
||||
via other entry points if you know them. There is absolutely no control over the network
|
||||
@@ -281,7 +282,7 @@ started is to install the latest release of Reticulum via pip:
|
||||
|
||||
.. code::
|
||||
|
||||
pip3 install rns
|
||||
pip install rns
|
||||
|
||||
The above command will install Reticulum and dependencies, and you will be
|
||||
ready to import and use RNS in your own programs. The next step will most
|
||||
@@ -291,7 +292,7 @@ For extended functionality, you can install optional dependencies:
|
||||
|
||||
.. code::
|
||||
|
||||
pip3 install pyserial
|
||||
pip install pyserial
|
||||
|
||||
|
||||
Further information can be found in the :ref:`API Reference<api-main>`.
|
||||
@@ -306,7 +307,7 @@ don't use pip, but try this recipe:
|
||||
.. code::
|
||||
|
||||
# Install dependencies
|
||||
pip3 install cryptography pyserial
|
||||
pip install cryptography pyserial
|
||||
|
||||
# Clone repository
|
||||
git clone https://github.com/markqvist/Reticulum.git
|
||||
@@ -316,25 +317,25 @@ don't use pip, but try this recipe:
|
||||
ln -s ../RNS ./Examples/
|
||||
|
||||
# Run an example
|
||||
python3 Examples/Echo.py -s
|
||||
python Examples/Echo.py -s
|
||||
|
||||
# Unless you've manually created a config file, Reticulum will do so now,
|
||||
# and immediately exit. Make any necessary changes to the file:
|
||||
nano ~/.reticulum/config
|
||||
|
||||
# ... and launch the example again.
|
||||
python3 Examples/Echo.py -s
|
||||
python Examples/Echo.py -s
|
||||
|
||||
# You can now repeat the process on another computer,
|
||||
# and run the same example with -h to get command line options.
|
||||
python3 Examples/Echo.py -h
|
||||
python Examples/Echo.py -h
|
||||
|
||||
# Run the example in client mode to "ping" the server.
|
||||
# Replace the hash below with the actual destination hash of your server.
|
||||
python3 Examples/Echo.py 174a64852a75682259ad8b921b8bf416
|
||||
python Examples/Echo.py 174a64852a75682259ad8b921b8bf416
|
||||
|
||||
# Have a look at another example
|
||||
python3 Examples/Filetransfer.py -h
|
||||
python Examples/Filetransfer.py -h
|
||||
|
||||
When you have experimented with the basic examples, it's time to go read the
|
||||
:ref:`Understanding Reticulum<understanding-main>` chapter. Before submitting
|
||||
@@ -446,11 +447,11 @@ detailed in this manual.
|
||||
|
||||
Debian Bookworm
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Debian released after April 2023, it is no longer possible
|
||||
On versions of Debian released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but installation
|
||||
via this method is not fully tested yet.
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -463,14 +464,28 @@ via this method is not fully tested yet.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
|
||||
.. code:: text
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
Please note that the "break-system-packages" directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this *could* in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems.
|
||||
|
||||
|
||||
Ubuntu Lunar
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible
|
||||
On versions of Ubuntu released after April 2023, it is no longer possible by default
|
||||
to use ``pip`` to install packages onto your system. Unfortunately, you will need to
|
||||
use the replacement ``pipx`` command instead, which places installed packages in an
|
||||
isolated environment. This should not negatively affect Reticulum, but installation
|
||||
via this method is not fully tested yet.
|
||||
isolated environment. This should not negatively affect Reticulum, but will not work
|
||||
for including and using Reticulum in your own scripts and programs.
|
||||
|
||||
.. code::
|
||||
|
||||
@@ -483,14 +498,24 @@ via this method is not fully tested yet.
|
||||
# Install Reticulum
|
||||
pipx install rns
|
||||
|
||||
Alternatively, you can restore normal behaviour to ``pip`` by creating or editing
|
||||
the configuration file located at ``~/.config/pip/pip.conf``, and adding the
|
||||
following section:
|
||||
|
||||
.. code:: text
|
||||
|
||||
[global]
|
||||
break-system-packages = true
|
||||
|
||||
Please note that the "break-system-packages" directive is a somewhat misleading choice
|
||||
of words. Setting it will of course not break any system packages, but will simply
|
||||
allow installing ``pip`` packages user- and system-wide. While this _could_ in rare
|
||||
cases lead to version conflicts, it does not generally pose any problems.
|
||||
|
||||
Pure-Python Reticulum
|
||||
==============================================
|
||||
In some rare cases, and on more obscure system types, it is not possible to
|
||||
install one or more dependencies
|
||||
|
||||
On more unusual systems, and in some rare cases, it might not be possible to
|
||||
install or even compile one or more of the above modules. In such situations,
|
||||
install one or more dependencies. In such situations,
|
||||
you can use the ``rnspure`` package instead of the ``rns`` package, or use ``pip``
|
||||
with the ``--no-dependencies`` command-line option. The ``rnspure``
|
||||
package requires no external dependencies for installation. Please note that the
|
||||
|
||||
+40
-18
@@ -24,11 +24,20 @@ starting from scratch.
|
||||
This chapter will outline a few different sensible starting paths to get
|
||||
real-world functional wireless communications up and running with minimal cost
|
||||
and effort. Two fundamental devices categories will be covered, *RNodes* and
|
||||
*WiFi-based radios*.
|
||||
*WiFi-based radios*. Additionally, other common options will be briefly described.
|
||||
|
||||
Knowing how to employ just a few different types of hardware will make it possible
|
||||
to build a wide range of useful networks with little effort.
|
||||
|
||||
Combining Hardware Types
|
||||
========================
|
||||
|
||||
It is useful to combine different link and hardware types when designing and
|
||||
building a network. One useful design pattern is to employ high-capacity point-to-point
|
||||
links based on WiFi or millimeter-wave radios (with high-gain directional antennas)
|
||||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.
|
||||
|
||||
While there are many other device categories that are useful in building Reticulum
|
||||
networks, knowing how to employ just these two will make it possible to build
|
||||
a wide range of useful networks with little effort.
|
||||
|
||||
.. _rnode-main:
|
||||
|
||||
@@ -190,13 +199,6 @@ such as serial port and on-air parameters. For v2.x firmwares, you just need to
|
||||
the Connection ID of the RNode, and Reticulum will automatically locate and connect to the
|
||||
RNode, using the parameters stored in the RNode itself.
|
||||
|
||||
.. _rnode-suppliers:
|
||||
|
||||
Suppliers
|
||||
^^^^^^^^^
|
||||
Get in touch if you want to have your RNode supplier listed here, or if you want help to
|
||||
get started with producing RNodes.
|
||||
|
||||
|
||||
WiFi-based Hardware
|
||||
===================
|
||||
@@ -231,11 +233,31 @@ that is relatively cheap while providing long range and high capacity for Reticu
|
||||
networks. As in all other cases, it is also possible for Reticulum to co-exist with IP
|
||||
networks running concurrently on such devices.
|
||||
|
||||
Combining Hardware Types
|
||||
========================
|
||||
Ethernet-based Hardware
|
||||
=======================
|
||||
|
||||
It is useful to combine different link and hardware types when designing and
|
||||
building a network. One useful design pattern is to employ high-capacity point-to-point
|
||||
links based on WiFi or millimeter-wave radios (with high-gain directional antennas)
|
||||
for the network backbone, and using LoRa-based RNodes for covering large areas with
|
||||
connectivity for client devices.
|
||||
Reticulum can run over any kind of hardware that can provide a switched Ethernet-based
|
||||
medium. This means that anything from a plain Ethernet switch, to fiber-optic systems,
|
||||
to data radios with Ethernet interfaces can be used by Reticulum.
|
||||
|
||||
The Ethernet medium does not need to have any IP infrastructure such as DHCP servers
|
||||
or routing set up, but in case such infrastructure does exist, Reticulum will simply
|
||||
co-exist with.
|
||||
|
||||
To use Reticulum over Ethernet-based mediums, it is generally enough to use the included
|
||||
:ref:`AutoInterface<interfaces-auto>`. This interface also works over any kind of
|
||||
virtual networking adapter, such as ``tun`` and ``tap`` devices in Linux.
|
||||
|
||||
Serial Lines & Devices
|
||||
======================
|
||||
|
||||
Using Reticulum over any kind of raw serial line is also possible with the
|
||||
:ref:`SerialInterface<interfaces-serial>`. This interface type is also useful for
|
||||
using Reticulum over communications hardware that provides a serial port interface.
|
||||
|
||||
Packet Radio Modems
|
||||
===================
|
||||
|
||||
Any packet radio modem that provides a standard KISS interface over USB, serial or TCP
|
||||
can be used with Reticulum. This includes virtual software modems such as
|
||||
`FreeDV TNC <https://github.com/xssfox/freedv-tnc>`_ and `Dire Wolf <https://github.com/wb2osz/direwolf>`_.
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
.. _interfaces-main:
|
||||
|
||||
********************
|
||||
Supported Interfaces
|
||||
********************
|
||||
**********************
|
||||
Configuring Interfaces
|
||||
**********************
|
||||
|
||||
Reticulum supports using many kinds of devices as networking interfaces, and
|
||||
allows you to mix and match them in any way you choose. The number of distinct
|
||||
@@ -365,6 +365,7 @@ can be used, and offers full control over LoRa parameters.
|
||||
# out identification on the channel with
|
||||
# a set interval by configuring the
|
||||
# following two parameters.
|
||||
|
||||
# id_callsign = MYCALL-0
|
||||
# id_interval = 600
|
||||
|
||||
@@ -372,7 +373,21 @@ can be used, and offers full control over LoRa parameters.
|
||||
# with low amounts of RAM, using packet
|
||||
# flow control can be useful. By default
|
||||
# it is disabled.
|
||||
flow_control = False
|
||||
|
||||
# flow_control = False
|
||||
|
||||
# It is possible to limit the airtime
|
||||
# utilisation of an RNode by using the
|
||||
# following two configuration options.
|
||||
# The short-term limit is applied in a
|
||||
# window of approximately 15 seconds,
|
||||
# and the long-term limit is enforced
|
||||
# over a rolling 60 minute window. Both
|
||||
# options are specified in percent.
|
||||
|
||||
# airtime_limit_long = 1.5
|
||||
# airtime_limit_short = 33
|
||||
|
||||
|
||||
.. _interfaces-serial:
|
||||
|
||||
@@ -746,3 +761,74 @@ conserve bandwidth, while very fast networks can support applications that
|
||||
need very frequent announces. Reticulum implements these mechanisms to ensure
|
||||
that a large span of network types can seamlessly *co-exist* and interconnect.
|
||||
|
||||
.. _interfaces-ingress-control:
|
||||
|
||||
New Destination Rate Limiting
|
||||
=============================
|
||||
|
||||
On public interfaces, where anyone may connect and announce new destinations,
|
||||
it can be useful to control the rate at which announces for *new* destinations are
|
||||
processed.
|
||||
|
||||
If a large influx of announces for newly created or previously unknown destinations
|
||||
occur within a short amount of time, Reticulum will place these announces on hold,
|
||||
so that announce traffic for known and previously established destinations can
|
||||
continue to be processed without interruptions.
|
||||
|
||||
After the burst subsides, and an additional waiting period has passed, the held
|
||||
announces will be released at a slow rate, until the hold queue is cleared. This
|
||||
also means, that should a node decide to connect to a public interface, announce
|
||||
a large amount of bogus destinations, and then disconnect, these destination will
|
||||
never make it into path tables and waste network bandwidth on retransmitted
|
||||
announces.
|
||||
|
||||
**It's important to note** that the ingress control works at the level of *individual
|
||||
sub-interfaces*. As an example, this means that one client on a :ref:`TCP Server Interface<interfaces-tcps>`
|
||||
cannot disrupt processing of incoming announces for other connected clients on the same
|
||||
:ref:`TCP Server Interface<interfaces-tcps>`. All other clients on the same interface will still have new announces
|
||||
processed without interruption.
|
||||
|
||||
By default, Reticulum will handle this automatically, and ingress announce
|
||||
control will be enabled on interface where it is sensible to do so. It should
|
||||
generally not be neccessary to modify the ingress control configuration,
|
||||
but all the parameters are exposed for configuration if needed.
|
||||
|
||||
* | The ``ingress_control`` option tells Reticulum whether or not
|
||||
to enable announce ingress control on the interface. Defaults to
|
||||
``True``.
|
||||
|
||||
* | The ``ic_new_time`` option configures how long (in seconds) an
|
||||
interface is considered newly spawned. Defaults to ``2*60*60`` seconds. This
|
||||
option is useful on publicly accessible interfaces that spawn new
|
||||
sub-interfaces when a new client connects.
|
||||
|
||||
* | The ``ic_burst_freq_new`` option sets the maximum announce ingress
|
||||
frequency for newly spawned interfaces. Defaults to ``3.5``
|
||||
announces per second.
|
||||
|
||||
* | The ``ic_burst_freq`` option sets the maximum announce ingress
|
||||
frequency for other interfaces. Defaults to ``12`` announces
|
||||
per second.
|
||||
|
||||
*If an interface exceeds its burst frequency, incoming announces
|
||||
for unknown destinations will be temporarily held in a queue, and
|
||||
not processed until later.*
|
||||
|
||||
* | The ``ic_max_held_announces`` option sets the maximum amount of
|
||||
unique announces that will be held in the queue. Any additional
|
||||
unique announces will be dropped. Defaults to ``256`` announces.
|
||||
|
||||
* | The ``ic_burst_hold`` option sets how much time (in seconds) must
|
||||
pass after the burst frequency drops below its threshold, for the
|
||||
announce burst to be considered cleared. Defaults to ``60``
|
||||
seconds.
|
||||
|
||||
* | The ``ic_burst_penalty`` option sets how much time (in seconds) must
|
||||
pass after the burst is considered cleared, before held announces can
|
||||
start being released from the queue. Defaults to ``5*60``
|
||||
seconds.
|
||||
|
||||
* | The ``ic_held_release_interval`` option sets how much time (in seconds)
|
||||
must pass between releasing each held announce from the queue. Defaults
|
||||
to ``30`` seconds.
|
||||
|
||||
|
||||
+320
-70
@@ -108,6 +108,17 @@ configuration file is created. The default configuration looks like this:
|
||||
panic_on_interface_error = No
|
||||
|
||||
|
||||
# When Transport is enabled, it is possible to allow the
|
||||
# Transport Instance to respond to probe requests from
|
||||
# the rnprobe utility. This can be a useful tool to test
|
||||
# connectivity. When this option is enabled, the probe
|
||||
# destination will be generated from the Identity of the
|
||||
# Transport Instance, and printed to the log at startup.
|
||||
# Optional, and disabled by default.
|
||||
|
||||
respond_to_probes = No
|
||||
|
||||
|
||||
[logging]
|
||||
# Valid log levels are 0 through 7:
|
||||
# 0: Log only critical information
|
||||
@@ -145,10 +156,19 @@ configuration file is created. The default configuration looks like this:
|
||||
If Reticulum infrastructure already exists locally, you probably don't need to
|
||||
change anything, and you may already be connected to a wider network. If not,
|
||||
you will probably need to add relevant *interfaces* to the configuration, in
|
||||
order to communicate with other systems. It is a good idea to read the comments
|
||||
and explanations in the above default config. It will teach you the basic
|
||||
concepts you need to understand to configure your network. Once you have done that,
|
||||
take a look at the :ref:`Interfaces<interfaces-main>` chapter of this manual.
|
||||
order to communicate with other systems.
|
||||
|
||||
You can generate a much more verbose configuration example by running the command:
|
||||
|
||||
``rnsd --exampleconfig``
|
||||
|
||||
The output includes examples for most interface types supported
|
||||
by Reticulum, along with additional options and configuration parameters.
|
||||
|
||||
It is a good idea to read the comments and explanations in the above default config.
|
||||
It will teach you the basic concepts you need to understand to configure your network.
|
||||
Once you have done that, take a look at the :ref:`Interfaces<interfaces-main>` chapter
|
||||
of this manual.
|
||||
|
||||
Included Utility Programs
|
||||
-------------------------
|
||||
@@ -170,28 +190,47 @@ When ``rnsd`` is running, it will keep all configured interfaces open, handle tr
|
||||
it is enabled, and allow any other programs to immediately utilise the
|
||||
Reticulum network it is configured for.
|
||||
|
||||
You can even run multiple instances of rnsd with different configurations on
|
||||
You can even run multiple instances of ``rnsd`` with different configurations on
|
||||
the same system.
|
||||
|
||||
.. code:: text
|
||||
**Usage Examples**
|
||||
|
||||
# Install Reticulum
|
||||
pip3 install rns
|
||||
|
||||
# Run rnsd
|
||||
rnsd
|
||||
Run ``rnsd``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnsd [-h] [--config CONFIG] [-v] [-q] [--version]
|
||||
$ rnsd
|
||||
|
||||
[2023-08-18 17:59:56] [Notice] Started rnsd version 0.5.8
|
||||
|
||||
Run ``rnsd`` in service mode, ensuring all logging output is sent directly to file:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnsd -s
|
||||
|
||||
Generate a verbose and detailed configuration example, with explanations of all the
|
||||
various configuration options, and interface configuration examples:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnsd --exampleconfig
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnsd.py [-h] [--config CONFIG] [-v] [-q] [-s] [--exampleconfig] [--version]
|
||||
|
||||
Reticulum Network Stack Daemon
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
-v, --verbose
|
||||
-q, --quiet
|
||||
-s, --service rnsd is running as a service and should log to file
|
||||
--exampleconfig print verbose configuration example to stdout and exit
|
||||
--version show program's version number and exit
|
||||
|
||||
You can easily add ``rnsd`` as an always-on service by :ref:`configuring a service<using-systemd>`.
|
||||
@@ -202,12 +241,14 @@ The rnstatus Utility
|
||||
Using the ``rnstatus`` utility, you can view the status of configured Reticulum
|
||||
interfaces, similar to the ``ifconfig`` program.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Run ``rnstatus``:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnstatus
|
||||
rnstatus
|
||||
$ rnstatus
|
||||
|
||||
# Example output
|
||||
Shared Instance[37428]
|
||||
Status : Up
|
||||
Serving : 1 program
|
||||
@@ -240,44 +281,175 @@ interfaces, similar to the ``ifconfig`` program.
|
||||
|
||||
Reticulum Transport Instance <5245a8efe1788c6a1cd36144a270e13b> running
|
||||
|
||||
Filter output to only show some interfaces:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnstatus [-h] [--config CONFIG] [--version] [-a] [-v]
|
||||
$ rnstatus rnode
|
||||
|
||||
RNodeInterface[RNode UHF]
|
||||
Status : Up
|
||||
Mode : Access Point
|
||||
Rate : 1.30 kbps
|
||||
Access : 64-bit IFAC by <…e702c42ba8>
|
||||
Traffic : 8.49 KB↑
|
||||
9.23 KB↓
|
||||
|
||||
Reticulum Transport Instance <5245a8efe1788c6a1cd36144a270e13b> running
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnstatus.py [-h] [--config CONFIG] [--version] [-a] [-A] [-s SORT]
|
||||
[-r] [-j] [-v] [filter]
|
||||
|
||||
Reticulum Network Stack Status
|
||||
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
-a, --all show all interfaces
|
||||
positional arguments:
|
||||
filter only display interfaces with names including filter
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
-a, --all show all interfaces
|
||||
-A, --announce-stats show announce stats
|
||||
-s SORT, --sort SORT sort interfaces by [rate, traffic, rx, tx, announces, arx, atx, held]
|
||||
-r, --reverse reverse sorting
|
||||
-j, --json output in JSON format
|
||||
-v, --verbose
|
||||
|
||||
|
||||
The rnid Utility
|
||||
====================
|
||||
|
||||
With the ``rnid`` utility, you can generate, manage and view Reticulum Identities.
|
||||
The program can also calculate Destination hashes, and perform encryption and
|
||||
decryption of files.
|
||||
|
||||
Using ``rnid``, it is possible to asymmetrically encrypt files and information for
|
||||
any Reticulum destination hash, and also to create and verify cryptographic signatures.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Generate a new Identity:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -g ./new_identity
|
||||
|
||||
Display Identity key information:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -i ./new_identity -p
|
||||
|
||||
Loaded Identity <984b74a3f768bef236af4371e6f248cd> from new_id
|
||||
Public Key : 0f4259fef4521ab75a3409e353fe9073eb10783b4912a6a9937c57bf44a62c1e
|
||||
Private Key : Hidden
|
||||
|
||||
Encrypt a file for an LXMF user:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -i 8dd57a738226809646089335a6b03695 -e my_file.txt
|
||||
|
||||
Recalled Identity <bc7291552be7a58f361522990465165c> for destination <8dd57a738226809646089335a6b03695>
|
||||
Encrypting my_file.txt
|
||||
File my_file.txt encrypted for <bc7291552be7a58f361522990465165c> to my_file.txt.rfe
|
||||
|
||||
If the Identity for the destination is not already known, you can fetch it from the network by using the ``-R`` command-line option:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -R -i 30602def3b3506a28ed33db6f60cc6c9 -e my_file.txt
|
||||
|
||||
Requesting unknown Identity for <30602def3b3506a28ed33db6f60cc6c9>...
|
||||
Received Identity <2b489d06eaf7c543808c76a5332a447d> for destination <30602def3b3506a28ed33db6f60cc6c9> from the network
|
||||
Encrypting my_file.txt
|
||||
File my_file.txt encrypted for <2b489d06eaf7c543808c76a5332a447d> to my_file.txt.rfe
|
||||
|
||||
Decrypt a file using the Reticulum Identity it was encrypted for:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnid -i ./my_identity -d my_file.txt.rfe
|
||||
|
||||
Loaded Identity <2225fdeecaf6e2db4556c3c2d7637294> from ./my_identity
|
||||
Decrypting ./my_file.txt.rfe...
|
||||
File ./my_file.txt.rfe decrypted with <2225fdeecaf6e2db4556c3c2d7637294> to ./my_file.txt
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnid.py [-h] [--config path] [-i identity] [-g path] [-v] [-q] [-a aspects]
|
||||
[-H aspects] [-e path] [-d path] [-s path] [-V path] [-r path] [-w path]
|
||||
[-f] [-R] [-t seconds] [-p] [-P] [--version]
|
||||
|
||||
Reticulum Identity & Encryption Utility
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config path path to alternative Reticulum config directory
|
||||
-i identity, --identity identity
|
||||
hexadecimal Reticulum Destination hash or path to Identity file
|
||||
-g path, --generate path
|
||||
generate a new Identity
|
||||
-v, --verbose increase verbosity
|
||||
-q, --quiet decrease verbosity
|
||||
-a aspects, --announce aspects
|
||||
announce a destination based on this Identity
|
||||
-H aspects, --hash aspects
|
||||
show destination hashes for other aspects for this Identity
|
||||
-e path, --encrypt path
|
||||
encrypt file
|
||||
-d path, --decrypt path
|
||||
decrypt file
|
||||
-s path, --sign path sign file
|
||||
-V path, --validate path
|
||||
validate signature
|
||||
-r path, --read path input file path
|
||||
-w path, --write path
|
||||
output file path
|
||||
-f, --force write output even if it overwrites existing files
|
||||
-R, --request request unknown Identities from the network
|
||||
-t seconds identity request timeout before giving up
|
||||
-p, --print-identity print identity info and exit
|
||||
-P, --print-private allow displaying private keys
|
||||
--version show program's version number and exit
|
||||
|
||||
|
||||
The rnpath Utility
|
||||
====================
|
||||
|
||||
With the ``rnpath`` utility, you can look up and view paths for
|
||||
destinations on the Reticulum network.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Resolve path to a destination:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnpath
|
||||
rnpath c89b4da064bf66d280f0e4d8abfd9806
|
||||
$ rnpath c89b4da064bf66d280f0e4d8abfd9806
|
||||
|
||||
# Example output
|
||||
Path found, destination <c89b4da064bf66d280f0e4d8abfd9806> is 4 hops away via <f53a1c4278e0726bb73fcc623d6ce763> on TCPInterface[Testnet/dublin.connect.reticulum.network:4965]
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnpath [-h] [--config CONFIG] [--version] [-t] [-r] [-d] [-D] [-w seconds] [-v] [destination]
|
||||
|
||||
usage: rnpath.py [-h] [--config CONFIG] [--version] [-t] [-r] [-d] [-D]
|
||||
[-x] [-w seconds] [-v] [destination]
|
||||
|
||||
Reticulum Path Discovery Utility
|
||||
|
||||
|
||||
positional arguments:
|
||||
destination hexadecimal hash of the destination
|
||||
|
||||
optional arguments:
|
||||
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
--version show program's version number and exit
|
||||
@@ -285,6 +457,7 @@ destinations on the Reticulum network.
|
||||
-r, --rates show announce rate info
|
||||
-d, --drop remove the path to a destination
|
||||
-D, --drop-announces drop all queued announces
|
||||
-x, --drop-via drop all paths via specified transport instance
|
||||
-w seconds timeout before giving up
|
||||
-v, --verbose
|
||||
|
||||
@@ -295,21 +468,53 @@ The rnprobe Utility
|
||||
The ``rnprobe`` utility lets you probe a destination for connectivity, similar
|
||||
to the ``ping`` program. Please note that probes will only be answered if the
|
||||
specified destination is configured to send proofs for received packets. Many
|
||||
destinations will not have this option enabled, and will not be probable.
|
||||
destinations will not have this option enabled, so most destinations will not
|
||||
be probable.
|
||||
|
||||
You can enable a probe-reply destination on Reticulum Transport Instances by
|
||||
setting the ``respond_to_probes`` configuration directive. Reticulum will then
|
||||
print the probe destination to the log on Transport Instance startup.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Probe a destination:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnprobe
|
||||
rnprobe example_utilities.echo.request 2d03725b327348980d570f739a3a5708
|
||||
$ rnprobe rnstransport.probe 2d03725b327348980d570f739a3a5708
|
||||
|
||||
# Example output
|
||||
Sent 16 byte probe to <2d03725b327348980d570f739a3a5708>
|
||||
Valid reply received from <2d03725b327348980d570f739a3a5708>
|
||||
Round-trip time is 38.469 milliseconds over 2 hops
|
||||
|
||||
Send a larger probe:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnprobe [-h] [--config CONFIG] [--version] [-v] [full_name] [destination_hash]
|
||||
$ rnprobe rnstransport.probe 2d03725b327348980d570f739a3a5708 -s 256
|
||||
|
||||
Sent 16 byte probe to <2d03725b327348980d570f739a3a5708>
|
||||
Valid reply received from <2d03725b327348980d570f739a3a5708>
|
||||
Round-trip time is 38.781 milliseconds over 2 hops
|
||||
|
||||
If the interface that receives the probe replies supports reporting radio
|
||||
parameters such as **RSSI** and **SNR**, the ``rnprobe`` utility will print
|
||||
these as part of the result as well.
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnprobe rnstransport.probe e7536ee90bd4a440e130490b87a25124
|
||||
|
||||
Sent 16 byte probe to <e7536ee90bd4a440e130490b87a25124>
|
||||
Valid reply received from <e7536ee90bd4a440e130490b87a25124>
|
||||
Round-trip time is 1.809 seconds over 1 hop [RSSI -73 dBm] [SNR 12.0 dB]
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnprobe [-h] [--config CONFIG] [--version] [-v] [-s SIZE]
|
||||
[full_name] [destination_hash]
|
||||
|
||||
Reticulum Probe Utility
|
||||
|
||||
@@ -320,6 +525,7 @@ destinations will not have this option enabled, and will not be probable.
|
||||
optional arguments:
|
||||
-h, --help show this help message and exit
|
||||
--config CONFIG path to alternative Reticulum config directory
|
||||
-s SIZE, --size SIZE size of probe packet payload in bytes
|
||||
--version show program's version number and exit
|
||||
-v, --verbose
|
||||
|
||||
@@ -330,20 +536,39 @@ The rncp Utility
|
||||
The ``rncp`` utility is a simple file transfer tool. Using it, you can transfer
|
||||
files through Reticulum.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Run rncp on the receiving system, specifying which identities are allowed to send files:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rncp on the receiving system, specifying which identities
|
||||
# are allowed to send files
|
||||
rncp --receive -a 1726dbad538775b5bf9b0ea25a4079c8 -a c50cc4e4f7838b6c31f60ab9032cbc62
|
||||
$ rncp --listen -a 1726dbad538775b5bf9b0ea25a4079c8 -a c50cc4e4f7838b6c31f60ab9032cbc62
|
||||
|
||||
# From another system, copy a file to the receiving system
|
||||
rncp ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
|
||||
You can specify as many allowed senders as needed, or complete disable authentication.
|
||||
You can also specify allowed identity hashes (one per line) in the file ~/.rncp/allowed_identities
|
||||
and simply running the program in listener mode:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rncp [-h] [--config path] [-v] [-q] [-p] [-r] [-b] [-a allowed_hash] [-n] [-w seconds] [--version] [file] [destination]
|
||||
$ rncp --listen
|
||||
|
||||
From another system, copy a file to the receiving system:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rncp ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
|
||||
Or fetch a file from the remote system:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rncp --fetch ~/path/to/file.tgz 73cbd378bb0286ed11a707c13447bb1e
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rncp.py [-h] [--config path] [-v] [-q] [-S] [-l] [-f] [-b seconds]
|
||||
[-a allowed_hash] [-n] [-p] [-w seconds] [--version] [file] [destination]
|
||||
|
||||
Reticulum File Transfer Utility
|
||||
|
||||
@@ -351,19 +576,20 @@ You can specify as many allowed senders as needed, or complete disable authentic
|
||||
file file to be transferred
|
||||
destination hexadecimal hash of the receiver
|
||||
|
||||
optional arguments:
|
||||
options:
|
||||
-h, --help show this help message and exit
|
||||
--config path path to alternative Reticulum config directory
|
||||
-v, --verbose increase verbosity
|
||||
-q, --quiet decrease verbosity
|
||||
-p, --print-identity print identity and destination info and exit
|
||||
-r, --receive wait for incoming files
|
||||
-b, --no-announce don't announce at program start
|
||||
-S, --silent disable transfer progress output
|
||||
-l, --listen listen for incoming transfer requests
|
||||
-f, --fetch fetch file from remote listener instead of sending
|
||||
-b seconds announce interval, 0 to only announce at startup
|
||||
-a allowed_hash accept from this identity
|
||||
-n, --no-auth accept files from anyone
|
||||
-n, --no-auth accept files and fetches from anyone
|
||||
-p, --print-identity print identity and destination info and exit
|
||||
-w seconds sender timeout before giving up
|
||||
--version show program's version number and exit
|
||||
-v, --verbose
|
||||
|
||||
|
||||
The rnx Utility
|
||||
@@ -371,32 +597,43 @@ The rnx Utility
|
||||
|
||||
The ``rnx`` utility is a basic remote command execution program. It allows you to
|
||||
execute commands on remote systems over Reticulum, and to view returned command
|
||||
output.
|
||||
output. For a fully interactive remote shell solution, be sure to also take a look
|
||||
at the `rnsh <https://github.com/acehoss/rnsh>`_ program.
|
||||
|
||||
**Usage Examples**
|
||||
|
||||
Run rnx on the listening system, specifying which identities are allowed to execute commands:
|
||||
|
||||
.. code:: text
|
||||
|
||||
# Run rnx on the listening system, specifying which identities
|
||||
# are allowed to execute commands
|
||||
rnx --listen -a 941bed5e228775e5a8079fc38b1ccf3f -a 1b03013c25f1c2ca068a4f080b844a10
|
||||
$ rnx --listen -a 941bed5e228775e5a8079fc38b1ccf3f -a 1b03013c25f1c2ca068a4f080b844a10
|
||||
|
||||
# From another system, run a command
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 "cat /proc/cpuinfo"
|
||||
|
||||
# Or enter the interactive mode pseudo-shell
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 -x
|
||||
|
||||
# The default identity file is stored in
|
||||
# ~/.reticulum/identities/rnx, but you can use
|
||||
# another one, which will be created if it does
|
||||
# not already exist
|
||||
rnx 7a55144adf826958a9529a3bcf08b149 -i /path/to/identity -x
|
||||
|
||||
You can specify as many allowed senders as needed, or completely disable authentication.
|
||||
From another system, run a command on the remote:
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnx [-h] [--config path] [-v] [-q] [-p] [-l] [-i identity] [-x] [-b] [-a allowed_hash] [-n] [-N] [-d] [-m] [-w seconds] [-W seconds] [--stdin STDIN] [--stdout STDOUT] [--stderr STDERR] [--version]
|
||||
[destination] [command]
|
||||
$ rnx 7a55144adf826958a9529a3bcf08b149 "cat /proc/cpuinfo"
|
||||
|
||||
Or enter the interactive mode pseudo-shell:
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnx 7a55144adf826958a9529a3bcf08b149 -x
|
||||
|
||||
The default identity file is stored in ``~/.reticulum/identities/rnx``, but you can use
|
||||
another one, which will be created if it does not already exist
|
||||
|
||||
.. code:: text
|
||||
|
||||
$ rnx 7a55144adf826958a9529a3bcf08b149 -i /path/to/identity -x
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnx [-h] [--config path] [-v] [-q] [-p] [-l] [-i identity] [-x] [-b] [-n] [-N]
|
||||
[-d] [-m] [-a allowed_hash] [-w seconds] [-W seconds] [--stdin STDIN]
|
||||
[--stdout STDOUT] [--stderr STDERR] [--version] [destination] [command]
|
||||
|
||||
Reticulum Remote Execution Utility
|
||||
|
||||
@@ -433,11 +670,19 @@ The rnodeconf Utility
|
||||
The ``rnodeconf`` utility allows you to inspect and configure existing :ref:`RNodes<rnode-main>`, and
|
||||
to create and provision new :ref:`RNodes<rnode-main>` from any supported hardware devices.
|
||||
|
||||
**All Command-Line Options**
|
||||
|
||||
.. code:: text
|
||||
|
||||
usage: rnodeconf [-h] [-i] [-a] [-u] [-U] [--fw-version version] [--nocheck] [-C] [-N] [-T] [-b] [-B] [-p] [--freq Hz] [--bw Hz] [--txp dBm] [--sf factor] [--cr rate] [--eeprom-backup] [--eeprom-dump] [--eeprom-wipe] [--version] [port]
|
||||
usage: rnodeconf.py [-h] [-i] [-a] [-u] [-U] [--fw-version version] [--nocheck] [-e]
|
||||
[-E] [-C] [--baud-flash baud_flash] [-N] [-T] [-b] [-B] [-p] [-D i]
|
||||
[--freq Hz] [--bw Hz] [--txp dBm] [--sf factor] [--cr rate]
|
||||
[--eeprom-backup] [--eeprom-dump] [--eeprom-wipe] [-P]
|
||||
[--trust-key hexbytes] [--version] [port]
|
||||
|
||||
RNode Configuration and firmware utility. This program allows you to change various settings and startup modes of RNode. It can also install, flash and update the firmware on supported devices.
|
||||
RNode Configuration and firmware utility. This program allows you to change various
|
||||
settings and startup modes of RNode. It can also install, flash and update the firmware
|
||||
on supported devices.
|
||||
|
||||
positional arguments:
|
||||
port serial port where RNode is attached
|
||||
@@ -453,11 +698,14 @@ to create and provision new :ref:`RNodes<rnode-main>` from any supported hardwar
|
||||
-e, --extract Extract firmware from connected RNode for later use
|
||||
-E, --use-extracted Use the extracted firmware for autoinstallation or update
|
||||
-C, --clear-cache Clear locally cached firmware files
|
||||
--baud-flash baud_flash
|
||||
Set specific baud rate when flashing device. Default is 921600
|
||||
-N, --normal Switch device to normal mode
|
||||
-T, --tnc Switch device to TNC mode
|
||||
-b, --bluetooth-on Turn device bluetooth on
|
||||
-B, --bluetooth-off Turn device bluetooth off
|
||||
-p, --bluetooth-pair Put device into bluetooth pairing mode
|
||||
-D i, --display i Set display intensity (0-255)
|
||||
--freq Hz Frequency in Hz for TNC mode
|
||||
--bw Hz Bandwidth in Hz for TNC mode
|
||||
--txp dBm TX power in dBm for TNC mode
|
||||
@@ -466,6 +714,8 @@ to create and provision new :ref:`RNodes<rnode-main>` from any supported hardwar
|
||||
--eeprom-backup Backup EEPROM to file
|
||||
--eeprom-dump Dump EEPROM to console
|
||||
--eeprom-wipe Unlock and wipe EEPROM
|
||||
-P, --public Display public part of signing key
|
||||
--trust-key hexbytes Public key to trust for device verification
|
||||
--version Print program version and exit
|
||||
|
||||
For more information on how to create your own RNodes, please read the :ref:`Creating RNodes<rnode-creating>`
|
||||
|
||||
@@ -21,15 +21,15 @@ networks, without any need for hierarchical or beaureucratic structures to contr
|
||||
or manage them, while ensuring individuals and communities full sovereignty
|
||||
over their own network segments.
|
||||
|
||||
Reticulum is a complete networking stack, and does not need IP or higher
|
||||
Reticulum is a **complete networking stack**, and does not need IP or higher
|
||||
layers, although it is easy to utilise IP (with TCP or UDP) as the underlying
|
||||
carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the
|
||||
Internet or private IP networks. Reticulum is built directly on cryptographic
|
||||
principles, allowing resilience and stable functionality in open and trustless
|
||||
networks.
|
||||
|
||||
No kernel modules or drivers are required. Reticulum runs completely in
|
||||
userland, and can run on practically any system that runs Python 3. Reticulum
|
||||
No kernel modules or drivers are required. Reticulum can run completely in
|
||||
userland, and will run on practically any system that runs Python 3. Reticulum
|
||||
runs well even on small single-board computers like the Pi Zero.
|
||||
|
||||
|
||||
@@ -38,7 +38,7 @@ Current Status
|
||||
**Please know!** Reticulum should currently be considered beta software. All core protocol
|
||||
features are implemented and functioning, but additions will probably occur as
|
||||
real-world use is explored. *There will be bugs*. The API and wire-format can be
|
||||
considered stable at the moment, but could change if absolutely warranted.
|
||||
considered complete and stable at the moment, but could change if absolutely warranted.
|
||||
|
||||
|
||||
What does Reticulum Offer?
|
||||
@@ -71,7 +71,7 @@ What does Reticulum Offer?
|
||||
|
||||
* Efficient link establishment
|
||||
|
||||
* Total bandwidth cost of setting up a link is only 3 packets, totalling 297 bytes
|
||||
* Total cost of setting up an encrypted and verified link is only 3 packets, totalling 297 bytes
|
||||
|
||||
* Low cost of keeping links open at only 0.44 bits per second
|
||||
|
||||
|
||||
@@ -50,6 +50,7 @@ setuptools.setup(
|
||||
'rncp=RNS.Utilities.rncp:main',
|
||||
'rnx=RNS.Utilities.rnx:main',
|
||||
'rnodeconf=RNS.Utilities.rnodeconf:main',
|
||||
'ir=RNS.Utilities.ir:main',
|
||||
]
|
||||
},
|
||||
install_requires=requirements,
|
||||
|
||||
+1
-1
@@ -407,7 +407,7 @@ class TestChannel(unittest.TestCase):
|
||||
def test_buffer_big(self):
|
||||
writer = RNS.Buffer.create_writer(15, self.h.channel)
|
||||
reader = RNS.Buffer.create_reader(15, self.h.channel)
|
||||
data = "01234556789"*1024 # 10 KB
|
||||
data = "01234556789"*1024*5 # 50 KB
|
||||
count = 0
|
||||
write_finished = False
|
||||
|
||||
|
||||
Reference in New Issue
Block a user