mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-22 05:30:17 +00:00
remove dangling spaces
This commit is contained in:
parent
2a5a439921
commit
011448c22d
@ -1214,7 +1214,7 @@ This beta release brings a range of improvements and bugfixes.
|
||||
- Improved documentation.
|
||||
- Improved request timeouts and handling.
|
||||
- Improved link establishment.
|
||||
- Improved resource transfer timing.
|
||||
- Improved resource transfer timing.
|
||||
|
||||
**Fixed bugs**
|
||||
- Fixed a race condition in inbound proof handling.
|
||||
|
@ -22,7 +22,7 @@ noble_gases = ["Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon", "Oganesso
|
||||
def program_setup(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our example
|
||||
identity = RNS.Identity()
|
||||
|
||||
@ -70,7 +70,7 @@ def program_setup(configpath):
|
||||
|
||||
# We register the announce handler with Reticulum
|
||||
RNS.Transport.register_announce_handler(announce_handler)
|
||||
|
||||
|
||||
# Everything's ready!
|
||||
# Let's hand over control to the announce loop
|
||||
announceLoop(destination_1, destination_2)
|
||||
@ -86,7 +86,7 @@ def announceLoop(destination_1, destination_2):
|
||||
# know how to create messages directed towards it.
|
||||
while True:
|
||||
entered = input()
|
||||
|
||||
|
||||
# Randomly select a fruit
|
||||
fruit = fruits[random.randint(0,len(fruits)-1)]
|
||||
|
||||
|
@ -17,7 +17,7 @@ APP_NAME = "example_utilities"
|
||||
def program_setup(configpath, channel=None):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# If the user did not select a "channel" we use
|
||||
# a default one called "public_information".
|
||||
# This "channel" is added to the destination name-
|
||||
@ -40,7 +40,7 @@ def program_setup(configpath, channel=None):
|
||||
# We specify a callback that will get called every time
|
||||
# the destination receives data.
|
||||
broadcast_destination.set_packet_callback(packet_callback)
|
||||
|
||||
|
||||
# Everything's ready!
|
||||
# Let's hand over control to the main loop
|
||||
broadcastLoop(broadcast_destination)
|
||||
|
@ -35,7 +35,7 @@ latest_buffer = None
|
||||
def server(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our example
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -151,7 +151,7 @@ def client(destination_hexhash, configpath):
|
||||
raise ValueError(
|
||||
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
|
||||
)
|
||||
|
||||
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
@ -251,7 +251,7 @@ def link_closed(link):
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
|
@ -98,7 +98,7 @@ latest_client_link = None
|
||||
def server(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our link example
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -206,7 +206,7 @@ def client(destination_hexhash, configpath):
|
||||
raise ValueError(
|
||||
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
|
||||
)
|
||||
|
||||
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
@ -315,7 +315,7 @@ def link_closed(link):
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
|
@ -26,7 +26,7 @@ def server(configpath):
|
||||
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our echo server
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -35,7 +35,7 @@ def server(configpath):
|
||||
# create a "single" destination that can receive encrypted
|
||||
# messages. This way the client can send a request and be
|
||||
# certain that no-one else than this destination was able
|
||||
# to read it.
|
||||
# to read it.
|
||||
echo_destination = RNS.Destination(
|
||||
server_identity,
|
||||
RNS.Destination.IN,
|
||||
@ -50,7 +50,7 @@ def server(configpath):
|
||||
# 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)
|
||||
|
||||
|
||||
# Tell the destination which function in our program to
|
||||
# run when a packet is received. We do this so we can
|
||||
# print a log message when the server receives a request
|
||||
@ -79,7 +79,7 @@ def announceLoop(destination):
|
||||
|
||||
def server_callback(message, packet):
|
||||
global reticulum
|
||||
|
||||
|
||||
# Tell the user that we received an echo request, and
|
||||
# that we are going to send a reply to the requester.
|
||||
# Sending the proof is handled automatically, since we
|
||||
@ -92,14 +92,14 @@ def server_callback(message, packet):
|
||||
|
||||
if reception_rssi != None:
|
||||
reception_stats += f" [RSSI {reception_rssi} dBm]"
|
||||
|
||||
|
||||
if reception_snr != None:
|
||||
reception_stats += f" [SNR {reception_snr} dBm]"
|
||||
|
||||
else:
|
||||
if packet.rssi != None:
|
||||
reception_stats += f" [RSSI {packet.rssi} dBm]"
|
||||
|
||||
|
||||
if packet.snr != None:
|
||||
reception_stats += f" [SNR {packet.snr} dB]"
|
||||
|
||||
@ -114,7 +114,7 @@ def server_callback(message, packet):
|
||||
# to run as a client
|
||||
def client(destination_hexhash, configpath, timeout=None):
|
||||
global reticulum
|
||||
|
||||
|
||||
# We need a binary representation of the destination
|
||||
# hash that was entered on the command line
|
||||
try:
|
||||
@ -149,7 +149,7 @@ def client(destination_hexhash, configpath, timeout=None):
|
||||
# command line.
|
||||
while True:
|
||||
input()
|
||||
|
||||
|
||||
# Let's first check if RNS knows a path to the destination.
|
||||
# If it does, we'll load the server identity and create a packet
|
||||
if RNS.Transport.has_path(destination_hash):
|
||||
@ -230,7 +230,7 @@ def packet_delivered(receipt):
|
||||
|
||||
if reception_rssi != None:
|
||||
reception_stats += f" [RSSI {reception_rssi} dBm]"
|
||||
|
||||
|
||||
if reception_snr != None:
|
||||
reception_stats += f" [SNR {reception_snr} dB]"
|
||||
|
||||
@ -238,7 +238,7 @@ def packet_delivered(receipt):
|
||||
if receipt.proof_packet != None:
|
||||
if receipt.proof_packet.rssi != None:
|
||||
reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]"
|
||||
|
||||
|
||||
if receipt.proof_packet.snr != None:
|
||||
reception_stats += f" [SNR {receipt.proof_packet.snr} dB]"
|
||||
|
||||
|
@ -44,7 +44,7 @@ serve_path = None
|
||||
def server(configpath, path):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our file server
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -120,7 +120,7 @@ def client_connected(link):
|
||||
RNS.log("Too many files in served directory!", RNS.LOG_ERROR)
|
||||
RNS.log("You should implement a function to split the filelist over multiple packets.", RNS.LOG_ERROR)
|
||||
RNS.log("Hint: The client already supports it :)", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
# After this, we're just going to keep the link
|
||||
# open until the client requests a file. We'll
|
||||
# configure a function that get's called when
|
||||
@ -147,7 +147,7 @@ def client_request(message, packet):
|
||||
# read it and pack it as a resource
|
||||
RNS.log(f"Client requested \"{filename}\"")
|
||||
file = open(os.path.join(serve_path, filename), "rb")
|
||||
|
||||
|
||||
file_resource = RNS.Resource(
|
||||
file,
|
||||
packet.link,
|
||||
@ -220,7 +220,7 @@ def client(destination_hexhash, configpath):
|
||||
raise ValueError(
|
||||
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
|
||||
)
|
||||
|
||||
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
@ -291,7 +291,7 @@ def download(filename):
|
||||
# packet receipt.
|
||||
request_packet = RNS.Packet(server_link, filename.encode("utf-8"), create_receipt=False)
|
||||
request_packet.send()
|
||||
|
||||
|
||||
print("")
|
||||
print(f"Requested \"{filename}\" from server, waiting for download to begin...")
|
||||
menu_mode = "download_started"
|
||||
@ -474,7 +474,7 @@ def link_closed(link):
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
@ -486,17 +486,17 @@ def link_closed(link):
|
||||
def download_began(resource):
|
||||
global menu_mode, current_download, download_started, transfer_size, file_size
|
||||
current_download = resource
|
||||
|
||||
|
||||
if download_started == 0:
|
||||
download_started = time.time()
|
||||
|
||||
|
||||
transfer_size += resource.size
|
||||
file_size = resource.total_size
|
||||
|
||||
|
||||
menu_mode = "downloading"
|
||||
|
||||
# When the download concludes, successfully
|
||||
# or not, we'll update our menu state and
|
||||
# or not, we'll update our menu state and
|
||||
# inform the user about how it all went.
|
||||
def download_concluded(resource):
|
||||
global menu_mode, current_filename, download_started, download_finished, download_time
|
||||
|
@ -27,7 +27,7 @@ latest_client_link = None
|
||||
def server(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our link example
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -99,7 +99,7 @@ def server_packet_received(message, packet):
|
||||
text = message.decode("utf-8")
|
||||
|
||||
RNS.log(f"Received data from {remote_peer}: {text}")
|
||||
|
||||
|
||||
reply_text = f"I received \"{text}\" over the link from {remote_peer}"
|
||||
reply_data = reply_text.encode("utf-8")
|
||||
RNS.Packet(latest_client_link, reply_data).send()
|
||||
@ -239,7 +239,7 @@ def link_closed(link):
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
|
@ -27,7 +27,7 @@ latest_client_link = None
|
||||
def server(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our link example
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -89,7 +89,7 @@ def server_packet_received(message, packet):
|
||||
# that connected.
|
||||
text = message.decode("utf-8")
|
||||
RNS.log(f"Received data on the link: {text}")
|
||||
|
||||
|
||||
reply_text = f"I received \"{text}\" over the link"
|
||||
reply_data = reply_text.encode("utf-8")
|
||||
RNS.Packet(latest_client_link, reply_data).send()
|
||||
@ -113,7 +113,7 @@ def client(destination_hexhash, configpath):
|
||||
raise ValueError(
|
||||
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
|
||||
)
|
||||
|
||||
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
@ -217,7 +217,7 @@ def link_closed(link):
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
|
@ -17,7 +17,7 @@ APP_NAME = "example_utilities"
|
||||
def program_setup(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our example
|
||||
identity = RNS.Identity()
|
||||
|
||||
@ -42,7 +42,7 @@ def program_setup(configpath):
|
||||
# tries to communicate with the destination know whether their
|
||||
# communication was received correctly.
|
||||
destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
|
||||
|
||||
|
||||
# Everything's ready!
|
||||
# Let's hand over control to the announce loop
|
||||
announceLoop(destination)
|
||||
|
@ -28,7 +28,7 @@ def server(configpath):
|
||||
|
||||
# TODO: Remove
|
||||
RNS.loglevel = RNS.LOG_DEBUG
|
||||
|
||||
|
||||
# Randomly create a new identity for our echo server
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -37,7 +37,7 @@ def server(configpath):
|
||||
# create a "single" destination that can receive encrypted
|
||||
# messages. This way the client can send a request and be
|
||||
# certain that no-one else than this destination was able
|
||||
# to read it.
|
||||
# to read it.
|
||||
echo_destination = RNS.Destination(
|
||||
server_identity,
|
||||
RNS.Destination.IN,
|
||||
@ -61,7 +61,7 @@ def server(configpath):
|
||||
# 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)
|
||||
|
||||
|
||||
# Tell the destination which function in our program to
|
||||
# run when a packet is received. We do this so we can
|
||||
# print a log message when the server receives a request
|
||||
@ -90,7 +90,7 @@ def announceLoop(destination):
|
||||
|
||||
def server_callback(message, packet):
|
||||
global reticulum
|
||||
|
||||
|
||||
# Tell the user that we received an echo request, and
|
||||
# that we are going to send a reply to the requester.
|
||||
# Sending the proof is handled automatically, since we
|
||||
@ -103,14 +103,14 @@ def server_callback(message, packet):
|
||||
|
||||
if reception_rssi != None:
|
||||
reception_stats += f" [RSSI {reception_rssi} dBm]"
|
||||
|
||||
|
||||
if reception_snr != None:
|
||||
reception_stats += f" [SNR {reception_snr} dBm]"
|
||||
|
||||
else:
|
||||
if packet.rssi != None:
|
||||
reception_stats += f" [RSSI {packet.rssi} dBm]"
|
||||
|
||||
|
||||
if packet.snr != None:
|
||||
reception_stats += f" [SNR {packet.snr} dB]"
|
||||
|
||||
@ -125,7 +125,7 @@ def server_callback(message, packet):
|
||||
# to run as a client
|
||||
def client(destination_hexhash, configpath, timeout=None):
|
||||
global reticulum
|
||||
|
||||
|
||||
# We need a binary representation of the destination
|
||||
# hash that was entered on the command line
|
||||
try:
|
||||
@ -160,7 +160,7 @@ def client(destination_hexhash, configpath, timeout=None):
|
||||
# command line.
|
||||
while True:
|
||||
input()
|
||||
|
||||
|
||||
# Let's first check if RNS knows a path to the destination.
|
||||
# If it does, we'll load the server identity and create a packet
|
||||
if RNS.Transport.has_path(destination_hash):
|
||||
@ -242,7 +242,7 @@ def packet_delivered(receipt):
|
||||
|
||||
if reception_rssi != None:
|
||||
reception_stats += f" [RSSI {reception_rssi} dBm]"
|
||||
|
||||
|
||||
if reception_snr != None:
|
||||
reception_stats += f" [SNR {reception_snr} dB]"
|
||||
|
||||
@ -250,7 +250,7 @@ def packet_delivered(receipt):
|
||||
if receipt.proof_packet != None:
|
||||
if receipt.proof_packet.rssi != None:
|
||||
reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]"
|
||||
|
||||
|
||||
if receipt.proof_packet.snr != None:
|
||||
reception_stats += f" [SNR {receipt.proof_packet.snr} dB]"
|
||||
|
||||
|
@ -33,7 +33,7 @@ def random_text_generator(path, data, request_id, link_id, remote_identity, requ
|
||||
def server(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our link example
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -113,7 +113,7 @@ def client(destination_hexhash, configpath):
|
||||
raise ValueError(
|
||||
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
|
||||
)
|
||||
|
||||
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
@ -223,7 +223,7 @@ def link_closed(link):
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
time.sleep(1.5)
|
||||
os._exit(0)
|
||||
|
@ -36,7 +36,7 @@ printed = False
|
||||
def server(configpath):
|
||||
# We must first initialise Reticulum
|
||||
reticulum = RNS.Reticulum(configpath)
|
||||
|
||||
|
||||
# Randomly create a new identity for our link example
|
||||
server_identity = RNS.Identity()
|
||||
|
||||
@ -113,9 +113,9 @@ def size_str(num, suffix='B'):
|
||||
|
||||
def server_packet_received(message, packet):
|
||||
global latest_client_link, first_packet_at, last_packet_at, received_data, rc, data_cap
|
||||
|
||||
|
||||
received_data += len(packet.data)
|
||||
|
||||
|
||||
rc += 1
|
||||
if rc >= 50:
|
||||
RNS.log(size_str(received_data))
|
||||
@ -127,7 +127,7 @@ def server_packet_received(message, packet):
|
||||
rc = 0
|
||||
|
||||
last_packet_at = time.time()
|
||||
|
||||
|
||||
# Print statistics
|
||||
download_time = last_packet_at-first_packet_at
|
||||
hours, rem = divmod(download_time, 3600)
|
||||
@ -169,7 +169,7 @@ def client(destination_hexhash, configpath):
|
||||
raise ValueError(
|
||||
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
|
||||
)
|
||||
|
||||
|
||||
destination_hash = bytes.fromhex(destination_hexhash)
|
||||
except:
|
||||
RNS.log("Invalid destination entered. Check your input!\n")
|
||||
@ -280,7 +280,7 @@ def link_closed(link):
|
||||
RNS.log("The link was closed by the server, exiting now")
|
||||
else:
|
||||
RNS.log("Link closed, exiting now")
|
||||
|
||||
|
||||
RNS.Reticulum.exit_handler()
|
||||
|
||||
time.sleep(1.5)
|
||||
|
18
README.md
18
README.md
@ -109,8 +109,8 @@ network, and vice versa.
|
||||
|
||||
## How do I get started?
|
||||
The best way to get started with the Reticulum Network Stack depends on what
|
||||
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)
|
||||
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`.
|
||||
@ -143,15 +143,15 @@ creating a more complex configuration.
|
||||
|
||||
If you have an old version of `pip` on your system, you may need to upgrade it first with `pip install pip --upgrade`. If you no not already have `pip` installed, you can install it using the package manager of your system with `sudo apt install python3-pip` or similar.
|
||||
|
||||
For more detailed examples on how to expand communication over many mediums such
|
||||
as packet radio or LoRa, serial ports, or over fast IP links and the Internet using
|
||||
the UDP and TCP interfaces, take a look at the [Supported Interfaces](https://markqvist.github.io/Reticulum/manual/interfaces.html)
|
||||
For more detailed examples on how to expand communication over many mediums such
|
||||
as packet radio or LoRa, serial ports, or over fast IP links and the Internet using
|
||||
the UDP and TCP interfaces, take a look at the [Supported Interfaces](https://markqvist.github.io/Reticulum/manual/interfaces.html)
|
||||
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
||||
|
||||
## Included Utilities
|
||||
Reticulum includes a range of useful utilities for managing your networks,
|
||||
viewing status and information, and other tasks. You can read more about these
|
||||
programs in the [Included Utility Programs](https://markqvist.github.io/Reticulum/manual/using.html#included-utility-programs)
|
||||
Reticulum includes a range of useful utilities for managing your networks,
|
||||
viewing status and information, and other tasks. You can read more about these
|
||||
programs in the [Included Utility Programs](https://markqvist.github.io/Reticulum/manual/using.html#included-utility-programs)
|
||||
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
||||
|
||||
- The system daemon `rnsd` for running Reticulum as an always-available service
|
||||
@ -242,7 +242,7 @@ The testnet is just that, an informal network for testing and experimenting.
|
||||
It will be up most of the time, and anyone can join, but it also means that
|
||||
there's no guarantees for service availability.
|
||||
|
||||
It probably goes without saying, but *don't use the testnet entry-points as
|
||||
It probably goes without saying, but *don't use the testnet entry-points as
|
||||
hardcoded or default interfaces in any applications you ship to users*. When
|
||||
shipping applications, the best practice is to provide your own default
|
||||
connectivity solutions, if needed and applicable, or in most cases, simply
|
||||
|
@ -244,7 +244,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager):
|
||||
processed_length = len(chunk)
|
||||
|
||||
message = StreamDataMessage(self._stream_id, chunk, self._eof, comp_success)
|
||||
|
||||
|
||||
self._channel.send(message)
|
||||
return processed_length
|
||||
|
||||
|
@ -136,7 +136,7 @@ class MessageBase(abc.ABC):
|
||||
MSGTYPE = None
|
||||
"""
|
||||
Defines a unique identifier for a message class.
|
||||
|
||||
|
||||
* Must be unique within all classes registered with a ``Channel``
|
||||
* Must be less than ``0xf000``. Values greater than or equal to ``0xf000`` are reserved.
|
||||
"""
|
||||
@ -247,11 +247,11 @@ class Channel(contextlib.AbstractContextManager):
|
||||
|
||||
# The maximum window size for transfers on fast links
|
||||
WINDOW_MAX_FAST = 48
|
||||
|
||||
|
||||
# For calculating maps and guard segments, this
|
||||
# must be set to the global maximum window.
|
||||
WINDOW_MAX = WINDOW_MAX_FAST
|
||||
|
||||
|
||||
# If the fast rate is sustained for this many request
|
||||
# rounds, the fast link window size will be allowed.
|
||||
FAST_RATE_THRESHOLD = 10
|
||||
@ -380,21 +380,21 @@ class Channel(contextlib.AbstractContextManager):
|
||||
def _emplace_envelope(self, envelope: Envelope, ring: collections.deque[Envelope]) -> bool:
|
||||
with self._lock:
|
||||
i = 0
|
||||
|
||||
|
||||
for existing in ring:
|
||||
|
||||
if envelope.sequence == existing.sequence:
|
||||
RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence {envelope.sequence}", RNS.LOG_EXTREME)
|
||||
return False
|
||||
|
||||
|
||||
if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2):
|
||||
ring.insert(i, envelope)
|
||||
|
||||
envelope.tracked = True
|
||||
return True
|
||||
|
||||
|
||||
i += 1
|
||||
|
||||
|
||||
envelope.tracked = True
|
||||
ring.append(envelope)
|
||||
|
||||
@ -449,7 +449,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
m = e.unpack(self._message_factories)
|
||||
else:
|
||||
m = e.message
|
||||
|
||||
|
||||
self._rx_ring.remove(e)
|
||||
self._run_callbacks(m)
|
||||
|
||||
@ -468,7 +468,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
with self._lock:
|
||||
outstanding = 0
|
||||
for envelope in self._tx_ring:
|
||||
if envelope.outlet == self._outlet:
|
||||
if envelope.outlet == self._outlet:
|
||||
if not envelope.packet or not self._outlet.get_packet_state(envelope.packet) == MessageState.MSGSTATE_DELIVERED:
|
||||
outstanding += 1
|
||||
|
||||
@ -508,7 +508,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
# TODO: Remove at some point
|
||||
# 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:
|
||||
@ -581,7 +581,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
with self._lock:
|
||||
if not self.is_ready_to_send():
|
||||
raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready")
|
||||
|
||||
|
||||
envelope = Envelope(self._outlet, message=message, sequence=self._next_sequence)
|
||||
self._next_sequence = (self._next_sequence + 1) % Channel.SEQ_MODULUS
|
||||
self._emplace_envelope(envelope, self._tx_ring)
|
||||
@ -592,7 +592,7 @@ class Channel(contextlib.AbstractContextManager):
|
||||
envelope.pack()
|
||||
if len(envelope.raw) > self._outlet.mdu:
|
||||
raise ChannelException(CEType.ME_TOO_BIG, f"Packed message too big for packet: {len(envelope.raw)} > {self._outlet.mdu}")
|
||||
|
||||
|
||||
envelope.packet = self._outlet.send(envelope.raw)
|
||||
envelope.tries += 1
|
||||
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)
|
||||
|
@ -25,7 +25,7 @@ import RNS.vendor.platformutils as pu
|
||||
|
||||
if cp.PROVIDER == cp.PROVIDER_INTERNAL:
|
||||
from .aes import AES
|
||||
|
||||
|
||||
elif cp.PROVIDER == cp.PROVIDER_PYCA:
|
||||
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
|
||||
|
||||
@ -46,7 +46,7 @@ class AES_128_CBC:
|
||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
|
||||
else:
|
||||
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
|
||||
|
||||
|
||||
encryptor = cipher.encryptor()
|
||||
ciphertext = encryptor.update(plaintext) + encryptor.finalize()
|
||||
return ciphertext
|
||||
|
@ -49,7 +49,7 @@ class Fernet():
|
||||
|
||||
if len(key) != 32:
|
||||
raise ValueError(f"Token key must be 32 bytes, not {len(key)}")
|
||||
|
||||
|
||||
self._signing_key = key[:16]
|
||||
self._encryption_key = key[16:]
|
||||
|
||||
|
@ -48,34 +48,34 @@ class sha256:
|
||||
_h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
|
||||
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)
|
||||
_output_size = 8
|
||||
|
||||
|
||||
blocksize = 1
|
||||
block_size = 64
|
||||
digest_size = 32
|
||||
|
||||
def __init__(self, m=None):
|
||||
|
||||
def __init__(self, m=None):
|
||||
self._buffer = b""
|
||||
self._counter = 0
|
||||
|
||||
|
||||
if m is not None:
|
||||
if type(m) is not bytes:
|
||||
raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}')
|
||||
self.update(m)
|
||||
|
||||
|
||||
def _rotr(self, x, y):
|
||||
return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF
|
||||
|
||||
|
||||
def _sha256_process(self, c):
|
||||
w = [0]*64
|
||||
w[0:16] = struct.unpack('!16L', c)
|
||||
|
||||
|
||||
for i in range(16, 64):
|
||||
s0 = self._rotr(w[i-15], 7) ^ self._rotr(w[i-15], 18) ^ (w[i-15] >> 3)
|
||||
s1 = self._rotr(w[i-2], 17) ^ self._rotr(w[i-2], 19) ^ (w[i-2] >> 10)
|
||||
w[i] = (w[i-16] + s0 + w[i-7] + s1) & 0xFFFFFFFF
|
||||
|
||||
|
||||
a,b,c,d,e,f,g,h = self._h
|
||||
|
||||
|
||||
for i in range(64):
|
||||
s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22)
|
||||
maj = (a & b) ^ (a & c) ^ (b & c)
|
||||
@ -83,7 +83,7 @@ class sha256:
|
||||
s1 = self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25)
|
||||
ch = (e & f) ^ ((~e) & g)
|
||||
t1 = h + s1 + ch + self._k[i] + w[i]
|
||||
|
||||
|
||||
h = g
|
||||
g = f
|
||||
f = e
|
||||
@ -92,38 +92,38 @@ class sha256:
|
||||
c = b
|
||||
b = a
|
||||
a = (t1 + t2) & 0xFFFFFFFF
|
||||
|
||||
|
||||
self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])]
|
||||
|
||||
|
||||
def update(self, m):
|
||||
if not m:
|
||||
return
|
||||
|
||||
if type(m) is not bytes:
|
||||
raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}')
|
||||
|
||||
|
||||
self._buffer += m
|
||||
self._counter += len(m)
|
||||
|
||||
|
||||
while len(self._buffer) >= 64:
|
||||
self._sha256_process(self._buffer[:64])
|
||||
self._buffer = self._buffer[64:]
|
||||
|
||||
|
||||
def digest(self):
|
||||
mdi = self._counter & 0x3F
|
||||
length = struct.pack('!Q', self._counter<<3)
|
||||
|
||||
|
||||
if mdi < 56:
|
||||
padlen = 55-mdi
|
||||
else:
|
||||
padlen = 119-mdi
|
||||
|
||||
|
||||
r = self.copy()
|
||||
r.update(b'\x80'+(b'\x00'*padlen)+length)
|
||||
return b''.join([struct.pack('!L', i) for i in r._h[:self._output_size]])
|
||||
|
||||
|
||||
def hexdigest(self):
|
||||
return self.digest().encode('hex')
|
||||
|
||||
|
||||
def copy(self):
|
||||
return copy.deepcopy(self)
|
||||
|
@ -138,9 +138,9 @@ class X25519PrivateKey:
|
||||
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
|
||||
|
||||
start = time.time()
|
||||
|
||||
|
||||
shared = _pack_number(_raw_curve25519(peer_public_key.x, self.a))
|
||||
|
||||
|
||||
end = time.time()
|
||||
duration = end-start
|
||||
|
||||
@ -150,7 +150,7 @@ class X25519PrivateKey:
|
||||
if end > X25519PrivateKey.T_CLEAR:
|
||||
X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW
|
||||
X25519PrivateKey.T_MAX = 0
|
||||
|
||||
|
||||
if duration < X25519PrivateKey.T_MAX or duration < X25519PrivateKey.MIN_EXEC_TIME:
|
||||
target = start+X25519PrivateKey.T_MAX
|
||||
|
||||
|
@ -144,7 +144,7 @@ class AES:
|
||||
return matrix2bytes(state)
|
||||
|
||||
|
||||
# will encrypt the entire data
|
||||
# will encrypt the entire data
|
||||
def encrypt(self, plaintext, iv):
|
||||
"""
|
||||
Encrypts `plaintext` using CBC mode and PKCS#7 padding, with the given
|
||||
@ -173,7 +173,7 @@ class AES:
|
||||
return b''.join(ciphertext_blocks)
|
||||
|
||||
|
||||
# will decrypt the entire data
|
||||
# will decrypt the entire data
|
||||
def decrypt(self, ciphertext, iv):
|
||||
"""
|
||||
Decrypts `ciphertext` using CBC mode and PKCS#7 padding, with the given
|
||||
@ -188,7 +188,7 @@ class AES:
|
||||
for ciphertext_block in split_blocks(ciphertext):
|
||||
# in CBC mode every block is XOR'd with the previous block
|
||||
xorred = xor_bytes(previous, self._decrypt_block(ciphertext_block))
|
||||
|
||||
|
||||
# append plaintext
|
||||
plaintext_blocks.append(xorred)
|
||||
previous = ciphertext_block
|
||||
@ -223,7 +223,7 @@ def test():
|
||||
print("Single Block Tests")
|
||||
print("------------------")
|
||||
print(f"iv: {iv.hex()}")
|
||||
|
||||
|
||||
print(f"plain text: '{single_block_text.decode()}'")
|
||||
ciphertext_block = _aes._encrypt_block(single_block_text)
|
||||
plaintext_block = _aes._decrypt_block(ciphertext_block)
|
||||
@ -268,4 +268,4 @@ def test():
|
||||
|
||||
if __name__ == "__main__":
|
||||
# test AES class
|
||||
test()
|
||||
test()
|
||||
|
@ -140,7 +140,7 @@ class Destination:
|
||||
|
||||
def __init__(self, identity, direction, type, app_name, *aspects):
|
||||
# Check input values and build name string
|
||||
if "." in app_name: raise ValueError("Dots can't be used in app names")
|
||||
if "." in app_name: raise ValueError("Dots can't be used in app names")
|
||||
if not type in Destination.types: raise ValueError("Unknown destination type")
|
||||
if not direction in Destination.directions: raise ValueError("Unknown destination direction")
|
||||
|
||||
@ -241,7 +241,7 @@ class Destination:
|
||||
|
||||
if self.direction != Destination.IN:
|
||||
raise TypeError("Only IN destination types can be announced")
|
||||
|
||||
|
||||
ratchet = b""
|
||||
now = time.time()
|
||||
stale_responses = []
|
||||
@ -264,7 +264,7 @@ class Destination:
|
||||
# multiple available paths, and to choose the best one.
|
||||
RNS.log(f"Using cached announce data for answering path request with tag {RNS.prettyhexrep(tag)}", RNS.LOG_EXTREME)
|
||||
announce_data = self.path_responses[tag][1]
|
||||
|
||||
|
||||
else:
|
||||
destination_hash = self.hash
|
||||
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big")
|
||||
@ -281,7 +281,7 @@ class Destination:
|
||||
returned_app_data = self.default_app_data()
|
||||
if isinstance(returned_app_data, bytes):
|
||||
app_data = returned_app_data
|
||||
|
||||
|
||||
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash+ratchet
|
||||
if app_data != None:
|
||||
signed_data += app_data
|
||||
|
@ -137,7 +137,7 @@ class Identity:
|
||||
# save, but the only changes. It might be possible to
|
||||
# simply overwrite on exit now that every local client
|
||||
# disconnect triggers a data persist.
|
||||
|
||||
|
||||
try:
|
||||
if hasattr(Identity, "saving_known_destinations"):
|
||||
wait_interval = 0.2
|
||||
@ -279,7 +279,7 @@ class Identity:
|
||||
ratchet_data = {"ratchet": ratchet, "received": time.time()}
|
||||
|
||||
ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets"
|
||||
|
||||
|
||||
if not os.path.isdir(ratchetdir):
|
||||
os.makedirs(ratchetdir)
|
||||
|
||||
@ -290,7 +290,7 @@ class Identity:
|
||||
ratchet_file.close()
|
||||
os.replace(outpath, finalpath)
|
||||
|
||||
|
||||
|
||||
threading.Thread(target=persist_job, daemon=True).start()
|
||||
|
||||
except Exception as e:
|
||||
@ -337,7 +337,7 @@ class Identity:
|
||||
Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"An error occurred while loading ratchet data for {RNS.prettyhexrep(destination_hash)} from storage.", RNS.LOG_ERROR)
|
||||
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
@ -444,7 +444,7 @@ class Identity:
|
||||
RNS.log(f"Received invalid announce for {RNS.prettyhexrep(destination_hash)}: Invalid signature.", RNS.LOG_DEBUG)
|
||||
del announced_identity
|
||||
return False
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Error occurred while validating announce. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
return False
|
||||
@ -567,7 +567,7 @@ class Identity:
|
||||
self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes)
|
||||
self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
|
||||
self.sig_prv = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes)
|
||||
|
||||
|
||||
self.pub = self.prv.public_key()
|
||||
self.pub_bytes = self.pub.public_bytes()
|
||||
|
||||
@ -640,7 +640,7 @@ class Identity:
|
||||
target_public_key = self.pub
|
||||
|
||||
shared_key = ephemeral_key.exchange(target_public_key)
|
||||
|
||||
|
||||
derived_key = RNS.Cryptography.hkdf(
|
||||
length=32,
|
||||
derive_from=shared_key,
|
||||
@ -690,9 +690,9 @@ class Identity:
|
||||
plaintext = fernet.decrypt(ciphertext)
|
||||
if ratchet_id_receiver:
|
||||
ratchet_id_receiver.latest_ratchet_id = ratchet_id
|
||||
|
||||
|
||||
break
|
||||
|
||||
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
@ -720,7 +720,7 @@ class Identity:
|
||||
RNS.log(f"Decryption by {RNS.prettyhexrep(self.hash)} failed: {e}", RNS.LOG_DEBUG)
|
||||
if ratchet_id_receiver:
|
||||
ratchet_id_receiver.latest_ratchet_id = None
|
||||
|
||||
|
||||
return plaintext;
|
||||
else:
|
||||
RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG)
|
||||
@ -739,7 +739,7 @@ class Identity:
|
||||
"""
|
||||
if self.sig_prv != None:
|
||||
try:
|
||||
return self.sig_prv.sign(message)
|
||||
return self.sig_prv.sign(message)
|
||||
except Exception as e:
|
||||
RNS.log(f"The identity {self} could not sign the requested message. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
raise e
|
||||
@ -770,7 +770,7 @@ class Identity:
|
||||
proof_data = signature
|
||||
else:
|
||||
proof_data = packet.packet_hash + signature
|
||||
|
||||
|
||||
if destination == None:
|
||||
destination = packet.generate_proof_destination()
|
||||
|
||||
|
@ -80,7 +80,7 @@ class AX25KISSInterface(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
|
||||
self.pyserial = serial
|
||||
self.serial = None
|
||||
self.owner = owner
|
||||
@ -343,7 +343,7 @@ class AX25KISSInterface(Interface):
|
||||
self.online = False
|
||||
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if RNS.Reticulum.panic_on_interface_error:
|
||||
RNS.panic()
|
||||
|
||||
|
@ -74,7 +74,7 @@ class KISSInterface(Interface):
|
||||
|
||||
from usbserial4a import serial4a as serial
|
||||
self.parity = "N"
|
||||
|
||||
|
||||
else:
|
||||
RNS.log("Could not load USB serial module for Android, KISS interface cannot be created.", RNS.LOG_CRITICAL)
|
||||
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
||||
@ -83,9 +83,9 @@ class KISSInterface(Interface):
|
||||
raise SystemError("Android-specific interface was used on non-Android OS")
|
||||
|
||||
super().__init__()
|
||||
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
|
||||
if beacon_data == None:
|
||||
beacon_data = ""
|
||||
|
||||
@ -172,7 +172,7 @@ class KISSInterface(Interface):
|
||||
self.serial.timeout = 0.1
|
||||
elif vid == 0x10C4:
|
||||
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
||||
self.serial.timeout = 0.012
|
||||
elif vid == 0x1A86 and pid == 0x55D4:
|
||||
@ -352,7 +352,7 @@ class KISSInterface(Interface):
|
||||
data_buffer = data_buffer+bytes([byte])
|
||||
elif (command == KISS.CMD_READY):
|
||||
self.process_queue()
|
||||
|
||||
|
||||
if got == 0:
|
||||
time_since_last = int(time.time()*1000) - last_read_ms
|
||||
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
||||
@ -379,7 +379,7 @@ class KISSInterface(Interface):
|
||||
self.online = False
|
||||
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if RNS.Reticulum.panic_on_interface_error:
|
||||
RNS.panic()
|
||||
|
||||
|
@ -42,7 +42,7 @@ class KISS():
|
||||
FESC = 0xDB
|
||||
TFEND = 0xDC
|
||||
TFESC = 0xDD
|
||||
|
||||
|
||||
CMD_UNKNOWN = 0xFE
|
||||
CMD_DATA = 0x00
|
||||
CMD_FREQUENCY = 0x01
|
||||
@ -78,11 +78,11 @@ class KISS():
|
||||
|
||||
DETECT_REQ = 0x73
|
||||
DETECT_RESP = 0x46
|
||||
|
||||
|
||||
RADIO_STATE_OFF = 0x00
|
||||
RADIO_STATE_ON = 0x01
|
||||
RADIO_STATE_ASK = 0xFF
|
||||
|
||||
|
||||
CMD_ERROR = 0x90
|
||||
ERROR_INITRADIO = 0x01
|
||||
ERROR_TXFAILED = 0x02
|
||||
@ -194,7 +194,7 @@ class AndroidBluetoothManager():
|
||||
if self.rfcomm_reader != None:
|
||||
self.rfcomm_reader.close()
|
||||
self.rfcomm_reader = None
|
||||
|
||||
|
||||
if self.rfcomm_writer != None:
|
||||
self.rfcomm_writer.close()
|
||||
self.rfcomm_writer = None
|
||||
@ -371,7 +371,7 @@ class RNodeInterface(Interface):
|
||||
|
||||
else:
|
||||
self.bt_manager = None
|
||||
|
||||
|
||||
else:
|
||||
RNS.log("Could not load USB serial module for Android, RNode interface cannot be created.", RNS.LOG_CRITICAL)
|
||||
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
||||
@ -382,7 +382,7 @@ class RNodeInterface(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 508
|
||||
|
||||
|
||||
self.pyserial = serial
|
||||
self.serial = None
|
||||
self.owner = owner
|
||||
@ -561,7 +561,7 @@ class RNodeInterface(Interface):
|
||||
# self.ble = BLEConnection(owner=self, target_name=self.ble_name, target_bt_addr=self.ble_addr)
|
||||
# self.serial = self.ble
|
||||
# RNS.log(f"New connection instance: "+str(self.ble))
|
||||
|
||||
|
||||
def open_port(self):
|
||||
if not self.use_ble:
|
||||
if self.port != None:
|
||||
@ -602,7 +602,7 @@ class RNodeInterface(Interface):
|
||||
self.serial.timeout = 0.1
|
||||
elif vid == 0x10C4:
|
||||
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
||||
self.serial.timeout = 0.012
|
||||
elif vid == 0x1A86 and pid == 0x55D4:
|
||||
@ -687,14 +687,14 @@ class RNodeInterface(Interface):
|
||||
RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR)
|
||||
RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
|
||||
RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if self.serial != None:
|
||||
self.serial.close()
|
||||
if self.bt_manager != None:
|
||||
self.bt_manager.close()
|
||||
|
||||
raise OSError("RNode interface did not pass configuration validation")
|
||||
|
||||
|
||||
|
||||
def initRadio(self):
|
||||
self.setFrequency()
|
||||
@ -702,22 +702,22 @@ class RNodeInterface(Interface):
|
||||
|
||||
self.setBandwidth()
|
||||
time.sleep(0.15)
|
||||
|
||||
|
||||
self.setTXPower()
|
||||
time.sleep(0.15)
|
||||
|
||||
|
||||
self.setSpreadingFactor()
|
||||
time.sleep(0.15)
|
||||
|
||||
|
||||
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)
|
||||
|
||||
@ -735,7 +735,7 @@ class RNodeInterface(Interface):
|
||||
written = self.write_mux(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError("An IO error occurred while sending host left command to device")
|
||||
|
||||
|
||||
def enable_bluetooth(self):
|
||||
kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND])
|
||||
written = self.write_mux(kiss_command)
|
||||
@ -788,7 +788,7 @@ class RNodeInterface(Interface):
|
||||
data = line_byte+line_data
|
||||
escaped_data = KISS.escape(data)
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
|
||||
|
||||
|
||||
written = self.write_mux(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError("An IO error occurred while writing framebuffer data device")
|
||||
@ -883,7 +883,7 @@ class RNodeInterface(Interface):
|
||||
if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
|
||||
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
|
||||
self.firmware_ok = True
|
||||
|
||||
|
||||
if self.firmware_ok:
|
||||
return
|
||||
|
||||
@ -1188,7 +1188,7 @@ class RNodeInterface(Interface):
|
||||
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
|
||||
@ -1289,10 +1289,10 @@ class RNodeInterface(Interface):
|
||||
if time.time() > self.first_tx + self.id_interval:
|
||||
RNS.log(f"Interface {self} is transmitting beacon data: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG)
|
||||
self.processOutgoing(self.id_callsign)
|
||||
|
||||
|
||||
if (time.time() - self.last_port_io > self.port_io_timeout):
|
||||
self.detect()
|
||||
|
||||
|
||||
if (time.time() - self.last_port_io > self.port_io_timeout*3):
|
||||
raise OSError(f"Connected port for {self} became unresponsive")
|
||||
|
||||
@ -1343,7 +1343,7 @@ class RNodeInterface(Interface):
|
||||
if self.last_imagedata != None:
|
||||
self.display_image(self.last_imagedata)
|
||||
self.enable_external_framebuffer()
|
||||
|
||||
|
||||
elif hasattr(self, "bt_manager") and self.bt_manager != None and self.bt_manager.connected:
|
||||
self.configure_device()
|
||||
if self.online:
|
||||
@ -1504,7 +1504,7 @@ class BLEConnection(BluetoothDispatcher):
|
||||
self.write_characteristic(self.rx_char, data)
|
||||
else:
|
||||
time.sleep(0.1)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("An error occurred in {self} write loop: {e}", RNS.LOG_ERROR)
|
||||
RNS.trace_exception(e)
|
||||
@ -1552,7 +1552,7 @@ class BLEConnection(BluetoothDispatcher):
|
||||
self.owner.hw_errors.append({"error": KISS.ERROR_INVALID_BLE_MTU, "description": "The Bluetooth Low Energy transfer MTU could not be configured for the connected device, and communication has failed. Restart Reticulum and any connected applications to retry connecting."})
|
||||
self.close()
|
||||
self.should_run = False
|
||||
|
||||
|
||||
self.close_gatt()
|
||||
|
||||
self.connect_job_running = False
|
||||
@ -1599,14 +1599,14 @@ class BLEConnection(BluetoothDispatcher):
|
||||
def on_services(self, status, services):
|
||||
if status == GATT_SUCCESS:
|
||||
self.rx_char = services.search(BLEConnection.UART_RX_CHAR_UUID)
|
||||
|
||||
|
||||
if self.rx_char is not None:
|
||||
self.tx_char = services.search(BLEConnection.UART_TX_CHAR_UUID)
|
||||
|
||||
if self.tx_char is not None:
|
||||
if self.tx_char is not None:
|
||||
if self.enable_notifications(self.tx_char):
|
||||
RNS.log("Enabled notifications for BLE TX characteristic", RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
RNS.log(f"Requesting BLE connection MTU update to {self.target_mtu}", RNS.LOG_DEBUG)
|
||||
self.mtu_requested_time = time.time()
|
||||
self.request_mtu(self.target_mtu)
|
||||
|
@ -64,7 +64,7 @@ class SerialInterface(Interface):
|
||||
|
||||
from usbserial4a import serial4a as serial
|
||||
self.parity = "N"
|
||||
|
||||
|
||||
else:
|
||||
RNS.log("Could not load USB serial module for Android, Serial interface cannot be created.", RNS.LOG_CRITICAL)
|
||||
RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
|
||||
@ -75,7 +75,7 @@ class SerialInterface(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
|
||||
self.pyserial = serial
|
||||
self.serial = None
|
||||
self.owner = owner
|
||||
@ -145,7 +145,7 @@ class SerialInterface(Interface):
|
||||
self.serial.timeout = 0.1
|
||||
elif vid == 0x10C4:
|
||||
# Hardware parameters for SiLabs CP210x @ 115200 baud
|
||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||
self.serial.DEFAULT_READ_BUFFER_SIZE = 64
|
||||
self.serial.USB_READ_TIMEOUT_MILLIS = 12
|
||||
self.serial.timeout = 0.012
|
||||
elif vid == 0x1A86 and pid == 0x55D4:
|
||||
@ -182,7 +182,7 @@ class SerialInterface(Interface):
|
||||
if self.online:
|
||||
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
||||
written = self.serial.write(data)
|
||||
self.txb += len(data)
|
||||
self.txb += len(data)
|
||||
if written != len(data):
|
||||
raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}")
|
||||
|
||||
@ -217,7 +217,7 @@ class SerialInterface(Interface):
|
||||
byte = HDLC.ESC
|
||||
escape = False
|
||||
data_buffer = data_buffer+bytes([byte])
|
||||
|
||||
|
||||
if got == 0:
|
||||
time_since_last = int(time.time()*1000) - last_read_ms
|
||||
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
||||
@ -225,12 +225,12 @@ class SerialInterface(Interface):
|
||||
in_frame = False
|
||||
escape = False
|
||||
# sleep(0.08)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.online = False
|
||||
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if RNS.Reticulum.panic_on_interface_error:
|
||||
RNS.panic()
|
||||
|
||||
|
@ -289,7 +289,7 @@ class AutoInterface(Interface):
|
||||
|
||||
udp_server = socketserver.UDPServer(address, self.handler_factory(self.processIncoming))
|
||||
self.interface_servers[ifname] = udp_server
|
||||
|
||||
|
||||
thread = threading.Thread(target=udp_server.serve_forever)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
@ -306,11 +306,11 @@ class AutoInterface(Interface):
|
||||
def discovery_handler(self, socket, ifname):
|
||||
def announce_loop():
|
||||
self.announce_handler(ifname)
|
||||
|
||||
|
||||
thread = threading.Thread(target=announce_loop)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
|
||||
while True:
|
||||
data, ipv6_src = socket.recvfrom(1024)
|
||||
expected_hash = RNS.Identity.full_hash(self.group_id+ipv6_src[0].encode("utf-8"))
|
||||
@ -396,13 +396,13 @@ class AutoInterface(Interface):
|
||||
self.carrier_changed = True
|
||||
RNS.log(f"{self} Carrier recovered on {ifname}", RNS.LOG_WARNING)
|
||||
self.timed_out_interfaces[ifname] = False
|
||||
|
||||
|
||||
|
||||
def announce_handler(self, ifname):
|
||||
while True:
|
||||
self.peer_announce(ifname)
|
||||
time.sleep(self.announce_interval)
|
||||
|
||||
|
||||
def peer_announce(self, ifname):
|
||||
try:
|
||||
link_local_address = self.adopted_interfaces[ifname]
|
||||
@ -414,7 +414,7 @@ class AutoInterface(Interface):
|
||||
announce_socket.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
|
||||
announce_socket.sendto(discovery_token, addr_info[0][4])
|
||||
announce_socket.close()
|
||||
|
||||
|
||||
except Exception as e:
|
||||
if (ifname in self.timed_out_interfaces and self.timed_out_interfaces[ifname] == False) or not ifname in self.timed_out_interfaces:
|
||||
RNS.log(f"{self} Detected possible carrier loss on {ifname}: {e}", RNS.LOG_WARNING)
|
||||
@ -471,9 +471,9 @@ class AutoInterface(Interface):
|
||||
except Exception as e:
|
||||
RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
|
||||
self.txb += len(data)
|
||||
|
||||
|
||||
|
||||
# Until per-device sub-interfacing is implemented,
|
||||
# ingress limiting should be disabled on AutoInterface
|
||||
|
@ -143,11 +143,11 @@ class I2PController:
|
||||
|
||||
self.loop.ext_owner = self
|
||||
result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result()
|
||||
|
||||
|
||||
if not i2p_destination in self.i2plib_tunnels:
|
||||
raise OSError("No tunnel control instance was created")
|
||||
|
||||
else:
|
||||
else:
|
||||
tn = self.i2plib_tunnels[i2p_destination]
|
||||
if tn != None and hasattr(tn, "status"):
|
||||
|
||||
@ -183,7 +183,7 @@ class I2PController:
|
||||
|
||||
except ConnectionRefusedError as e:
|
||||
raise e
|
||||
|
||||
|
||||
except ConnectionAbortedError as e:
|
||||
raise e
|
||||
|
||||
@ -222,13 +222,13 @@ class I2PController:
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound):
|
||||
RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound):
|
||||
RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError):
|
||||
RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout):
|
||||
RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR)
|
||||
|
||||
@ -320,7 +320,7 @@ class I2PController:
|
||||
|
||||
elif i2p_exception != None:
|
||||
RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer):
|
||||
RNS.log(f"The I2P daemon can't reach peer {i2p_destination}", RNS.LOG_ERROR)
|
||||
|
||||
@ -338,13 +338,13 @@ class I2PController:
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound):
|
||||
RNS.log(f"The I2P daemon could not find the key for {i2p_destination}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.PeerNotFound):
|
||||
RNS.log(f"The I2P daemon mould not find the peer {i2p_destination}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError):
|
||||
RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout):
|
||||
RNS.log(f"I2P daemon timed out while setting up client tunnel to {i2p_destination}", RNS.LOG_ERROR)
|
||||
|
||||
@ -393,7 +393,7 @@ class I2PInterfacePeer(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.socket = None
|
||||
@ -492,7 +492,7 @@ class I2PInterfacePeer(Interface):
|
||||
while self.awaiting_i2p_tunnel:
|
||||
time.sleep(0.25)
|
||||
time.sleep(2)
|
||||
|
||||
|
||||
if not self.kiss_framing:
|
||||
self.wants_tunnel = True
|
||||
|
||||
@ -525,7 +525,7 @@ class I2PInterfacePeer(Interface):
|
||||
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(I2PInterfacePeer.I2P_PROBE_AFTER))
|
||||
|
||||
|
||||
def shutdown_socket(self, target_socket):
|
||||
if callable(target_socket.close):
|
||||
try:
|
||||
@ -538,15 +538,15 @@ class I2PInterfacePeer(Interface):
|
||||
if socket != None:
|
||||
target_socket.close()
|
||||
except Exception as e:
|
||||
RNS.log(f"Error while closing socket for {self}: {e}")
|
||||
|
||||
RNS.log(f"Error while closing socket for {self}: {e}")
|
||||
|
||||
def detach(self):
|
||||
RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
|
||||
if self.socket != None:
|
||||
if hasattr(self.socket, "close"):
|
||||
if callable(self.socket.close):
|
||||
self.detached = True
|
||||
|
||||
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except Exception as e:
|
||||
@ -564,7 +564,7 @@ class I2PInterfacePeer(Interface):
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.connect((self.target_ip, self.target_port))
|
||||
self.online = True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
if initial:
|
||||
if not self.awaiting_i2p_tunnel:
|
||||
@ -572,7 +572,7 @@ class I2PInterfacePeer(Interface):
|
||||
RNS.log(f"Leaving unconnected and retrying connection in {I2PInterfacePeer.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR)
|
||||
|
||||
return False
|
||||
|
||||
|
||||
else:
|
||||
raise e
|
||||
|
||||
@ -580,7 +580,7 @@ class I2PInterfacePeer(Interface):
|
||||
self.set_timeouts_linux()
|
||||
elif platform.system() == "Darwin":
|
||||
self.set_timeouts_osx()
|
||||
|
||||
|
||||
self.online = True
|
||||
self.writing = False
|
||||
self.never_connected = False
|
||||
@ -631,7 +631,7 @@ class I2PInterfacePeer(Interface):
|
||||
self.rxb += len(data)
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
|
||||
self.parent_interface.rxb += len(data)
|
||||
|
||||
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
def processOutgoing(self, data):
|
||||
@ -651,7 +651,7 @@ class I2PInterfacePeer(Interface):
|
||||
self.writing = False
|
||||
self.txb += len(data)
|
||||
self.last_write = time.time()
|
||||
|
||||
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
|
||||
self.parent_interface.txb += len(data)
|
||||
|
||||
@ -686,7 +686,7 @@ class I2PInterfacePeer(Interface):
|
||||
RNS.log(f"An error ocurred while sending I2P keepalive. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
self.shutdown_socket(self.socket)
|
||||
should_run = False
|
||||
|
||||
|
||||
if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT):
|
||||
RNS.log("I2P socket is unresponsive, restarting...", RNS.LOG_WARNING)
|
||||
if self.socket != None:
|
||||
@ -790,7 +790,7 @@ class I2PInterfacePeer(Interface):
|
||||
|
||||
break
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.online = False
|
||||
RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING)
|
||||
@ -832,7 +832,7 @@ class I2PInterface(Interface):
|
||||
|
||||
def __init__(self, owner, name, rns_storagepath, peers, connectable = False, ifac_size = 16, ifac_netname = None, ifac_netkey = None):
|
||||
super().__init__()
|
||||
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
self.online = False
|
||||
@ -882,7 +882,7 @@ class I2PInterface(Interface):
|
||||
def createHandler(*args, **keys):
|
||||
return I2PInterfaceHandler(callback, *args, **keys)
|
||||
return createHandler
|
||||
|
||||
|
||||
ThreadingI2PServer.allow_reuse_address = True
|
||||
self.server = ThreadingI2PServer(self.address, handlerFactory(self.incoming_connection))
|
||||
|
||||
|
@ -146,7 +146,7 @@ class Interface:
|
||||
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(f"An error occurred while processing held announces for {self}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
@ -170,7 +170,7 @@ class Interface:
|
||||
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:
|
||||
@ -187,7 +187,7 @@ class Interface:
|
||||
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:
|
||||
|
@ -71,9 +71,9 @@ class KISSInterface(Interface):
|
||||
RNS.panic()
|
||||
|
||||
super().__init__()
|
||||
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
|
||||
if beacon_data == None:
|
||||
beacon_data = ""
|
||||
|
||||
@ -218,7 +218,7 @@ class KISSInterface(Interface):
|
||||
|
||||
|
||||
def processIncoming(self, data):
|
||||
self.rxb += len(data)
|
||||
self.rxb += len(data)
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
|
||||
@ -325,7 +325,7 @@ class KISSInterface(Interface):
|
||||
self.online = False
|
||||
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if RNS.Reticulum.panic_on_interface_error:
|
||||
RNS.panic()
|
||||
|
||||
|
@ -58,11 +58,11 @@ class LocalClientInterface(Interface):
|
||||
|
||||
# TODO: Remove at some point
|
||||
# self.rxptime = 0
|
||||
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
self.online = False
|
||||
|
||||
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.socket = None
|
||||
@ -146,7 +146,7 @@ class LocalClientInterface(Interface):
|
||||
time.sleep(LocalClientInterface.RECONNECT_WAIT+2)
|
||||
RNS.Transport.shared_connection_reappeared()
|
||||
threading.Thread(target=job, daemon=True).start()
|
||||
|
||||
|
||||
else:
|
||||
RNS.log("Attempt to reconnect on a non-initiator shared local interface. This should not happen.", RNS.LOG_ERROR)
|
||||
raise OSError("Attempt to reconnect on a non-initiator local interface")
|
||||
@ -156,10 +156,10 @@ class LocalClientInterface(Interface):
|
||||
self.rxb += len(data)
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||
self.parent_interface.rxb += len(data)
|
||||
|
||||
|
||||
# TODO: Remove at some point
|
||||
# processing_start = time.time()
|
||||
|
||||
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
# TODO: Remove at some point
|
||||
@ -234,7 +234,7 @@ class LocalClientInterface(Interface):
|
||||
|
||||
break
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.online = False
|
||||
RNS.log(f"An interface error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
@ -247,7 +247,7 @@ class LocalClientInterface(Interface):
|
||||
if callable(self.socket.close):
|
||||
RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
|
||||
self.detached = True
|
||||
|
||||
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except Exception as e:
|
||||
@ -283,7 +283,7 @@ class LocalClientInterface(Interface):
|
||||
if self.is_connected_to_shared_instance:
|
||||
if nowarning == False:
|
||||
RNS.log("Permanently lost connection to local shared RNS instance. Exiting now.", RNS.LOG_CRITICAL)
|
||||
|
||||
|
||||
RNS.exit()
|
||||
|
||||
|
||||
@ -297,7 +297,7 @@ class LocalServerInterface(Interface):
|
||||
super().__init__()
|
||||
self.online = False
|
||||
self.clients = 0
|
||||
|
||||
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.name = "Reticulum"
|
||||
|
@ -49,7 +49,7 @@ class PipeInterface(Interface):
|
||||
|
||||
owner = None
|
||||
command = None
|
||||
|
||||
|
||||
def __init__(self, owner, name, command, respawn_delay):
|
||||
if respawn_delay == None:
|
||||
respawn_delay = 5
|
||||
@ -57,7 +57,7 @@ class PipeInterface(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
|
||||
self.owner = owner
|
||||
self.name = name
|
||||
self.command = command
|
||||
@ -83,7 +83,7 @@ class PipeInterface(Interface):
|
||||
|
||||
def open_pipe(self):
|
||||
RNS.log(f"Connecting subprocess pipe for {self}...", RNS.LOG_VERBOSE)
|
||||
|
||||
|
||||
try:
|
||||
self.process = subprocess.Popen(shlex.split(self.command), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
|
||||
self.pipe_is_open = True
|
||||
@ -102,7 +102,7 @@ class PipeInterface(Interface):
|
||||
|
||||
|
||||
def processIncoming(self, data):
|
||||
self.rxb += len(data)
|
||||
self.rxb += len(data)
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
|
||||
@ -111,7 +111,7 @@ class PipeInterface(Interface):
|
||||
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
||||
written = self.process.stdin.write(data)
|
||||
self.process.stdin.flush()
|
||||
self.txb += len(data)
|
||||
self.txb += len(data)
|
||||
if written != len(data):
|
||||
raise OSError(f"Pipe interface only wrote {written} bytes of {len(data)}")
|
||||
|
||||
@ -152,7 +152,7 @@ class PipeInterface(Interface):
|
||||
|
||||
RNS.log(f"Subprocess terminated on {self}")
|
||||
self.process.kill()
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.online = False
|
||||
try:
|
||||
@ -162,7 +162,7 @@ class PipeInterface(Interface):
|
||||
|
||||
RNS.log(f"A pipe error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if RNS.Reticulum.panic_on_interface_error:
|
||||
RNS.panic()
|
||||
|
||||
|
@ -33,7 +33,7 @@ class KISS():
|
||||
FESC = 0xDB
|
||||
TFEND = 0xDC
|
||||
TFESC = 0xDD
|
||||
|
||||
|
||||
CMD_UNKNOWN = 0xFE
|
||||
CMD_DATA = 0x00
|
||||
CMD_FREQUENCY = 0x01
|
||||
@ -69,11 +69,11 @@ class KISS():
|
||||
|
||||
DETECT_REQ = 0x73
|
||||
DETECT_RESP = 0x46
|
||||
|
||||
|
||||
RADIO_STATE_OFF = 0x00
|
||||
RADIO_STATE_ON = 0x01
|
||||
RADIO_STATE_ASK = 0xFF
|
||||
|
||||
|
||||
CMD_ERROR = 0x90
|
||||
ERROR_INITRADIO = 0x01
|
||||
ERROR_TXFAILED = 0x02
|
||||
@ -91,7 +91,7 @@ class KISS():
|
||||
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
|
||||
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
|
||||
return data
|
||||
|
||||
|
||||
|
||||
class RNodeInterface(Interface):
|
||||
MAX_CHUNK = 32768
|
||||
@ -132,7 +132,7 @@ class RNodeInterface(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 508
|
||||
|
||||
|
||||
self.pyserial = serial
|
||||
self.serial = None
|
||||
self.owner = owner
|
||||
@ -287,7 +287,7 @@ class RNodeInterface(Interface):
|
||||
write_timeout = None,
|
||||
dsrdtr = False,
|
||||
)
|
||||
|
||||
|
||||
else:
|
||||
RNS.log(f"Opening BLE connection for {self}...")
|
||||
if self.ble == None:
|
||||
@ -325,7 +325,7 @@ class RNodeInterface(Interface):
|
||||
detect_time = RNS.prettytime(time.time()-detect_time)
|
||||
else:
|
||||
RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if not self.detected:
|
||||
RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR)
|
||||
self.serial.close()
|
||||
@ -346,7 +346,7 @@ class RNodeInterface(Interface):
|
||||
RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
|
||||
RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
|
||||
self.serial.close()
|
||||
|
||||
|
||||
|
||||
def initRadio(self):
|
||||
self.setFrequency()
|
||||
@ -366,13 +366,13 @@ class RNodeInterface(Interface):
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError(f"An IO error occurred while detecting hardware for {self}")
|
||||
|
||||
|
||||
def leave(self):
|
||||
kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError("An IO error occurred while sending host left command to device")
|
||||
|
||||
|
||||
def enable_external_framebuffer(self):
|
||||
if self.display != None:
|
||||
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND])
|
||||
@ -406,7 +406,7 @@ class RNodeInterface(Interface):
|
||||
data = line_byte+line_data
|
||||
escaped_data = KISS.escape(data)
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
|
||||
|
||||
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError("An IO error occurred while writing framebuffer data device")
|
||||
@ -501,7 +501,7 @@ class RNodeInterface(Interface):
|
||||
if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
|
||||
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
|
||||
self.firmware_ok = True
|
||||
|
||||
|
||||
if self.firmware_ok:
|
||||
return
|
||||
|
||||
@ -784,7 +784,7 @@ class RNodeInterface(Interface):
|
||||
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
|
||||
@ -870,7 +870,7 @@ class RNodeInterface(Interface):
|
||||
self.detected = True
|
||||
else:
|
||||
self.detected = False
|
||||
|
||||
|
||||
else:
|
||||
time_since_last = int(time.time()*1000) - last_read_ms
|
||||
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
||||
@ -928,7 +928,7 @@ class RNodeInterface(Interface):
|
||||
self.disable_external_framebuffer()
|
||||
self.setRadioState(KISS.RADIO_STATE_OFF)
|
||||
self.leave()
|
||||
|
||||
|
||||
if self.use_ble:
|
||||
self.ble.close()
|
||||
|
||||
@ -1021,7 +1021,7 @@ class BLEConnection():
|
||||
if importlib.util.find_spec("bleak") != None:
|
||||
import bleak
|
||||
BLEConnection.bleak = bleak
|
||||
|
||||
|
||||
import asyncio
|
||||
BLEConnection.asyncio = asyncio
|
||||
else:
|
||||
@ -1100,7 +1100,7 @@ class BLEConnection():
|
||||
else:
|
||||
if self.target_bt_addr != None and device.address == self.target_bt_addr:
|
||||
RNS.log(f"Can't connect to target device {self.target_bt_addr} over BLE, device is not bonded", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
elif self.target_name != None and device.name == self.target_name:
|
||||
RNS.log(f"Can't connect to target device {self.target_name} over BLE, device is not bonded", RNS.LOG_ERROR)
|
||||
|
||||
@ -1115,7 +1115,7 @@ class BLEConnection():
|
||||
if "props" in device.details and "Bonded" in device.details["props"]:
|
||||
if device.details["props"]["Bonded"] == True:
|
||||
return True
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Error while determining device bond status for {device}, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
|
@ -33,7 +33,7 @@ class KISS():
|
||||
FESC = 0xDB
|
||||
TFEND = 0xDC
|
||||
TFESC = 0xDD
|
||||
|
||||
|
||||
CMD_UNKNOWN = 0xFE
|
||||
CMD_FREQUENCY = 0x01
|
||||
CMD_BANDWIDTH = 0x02
|
||||
@ -94,11 +94,11 @@ class KISS():
|
||||
|
||||
DETECT_REQ = 0x73
|
||||
DETECT_RESP = 0x46
|
||||
|
||||
|
||||
RADIO_STATE_OFF = 0x00
|
||||
RADIO_STATE_ON = 0x01
|
||||
RADIO_STATE_ASK = 0xFF
|
||||
|
||||
|
||||
CMD_ERROR = 0x90
|
||||
ERROR_INITRADIO = 0x01
|
||||
ERROR_TXFAILED = 0x02
|
||||
@ -159,7 +159,7 @@ class KISS():
|
||||
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
|
||||
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
|
||||
return data
|
||||
|
||||
|
||||
|
||||
class RNodeMultiInterface(Interface):
|
||||
MAX_CHUNK = 32768
|
||||
@ -188,7 +188,7 @@ class RNodeMultiInterface(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 508
|
||||
|
||||
|
||||
self.clients = 0
|
||||
self.pyserial = serial
|
||||
self.serial = None
|
||||
@ -294,7 +294,7 @@ class RNodeMultiInterface(Interface):
|
||||
|
||||
self.detect()
|
||||
sleep(0.2)
|
||||
|
||||
|
||||
if not self.detected:
|
||||
RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR)
|
||||
self.serial.close()
|
||||
@ -327,7 +327,7 @@ class RNodeMultiInterface(Interface):
|
||||
|
||||
interface.OUT = subint[10]
|
||||
interface.IN = True
|
||||
|
||||
|
||||
interface.announce_rate_target = self.announce_rate_target
|
||||
interface.mode = self.mode
|
||||
interface.HW_MTU = self.HW_MTU
|
||||
@ -345,13 +345,13 @@ class RNodeMultiInterface(Interface):
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError(f"An IO error occurred while detecting hardware for {self}")
|
||||
|
||||
|
||||
def leave(self):
|
||||
kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND])
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError("An IO error occurred while sending host left command to device")
|
||||
|
||||
|
||||
def enable_external_framebuffer(self):
|
||||
if self.display != None:
|
||||
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND])
|
||||
@ -385,7 +385,7 @@ class RNodeMultiInterface(Interface):
|
||||
data = line_byte+line_data
|
||||
escaped_data = KISS.escape(data)
|
||||
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
|
||||
|
||||
|
||||
written = self.serial.write(kiss_command)
|
||||
if written != len(kiss_command):
|
||||
raise OSError("An IO error occurred while writing framebuffer data device")
|
||||
@ -485,7 +485,7 @@ class RNodeMultiInterface(Interface):
|
||||
if (self.maj_version >= RNodeMultiInterface.REQUIRED_FW_VER_MAJ):
|
||||
if (self.min_version >= RNodeMultiInterface.REQUIRED_FW_VER_MIN):
|
||||
self.firmware_ok = True
|
||||
|
||||
|
||||
if self.firmware_ok:
|
||||
return
|
||||
|
||||
@ -737,7 +737,7 @@ class RNodeMultiInterface(Interface):
|
||||
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
|
||||
@ -804,7 +804,7 @@ class RNodeMultiInterface(Interface):
|
||||
# add the interface to the back of the list, they're all given from vport 0 and up in order
|
||||
self.subinterface_types.append(KISS.interface_type_to_str(command_buffer[1]))
|
||||
command_buffer = b""
|
||||
|
||||
|
||||
else:
|
||||
time_since_last = int(time.time()*1000) - last_read_ms
|
||||
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
||||
@ -918,7 +918,7 @@ class RNodeSubInterface(Interface):
|
||||
RNS.panic()
|
||||
|
||||
super().__init__()
|
||||
|
||||
|
||||
if index == 0:
|
||||
sel_cmd = KISS.CMD_SEL_INT0
|
||||
data_cmd= KISS.CMD_INT0_DATA
|
||||
@ -1079,7 +1079,7 @@ class RNodeSubInterface(Interface):
|
||||
RNS.log(f"After configuring {self}, the reported radio parameters did not match your configuration.", RNS.LOG_ERROR)
|
||||
RNS.log("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
|
||||
RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
|
||||
def initRadio(self):
|
||||
self.parent_interface.setFrequency(self.frequency, self)
|
||||
|
@ -63,7 +63,7 @@ class SerialInterface(Interface):
|
||||
super().__init__()
|
||||
|
||||
self.HW_MTU = 564
|
||||
|
||||
|
||||
self.pyserial = serial
|
||||
self.serial = None
|
||||
self.owner = owner
|
||||
@ -122,7 +122,7 @@ class SerialInterface(Interface):
|
||||
|
||||
|
||||
def processIncoming(self, data):
|
||||
self.rxb += len(data)
|
||||
self.rxb += len(data)
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
|
||||
@ -130,7 +130,7 @@ class SerialInterface(Interface):
|
||||
if self.online:
|
||||
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
||||
written = self.serial.write(data)
|
||||
self.txb += len(data)
|
||||
self.txb += len(data)
|
||||
if written != len(data):
|
||||
raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}")
|
||||
|
||||
@ -164,7 +164,7 @@ class SerialInterface(Interface):
|
||||
byte = HDLC.ESC
|
||||
escape = False
|
||||
data_buffer = data_buffer+bytes([byte])
|
||||
|
||||
|
||||
else:
|
||||
time_since_last = int(time.time()*1000) - last_read_ms
|
||||
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
||||
@ -172,12 +172,12 @@ class SerialInterface(Interface):
|
||||
in_frame = False
|
||||
escape = False
|
||||
sleep(0.08)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.online = False
|
||||
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
if RNS.Reticulum.panic_on_interface_error:
|
||||
RNS.panic()
|
||||
|
||||
|
@ -80,9 +80,9 @@ class TCPClientInterface(Interface):
|
||||
|
||||
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):
|
||||
super().__init__()
|
||||
|
||||
|
||||
self.HW_MTU = 1064
|
||||
|
||||
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.socket = None
|
||||
@ -99,7 +99,7 @@ class TCPClientInterface(Interface):
|
||||
self.i2p_tunneled = i2p_tunneled
|
||||
self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL
|
||||
self.bitrate = TCPClientInterface.BITRATE_GUESS
|
||||
|
||||
|
||||
if max_reconnect_tries == None:
|
||||
self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES
|
||||
else:
|
||||
@ -128,14 +128,14 @@ class TCPClientInterface(Interface):
|
||||
self.connect_timeout = connect_timeout
|
||||
else:
|
||||
self.connect_timeout = TCPClientInterface.INITIAL_CONNECT_TIMEOUT
|
||||
|
||||
|
||||
if TCPClientInterface.SYNCHRONOUS_START:
|
||||
self.initial_connect()
|
||||
else:
|
||||
thread = threading.Thread(target=self.initial_connect)
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
|
||||
def initial_connect(self):
|
||||
if not self.connect(initial=True):
|
||||
thread = threading.Thread(target=self.reconnect)
|
||||
@ -170,19 +170,19 @@ class TCPClientInterface(Interface):
|
||||
TCP_KEEPIDLE = 0x10
|
||||
|
||||
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
|
||||
|
||||
if not self.i2p_tunneled:
|
||||
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER))
|
||||
else:
|
||||
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.I2P_PROBE_AFTER))
|
||||
|
||||
|
||||
def detach(self):
|
||||
if self.socket != None:
|
||||
if hasattr(self.socket, "close"):
|
||||
if callable(self.socket.close):
|
||||
RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
|
||||
self.detached = True
|
||||
|
||||
|
||||
try:
|
||||
self.socket.shutdown(socket.SHUT_RDWR)
|
||||
except Exception as e:
|
||||
@ -209,13 +209,13 @@ class TCPClientInterface(Interface):
|
||||
|
||||
if initial:
|
||||
RNS.log(f"TCP connection for {self} established", RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
if initial:
|
||||
RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR)
|
||||
RNS.log(f"Leaving unconnected and retrying connection in {TCPClientInterface.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR)
|
||||
return False
|
||||
|
||||
|
||||
else:
|
||||
raise e
|
||||
|
||||
@ -223,7 +223,7 @@ class TCPClientInterface(Interface):
|
||||
self.set_timeouts_linux()
|
||||
elif platform.system() == "Darwin":
|
||||
self.set_timeouts_osx()
|
||||
|
||||
|
||||
self.online = True
|
||||
self.writing = False
|
||||
self.never_connected = False
|
||||
@ -269,7 +269,7 @@ class TCPClientInterface(Interface):
|
||||
self.rxb += len(data)
|
||||
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
||||
self.parent_interface.rxb += len(data)
|
||||
|
||||
|
||||
self.owner.inbound(data, self)
|
||||
|
||||
def processOutgoing(self, data):
|
||||
@ -369,7 +369,7 @@ class TCPClientInterface(Interface):
|
||||
|
||||
break
|
||||
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.online = False
|
||||
RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING)
|
||||
@ -427,7 +427,7 @@ class TCPServerInterface(Interface):
|
||||
|
||||
self.online = False
|
||||
self.clients = 0
|
||||
|
||||
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.name = name
|
||||
@ -474,7 +474,7 @@ class TCPServerInterface(Interface):
|
||||
spawned_interface.target_port = str(handler.client_address[1])
|
||||
spawned_interface.parent_interface = self
|
||||
spawned_interface.bitrate = self.bitrate
|
||||
|
||||
|
||||
spawned_interface.ifac_size = self.ifac_size
|
||||
spawned_interface.ifac_netname = self.ifac_netname
|
||||
spawned_interface.ifac_netkey = self.ifac_netkey
|
||||
|
@ -99,7 +99,7 @@ class UDPInterface(Interface):
|
||||
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
|
||||
udp_socket.sendto(data, (self.forward_ip, self.forward_port))
|
||||
self.txb += len(data)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
|
32
RNS/Link.py
32
RNS/Link.py
@ -124,7 +124,7 @@ class Link:
|
||||
RNS.Transport.register_link(link)
|
||||
link.last_inbound = time.time()
|
||||
link.start_watchdog()
|
||||
|
||||
|
||||
RNS.log(f"Incoming link request {link} accepted on {link.attached_interface}", RNS.LOG_DEBUG)
|
||||
return link
|
||||
|
||||
@ -189,7 +189,7 @@ class Link:
|
||||
self.sig_prv = Ed25519PrivateKey.generate()
|
||||
|
||||
self.fernet = None
|
||||
|
||||
|
||||
self.pub = self.prv.public_key()
|
||||
self.pub_bytes = self.pub.public_bytes()
|
||||
|
||||
@ -288,7 +288,7 @@ class Link:
|
||||
self.establishment_cost += len(packet.raw)
|
||||
signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes
|
||||
signature = packet.data[:RNS.Identity.SIGLENGTH//8]
|
||||
|
||||
|
||||
if self.destination.identity.validate(signature, signed_data):
|
||||
if self.status != Link.HANDSHAKE:
|
||||
raise OSError(f"Invalid link state for proof validation: {self.status}")
|
||||
@ -301,7 +301,7 @@ class Link:
|
||||
self.last_proof = self.activated_at
|
||||
RNS.Transport.activate_link(self)
|
||||
RNS.log(f"Link {self} established with {self.destination}, RTT is {round(self.rtt, 3)}s", RNS.LOG_VERBOSE)
|
||||
|
||||
|
||||
if self.rtt != None and self.establishment_cost != None and self.rtt > 0 and self.establishment_cost > 0:
|
||||
self.establishment_rate = self.establishment_cost/self.rtt
|
||||
|
||||
@ -316,7 +316,7 @@ class Link:
|
||||
thread.start()
|
||||
else:
|
||||
RNS.log(f"Invalid link proof signature received by {self}. Ignoring.", RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
self.status = Link.CLOSED
|
||||
RNS.log(f"An error ocurred while validating link request proof on {self}.", RNS.LOG_ERROR)
|
||||
@ -377,7 +377,7 @@ class Link:
|
||||
timeout = timeout,
|
||||
request_size = len(packed_request),
|
||||
)
|
||||
|
||||
|
||||
else:
|
||||
request_id = RNS.Identity.truncated_hash(packed_request)
|
||||
RNS.log(f"Sending request {RNS.prettyhexrep(request_id)} as resource.", RNS.LOG_DEBUG)
|
||||
@ -547,7 +547,7 @@ class Link:
|
||||
resource.cancel()
|
||||
if self._channel:
|
||||
self._channel._shutdown()
|
||||
|
||||
|
||||
self.prv = None
|
||||
self.pub = None
|
||||
self.pub_bytes = None
|
||||
@ -620,7 +620,7 @@ class Link:
|
||||
self.status = Link.STALE
|
||||
else:
|
||||
sleep_time = self.keepalive
|
||||
|
||||
|
||||
else:
|
||||
sleep_time = (last_inbound + self.keepalive) - time.time()
|
||||
|
||||
@ -655,7 +655,7 @@ class Link:
|
||||
self.snr = packet.snr
|
||||
if packet.q != None:
|
||||
self.q = packet.q
|
||||
|
||||
|
||||
def send_keepalive(self):
|
||||
keepalive_packet = RNS.Packet(self, bytes([0xFF]), context=RNS.Packet.KEEPALIVE)
|
||||
keepalive_packet.send()
|
||||
@ -782,7 +782,7 @@ class Link:
|
||||
thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet))
|
||||
thread.daemon = True
|
||||
thread.start()
|
||||
|
||||
|
||||
if self.destination.proof_strategy == RNS.Destination.PROVE_ALL:
|
||||
packet.prove()
|
||||
should_query = True
|
||||
@ -815,7 +815,7 @@ class Link:
|
||||
self.callbacks.remote_identified(self, self.__remote_identity)
|
||||
except Exception as e:
|
||||
RNS.log(f"Error while executing remote identified callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
self.__update_phy_stats(packet, query_shared=True)
|
||||
|
||||
elif packet.context == RNS.Packet.REQUEST:
|
||||
@ -903,7 +903,7 @@ class Link:
|
||||
if not packet.packet_hash in resource.req_hashlist:
|
||||
resource.req_hashlist.append(packet.packet_hash)
|
||||
resource.request(plaintext)
|
||||
|
||||
|
||||
# TODO: Test and possibly enable this at some point
|
||||
# def request_job():
|
||||
# resource.request(plaintext)
|
||||
@ -984,7 +984,7 @@ class Link:
|
||||
try:
|
||||
if not self.fernet:
|
||||
self.fernet = Fernet(self.derived_key)
|
||||
|
||||
|
||||
return self.fernet.decrypt(ciphertext)
|
||||
|
||||
except Exception as e:
|
||||
@ -1140,7 +1140,7 @@ class RequestReceipt():
|
||||
elif self.resource != None:
|
||||
self.hash = resource.request_id
|
||||
resource.set_callback(self.request_resource_concluded)
|
||||
|
||||
|
||||
self.link = link
|
||||
self.request_id = self.hash
|
||||
self.request_size = request_size
|
||||
@ -1224,7 +1224,7 @@ class RequestReceipt():
|
||||
self.packet_receipt.callbacks.delivery(self.packet_receipt)
|
||||
|
||||
self.progress = resource.get_progress()
|
||||
|
||||
|
||||
if self.callbacks.progress != None:
|
||||
try:
|
||||
self.callbacks.progress(self)
|
||||
@ -1233,7 +1233,7 @@ class RequestReceipt():
|
||||
else:
|
||||
resource.cancel()
|
||||
|
||||
|
||||
|
||||
def response_received(self, response):
|
||||
if not self.status == RequestReceipt.FAILED:
|
||||
self.progress = 1.0
|
||||
|
@ -97,7 +97,7 @@ class Packet:
|
||||
# the below calculation; 383 bytes.
|
||||
ENCRYPTED_MDU = math.floor((RNS.Reticulum.MDU-RNS.Identity.FERNET_OVERHEAD-RNS.Identity.KEYSIZE//16)/RNS.Identity.AES128_BLOCKSIZE)*RNS.Identity.AES128_BLOCKSIZE - 1
|
||||
"""
|
||||
The maximum size of the payload data in a single encrypted packet
|
||||
The maximum size of the payload data in a single encrypted packet
|
||||
"""
|
||||
PLAIN_MDU = MDU
|
||||
"""
|
||||
@ -256,7 +256,7 @@ class Packet:
|
||||
def send(self):
|
||||
"""
|
||||
Sends the packet.
|
||||
|
||||
|
||||
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
||||
"""
|
||||
if not self.sent:
|
||||
@ -278,21 +278,21 @@ class Packet:
|
||||
self.sent = False
|
||||
self.receipt = None
|
||||
return False
|
||||
|
||||
|
||||
else:
|
||||
raise OSError("Packet was already sent")
|
||||
|
||||
def resend(self):
|
||||
"""
|
||||
Re-sends the packet.
|
||||
|
||||
|
||||
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
||||
"""
|
||||
if self.sent:
|
||||
# Re-pack the packet to obtain new ciphertext for
|
||||
# encrypted destinations
|
||||
self.pack()
|
||||
|
||||
|
||||
if RNS.Transport.outbound(self):
|
||||
return self.receipt
|
||||
else:
|
||||
@ -388,7 +388,7 @@ class PacketReceipt:
|
||||
|
||||
def get_status(self):
|
||||
"""
|
||||
:returns: The status of the associated :ref:`RNS.Packet<api-packet>` instance. Can be one of ``RNS.PacketReceipt.SENT``, ``RNS.PacketReceipt.DELIVERED``, ``RNS.PacketReceipt.FAILED`` or ``RNS.PacketReceipt.CULLED``.
|
||||
:returns: The status of the associated :ref:`RNS.Packet<api-packet>` instance. Can be one of ``RNS.PacketReceipt.SENT``, ``RNS.PacketReceipt.DELIVERED``, ``RNS.PacketReceipt.FAILED`` or ``RNS.PacketReceipt.CULLED``.
|
||||
"""
|
||||
return self.status
|
||||
|
||||
@ -422,7 +422,7 @@ class PacketReceipt:
|
||||
RNS.log(f"An error occurred while evaluating external delivery callback for {link}", RNS.LOG_ERROR)
|
||||
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
RNS.trace_exception(e)
|
||||
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -490,7 +490,7 @@ class PacketReceipt:
|
||||
self.callbacks.delivery(self)
|
||||
except Exception as e:
|
||||
RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
@ -524,7 +524,7 @@ class PacketReceipt:
|
||||
def set_timeout(self, timeout):
|
||||
"""
|
||||
Sets a timeout in seconds
|
||||
|
||||
|
||||
:param timeout: The timeout in seconds.
|
||||
"""
|
||||
self.timeout = float(timeout)
|
||||
|
@ -21,7 +21,7 @@
|
||||
# SOFTWARE.
|
||||
|
||||
class Resolver:
|
||||
|
||||
|
||||
@staticmethod
|
||||
def resolve_identity(full_name):
|
||||
pass
|
@ -59,11 +59,11 @@ class Resource:
|
||||
|
||||
# The maximum window size for transfers on fast links
|
||||
WINDOW_MAX_FAST = 75
|
||||
|
||||
|
||||
# For calculating maps and guard segments, this
|
||||
# must be set to the global maximum window.
|
||||
WINDOW_MAX = WINDOW_MAX_FAST
|
||||
|
||||
|
||||
# If the fast rate is sustained for this many request
|
||||
# rounds, the fast link window size will be allowed.
|
||||
FAST_RATE_THRESHOLD = WINDOW_MAX_SLOW - WINDOW - 2
|
||||
@ -111,7 +111,7 @@ class Resource:
|
||||
# fit in 3 bytes in resource advertisements.
|
||||
MAX_EFFICIENT_SIZE = 16 * 1024 * 1024 - 1
|
||||
RESPONSE_MAX_GRACE_TIME = 10
|
||||
|
||||
|
||||
# The maximum size to auto-compress with
|
||||
# bz2 before sending.
|
||||
AUTO_COMPRESS_MAX_SIZE = MAX_EFFICIENT_SIZE
|
||||
@ -185,7 +185,7 @@ class Resource:
|
||||
resource.waiting_for_hmu = False
|
||||
resource.receiving_part = False
|
||||
resource.consecutive_completed_height = -1
|
||||
|
||||
|
||||
if not resource.link.has_incoming_resource(resource):
|
||||
resource.link.register_incoming_resource(resource)
|
||||
|
||||
@ -256,7 +256,7 @@ class Resource:
|
||||
data_size = len(data)
|
||||
self.grand_total_parts = math.ceil(data_size/Resource.SDU)
|
||||
self.total_size = data_size
|
||||
|
||||
|
||||
resource_data = data
|
||||
self.total_segments = 1
|
||||
self.segment_index = 1
|
||||
@ -323,7 +323,7 @@ class Resource:
|
||||
self.data = b""
|
||||
self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE]
|
||||
self.data += self.compressed_data
|
||||
|
||||
|
||||
self.compressed = True
|
||||
self.uncompressed_data = None
|
||||
|
||||
@ -348,7 +348,7 @@ class Resource:
|
||||
self.size = len(self.data)
|
||||
self.sent_parts = 0
|
||||
hashmap_entries = int(math.ceil(self.size/float(Resource.SDU)))
|
||||
|
||||
|
||||
hashmap_ok = False
|
||||
while not hashmap_ok:
|
||||
hashmap_computation_began = time.time()
|
||||
@ -389,12 +389,12 @@ class Resource:
|
||||
self.parts.append(part)
|
||||
|
||||
RNS.log(f"Hashmap computation concluded in {round(time.time() - hashmap_computation_began, 3)} seconds", RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
if advertise:
|
||||
self.advertise()
|
||||
else:
|
||||
self.receive_lock = Lock()
|
||||
|
||||
|
||||
|
||||
def hashmap_update_packet(self, plaintext):
|
||||
if not self.status == Resource.FAILED:
|
||||
@ -489,7 +489,7 @@ class Resource:
|
||||
except Exception as e:
|
||||
RNS.log(f"Could not resend advertisement packet, cancelling resource. The contained exception was: {e}", RNS.LOG_VERBOSE)
|
||||
self.cancel()
|
||||
|
||||
|
||||
|
||||
elif self.status == Resource.TRANSFERRING:
|
||||
if not self.initiator:
|
||||
@ -504,7 +504,7 @@ class Resource:
|
||||
retries_used = self.max_retries - self.retries_left
|
||||
extra_wait = retries_used * Resource.PER_RETRY_DELAY
|
||||
sleep_time = self.last_activity + (rtt*(self.part_timeout_factor+window_remaining)) + Resource.RETRY_GRACE_TIME + extra_wait - time.time()
|
||||
|
||||
|
||||
if sleep_time < 0:
|
||||
if self.retries_left > 0:
|
||||
ms = "" if self.outstanding_parts == 1 else "s"
|
||||
@ -554,7 +554,7 @@ class Resource:
|
||||
if sleep_time == None or sleep_time < 0:
|
||||
RNS.log("Timing error, cancelling resource transfer.", RNS.LOG_ERROR)
|
||||
self.cancel()
|
||||
|
||||
|
||||
if sleep_time != None:
|
||||
sleep(min(sleep_time, Resource.WATCHDOG_MAX_SLEEP))
|
||||
|
||||
@ -692,7 +692,7 @@ class Resource:
|
||||
if self.req_resp == None:
|
||||
self.req_resp = self.last_activity
|
||||
rtt = self.req_resp-self.req_sent
|
||||
|
||||
|
||||
self.part_timeout_factor = Resource.PART_TIMEOUT_FACTOR_AFTER_RTT
|
||||
if self.rtt == None:
|
||||
self.rtt = self.link.rtt
|
||||
@ -732,7 +732,7 @@ class Resource:
|
||||
# Update consecutive completed pointer
|
||||
if i == self.consecutive_completed_height + 1:
|
||||
self.consecutive_completed_height = i
|
||||
|
||||
|
||||
cp = self.consecutive_completed_height + 1
|
||||
while cp < len(self.parts) and self.parts[cp] != None:
|
||||
self.consecutive_completed_height = cp
|
||||
@ -797,7 +797,7 @@ class Resource:
|
||||
i = 0; pn = self.consecutive_completed_height+1
|
||||
search_start = pn
|
||||
search_size = self.window
|
||||
|
||||
|
||||
for part in self.parts[search_start:search_start+search_size]:
|
||||
if part == None:
|
||||
part_hash = self.hashmap[pn]
|
||||
@ -878,10 +878,10 @@ class Resource:
|
||||
RNS.log("Resource could not send parts, cancelling transfer!", RNS.LOG_DEBUG)
|
||||
RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG)
|
||||
self.cancel()
|
||||
|
||||
|
||||
if wants_more_hashmap:
|
||||
last_map_hash = request_data[1:Resource.MAPHASH_LEN+1]
|
||||
|
||||
|
||||
part_index = self.receiver_min_consecutive_height
|
||||
search_start = part_index
|
||||
search_end = self.receiver_min_consecutive_height+ResourceAdvertisement.COLLISION_GUARD_SIZE
|
||||
@ -899,7 +899,7 @@ class Resource:
|
||||
else:
|
||||
segment = part_index // ResourceAdvertisement.HASHMAP_MAX_LEN
|
||||
|
||||
|
||||
|
||||
hashmap_start = segment*ResourceAdvertisement.HASHMAP_MAX_LEN
|
||||
hashmap_end = min((segment+1)*ResourceAdvertisement.HASHMAP_MAX_LEN, len(self.parts))
|
||||
|
||||
@ -943,7 +943,7 @@ class Resource:
|
||||
self.link.cancel_outgoing_resource(self)
|
||||
else:
|
||||
self.link.cancel_incoming_resource(self)
|
||||
|
||||
|
||||
if self.callback != None:
|
||||
try:
|
||||
self.link.resource_concluded(self)
|
||||
@ -968,7 +968,7 @@ class Resource:
|
||||
self.processed_parts += self.sent_parts
|
||||
self.progress_total_parts = float(self.grand_total_parts)
|
||||
else:
|
||||
self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
|
||||
self.processed_parts = (self.segment_index-1)*math.ceil(Resource.MAX_EFFICIENT_SIZE/Resource.SDU)
|
||||
self.processed_parts += self.received_count
|
||||
if self.split:
|
||||
self.progress_total_parts = float(math.ceil(self.total_size/Resource.SDU))
|
||||
@ -1141,7 +1141,7 @@ class ResourceAdvertisement:
|
||||
@staticmethod
|
||||
def unpack(data):
|
||||
dictionary = umsgpack.unpackb(data)
|
||||
|
||||
|
||||
adv = ResourceAdvertisement()
|
||||
adv.t = dictionary["t"]
|
||||
adv.d = dictionary["d"]
|
||||
|
@ -128,7 +128,7 @@ class Reticulum:
|
||||
HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2
|
||||
IFAC_MIN_SIZE = 1
|
||||
IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
|
||||
|
||||
|
||||
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
|
||||
|
||||
RESOURCE_CACHE = 24*60*60
|
||||
@ -139,7 +139,7 @@ class Reticulum:
|
||||
|
||||
router = None
|
||||
config = None
|
||||
|
||||
|
||||
# The default configuration path will be expanded to a directory
|
||||
# named ".reticulum" inside the current users home directory
|
||||
userdir = os.path.expanduser("~")
|
||||
@ -149,7 +149,7 @@ class Reticulum:
|
||||
cachepath = ""
|
||||
|
||||
__instance = None
|
||||
|
||||
|
||||
@staticmethod
|
||||
def exit_handler():
|
||||
# This exit handler is called whenever Reticulum is asked to
|
||||
@ -211,7 +211,7 @@ class Reticulum:
|
||||
if logdest == RNS.LOG_FILE:
|
||||
RNS.logdest = RNS.LOG_FILE
|
||||
RNS.logfile = f"{Reticulum.configdir}/logfile"
|
||||
|
||||
|
||||
Reticulum.configpath = f"{Reticulum.configdir}/config"
|
||||
Reticulum.storagepath = f"{Reticulum.configdir}/storage"
|
||||
Reticulum.cachepath = f"{Reticulum.configdir}/storage/cache"
|
||||
@ -277,7 +277,7 @@ class Reticulum:
|
||||
|
||||
self.__apply_config()
|
||||
RNS.log(f"Configuration loaded from {self.configpath}", RNS.LOG_VERBOSE)
|
||||
|
||||
|
||||
RNS.Identity.load_known_destinations()
|
||||
|
||||
RNS.Transport.start(self)
|
||||
@ -285,7 +285,7 @@ class Reticulum:
|
||||
self.rpc_addr = ("127.0.0.1", self.local_control_port)
|
||||
if self.rpc_key == None:
|
||||
self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key())
|
||||
|
||||
|
||||
if self.is_shared_instance:
|
||||
self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key)
|
||||
thread = threading.Thread(target=self.rpc_loop)
|
||||
@ -313,7 +313,7 @@ class Reticulum:
|
||||
|
||||
if now > self.last_data_persist+Reticulum.PERSIST_INTERVAL:
|
||||
self.__persist_data()
|
||||
|
||||
|
||||
time.sleep(Reticulum.JOB_INTERVAL)
|
||||
|
||||
def __start_local_interface(self):
|
||||
@ -329,7 +329,7 @@ class Reticulum:
|
||||
interface._force_bitrate = Reticulum._force_shared_instance_bitrate
|
||||
RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING)
|
||||
RNS.Transport.interfaces.append(interface)
|
||||
|
||||
|
||||
self.is_shared_instance = True
|
||||
RNS.log(f"Started shared instance interface: {interface}", RNS.LOG_DEBUG)
|
||||
self.__start_jobs()
|
||||
@ -454,7 +454,7 @@ class Reticulum:
|
||||
c = self.config["interfaces"][name]
|
||||
|
||||
interface_mode = Interface.Interface.MODE_FULL
|
||||
|
||||
|
||||
if "interface_mode" in c:
|
||||
c["interface_mode"] = str(c["interface_mode"]).lower()
|
||||
if c["interface_mode"] == "full":
|
||||
@ -489,7 +489,7 @@ class Reticulum:
|
||||
if "ifac_size" in c:
|
||||
if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8:
|
||||
ifac_size = c.as_int("ifac_size")//8
|
||||
|
||||
|
||||
ifac_netname = None
|
||||
if "networkname" in c:
|
||||
if c["networkname"] != "":
|
||||
@ -505,7 +505,7 @@ class Reticulum:
|
||||
if "pass_phrase" in c:
|
||||
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
|
||||
@ -532,12 +532,12 @@ class Reticulum:
|
||||
if "announce_rate_target" in c:
|
||||
if c.as_int("announce_rate_target") > 0:
|
||||
announce_rate_target = c.as_int("announce_rate_target")
|
||||
|
||||
|
||||
announce_rate_grace = None
|
||||
if "announce_rate_grace" in c:
|
||||
if c.as_int("announce_rate_grace") >= 0:
|
||||
announce_rate_grace = c.as_int("announce_rate_grace")
|
||||
|
||||
|
||||
announce_rate_penalty = None
|
||||
if "announce_rate_penalty" in c:
|
||||
if c.as_int("announce_rate_penalty") >= 0:
|
||||
@ -553,7 +553,7 @@ class Reticulum:
|
||||
if "announce_cap" in c:
|
||||
if c.as_float("announce_cap") > 0 and c.as_float("announce_cap") <= 100:
|
||||
announce_cap = c.as_float("announce_cap")/100.0
|
||||
|
||||
|
||||
try:
|
||||
interface = None
|
||||
|
||||
@ -660,7 +660,7 @@ class Reticulum:
|
||||
if interface_mode == Interface.Interface.MODE_ACCESS_POINT:
|
||||
RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING)
|
||||
interface_mode = Interface.Interface.MODE_FULL
|
||||
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
@ -697,7 +697,7 @@ class Reticulum:
|
||||
if interface_mode == Interface.Interface.MODE_ACCESS_POINT:
|
||||
RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING)
|
||||
interface_mode = Interface.Interface.MODE_FULL
|
||||
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
@ -734,7 +734,7 @@ class Reticulum:
|
||||
if interface_mode == Interface.Interface.MODE_ACCESS_POINT:
|
||||
RNS.log(f"{interface} does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING)
|
||||
interface_mode = Interface.Interface.MODE_FULL
|
||||
|
||||
|
||||
interface.mode = interface_mode
|
||||
|
||||
interface.announce_cap = announce_cap
|
||||
@ -937,7 +937,7 @@ class Reticulum:
|
||||
ble_addr = ble_string
|
||||
else:
|
||||
ble_name = ble_string
|
||||
|
||||
|
||||
interface = RNodeInterface.RNodeInterface(
|
||||
RNS.Transport,
|
||||
name,
|
||||
@ -1011,11 +1011,11 @@ class Reticulum:
|
||||
txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None
|
||||
subint_config[subint_index][4] = txpower
|
||||
spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None
|
||||
subint_config[subint_index][5] = spreadingfactor
|
||||
subint_config[subint_index][5] = spreadingfactor
|
||||
codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None
|
||||
subint_config[subint_index][6] = codingrate
|
||||
flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False
|
||||
subint_config[subint_index][7] = flow_control
|
||||
subint_config[subint_index][7] = flow_control
|
||||
st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None
|
||||
subint_config[subint_index][8] = st_alock
|
||||
lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None
|
||||
@ -1037,7 +1037,7 @@ class Reticulum:
|
||||
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
|
||||
port = c["port"] if "port" in c else None
|
||||
|
||||
|
||||
if port == None:
|
||||
raise ValueError(f"No port specified for {name}")
|
||||
|
||||
@ -1121,7 +1121,7 @@ class Reticulum:
|
||||
def _add_interface(self,interface, mode = None, configured_bitrate=None, ifac_size=None, ifac_netname=None, ifac_netkey=None, announce_cap=None, announce_rate_target=None, announce_rate_grace=None, announce_rate_penalty=None):
|
||||
if not self.is_connected_to_shared_instance:
|
||||
if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface):
|
||||
|
||||
|
||||
if mode == None:
|
||||
mode = Interface.Interface.MODE_FULL
|
||||
interface.mode = mode
|
||||
@ -1199,14 +1199,14 @@ class Reticulum:
|
||||
age = now - mtime
|
||||
if age > RNS.Transport.DESTINATION_TIMEOUT:
|
||||
os.unlink(filepath)
|
||||
|
||||
|
||||
except Exception as e:
|
||||
RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR)
|
||||
|
||||
def __create_default_config(self):
|
||||
self.config = ConfigObj(__default_rns_config__)
|
||||
self.config.filename = Reticulum.configpath
|
||||
|
||||
|
||||
if not os.path.isdir(Reticulum.configdir):
|
||||
os.makedirs(Reticulum.configdir)
|
||||
self.config.write()
|
||||
@ -1278,7 +1278,7 @@ class Reticulum:
|
||||
interfaces = []
|
||||
for interface in RNS.Transport.interfaces:
|
||||
ifstats = {}
|
||||
|
||||
|
||||
if hasattr(interface, "clients"):
|
||||
ifstats["clients"] = interface.clients
|
||||
else:
|
||||
|
@ -51,7 +51,7 @@ class Transport:
|
||||
"""
|
||||
Maximum amount of hops that Reticulum will transport a packet.
|
||||
"""
|
||||
|
||||
|
||||
PATHFINDER_R = 1 # Retransmit retries
|
||||
PATHFINDER_G = 5 # Retry grace period
|
||||
PATHFINDER_RW = 0.5 # Random window for announce rebroadcast
|
||||
@ -101,7 +101,7 @@ class Transport:
|
||||
announce_rate_table = {} # A table for keeping track of announce rates
|
||||
path_requests = {} # A table for storing path request timestamps
|
||||
path_states = {} # A table for keeping track of path states
|
||||
|
||||
|
||||
discovery_path_requests = {} # A table for keeping track of path requests on behalf of other nodes
|
||||
discovery_pr_tags = [] # A table for keeping track of tagged path requests
|
||||
max_pr_tags = 32000 # Maximum amount of unique path request tags to remember
|
||||
@ -150,7 +150,7 @@ class Transport:
|
||||
if Transport.identity == None:
|
||||
transport_identity_path = f"{RNS.Reticulum.storagepath}/transport_identity"
|
||||
if os.path.isfile(transport_identity_path):
|
||||
Transport.identity = RNS.Identity.from_file(transport_identity_path)
|
||||
Transport.identity = RNS.Identity.from_file(transport_identity_path)
|
||||
|
||||
if Transport.identity == None:
|
||||
RNS.log("No valid Transport Identity in storage, creating...", RNS.LOG_VERBOSE)
|
||||
@ -187,7 +187,7 @@ class Transport:
|
||||
Transport.control_destinations.append(Transport.remote_management_destination)
|
||||
Transport.control_hashes.append(Transport.remote_management_destination.hash)
|
||||
RNS.log(f"Enabled remote management on {Transport.remote_management_destination}", RNS.LOG_NOTICE)
|
||||
|
||||
|
||||
Transport.jobs_running = False
|
||||
thread = threading.Thread(target=Transport.jobloop, daemon=True)
|
||||
thread.start()
|
||||
@ -405,7 +405,7 @@ class Transport:
|
||||
announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
|
||||
announce_destination.hash = packet.destination_hash
|
||||
announce_destination.hexhash = announce_destination.hash.hex()
|
||||
|
||||
|
||||
new_packet = RNS.Packet(
|
||||
announce_destination,
|
||||
announce_data,
|
||||
@ -423,7 +423,7 @@ class Transport:
|
||||
RNS.log(f"Rebroadcasting announce as path response for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG)
|
||||
else:
|
||||
RNS.log(f"Rebroadcasting announce for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
outgoing.append(new_packet)
|
||||
|
||||
# This handles an edge case where a peer sends a past
|
||||
@ -486,7 +486,7 @@ class Transport:
|
||||
|
||||
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]):
|
||||
@ -726,7 +726,7 @@ class Transport:
|
||||
|
||||
# Assemble new payload with IFAC
|
||||
new_raw = new_header+ifac+raw[2:]
|
||||
|
||||
|
||||
# Mask payload
|
||||
i = 0; masked_raw = b""
|
||||
for byte in new_raw:
|
||||
@ -781,7 +781,7 @@ class Transport:
|
||||
if generate_receipt:
|
||||
packet.receipt = RNS.PacketReceipt(packet)
|
||||
Transport.receipts.append(packet.receipt)
|
||||
|
||||
|
||||
# TODO: Enable when caching has been redesigned
|
||||
# Transport.cache(packet)
|
||||
|
||||
@ -850,7 +850,7 @@ class Transport:
|
||||
should_transmit = False
|
||||
if interface != packet.destination.attached_interface:
|
||||
should_transmit = False
|
||||
|
||||
|
||||
if packet.attached_interface != None and interface != packet.attached_interface:
|
||||
should_transmit = False
|
||||
|
||||
@ -919,7 +919,7 @@ class Transport:
|
||||
tx_time = (len(packet.raw)*8) / interface.bitrate
|
||||
wait_time = (tx_time / interface.announce_cap)
|
||||
interface.announce_allowed_at = outbound_time + wait_time
|
||||
|
||||
|
||||
else:
|
||||
should_transmit = False
|
||||
if not len(interface.announce_queue) >= RNS.Reticulum.MAX_QUEUED_ANNOUNCES:
|
||||
@ -979,10 +979,10 @@ class Transport:
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
if should_transmit:
|
||||
if not stored_hash:
|
||||
Transport.packet_hashlist.append(packet.packet_hash)
|
||||
@ -1134,14 +1134,14 @@ class Transport:
|
||||
|
||||
if Transport.identity == None:
|
||||
return
|
||||
|
||||
|
||||
Transport.jobs_locked = True
|
||||
|
||||
|
||||
packet = RNS.Packet(None, raw)
|
||||
if not packet.unpack():
|
||||
Transport.jobs_locked = False
|
||||
return
|
||||
|
||||
|
||||
packet.receiving_interface = interface
|
||||
packet.hops += 1
|
||||
|
||||
@ -1205,7 +1205,7 @@ class Transport:
|
||||
Transport.packet_hashlist.append(packet.packet_hash)
|
||||
# TODO: Enable when caching has been redesigned
|
||||
# Transport.cache(packet)
|
||||
|
||||
|
||||
# Check special conditions for local clients connected
|
||||
# through a shared Reticulum instance
|
||||
from_local_client = (packet.receiving_interface in Transport.local_client_interfaces)
|
||||
@ -1262,7 +1262,7 @@ class Transport:
|
||||
if packet.destination_hash in Transport.destination_table:
|
||||
next_hop = Transport.destination_table[packet.destination_hash][1]
|
||||
remaining_hops = Transport.destination_table[packet.destination_hash][2]
|
||||
|
||||
|
||||
if remaining_hops > 1:
|
||||
# Just increase hop count and transmit
|
||||
new_raw = packet.raw[0:1]
|
||||
@ -1356,7 +1356,7 @@ class Transport:
|
||||
new_raw += packet.raw[2:]
|
||||
Transport.transmit(outbound_interface, new_raw)
|
||||
Transport.link_table[packet.destination_hash][0] = time.time()
|
||||
|
||||
|
||||
# TODO: Test and possibly enable this at some point
|
||||
# Transport.jobs_locked = False
|
||||
# return
|
||||
@ -1383,13 +1383,13 @@ class Transport:
|
||||
if local_destination == None and RNS.Identity.validate_announce(packet):
|
||||
if packet.transport_id != None:
|
||||
received_from = packet.transport_id
|
||||
|
||||
|
||||
# Check if this is a next retransmission from
|
||||
# another node. If it is, we're removing the
|
||||
# announce in question from our pending table
|
||||
if RNS.Reticulum.transport_enabled() and packet.destination_hash in Transport.announce_table:
|
||||
announce_entry = Transport.announce_table[packet.destination_hash]
|
||||
|
||||
|
||||
if packet.hops-1 == announce_entry[4]:
|
||||
RNS.log(f"Heard a local rebroadcast of announce for {RNS.prettyhexrep(packet.destination_hash)}", RNS.LOG_DEBUG)
|
||||
announce_entry[6] += 1
|
||||
@ -1415,7 +1415,7 @@ class Transport:
|
||||
# local to this system, and that hops are less than the max
|
||||
if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1):
|
||||
announce_emitted = Transport.announce_emitted(packet)
|
||||
|
||||
|
||||
random_blob = packet.data[RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.NAME_HASH_LENGTH//8+10]
|
||||
random_blobs = []
|
||||
if packet.destination_hash in Transport.destination_table:
|
||||
@ -1442,7 +1442,7 @@ class Transport:
|
||||
# the emission timestamp is more recent.
|
||||
now = time.time()
|
||||
path_expires = Transport.destination_table[packet.destination_hash][3]
|
||||
|
||||
|
||||
path_announce_emitted = 0
|
||||
for path_random_blob in random_blobs:
|
||||
path_announce_emitted = max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big"))
|
||||
@ -1474,7 +1474,7 @@ class Transport:
|
||||
should_add = True
|
||||
else:
|
||||
should_add = False
|
||||
|
||||
|
||||
# If we have already heard this announce before,
|
||||
# but the path has been marked as unresponsive
|
||||
# by a failed communications attempt or similar,
|
||||
@ -1527,14 +1527,14 @@ class Transport:
|
||||
|
||||
else:
|
||||
rate_blocked = True
|
||||
|
||||
|
||||
|
||||
retries = 0
|
||||
announce_hops = packet.hops
|
||||
local_rebroadcasts = 0
|
||||
block_rebroadcasts = False
|
||||
attached_interface = None
|
||||
|
||||
|
||||
retransmit_timeout = now + (RNS.rand() * Transport.PATHFINDER_RW)
|
||||
|
||||
if hasattr(packet.receiving_interface, "mode") and packet.receiving_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ACCESS_POINT:
|
||||
@ -1543,7 +1543,7 @@ class Transport:
|
||||
expires = now + Transport.ROAMING_PATH_TIME
|
||||
else:
|
||||
expires = now + Transport.PATHFINDER_E
|
||||
|
||||
|
||||
random_blobs.append(random_blob)
|
||||
random_blobs = random_blobs[-Transport.MAX_RANDOM_BLOBS:]
|
||||
|
||||
@ -1552,7 +1552,7 @@ class Transport:
|
||||
|
||||
if rate_blocked:
|
||||
RNS.log(f"Blocking rebroadcast of announce from {RNS.prettyhexrep(packet.destination_hash)} due to excessive announce rate", RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
else:
|
||||
if Transport.from_local_client(packet):
|
||||
# If the announce is from a local client,
|
||||
@ -1619,7 +1619,7 @@ class Transport:
|
||||
attached_interface = local_interface,
|
||||
context_flag = packet.context_flag,
|
||||
)
|
||||
|
||||
|
||||
new_announce.hops = packet.hops
|
||||
new_announce.send()
|
||||
|
||||
@ -1730,7 +1730,7 @@ class Transport:
|
||||
if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
|
||||
packet.destination = destination
|
||||
destination.receive(packet)
|
||||
|
||||
|
||||
# Handling for local data packets
|
||||
elif packet.packet_type == RNS.Packet.DATA:
|
||||
if packet.destination_type == RNS.Destination.LINK:
|
||||
@ -1835,7 +1835,7 @@ class Transport:
|
||||
for link in Transport.active_links:
|
||||
if link.link_id == packet.destination_hash:
|
||||
packet.link = link
|
||||
|
||||
|
||||
if len(packet.data) == RNS.PacketReceipt.EXPL_LENGTH:
|
||||
proof_hash = packet.data[:RNS.Identity.HASHLENGTH//8]
|
||||
else:
|
||||
@ -1875,13 +1875,13 @@ class Transport:
|
||||
interface_hash = interface.get_hash()
|
||||
public_key = RNS.Transport.identity.get_public_key()
|
||||
random_hash = RNS.Identity.get_random_hash()
|
||||
|
||||
|
||||
tunnel_id_data = public_key+interface_hash
|
||||
tunnel_id = RNS.Identity.full_hash(tunnel_id_data)
|
||||
|
||||
signed_data = tunnel_id_data+random_hash
|
||||
signature = Transport.identity.sign(signed_data)
|
||||
|
||||
|
||||
data = signed_data+signature
|
||||
|
||||
tnl_snth_dst = RNS.Destination(None, RNS.Destination.OUT, RNS.Destination.PLAIN, Transport.APP_NAME, "tunnel", "synthesize")
|
||||
@ -1901,7 +1901,7 @@ class Transport:
|
||||
tunnel_id_data = public_key+interface_hash
|
||||
tunnel_id = RNS.Identity.full_hash(tunnel_id_data)
|
||||
random_hash = data[RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8:RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8]
|
||||
|
||||
|
||||
signature = data[RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8:expected_length]
|
||||
signed_data = tunnel_id_data+random_hash
|
||||
|
||||
@ -1974,7 +1974,7 @@ class Transport:
|
||||
for registered_destination in Transport.destinations:
|
||||
if destination.hash == registered_destination.hash:
|
||||
raise KeyError("Attempt to register an already registered destination.")
|
||||
|
||||
|
||||
Transport.destinations.append(destination)
|
||||
|
||||
if Transport.owner.is_connected_to_shared_instance:
|
||||
@ -2061,7 +2061,7 @@ class Transport:
|
||||
if packet.receiving_interface != None:
|
||||
interface_reference = str(packet.receiving_interface)
|
||||
|
||||
file = open(f"{RNS.Reticulum.cachepath}/{packet_hash}", "wb")
|
||||
file = open(f"{RNS.Reticulum.cachepath}/{packet_hash}", "wb")
|
||||
file.write(umsgpack.packb([packet.raw, interface_reference]))
|
||||
file.close()
|
||||
|
||||
@ -2419,11 +2419,11 @@ class Transport:
|
||||
if len(Transport.local_client_interfaces) > 0:
|
||||
if destination_hash in Transport.destination_table:
|
||||
destination_interface = Transport.destination_table[destination_hash][5]
|
||||
|
||||
|
||||
if Transport.is_local_client_interface(destination_interface):
|
||||
destination_exists_on_local_client = True
|
||||
Transport.pending_local_path_requests[destination_hash] = attached_interface
|
||||
|
||||
|
||||
local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
|
||||
if local_destination != None:
|
||||
local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface)
|
||||
@ -2436,7 +2436,7 @@ class Transport:
|
||||
|
||||
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:
|
||||
if requestor_transport_id != None and next_hop == requestor_transport_id:
|
||||
# TODO: Find a bandwidth efficient way to invalidate our
|
||||
@ -2480,7 +2480,7 @@ class Transport:
|
||||
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:
|
||||
@ -2554,7 +2554,7 @@ class Transport:
|
||||
detachable_interfaces.append(interface)
|
||||
else:
|
||||
pass
|
||||
|
||||
|
||||
for interface in Transport.local_client_interfaces:
|
||||
# Currently no rules are being applied
|
||||
# here, and all interfaces will be sent
|
||||
|
@ -58,7 +58,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
|
||||
|
||||
identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}"
|
||||
if os.path.isfile(identity_path):
|
||||
identity = RNS.Identity.from_file(identity_path)
|
||||
identity = RNS.Identity.from_file(identity_path)
|
||||
|
||||
if identity == None:
|
||||
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
||||
@ -102,7 +102,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
|
||||
ms = "y"
|
||||
else:
|
||||
ms = "ies"
|
||||
|
||||
|
||||
RNS.log(f"Loaded {len(ali)} allowed identit{ms} from {allowed_file}", RNS.LOG_VERBOSE)
|
||||
|
||||
except Exception as e:
|
||||
@ -180,7 +180,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
|
||||
destination.announce()
|
||||
|
||||
threading.Thread(target=job, daemon=True).start()
|
||||
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
@ -206,7 +206,7 @@ def receive_sender_identified(link, identity):
|
||||
|
||||
def receive_resource_callback(resource):
|
||||
global allow_all
|
||||
|
||||
|
||||
sender_identity = resource.link.get_remote_identity()
|
||||
|
||||
if sender_identity != None:
|
||||
@ -239,7 +239,7 @@ def receive_resource_concluded(resource):
|
||||
while os.path.isfile(saved_filename):
|
||||
counter += 1
|
||||
saved_filename = f"{filename}.{counter}"
|
||||
|
||||
|
||||
file = open(saved_filename, "wb")
|
||||
file.write(resource.data.read())
|
||||
file.close()
|
||||
@ -412,7 +412,7 @@ def fetch(configdir, verbosity = 0, quietness = 0, destination = None, file = No
|
||||
while os.path.isfile(saved_filename):
|
||||
counter += 1
|
||||
saved_filename = f"{filename}.{counter}"
|
||||
|
||||
|
||||
file = open(saved_filename, "wb")
|
||||
file.write(resource.data.read())
|
||||
file.close()
|
||||
@ -521,7 +521,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
print(str(e))
|
||||
exit(1)
|
||||
|
||||
|
||||
|
||||
file_path = os.path.expanduser(file)
|
||||
if not os.path.isfile(file_path):
|
||||
print("File not found")
|
||||
@ -637,7 +637,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
|
||||
sys.stdout.flush()
|
||||
i = (i+1)%len(syms)
|
||||
|
||||
|
||||
|
||||
if resource.status > RNS.Resource.COMPLETE:
|
||||
if silent:
|
||||
print(f"File was not accepted by {RNS.prettyhexrep(destination_hash)}")
|
||||
@ -708,7 +708,7 @@ def main():
|
||||
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=f"rncp {__version__}")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.listen or args.print_identity:
|
||||
|
@ -82,7 +82,7 @@ def main():
|
||||
parser.add_argument("-w", "--write", metavar="file", action="store", default=None, help="output file path", type=str)
|
||||
parser.add_argument("-f", "--force", action="store_true", default=None, help="write output even if it overwrites existing files")
|
||||
parser.add_argument("-I", "--stdin", action="store_true", default=False, help=argparse.SUPPRESS) # "read input from STDIN instead of file"
|
||||
parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file",
|
||||
parser.add_argument("-O", "--stdout", action="store_true", default=False, help=argparse.SUPPRESS) # help="write output to STDOUT instead of file",
|
||||
|
||||
parser.add_argument("-R", "--request", action="store_true", default=False, help="request unknown Identities from the network")
|
||||
parser.add_argument("-t", action="store", metavar="seconds", type=float, help="identity request timeout before giving up", default=RNS.Transport.PATH_REQUEST_TIMEOUT)
|
||||
@ -93,14 +93,14 @@ def main():
|
||||
parser.add_argument("-B", "--base32", action="store_true", default=False, help="Use base32-encoded input and output")
|
||||
|
||||
parser.add_argument("--version", action="version", version=f"rnid {__version__}")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
ops = 0;
|
||||
for t in [args.encrypt, args.decrypt, args.validate, args.sign]:
|
||||
if t:
|
||||
ops += 1
|
||||
|
||||
|
||||
if ops > 1:
|
||||
RNS.log("This utility currently only supports one of the encrypt, decrypt, sign or verify operations per invocation", RNS.LOG_ERROR)
|
||||
exit(1)
|
||||
@ -179,7 +179,7 @@ def main():
|
||||
quietness = args.quiet
|
||||
if verbosity != 0 or quietness != 0:
|
||||
targetloglevel = targetloglevel+verbosity-quietness
|
||||
|
||||
|
||||
# Start Reticulum
|
||||
reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel)
|
||||
RNS.compact_log_fmt = True
|
||||
@ -234,7 +234,7 @@ def main():
|
||||
RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR)
|
||||
exit(7)
|
||||
|
||||
|
||||
|
||||
else:
|
||||
# Try loading Identity from file
|
||||
if not os.path.isfile(identity_str):
|
||||
@ -391,7 +391,7 @@ def main():
|
||||
RNS.log("Could not open output file for writing", RNS.LOG_ERROR)
|
||||
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
|
||||
exit(15)
|
||||
|
||||
|
||||
# TODO: Actually expand this to a good solution
|
||||
# probably need to create a wrapper that takes
|
||||
# into account not closing stdout when done
|
||||
@ -415,12 +415,12 @@ def main():
|
||||
|
||||
if not args.stdout:
|
||||
RNS.log(f"Signing {args.read}")
|
||||
|
||||
|
||||
try:
|
||||
data_output.write(identity.sign(data_input.read()))
|
||||
data_output.close()
|
||||
data_input.close()
|
||||
|
||||
|
||||
if not args.stdout:
|
||||
if args.read:
|
||||
RNS.log(f"File {args.read} signed with {identity} to {args.write}")
|
||||
@ -448,7 +448,7 @@ def main():
|
||||
else:
|
||||
# if not args.stdout:
|
||||
# RNS.log("Verifying "+str(args.validate)+" for "+str(args.read))
|
||||
|
||||
|
||||
try:
|
||||
try:
|
||||
sig_input = open(args.validate, "rb")
|
||||
@ -498,7 +498,7 @@ def main():
|
||||
|
||||
if not args.stdout:
|
||||
RNS.log(f"Encrypting {args.read}")
|
||||
|
||||
|
||||
try:
|
||||
more_data = True
|
||||
while more_data:
|
||||
@ -545,7 +545,7 @@ def main():
|
||||
|
||||
if not args.stdout:
|
||||
RNS.log(f"Decrypting {args.read}...")
|
||||
|
||||
|
||||
try:
|
||||
more_data = True
|
||||
while more_data:
|
||||
|
@ -49,7 +49,7 @@ def main():
|
||||
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=f"ir {__version__}")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.exampleconfig:
|
||||
|
@ -61,7 +61,7 @@ class KISS():
|
||||
FESC = 0xDB
|
||||
TFEND = 0xDC
|
||||
TFESC = 0xDD
|
||||
|
||||
|
||||
CMD_UNKNOWN = 0xFE
|
||||
CMD_DATA = 0x00
|
||||
CMD_FREQUENCY = 0x01
|
||||
@ -104,11 +104,11 @@ class KISS():
|
||||
|
||||
DETECT_REQ = 0x73
|
||||
DETECT_RESP = 0x46
|
||||
|
||||
|
||||
RADIO_STATE_OFF = 0x00
|
||||
RADIO_STATE_ON = 0x01
|
||||
RADIO_STATE_ASK = 0xFF
|
||||
|
||||
|
||||
CMD_ERROR = 0x90
|
||||
ERROR_INITRADIO = 0x01
|
||||
ERROR_TXFAILED = 0x02
|
||||
@ -191,7 +191,7 @@ class ROM():
|
||||
PRODUCT_TECHO = 0x15
|
||||
MODEL_T4 = 0x16
|
||||
MODEL_T9 = 0x17
|
||||
|
||||
|
||||
PRODUCT_HMBRW = 0xF0
|
||||
MODEL_FF = 0xFF
|
||||
MODEL_FE = 0xFE
|
||||
@ -610,7 +610,7 @@ class RNode():
|
||||
self.detected = True
|
||||
else:
|
||||
self.detected = False
|
||||
|
||||
|
||||
else:
|
||||
time_since_last = int(time.time()*1000) - last_read_ms
|
||||
if len(data_buffer) > 0 and time_since_last > self.timeout:
|
||||
@ -886,7 +886,7 @@ class RNode():
|
||||
from cryptography.hazmat.primitives.serialization import load_der_private_key
|
||||
from cryptography.hazmat.primitives.asymmetric import padding
|
||||
|
||||
# Try loading local signing key for
|
||||
# Try loading local signing key for
|
||||
# validation of self-signed devices
|
||||
if os.path.isdir(FWD_DIR) and os.path.isfile(FWD_DIR+"/signing.key"):
|
||||
private_bytes = None
|
||||
@ -922,7 +922,7 @@ class RNode():
|
||||
RNS.log("Could not deserialize local signing key")
|
||||
RNS.log(str(e))
|
||||
|
||||
# Try loading trusted signing key for
|
||||
# Try loading trusted signing key for
|
||||
# validation of devices
|
||||
if os.path.isdir(TK_DIR):
|
||||
for f in os.listdir(TK_DIR):
|
||||
@ -1230,11 +1230,11 @@ def rnode_open_serial(port):
|
||||
write_timeout = None,
|
||||
dsrdtr = False
|
||||
)
|
||||
|
||||
|
||||
|
||||
|
||||
def graceful_exit(C=0):
|
||||
if RNS.vendor.platformutils.is_windows():
|
||||
RNS.log("Windows detected; delaying DTR",RNS.LOG_VERBOSE)
|
||||
RNS.log("Windows detected; delaying DTR",RNS.LOG_VERBOSE)
|
||||
if rnode:
|
||||
RNS.log("Sending \"Leave\" to Rnode",RNS.LOG_VERBOSE)
|
||||
rnode.leave() # Leave has wait built in
|
||||
@ -1319,13 +1319,13 @@ def main():
|
||||
|
||||
parser.add_argument("-f", "--flash", action="store_true", help="Flash firmware and bootstrap EEPROM")
|
||||
parser.add_argument("-r", "--rom", action="store_true", help="Bootstrap EEPROM without flashing firmware")
|
||||
parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") #
|
||||
parser.add_argument("-k", "--key", action="store_true", help="Generate a new signing key and exit") #
|
||||
parser.add_argument("-S", "--sign", action="store_true", help="Display public part of signing key")
|
||||
parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash")
|
||||
parser.add_argument("-K", "--get-target-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get target firmware hash from device
|
||||
parser.add_argument("-L", "--get-firmware-hash", action="store_true", help=argparse.SUPPRESS) # Get calculated firmware hash from device
|
||||
parser.add_argument("--platform", action="store", metavar="platform", type=str, default=None, help="Platform specification for device bootstrap")
|
||||
parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") #
|
||||
parser.add_argument("--product", action="store", metavar="product", type=str, default=None, help="Product specification for device bootstrap") #
|
||||
parser.add_argument("--model", action="store", metavar="model", type=str, default=None, help="Model code for device bootstrap")
|
||||
parser.add_argument("--hwrev", action="store", metavar="revision", type=int, default=None, help="Hardware revision for device bootstrap")
|
||||
|
||||
@ -1354,7 +1354,7 @@ def main():
|
||||
|
||||
if args.fw_version != None:
|
||||
selected_version = args.fw_version
|
||||
try:
|
||||
try:
|
||||
check_float = float(selected_version)
|
||||
except ValueError:
|
||||
RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.")
|
||||
@ -1368,7 +1368,7 @@ def main():
|
||||
|
||||
if args.nocheck:
|
||||
upd_nocheck = True
|
||||
|
||||
|
||||
if args.public or args.key or args.flash or args.rom or args.autoinstall or args.trust_key:
|
||||
from cryptography.hazmat.primitives import hashes
|
||||
from cryptography.hazmat.backends import default_backend
|
||||
@ -1419,8 +1419,8 @@ def main():
|
||||
ports = list_ports.comports()
|
||||
portlist = []
|
||||
for port in ports:
|
||||
portlist.insert(0, port)
|
||||
|
||||
portlist.insert(0, port)
|
||||
|
||||
pi = 1
|
||||
print("Detected serial ports:")
|
||||
for port in portlist:
|
||||
@ -1556,8 +1556,8 @@ def main():
|
||||
ports = list_ports.comports()
|
||||
portlist = []
|
||||
for port in ports:
|
||||
portlist.insert(0, port)
|
||||
|
||||
portlist.insert(0, port)
|
||||
|
||||
pi = 1
|
||||
print("Detected serial ports:")
|
||||
for port in portlist:
|
||||
@ -1638,7 +1638,7 @@ def main():
|
||||
print("correct firmware and provision it.")
|
||||
else:
|
||||
print("\nIt looks like this is a fresh device with no RNode firmware.")
|
||||
|
||||
|
||||
print("")
|
||||
print("What kind of device is this?\n")
|
||||
print("[1] A specific kind of RNode")
|
||||
@ -2224,7 +2224,7 @@ def main():
|
||||
fw_filename = "rnode_firmware.hex"
|
||||
elif selected_mcu == ROM.MCU_2560:
|
||||
fw_filename = "rnode_firmware_m2560.hex"
|
||||
|
||||
|
||||
elif selected_platform == ROM.PLATFORM_ESP32:
|
||||
fw_filename = None
|
||||
print("\nWhat kind of ESP32 board is this?\n")
|
||||
@ -2337,7 +2337,7 @@ def main():
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Could not load device signing key")
|
||||
|
||||
|
||||
|
||||
graceful_exit()
|
||||
|
||||
@ -2413,7 +2413,7 @@ def main():
|
||||
return part_hash
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
elif platform == ROM.PLATFORM_NRF52:
|
||||
# Calculate digest manually, as it is not included in the image.
|
||||
firmware_data = open(partition_file, "rb")
|
||||
@ -2994,7 +2994,7 @@ def main():
|
||||
wants_fw_provision = False
|
||||
if args.flash:
|
||||
from subprocess import call
|
||||
|
||||
|
||||
if fw_filename == None:
|
||||
fw_filename = "rnode_firmware.hex"
|
||||
|
||||
@ -3032,7 +3032,7 @@ def main():
|
||||
RNS.log("Error while flashing")
|
||||
RNS.log(str(e))
|
||||
graceful_exit(1)
|
||||
|
||||
|
||||
else:
|
||||
fw_src = UPD_DIR+"/"+selected_version+"/"
|
||||
if os.path.isfile(fw_src+fw_filename):
|
||||
@ -3215,7 +3215,7 @@ def main():
|
||||
update_full_path = EXT_DIR+"/extracted_rnode_firmware.version"
|
||||
else:
|
||||
update_full_path = UPD_DIR+"/"+selected_version+"/"+fw_filename
|
||||
if os.path.isfile(update_full_path):
|
||||
if os.path.isfile(update_full_path):
|
||||
try:
|
||||
args.info = False
|
||||
RNS.log("Updating RNode firmware for device on "+args.port)
|
||||
@ -3468,7 +3468,7 @@ def main():
|
||||
if args.autoinstall:
|
||||
RNS.log("Clearing old EEPROM, this will take about 15 seconds...")
|
||||
rnode.wipe_eeprom()
|
||||
|
||||
|
||||
if rnode.platform == ROM.PLATFORM_ESP32:
|
||||
RNS.log("Waiting for ESP32 reset...")
|
||||
time.sleep(6)
|
||||
@ -3849,7 +3849,7 @@ def main():
|
||||
else:
|
||||
RNS.log("This device has not been provisioned yet, cannot get firmware hash")
|
||||
exit(77)
|
||||
|
||||
|
||||
if args.get_firmware_hash:
|
||||
if rnode.provisioned:
|
||||
RNS.log(f"The actual firmware hash is: {rnode.firmware_hash.hex()}")
|
||||
@ -3923,7 +3923,7 @@ def main():
|
||||
except KeyboardInterrupt:
|
||||
print("")
|
||||
graceful_exit()
|
||||
|
||||
|
||||
graceful_exit()
|
||||
|
||||
def extract_recovery_esptool():
|
||||
|
@ -235,7 +235,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
||||
hour_rate = round(len(entry["timestamps"])/span_hours, 3)
|
||||
if hour_rate-int(hour_rate) == 0:
|
||||
hour_rate = int(hour_rate)
|
||||
|
||||
|
||||
if entry["rate_violations"] > 0:
|
||||
if entry["rate_violations"] == 1:
|
||||
s_str = ""
|
||||
@ -245,14 +245,14 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
||||
rv_str = f", {entry['rate_violations']} active rate violation{s_str}"
|
||||
else:
|
||||
rv_str = ""
|
||||
|
||||
|
||||
if entry["blocked_until"] > time.time():
|
||||
bli = time.time()-(int(entry["blocked_until"])-time.time())
|
||||
bl_str = f", new announces allowed in {pretty_date(int(bli))}"
|
||||
else:
|
||||
bl_str = ""
|
||||
|
||||
|
||||
|
||||
print(f"{RNS.prettyhexrep(entry['hash'])} last heard {last_str} ago, {hour_rate} announces/hour in the last {span_str}{rv_str}{bl_str}")
|
||||
|
||||
except Exception as e:
|
||||
@ -272,7 +272,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
||||
|
||||
print("Dropping announce queues on all interfaces...")
|
||||
reticulum.drop_announce_queues()
|
||||
|
||||
|
||||
elif drop:
|
||||
if remote_link:
|
||||
if not no_output:
|
||||
@ -341,7 +341,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
if not RNS.Transport.has_path(destination_hash):
|
||||
RNS.Transport.request_path(destination_hash)
|
||||
print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ")
|
||||
@ -376,7 +376,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
|
||||
print("\r \rPath not found")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
@ -479,7 +479,7 @@ def main():
|
||||
help="timeout before giving up on remote queries",
|
||||
default=RNS.Transport.PATH_REQUEST_TIMEOUT
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--json",
|
||||
@ -497,7 +497,7 @@ def main():
|
||||
)
|
||||
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.config:
|
||||
|
@ -38,7 +38,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
|
||||
if full_name == None:
|
||||
print("The full destination name including application name aspects must be specified for the destination")
|
||||
exit()
|
||||
|
||||
|
||||
try:
|
||||
app_name, aspects = RNS.Destination.app_and_aspects_from_name(full_name)
|
||||
|
||||
@ -133,7 +133,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
|
||||
|
||||
if time.time() > _timeout:
|
||||
print("\r \rProbe timed out")
|
||||
|
||||
|
||||
else:
|
||||
print("\b\b ")
|
||||
sys.stdout.flush()
|
||||
@ -162,10 +162,10 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
|
||||
|
||||
if reception_rssi != None:
|
||||
reception_stats += f" [RSSI {reception_rssi} dBm]"
|
||||
|
||||
|
||||
if reception_snr != None:
|
||||
reception_stats += f" [SNR {reception_snr} dB]"
|
||||
|
||||
|
||||
if reception_q != None:
|
||||
reception_stats += f" [Link Quality {reception_q}%]"
|
||||
|
||||
@ -173,7 +173,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
|
||||
if receipt.proof_packet != None:
|
||||
if receipt.proof_packet.rssi != None:
|
||||
reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]"
|
||||
|
||||
|
||||
if receipt.proof_packet.snr != None:
|
||||
reception_stats += f" [SNR {receipt.proof_packet.snr} dB]"
|
||||
|
||||
@ -192,7 +192,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
|
||||
exit(2)
|
||||
else:
|
||||
exit(0)
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
try:
|
||||
|
@ -56,7 +56,7 @@ def main():
|
||||
parser.add_argument('-s', '--service', action='store_true', default=False, help="rnsd is running as a service and should log to file")
|
||||
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=f"rnsd {__version__}")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.exampleconfig:
|
||||
@ -192,7 +192,7 @@ loglevel = 4
|
||||
|
||||
# The following example enables communication with other
|
||||
# local Reticulum peers using UDP broadcasts.
|
||||
|
||||
|
||||
[[UDP Interface]]
|
||||
type = UDPInterface
|
||||
enabled = no
|
||||
@ -235,24 +235,24 @@ loglevel = 4
|
||||
# This example demonstrates a TCP server interface.
|
||||
# It will listen for incoming connections on the
|
||||
# specified IP address and port number.
|
||||
|
||||
|
||||
[[TCP Server Interface]]
|
||||
type = TCPServerInterface
|
||||
enabled = no
|
||||
|
||||
# This configuration will listen on all IP
|
||||
# interfaces on port 4242
|
||||
|
||||
|
||||
listen_ip = 0.0.0.0
|
||||
listen_port = 4242
|
||||
|
||||
# Alternatively you can bind to a specific IP
|
||||
|
||||
|
||||
# listen_ip = 10.0.0.88
|
||||
# listen_port = 4242
|
||||
|
||||
# Or a specific network device
|
||||
|
||||
|
||||
# device = eth0
|
||||
# port = 4242
|
||||
|
||||
@ -300,7 +300,7 @@ loglevel = 4
|
||||
# host device before connecting. BLE
|
||||
# devices can be connected by name,
|
||||
# BLE MAC address or by any available.
|
||||
|
||||
|
||||
# Connect to specific device by name
|
||||
# port = ble://RNode 3B87
|
||||
|
||||
@ -320,7 +320,7 @@ loglevel = 4
|
||||
# Set TX power to 7 dBm (5 mW)
|
||||
txpower = 7
|
||||
|
||||
# Select spreading factor 8. Valid
|
||||
# Select spreading factor 8. Valid
|
||||
# range is 7 through 12, with 7
|
||||
# being the fastest and 12 having
|
||||
# the longest range.
|
||||
@ -349,8 +349,8 @@ loglevel = 4
|
||||
# flow control can be useful. By default
|
||||
# it is disabled.
|
||||
flow_control = False
|
||||
|
||||
|
||||
|
||||
|
||||
# An example KISS modem interface. Useful for running
|
||||
# Reticulum over packet radio hardware.
|
||||
|
||||
@ -365,7 +365,7 @@ loglevel = 4
|
||||
|
||||
# Set the serial baud-rate and other
|
||||
# configuration parameters.
|
||||
speed = 115200
|
||||
speed = 115200
|
||||
databits = 8
|
||||
parity = none
|
||||
stopbits = 1
|
||||
@ -413,7 +413,7 @@ loglevel = 4
|
||||
# way, Reticulum will automatically encapsulate it's
|
||||
# traffic in AX.25 and also identify your stations
|
||||
# transmissions with your callsign and SSID.
|
||||
#
|
||||
#
|
||||
# Only do this if you really need to! Reticulum doesn't
|
||||
# need the AX.25 layer for anything, and it incurs extra
|
||||
# overhead on every packet to encapsulate in AX.25.
|
||||
@ -436,7 +436,7 @@ loglevel = 4
|
||||
|
||||
# Set the serial baud-rate and other
|
||||
# configuration parameters.
|
||||
speed = 115200
|
||||
speed = 115200
|
||||
databits = 8
|
||||
parity = none
|
||||
stopbits = 1
|
||||
|
@ -161,7 +161,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
stats, link_count = remote_status
|
||||
except Exception as e:
|
||||
raise e
|
||||
|
||||
|
||||
except Exception as e:
|
||||
print(str(e))
|
||||
exit(20)
|
||||
@ -215,7 +215,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
if sorting == "held":
|
||||
interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse)
|
||||
|
||||
|
||||
|
||||
for ifstat in interfaces:
|
||||
name = ifstat["name"]
|
||||
|
||||
@ -301,10 +301,10 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
|
||||
if "airtime_short" in ifstat and "airtime_long" in ifstat:
|
||||
print(" Airtime : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["airtime_short"]),atl=str(ifstat["airtime_long"])))
|
||||
|
||||
|
||||
if "channel_load_short" in ifstat and "channel_load_long" in ifstat:
|
||||
print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
|
||||
|
||||
|
||||
if "peers" in ifstat and ifstat["peers"] != None:
|
||||
print(" Peers : {np} reachable".format(np=ifstat["peers"]))
|
||||
|
||||
@ -314,7 +314,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
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))
|
||||
|
||||
|
||||
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
|
||||
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
|
||||
|
||||
@ -324,14 +324,14 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
print(" Queued : {np} announce".format(np=aqn))
|
||||
else:
|
||||
print(" Queued : {np} announces".format(np=aqn))
|
||||
|
||||
|
||||
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"])))
|
||||
@ -357,7 +357,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
|
||||
print(f"\n{lstr}")
|
||||
|
||||
print("")
|
||||
|
||||
|
||||
else:
|
||||
if not remote:
|
||||
print("Could not get RNS status")
|
||||
@ -378,7 +378,7 @@ def main():
|
||||
help="show all interfaces",
|
||||
default=False
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
"-A",
|
||||
"--announce-stats",
|
||||
@ -386,7 +386,7 @@ def main():
|
||||
help="show announce stats",
|
||||
default=False
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
"-l",
|
||||
"--link-stats",
|
||||
@ -394,7 +394,7 @@ def main():
|
||||
help="show link stats",
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--sort",
|
||||
@ -403,7 +403,7 @@ def main():
|
||||
default=None,
|
||||
type=str
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
"-r",
|
||||
"--reverse",
|
||||
@ -411,7 +411,7 @@ def main():
|
||||
help="reverse sorting",
|
||||
default=False,
|
||||
)
|
||||
|
||||
|
||||
parser.add_argument(
|
||||
"-j",
|
||||
"--json",
|
||||
@ -450,7 +450,7 @@ def main():
|
||||
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||
|
||||
parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str)
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.config:
|
||||
|
@ -45,7 +45,7 @@ def prepare_identity(identity_path):
|
||||
identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}"
|
||||
|
||||
if os.path.isfile(identity_path):
|
||||
identity = RNS.Identity.from_file(identity_path)
|
||||
identity = RNS.Identity.from_file(identity_path)
|
||||
|
||||
if identity == None:
|
||||
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
|
||||
@ -57,7 +57,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed
|
||||
|
||||
targetloglevel = 3+verbosity-quietness
|
||||
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
|
||||
|
||||
|
||||
prepare_identity(identitypath)
|
||||
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute")
|
||||
|
||||
@ -107,7 +107,7 @@ def listen(configdir, identitypath = None, verbosity = 0, quietness = 0, allowed
|
||||
|
||||
if not disable_announce:
|
||||
destination.announce()
|
||||
|
||||
|
||||
while True:
|
||||
time.sleep(1)
|
||||
|
||||
@ -338,7 +338,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
|
||||
if link == None or link.status == RNS.Link.CLOSED or link.status == RNS.Link.PENDING:
|
||||
link = RNS.Link(listener_destination)
|
||||
link.did_identify = False
|
||||
|
||||
|
||||
if not spin(until=lambda: link.status == RNS.Link.ACTIVE, msg=f"Establishing link with {RNS.prettyhexrep(destination_hash)}", timeout=timeout):
|
||||
print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}")
|
||||
exit(243)
|
||||
@ -467,7 +467,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
|
||||
else:
|
||||
tstr = ""
|
||||
print(f"Remote wrote {outlen} bytes to stdout{tstr}")
|
||||
|
||||
|
||||
if errlen != None and stderr != None:
|
||||
if len(stderr) < errlen:
|
||||
tstr = f", {len(stderr)} bytes displayed"
|
||||
@ -548,7 +548,7 @@ def main():
|
||||
parser.add_argument("--stdout", action='store', default=None, help="max size in bytes of returned stdout", type=int)
|
||||
parser.add_argument("--stderr", action='store', default=None, help="max size in bytes of returned stderr", type=int)
|
||||
parser.add_argument("--version", action="version", version=f"rnx {__version__}")
|
||||
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.listen or args.print_identity:
|
||||
@ -600,8 +600,8 @@ def main():
|
||||
# while True:
|
||||
# ch = sys.stdin.read(1)
|
||||
# cmdbuf += ch.encode("utf-8")
|
||||
# print("\r"+prompt+cmdbuf.decode("utf-8"), end="")
|
||||
|
||||
# print("\r"+prompt+cmdbuf.decode("utf-8"), end="")
|
||||
|
||||
command = input()
|
||||
if command.lower() == "exit" or command.lower() == "quit":
|
||||
exit(0)
|
||||
@ -676,7 +676,7 @@ def pretty_time(time, verbose=False):
|
||||
minutes = int(time // 60)
|
||||
time %= 60
|
||||
seconds = round(time, 2)
|
||||
|
||||
|
||||
ss = "" if seconds == 1 else "s"
|
||||
sm = "" if minutes == 1 else "s"
|
||||
sh = "" if hours == 1 else "s"
|
||||
|
@ -90,7 +90,7 @@ def loglevelname(level):
|
||||
return "Debug"
|
||||
if (level == LOG_EXTREME):
|
||||
return "Extra"
|
||||
|
||||
|
||||
return "Unknown"
|
||||
|
||||
def version():
|
||||
@ -124,7 +124,7 @@ def log(msg, level=3, _override_destination = False):
|
||||
file = open(logfile, "a")
|
||||
file.write(logstring+"\n")
|
||||
file.close()
|
||||
|
||||
|
||||
if os.path.getsize(logfile) > LOG_MAXSIZE:
|
||||
prevfile = logfile+".1"
|
||||
if os.path.isfile(prevfile):
|
||||
@ -138,7 +138,7 @@ def log(msg, level=3, _override_destination = False):
|
||||
log("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL)
|
||||
log("Dumping future log events to console!", LOG_CRITICAL)
|
||||
log(msg, level)
|
||||
|
||||
|
||||
|
||||
def rand():
|
||||
result = instance_random.random()
|
||||
@ -155,7 +155,7 @@ def hexrep(data, delimit=True):
|
||||
iter(data)
|
||||
except TypeError:
|
||||
data = [data]
|
||||
|
||||
|
||||
delimiter = ":"
|
||||
if not delimit:
|
||||
delimiter = ""
|
||||
@ -228,7 +228,7 @@ def prettytime(time, verbose=False, compact=False):
|
||||
seconds = int(time)
|
||||
else:
|
||||
seconds = round(time, 2)
|
||||
|
||||
|
||||
ss = "" if seconds == 1 else "s"
|
||||
sm = "" if minutes == 1 else "s"
|
||||
sh = "" if hours == 1 else "s"
|
||||
@ -272,7 +272,7 @@ def prettytime(time, verbose=False, compact=False):
|
||||
|
||||
def prettyshorttime(time, verbose=False, compact=False):
|
||||
time = time*1e6
|
||||
|
||||
|
||||
seconds = int(time // 1e6); time %= 1e6
|
||||
milliseconds = int(time // 1e3); time %= 1e3
|
||||
|
||||
@ -280,7 +280,7 @@ def prettyshorttime(time, verbose=False, compact=False):
|
||||
microseconds = int(time)
|
||||
else:
|
||||
microseconds = round(time, 2)
|
||||
|
||||
|
||||
ss = "" if seconds == 1 else "s"
|
||||
sms = "" if milliseconds == 1 else "s"
|
||||
sus = "" if microseconds == 1 else "s"
|
||||
@ -365,16 +365,16 @@ def profiler(tag=None, capture=False, super_tag=None):
|
||||
def profiler_results():
|
||||
from statistics import mean, median, stdev
|
||||
results = {}
|
||||
|
||||
|
||||
for tag in profiler_tags:
|
||||
tag_captures = []
|
||||
tag_entry = profiler_tags[tag]
|
||||
|
||||
|
||||
for thread_ident in tag_entry["threads"]:
|
||||
thread_entry = tag_entry["threads"][thread_ident]
|
||||
thread_captures = thread_entry["captures"]
|
||||
sample_count = len(thread_captures)
|
||||
|
||||
|
||||
if sample_count > 2:
|
||||
thread_results = {
|
||||
"count": sample_count,
|
||||
|
382
RNS/vendor/configobj.py
vendored
382
RNS/vendor/configobj.py
vendored
File diff suppressed because it is too large
Load Diff
4
RNS/vendor/i2plib/__init__.py
vendored
4
RNS/vendor/i2plib/__init__.py
vendored
@ -1,5 +1,5 @@
|
||||
"""
|
||||
A modern asynchronous library for building I2P applications.
|
||||
A modern asynchronous library for building I2P applications.
|
||||
"""
|
||||
|
||||
from .__version__ import (
|
||||
@ -10,7 +10,7 @@ from .__version__ import (
|
||||
from .sam import Destination, PrivateKey
|
||||
|
||||
from .aiosam import (
|
||||
get_sam_socket, dest_lookup, new_destination,
|
||||
get_sam_socket, dest_lookup, new_destination,
|
||||
create_session, stream_connect, stream_accept,
|
||||
Session, StreamConnection, StreamAcceptor
|
||||
)
|
||||
|
42
RNS/vendor/i2plib/aiosam.py
vendored
42
RNS/vendor/i2plib/aiosam.py
vendored
@ -34,12 +34,12 @@ async def get_sam_socket(sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
||||
writer.close()
|
||||
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]()
|
||||
|
||||
async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS,
|
||||
async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS,
|
||||
loop=None):
|
||||
"""A coroutine used to lookup a full I2P destination by .i2p domain or
|
||||
"""A coroutine used to lookup a full I2P destination by .i2p domain or
|
||||
.b32.i2p address.
|
||||
|
||||
:param domain: Address to be resolved, can be a .i2p domain or a .b32.i2p
|
||||
:param domain: Address to be resolved, can be a .i2p domain or a .b32.i2p
|
||||
address.
|
||||
:param sam_address: (optional) SAM API address
|
||||
:param loop: (optional) Event loop instance
|
||||
@ -56,7 +56,7 @@ async def dest_lookup(domain, sam_address=sam.DEFAULT_ADDRESS,
|
||||
|
||||
async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None,
|
||||
sig_type=sam.Destination.default_sig_type):
|
||||
"""A coroutine used to generate a new destination with a private key of a
|
||||
"""A coroutine used to generate a new destination with a private key of a
|
||||
chosen signature type.
|
||||
|
||||
:param sam_address: (optional) SAM API address
|
||||
@ -70,7 +70,7 @@ async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None,
|
||||
writer.close()
|
||||
return sam.Destination(reply["PRIV"], has_private_key=True)
|
||||
|
||||
async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
loop=None, style="STREAM",
|
||||
signature_type=sam.Destination.default_sig_type,
|
||||
destination=None, options={}):
|
||||
@ -80,10 +80,10 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
:param sam_address: (optional) SAM API address
|
||||
:param loop: (optional) Event loop instance
|
||||
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW
|
||||
:param signature_type: (optional) If the destination is TRANSIENT, this
|
||||
:param signature_type: (optional) If the destination is TRANSIENT, this
|
||||
signature type is used
|
||||
:param destination: (optional) Destination to use in this session. Can be
|
||||
a base64 encoded string, :class:`Destination`
|
||||
:param destination: (optional) Destination to use in this session. Can be
|
||||
a base64 encoded string, :class:`Destination`
|
||||
instance or None. TRANSIENT destination is used when it
|
||||
is None.
|
||||
:param options: (optional) A dict object with i2cp options
|
||||
@ -111,7 +111,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
if reply.ok:
|
||||
if not destination:
|
||||
destination = sam.Destination(
|
||||
reply["DESTINATION"], has_private_key=True)
|
||||
reply["DESTINATION"], has_private_key=True)
|
||||
logger.debug(destination.base32)
|
||||
logger.debug(f"Session created {session_name}")
|
||||
return (reader, writer)
|
||||
@ -119,7 +119,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
writer.close()
|
||||
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]()
|
||||
|
||||
async def stream_connect(session_name, destination,
|
||||
async def stream_connect(session_name, destination,
|
||||
sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
||||
"""A coroutine used to connect to a remote I2P destination.
|
||||
|
||||
@ -173,16 +173,16 @@ class Session:
|
||||
:param sam_address: (optional) SAM API address
|
||||
:param loop: (optional) Event loop instance
|
||||
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW
|
||||
:param signature_type: (optional) If the destination is TRANSIENT, this
|
||||
:param signature_type: (optional) If the destination is TRANSIENT, this
|
||||
signature type is used
|
||||
:param destination: (optional) Destination to use in this session. Can be
|
||||
a base64 encoded string, :class:`Destination`
|
||||
:param destination: (optional) Destination to use in this session. Can be
|
||||
a base64 encoded string, :class:`Destination`
|
||||
instance or None. TRANSIENT destination is used when it
|
||||
is None.
|
||||
:param options: (optional) A dict object with i2cp options
|
||||
:return: :class:`Session` object
|
||||
"""
|
||||
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
loop=None, style="STREAM",
|
||||
signature_type=sam.Destination.default_sig_type,
|
||||
destination=None, options={}):
|
||||
@ -195,9 +195,9 @@ class Session:
|
||||
self.options = options
|
||||
|
||||
async def __aenter__(self):
|
||||
self.reader, self.writer = await create_session(self.session_name,
|
||||
sam_address=self.sam_address, loop=self.loop, style=self.style,
|
||||
signature_type=self.signature_type,
|
||||
self.reader, self.writer = await create_session(self.session_name,
|
||||
sam_address=self.sam_address, loop=self.loop, style=self.style,
|
||||
signature_type=self.signature_type,
|
||||
destination=self.destination, options=self.options)
|
||||
return self
|
||||
|
||||
@ -214,7 +214,7 @@ class StreamConnection:
|
||||
:param loop: (optional) Event loop instance
|
||||
:return: :class:`StreamConnection` object
|
||||
"""
|
||||
def __init__(self, session_name, destination,
|
||||
def __init__(self, session_name, destination,
|
||||
sam_address=sam.DEFAULT_ADDRESS, loop=None):
|
||||
self.session_name = session_name
|
||||
self.sam_address = sam_address
|
||||
@ -222,7 +222,7 @@ class StreamConnection:
|
||||
self.destination = destination
|
||||
|
||||
async def __aenter__(self):
|
||||
self.reader, self.writer = await stream_connect(self.session_name,
|
||||
self.reader, self.writer = await stream_connect(self.session_name,
|
||||
self.destination, sam_address=self.sam_address, loop=self.loop)
|
||||
self.read = self.reader.read
|
||||
self.write = self.writer.write
|
||||
@ -240,14 +240,14 @@ class StreamAcceptor:
|
||||
:param loop: (optional) Event loop instance
|
||||
:return: :class:`StreamAcceptor` object
|
||||
"""
|
||||
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
def __init__(self, session_name, sam_address=sam.DEFAULT_ADDRESS,
|
||||
loop=None):
|
||||
self.session_name = session_name
|
||||
self.sam_address = sam_address
|
||||
self.loop = loop
|
||||
|
||||
async def __aenter__(self):
|
||||
self.reader, self.writer = await stream_accept(self.session_name,
|
||||
self.reader, self.writer = await stream_accept(self.session_name,
|
||||
sam_address=self.sam_address, loop=self.loop)
|
||||
self.read = self.reader.read
|
||||
self.write = self.writer.write
|
||||
|
20
RNS/vendor/i2plib/sam.py
vendored
20
RNS/vendor/i2plib/sam.py
vendored
@ -8,7 +8,7 @@ I2P_B64_CHARS = "-~"
|
||||
|
||||
def i2p_b64encode(x):
|
||||
"""Encode I2P destination"""
|
||||
return b64encode(x, altchars=I2P_B64_CHARS.encode()).decode()
|
||||
return b64encode(x, altchars=I2P_B64_CHARS.encode()).decode()
|
||||
|
||||
def i2p_b64decode(x):
|
||||
"""Decode I2P destination"""
|
||||
@ -79,9 +79,9 @@ class Destination:
|
||||
|
||||
https://geti2p.net/spec/common-structures#destination
|
||||
|
||||
:param data: (optional) Base64 encoded data or binary data
|
||||
:param path: (optional) A path to a file with binary data
|
||||
:param has_private_key: (optional) Does data have a private key?
|
||||
:param data: (optional) Base64 encoded data or binary data
|
||||
:param path: (optional) A path to a file with binary data
|
||||
:param has_private_key: (optional) Does data have a private key?
|
||||
"""
|
||||
|
||||
ECDSA_SHA256_P256 = 1
|
||||
@ -97,12 +97,12 @@ class Destination:
|
||||
|
||||
def __init__(self, data=None, path=None, has_private_key=False):
|
||||
#: Binary destination
|
||||
self.data = b''
|
||||
self.data = b''
|
||||
#: Base64 encoded destination
|
||||
self.base64 = ""
|
||||
self.base64 = ""
|
||||
#: :class:`RNS.vendor.i2plib.PrivateKey` instance or None
|
||||
self.private_key = None
|
||||
|
||||
self.private_key = None
|
||||
|
||||
if path:
|
||||
with open(path, "rb") as f: data = f.read()
|
||||
|
||||
@ -126,13 +126,13 @@ class Destination:
|
||||
"""Base32 destination hash of this destination"""
|
||||
desthash = sha256(self.data).digest()
|
||||
return b32encode(desthash).decode()[:52].lower()
|
||||
|
||||
|
||||
class PrivateKey:
|
||||
"""I2P private key
|
||||
|
||||
https://geti2p.net/spec/common-structures#keysandcert
|
||||
|
||||
:param data: Base64 encoded data or binary data
|
||||
:param data: Base64 encoded data or binary data
|
||||
"""
|
||||
|
||||
def __init__(self, data):
|
||||
|
40
RNS/vendor/i2plib/tunnel.py
vendored
40
RNS/vendor/i2plib/tunnel.py
vendored
@ -2,7 +2,7 @@ import logging
|
||||
import asyncio
|
||||
import argparse
|
||||
|
||||
from . import sam
|
||||
from . import sam
|
||||
from . import aiosam
|
||||
from . import utils
|
||||
from .log import logger
|
||||
@ -29,9 +29,9 @@ async def proxy_data(reader, writer):
|
||||
class I2PTunnel:
|
||||
"""Base I2P Tunnel object, not to be used directly
|
||||
|
||||
:param local_address: A local address to use for a tunnel.
|
||||
:param local_address: A local address to use for a tunnel.
|
||||
E.g. ("127.0.0.1", 6668)
|
||||
:param destination: (optional) Destination to use for this tunnel. Can be
|
||||
:param destination: (optional) Destination to use for this tunnel. Can be
|
||||
a base64 encoded string, :class:`Destination`
|
||||
instance or None. A new destination is created when it
|
||||
is None.
|
||||
@ -42,7 +42,7 @@ class I2PTunnel:
|
||||
:param sam_address: (optional) SAM API address
|
||||
"""
|
||||
|
||||
def __init__(self, local_address, destination=None, session_name=None,
|
||||
def __init__(self, local_address, destination=None, session_name=None,
|
||||
options={}, loop=None, sam_address=sam.DEFAULT_ADDRESS):
|
||||
self.local_address = local_address
|
||||
self.destination = destination
|
||||
@ -57,7 +57,7 @@ class I2PTunnel:
|
||||
sam_address=self.sam_address, loop=self.loop)
|
||||
_, self.session_writer = await aiosam.create_session(
|
||||
self.session_name, style=self.style, options=self.options,
|
||||
sam_address=self.sam_address,
|
||||
sam_address=self.sam_address,
|
||||
loop=self.loop, destination=self.destination)
|
||||
|
||||
def stop(self):
|
||||
@ -68,11 +68,11 @@ class ClientTunnel(I2PTunnel):
|
||||
"""Client tunnel, a subclass of tunnel.I2PTunnel
|
||||
|
||||
If you run a client tunnel with a local address ("127.0.0.1", 6668) and
|
||||
a remote destination "irc.echelon.i2p", all connections to 127.0.0.1:6668
|
||||
a remote destination "irc.echelon.i2p", all connections to 127.0.0.1:6668
|
||||
will be proxied to irc.echelon.i2p.
|
||||
|
||||
:param remote_destination: Remote I2P destination, can be either .i2p
|
||||
domain, .b32.i2p address, base64 destination or
|
||||
:param remote_destination: Remote I2P destination, can be either .i2p
|
||||
domain, .b32.i2p address, base64 destination or
|
||||
:class:`Destination` instance
|
||||
"""
|
||||
|
||||
@ -90,12 +90,12 @@ class ClientTunnel(I2PTunnel):
|
||||
"""Handle local client connection"""
|
||||
try:
|
||||
sc_task = aiosam.stream_connect(
|
||||
self.session_name, self.remote_destination,
|
||||
self.session_name, self.remote_destination,
|
||||
sam_address=self.sam_address, loop=self.loop)
|
||||
self.status["connect_tasks"].append(sc_task)
|
||||
|
||||
|
||||
remote_reader, remote_writer = await sc_task
|
||||
asyncio.ensure_future(proxy_data(remote_reader, client_writer),
|
||||
asyncio.ensure_future(proxy_data(remote_reader, client_writer),
|
||||
loop=self.loop)
|
||||
asyncio.ensure_future(proxy_data(client_reader, remote_writer),
|
||||
loop=self.loop)
|
||||
@ -123,8 +123,8 @@ class ServerTunnel(I2PTunnel):
|
||||
"""Server tunnel, a subclass of tunnel.I2PTunnel
|
||||
|
||||
If you want to expose a local service 127.0.0.1:80 to the I2P network, run
|
||||
a server tunnel with a local address ("127.0.0.1", 80). If you don't
|
||||
provide a private key or a session name, it will use a TRANSIENT
|
||||
a server tunnel with a local address ("127.0.0.1", 80). If you don't
|
||||
provide a private key or a session name, it will use a TRANSIENT
|
||||
destination.
|
||||
"""
|
||||
def __init__(self, *args, **kwargs):
|
||||
@ -139,7 +139,7 @@ class ServerTunnel(I2PTunnel):
|
||||
async def handle_client(incoming, client_reader, client_writer):
|
||||
try:
|
||||
# data and dest may come in one chunk
|
||||
dest, data = incoming.split(b"\n", 1)
|
||||
dest, data = incoming.split(b"\n", 1)
|
||||
remote_destination = sam.Destination(dest.decode())
|
||||
logger.debug(f"{self.session_name} client connected: {remote_destination.base32}.b32.i2p")
|
||||
|
||||
@ -151,7 +151,7 @@ class ServerTunnel(I2PTunnel):
|
||||
try:
|
||||
sc_task = asyncio.wait_for(
|
||||
asyncio.open_connection(
|
||||
host=self.local_address[0],
|
||||
host=self.local_address[0],
|
||||
port=self.local_address[1]),
|
||||
timeout=5)
|
||||
self.status["connect_tasks"].append(sc_task)
|
||||
@ -172,7 +172,7 @@ class ServerTunnel(I2PTunnel):
|
||||
try:
|
||||
while True:
|
||||
client_reader, client_writer = await aiosam.stream_accept(
|
||||
self.session_name, sam_address=self.sam_address,
|
||||
self.session_name, sam_address=self.sam_address,
|
||||
loop=self.loop)
|
||||
incoming = await client_reader.read(BUFFER_SIZE)
|
||||
asyncio.ensure_future(handle_client(
|
||||
@ -192,13 +192,13 @@ if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser()
|
||||
parser.add_argument('type', metavar="TYPE", choices=('server', 'client'),
|
||||
help="Tunnel type (server or client)")
|
||||
parser.add_argument('address', metavar="ADDRESS",
|
||||
parser.add_argument('address', metavar="ADDRESS",
|
||||
help="Local address (e.g. 127.0.0.1:8000)")
|
||||
parser.add_argument('--debug', '-d', action='store_true',
|
||||
help='Debugging')
|
||||
parser.add_argument('--key', '-k', default='', metavar='PRIVATE_KEY',
|
||||
help='Path to private key file')
|
||||
parser.add_argument('--destination', '-D', default='',
|
||||
parser.add_argument('--destination', '-D', default='',
|
||||
metavar='DESTINATION', help='Remote destination')
|
||||
args = parser.parse_args()
|
||||
|
||||
@ -216,10 +216,10 @@ if __name__ == '__main__':
|
||||
local_address = utils.address_from_string(args.address)
|
||||
|
||||
if args.type == "client":
|
||||
tunnel = ClientTunnel(args.destination, local_address, loop=loop,
|
||||
tunnel = ClientTunnel(args.destination, local_address, loop=loop,
|
||||
destination=destination, sam_address=SAM_ADDRESS)
|
||||
elif args.type == "server":
|
||||
tunnel = ServerTunnel(local_address, loop=loop, destination=destination,
|
||||
tunnel = ServerTunnel(local_address, loop=loop, destination=destination,
|
||||
sam_address=SAM_ADDRESS)
|
||||
|
||||
asyncio.ensure_future(tunnel.run(), loop=loop)
|
||||
|
@ -62,7 +62,7 @@ class Packet:
|
||||
|
||||
def set_delivered_callback(self, callback: Callable[[Packet], None]):
|
||||
self.delivered_callback = callback
|
||||
|
||||
|
||||
def delivered(self):
|
||||
with self.lock:
|
||||
self.state = MessageState.MSGSTATE_DELIVERED
|
||||
|
@ -187,7 +187,7 @@ class TestIdentity(unittest.TestCase):
|
||||
lb = 1
|
||||
else:
|
||||
lb = 8
|
||||
|
||||
|
||||
for i in range(1, lb):
|
||||
msg = os.urandom(mlen)
|
||||
b += mlen
|
||||
|
@ -105,7 +105,7 @@ class TestLink(unittest.TestCase):
|
||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||
|
||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||
|
||||
|
||||
l1 = RNS.Link(dest)
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||
@ -129,7 +129,7 @@ class TestLink(unittest.TestCase):
|
||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||
|
||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||
|
||||
|
||||
l1 = RNS.Link(dest)
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||
@ -176,7 +176,7 @@ class TestLink(unittest.TestCase):
|
||||
if n_failed > 0:
|
||||
ns = "s" if n_failed != 1 else ""
|
||||
print(f"Failed to receive proof for {n_failed} packet{ns}")
|
||||
|
||||
|
||||
self.assertEqual(all_ok, True)
|
||||
print("OK!")
|
||||
print(f"Single packet and proof round-trip throughput is {self.size_str(b / pduration, 'b')}ps")
|
||||
@ -201,7 +201,7 @@ class TestLink(unittest.TestCase):
|
||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||
|
||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||
|
||||
|
||||
l1 = RNS.Link(dest)
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||
@ -241,7 +241,7 @@ class TestLink(unittest.TestCase):
|
||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||
|
||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||
|
||||
|
||||
l1 = RNS.Link(dest)
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||
@ -280,7 +280,7 @@ class TestLink(unittest.TestCase):
|
||||
|
||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||
|
||||
|
||||
l1 = RNS.Link(dest)
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||
@ -310,7 +310,7 @@ class TestLink(unittest.TestCase):
|
||||
if RNS.Cryptography.backend() == "internal":
|
||||
print("Skipping medium resource test...")
|
||||
return
|
||||
|
||||
|
||||
init_rns(self)
|
||||
print("")
|
||||
print("Medium resource test")
|
||||
@ -324,7 +324,7 @@ class TestLink(unittest.TestCase):
|
||||
|
||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||
|
||||
|
||||
l1 = RNS.Link(dest)
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||
@ -371,7 +371,7 @@ class TestLink(unittest.TestCase):
|
||||
|
||||
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
|
||||
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
|
||||
|
||||
|
||||
l1 = RNS.Link(dest)
|
||||
time.sleep(0.5)
|
||||
self.assertEqual(l1.status, RNS.Link.ACTIVE)
|
||||
@ -553,11 +553,11 @@ class TestLink(unittest.TestCase):
|
||||
target_bytes = 3000
|
||||
else:
|
||||
target_bytes = BUFFER_TEST_TARGET
|
||||
|
||||
|
||||
random.seed(154889)
|
||||
message = random.randbytes(target_bytes)
|
||||
buffer_read_target = len(message)
|
||||
|
||||
|
||||
# the return message will have an appendage string " back at you"
|
||||
# for every StreamDataMessage that arrives. To verify, we need
|
||||
# to insert that string every MAX_DATA_LEN and also at the end.
|
||||
@ -572,7 +572,7 @@ class TestLink(unittest.TestCase):
|
||||
# StreamDataMessage, the appended text will end up in a
|
||||
# separate packet.
|
||||
print(f"Sending {len(message)} bytes, receiving {len(expected_rx_message)} bytes, ")
|
||||
|
||||
|
||||
buffer.write(message)
|
||||
buffer.flush()
|
||||
|
||||
@ -723,7 +723,7 @@ def profile_resource():
|
||||
resource_profiling()
|
||||
|
||||
def profile_targets():
|
||||
|
||||
|
||||
targets_profiling(yp=True)
|
||||
# cProfile.runctx("entry()", {"entry": targets_profiling, "size_str": size_str}, {}, "profile-targets.data")
|
||||
# p = pstats.Stats("profile-targets.data")
|
||||
@ -749,7 +749,7 @@ def resource_profiling():
|
||||
|
||||
import yappi
|
||||
yappi.start()
|
||||
|
||||
|
||||
resource = RNS.Resource(data, l1, timeout=resource_timeout)
|
||||
start = time.time()
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user