remove dangling spaces

This commit is contained in:
Pavol Rusnak 2024-10-07 10:52:43 +02:00
parent ce9dc56048
commit 06b9555462
No known key found for this signature in database
GPG Key ID: 91F3B339B9A02A3D
62 changed files with 763 additions and 763 deletions

View File

@ -1247,7 +1247,7 @@ This beta release brings a range of improvements and bugfixes.
- Improved documentation. - Improved documentation.
- Improved request timeouts and handling. - Improved request timeouts and handling.
- Improved link establishment. - Improved link establishment.
- Improved resource transfer timing. - Improved resource transfer timing.
**Fixed bugs** **Fixed bugs**
- Fixed a race condition in inbound proof handling. - Fixed a race condition in inbound proof handling.

View File

@ -22,7 +22,7 @@ noble_gases = ["Helium", "Neon", "Argon", "Krypton", "Xenon", "Radon", "Oganesso
def program_setup(configpath): def program_setup(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our example # Randomly create a new identity for our example
identity = RNS.Identity() identity = RNS.Identity()
@ -70,7 +70,7 @@ def program_setup(configpath):
# We register the announce handler with Reticulum # We register the announce handler with Reticulum
RNS.Transport.register_announce_handler(announce_handler) RNS.Transport.register_announce_handler(announce_handler)
# Everything's ready! # Everything's ready!
# Let's hand over control to the announce loop # Let's hand over control to the announce loop
announceLoop(destination_1, destination_2) announceLoop(destination_1, destination_2)
@ -86,7 +86,7 @@ def announceLoop(destination_1, destination_2):
# know how to create messages directed towards it. # know how to create messages directed towards it.
while True: while True:
entered = input() entered = input()
# Randomly select a fruit # Randomly select a fruit
fruit = fruits[random.randint(0,len(fruits)-1)] fruit = fruits[random.randint(0,len(fruits)-1)]

View File

@ -17,7 +17,7 @@ APP_NAME = "example_utilities"
def program_setup(configpath, channel=None): def program_setup(configpath, channel=None):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# If the user did not select a "channel" we use # If the user did not select a "channel" we use
# a default one called "public_information". # a default one called "public_information".
# This "channel" is added to the destination name- # 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 # We specify a callback that will get called every time
# the destination receives data. # the destination receives data.
broadcast_destination.set_packet_callback(packet_callback) broadcast_destination.set_packet_callback(packet_callback)
# Everything's ready! # Everything's ready!
# Let's hand over control to the main loop # Let's hand over control to the main loop
broadcastLoop(broadcast_destination) broadcastLoop(broadcast_destination)

View File

@ -35,7 +35,7 @@ latest_buffer = None
def server(configpath): def server(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our example # Randomly create a new identity for our example
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -151,7 +151,7 @@ def client(destination_hexhash, configpath):
raise ValueError( raise ValueError(
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
) )
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except: except:
RNS.log("Invalid destination entered. Check your input!\n") 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") RNS.log("The link was closed by the server, exiting now")
else: else:
RNS.log("Link closed, exiting now") RNS.log("Link closed, exiting now")
RNS.Reticulum.exit_handler() RNS.Reticulum.exit_handler()
time.sleep(1.5) time.sleep(1.5)
os._exit(0) os._exit(0)

View File

@ -98,7 +98,7 @@ latest_client_link = None
def server(configpath): def server(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our link example # Randomly create a new identity for our link example
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -206,7 +206,7 @@ def client(destination_hexhash, configpath):
raise ValueError( raise ValueError(
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
) )
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except: except:
RNS.log("Invalid destination entered. Check your input!\n") 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") RNS.log("The link was closed by the server, exiting now")
else: else:
RNS.log("Link closed, exiting now") RNS.log("Link closed, exiting now")
RNS.Reticulum.exit_handler() RNS.Reticulum.exit_handler()
time.sleep(1.5) time.sleep(1.5)
os._exit(0) os._exit(0)

View File

@ -26,7 +26,7 @@ def server(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our echo server # Randomly create a new identity for our echo server
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -35,7 +35,7 @@ def server(configpath):
# create a "single" destination that can receive encrypted # create a "single" destination that can receive encrypted
# messages. This way the client can send a request and be # messages. This way the client can send a request and be
# certain that no-one else than this destination was able # certain that no-one else than this destination was able
# to read it. # to read it.
echo_destination = RNS.Destination( echo_destination = RNS.Destination(
server_identity, server_identity,
RNS.Destination.IN, RNS.Destination.IN,
@ -50,7 +50,7 @@ def server(configpath):
# generate a proof for each incoming packet and transmit it # generate a proof for each incoming packet and transmit it
# back to the sender of that packet. # back to the sender of that packet.
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
# Tell the destination which function in our program to # Tell the destination which function in our program to
# run when a packet is received. We do this so we can # run when a packet is received. We do this so we can
# print a log message when the server receives a request # print a log message when the server receives a request
@ -79,7 +79,7 @@ def announceLoop(destination):
def server_callback(message, packet): def server_callback(message, packet):
global reticulum global reticulum
# Tell the user that we received an echo request, and # Tell the user that we received an echo request, and
# that we are going to send a reply to the requester. # that we are going to send a reply to the requester.
# Sending the proof is handled automatically, since we # Sending the proof is handled automatically, since we
@ -92,14 +92,14 @@ def server_callback(message, packet):
if reception_rssi != None: if reception_rssi != None:
reception_stats += f" [RSSI {reception_rssi} dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += f" [SNR {reception_snr} dBm]" reception_stats += f" [SNR {reception_snr} dBm]"
else: else:
if packet.rssi != None: if packet.rssi != None:
reception_stats += f" [RSSI {packet.rssi} dBm]" reception_stats += f" [RSSI {packet.rssi} dBm]"
if packet.snr != None: if packet.snr != None:
reception_stats += f" [SNR {packet.snr} dB]" reception_stats += f" [SNR {packet.snr} dB]"
@ -114,7 +114,7 @@ def server_callback(message, packet):
# to run as a client # to run as a client
def client(destination_hexhash, configpath, timeout=None): def client(destination_hexhash, configpath, timeout=None):
global reticulum global reticulum
# We need a binary representation of the destination # We need a binary representation of the destination
# hash that was entered on the command line # hash that was entered on the command line
try: try:
@ -149,7 +149,7 @@ def client(destination_hexhash, configpath, timeout=None):
# command line. # command line.
while True: while True:
input() input()
# Let's first check if RNS knows a path to the destination. # 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 it does, we'll load the server identity and create a packet
if RNS.Transport.has_path(destination_hash): if RNS.Transport.has_path(destination_hash):
@ -230,7 +230,7 @@ def packet_delivered(receipt):
if reception_rssi != None: if reception_rssi != None:
reception_stats += f" [RSSI {reception_rssi} dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += f" [SNR {reception_snr} dB]" reception_stats += f" [SNR {reception_snr} dB]"
@ -238,7 +238,7 @@ def packet_delivered(receipt):
if receipt.proof_packet != None: if receipt.proof_packet != None:
if receipt.proof_packet.rssi != None: if receipt.proof_packet.rssi != None:
reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]"
if receipt.proof_packet.snr != None: if receipt.proof_packet.snr != None:
reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" reception_stats += f" [SNR {receipt.proof_packet.snr} dB]"

View File

@ -44,7 +44,7 @@ serve_path = None
def server(configpath, path): def server(configpath, path):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our file server # Randomly create a new identity for our file server
server_identity = RNS.Identity() 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("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("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) RNS.log("Hint: The client already supports it :)", RNS.LOG_ERROR)
# After this, we're just going to keep the link # After this, we're just going to keep the link
# open until the client requests a file. We'll # open until the client requests a file. We'll
# configure a function that get's called when # 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 # read it and pack it as a resource
RNS.log(f"Client requested \"{filename}\"") RNS.log(f"Client requested \"{filename}\"")
file = open(os.path.join(serve_path, filename), "rb") file = open(os.path.join(serve_path, filename), "rb")
file_resource = RNS.Resource( file_resource = RNS.Resource(
file, file,
packet.link, packet.link,
@ -220,7 +220,7 @@ def client(destination_hexhash, configpath):
raise ValueError( raise ValueError(
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
) )
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except: except:
RNS.log("Invalid destination entered. Check your input!\n") RNS.log("Invalid destination entered. Check your input!\n")
@ -291,7 +291,7 @@ def download(filename):
# packet receipt. # packet receipt.
request_packet = RNS.Packet(server_link, filename.encode("utf-8"), create_receipt=False) request_packet = RNS.Packet(server_link, filename.encode("utf-8"), create_receipt=False)
request_packet.send() request_packet.send()
print("") print("")
print(f"Requested \"{filename}\" from server, waiting for download to begin...") print(f"Requested \"{filename}\" from server, waiting for download to begin...")
menu_mode = "download_started" menu_mode = "download_started"
@ -474,7 +474,7 @@ def link_closed(link):
RNS.log("The link was closed by the server, exiting now") RNS.log("The link was closed by the server, exiting now")
else: else:
RNS.log("Link closed, exiting now") RNS.log("Link closed, exiting now")
RNS.Reticulum.exit_handler() RNS.Reticulum.exit_handler()
time.sleep(1.5) time.sleep(1.5)
os._exit(0) os._exit(0)
@ -486,17 +486,17 @@ def link_closed(link):
def download_began(resource): def download_began(resource):
global menu_mode, current_download, download_started, transfer_size, file_size global menu_mode, current_download, download_started, transfer_size, file_size
current_download = resource current_download = resource
if download_started == 0: if download_started == 0:
download_started = time.time() download_started = time.time()
transfer_size += resource.size transfer_size += resource.size
file_size = resource.total_size file_size = resource.total_size
menu_mode = "downloading" menu_mode = "downloading"
# When the download concludes, successfully # 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. # inform the user about how it all went.
def download_concluded(resource): def download_concluded(resource):
global menu_mode, current_filename, download_started, download_finished, download_time global menu_mode, current_filename, download_started, download_finished, download_time

View File

@ -27,7 +27,7 @@ latest_client_link = None
def server(configpath): def server(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our link example # Randomly create a new identity for our link example
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -99,7 +99,7 @@ def server_packet_received(message, packet):
text = message.decode("utf-8") text = message.decode("utf-8")
RNS.log(f"Received data from {remote_peer}: {text}") RNS.log(f"Received data from {remote_peer}: {text}")
reply_text = f"I received \"{text}\" over the link from {remote_peer}" reply_text = f"I received \"{text}\" over the link from {remote_peer}"
reply_data = reply_text.encode("utf-8") reply_data = reply_text.encode("utf-8")
RNS.Packet(latest_client_link, reply_data).send() 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") RNS.log("The link was closed by the server, exiting now")
else: else:
RNS.log("Link closed, exiting now") RNS.log("Link closed, exiting now")
RNS.Reticulum.exit_handler() RNS.Reticulum.exit_handler()
time.sleep(1.5) time.sleep(1.5)
os._exit(0) os._exit(0)

View File

@ -27,7 +27,7 @@ latest_client_link = None
def server(configpath): def server(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our link example # Randomly create a new identity for our link example
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -89,7 +89,7 @@ def server_packet_received(message, packet):
# that connected. # that connected.
text = message.decode("utf-8") text = message.decode("utf-8")
RNS.log(f"Received data on the link: {text}") RNS.log(f"Received data on the link: {text}")
reply_text = f"I received \"{text}\" over the link" reply_text = f"I received \"{text}\" over the link"
reply_data = reply_text.encode("utf-8") reply_data = reply_text.encode("utf-8")
RNS.Packet(latest_client_link, reply_data).send() RNS.Packet(latest_client_link, reply_data).send()
@ -113,7 +113,7 @@ def client(destination_hexhash, configpath):
raise ValueError( raise ValueError(
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
) )
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except: except:
RNS.log("Invalid destination entered. Check your input!\n") 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") RNS.log("The link was closed by the server, exiting now")
else: else:
RNS.log("Link closed, exiting now") RNS.log("Link closed, exiting now")
RNS.Reticulum.exit_handler() RNS.Reticulum.exit_handler()
time.sleep(1.5) time.sleep(1.5)
os._exit(0) os._exit(0)

View File

@ -17,7 +17,7 @@ APP_NAME = "example_utilities"
def program_setup(configpath): def program_setup(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our example # Randomly create a new identity for our example
identity = RNS.Identity() identity = RNS.Identity()
@ -42,7 +42,7 @@ def program_setup(configpath):
# tries to communicate with the destination know whether their # tries to communicate with the destination know whether their
# communication was received correctly. # communication was received correctly.
destination.set_proof_strategy(RNS.Destination.PROVE_ALL) destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
# Everything's ready! # Everything's ready!
# Let's hand over control to the announce loop # Let's hand over control to the announce loop
announceLoop(destination) announceLoop(destination)

View File

@ -28,7 +28,7 @@ def server(configpath):
# TODO: Remove # TODO: Remove
RNS.loglevel = RNS.LOG_DEBUG RNS.loglevel = RNS.LOG_DEBUG
# Randomly create a new identity for our echo server # Randomly create a new identity for our echo server
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -37,7 +37,7 @@ def server(configpath):
# create a "single" destination that can receive encrypted # create a "single" destination that can receive encrypted
# messages. This way the client can send a request and be # messages. This way the client can send a request and be
# certain that no-one else than this destination was able # certain that no-one else than this destination was able
# to read it. # to read it.
echo_destination = RNS.Destination( echo_destination = RNS.Destination(
server_identity, server_identity,
RNS.Destination.IN, RNS.Destination.IN,
@ -61,7 +61,7 @@ def server(configpath):
# generate a proof for each incoming packet and transmit it # generate a proof for each incoming packet and transmit it
# back to the sender of that packet. # back to the sender of that packet.
echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL) echo_destination.set_proof_strategy(RNS.Destination.PROVE_ALL)
# Tell the destination which function in our program to # Tell the destination which function in our program to
# run when a packet is received. We do this so we can # run when a packet is received. We do this so we can
# print a log message when the server receives a request # print a log message when the server receives a request
@ -90,7 +90,7 @@ def announceLoop(destination):
def server_callback(message, packet): def server_callback(message, packet):
global reticulum global reticulum
# Tell the user that we received an echo request, and # Tell the user that we received an echo request, and
# that we are going to send a reply to the requester. # that we are going to send a reply to the requester.
# Sending the proof is handled automatically, since we # Sending the proof is handled automatically, since we
@ -103,14 +103,14 @@ def server_callback(message, packet):
if reception_rssi != None: if reception_rssi != None:
reception_stats += f" [RSSI {reception_rssi} dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += f" [SNR {reception_snr} dBm]" reception_stats += f" [SNR {reception_snr} dBm]"
else: else:
if packet.rssi != None: if packet.rssi != None:
reception_stats += f" [RSSI {packet.rssi} dBm]" reception_stats += f" [RSSI {packet.rssi} dBm]"
if packet.snr != None: if packet.snr != None:
reception_stats += f" [SNR {packet.snr} dB]" reception_stats += f" [SNR {packet.snr} dB]"
@ -125,7 +125,7 @@ def server_callback(message, packet):
# to run as a client # to run as a client
def client(destination_hexhash, configpath, timeout=None): def client(destination_hexhash, configpath, timeout=None):
global reticulum global reticulum
# We need a binary representation of the destination # We need a binary representation of the destination
# hash that was entered on the command line # hash that was entered on the command line
try: try:
@ -160,7 +160,7 @@ def client(destination_hexhash, configpath, timeout=None):
# command line. # command line.
while True: while True:
input() input()
# Let's first check if RNS knows a path to the destination. # 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 it does, we'll load the server identity and create a packet
if RNS.Transport.has_path(destination_hash): if RNS.Transport.has_path(destination_hash):
@ -242,7 +242,7 @@ def packet_delivered(receipt):
if reception_rssi != None: if reception_rssi != None:
reception_stats += f" [RSSI {reception_rssi} dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += f" [SNR {reception_snr} dB]" reception_stats += f" [SNR {reception_snr} dB]"
@ -250,7 +250,7 @@ def packet_delivered(receipt):
if receipt.proof_packet != None: if receipt.proof_packet != None:
if receipt.proof_packet.rssi != None: if receipt.proof_packet.rssi != None:
reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]"
if receipt.proof_packet.snr != None: if receipt.proof_packet.snr != None:
reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" reception_stats += f" [SNR {receipt.proof_packet.snr} dB]"

View File

@ -33,7 +33,7 @@ def random_text_generator(path, data, request_id, link_id, remote_identity, requ
def server(configpath): def server(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our link example # Randomly create a new identity for our link example
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -113,7 +113,7 @@ def client(destination_hexhash, configpath):
raise ValueError( raise ValueError(
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
) )
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except: except:
RNS.log("Invalid destination entered. Check your input!\n") 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") RNS.log("The link was closed by the server, exiting now")
else: else:
RNS.log("Link closed, exiting now") RNS.log("Link closed, exiting now")
RNS.Reticulum.exit_handler() RNS.Reticulum.exit_handler()
time.sleep(1.5) time.sleep(1.5)
os._exit(0) os._exit(0)

View File

@ -36,7 +36,7 @@ printed = False
def server(configpath): def server(configpath):
# We must first initialise Reticulum # We must first initialise Reticulum
reticulum = RNS.Reticulum(configpath) reticulum = RNS.Reticulum(configpath)
# Randomly create a new identity for our link example # Randomly create a new identity for our link example
server_identity = RNS.Identity() server_identity = RNS.Identity()
@ -113,9 +113,9 @@ def size_str(num, suffix='B'):
def server_packet_received(message, packet): def server_packet_received(message, packet):
global latest_client_link, first_packet_at, last_packet_at, received_data, rc, data_cap global latest_client_link, first_packet_at, last_packet_at, received_data, rc, data_cap
received_data += len(packet.data) received_data += len(packet.data)
rc += 1 rc += 1
if rc >= 50: if rc >= 50:
RNS.log(size_str(received_data)) RNS.log(size_str(received_data))
@ -127,7 +127,7 @@ def server_packet_received(message, packet):
rc = 0 rc = 0
last_packet_at = time.time() last_packet_at = time.time()
# Print statistics # Print statistics
download_time = last_packet_at-first_packet_at download_time = last_packet_at-first_packet_at
hours, rem = divmod(download_time, 3600) hours, rem = divmod(download_time, 3600)
@ -169,7 +169,7 @@ def client(destination_hexhash, configpath):
raise ValueError( raise ValueError(
f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)." f"Destination length is invalid, must be {dest_len} hexadecimal characters ({dest_len // 2} bytes)."
) )
destination_hash = bytes.fromhex(destination_hexhash) destination_hash = bytes.fromhex(destination_hexhash)
except: except:
RNS.log("Invalid destination entered. Check your input!\n") 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") RNS.log("The link was closed by the server, exiting now")
else: else:
RNS.log("Link closed, exiting now") RNS.log("Link closed, exiting now")
RNS.Reticulum.exit_handler() RNS.Reticulum.exit_handler()
time.sleep(1.5) time.sleep(1.5)

View File

@ -109,8 +109,8 @@ network, and vice versa.
## How do I get started? ## How do I get started?
The best way to get started with the Reticulum Network Stack depends on what 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 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) [Getting Started Fast](https://markqvist.github.io/Reticulum/manual/gettingstartedfast.html)
section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/). section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
To simply install Reticulum and related utilities on your system, the easiest way is via `pip`. To simply install Reticulum and related utilities on your system, the easiest way is via `pip`.
@ -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. 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 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 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) 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/). section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
## Included Utilities ## Included Utilities
Reticulum includes a range of useful utilities for managing your networks, Reticulum includes a range of useful utilities for managing your networks,
viewing status and information, and other tasks. You can read more about these 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) 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/). section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
- The system daemon `rnsd` for running Reticulum as an always-available service - 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 It will be up most of the time, and anyone can join, but it also means that
there's no guarantees for service availability. 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 hardcoded or default interfaces in any applications you ship to users*. When
shipping applications, the best practice is to provide your own default shipping applications, the best practice is to provide your own default
connectivity solutions, if needed and applicable, or in most cases, simply connectivity solutions, if needed and applicable, or in most cases, simply

View File

@ -244,7 +244,7 @@ class RawChannelWriter(RawIOBase, AbstractContextManager):
processed_length = len(chunk) processed_length = len(chunk)
message = StreamDataMessage(self._stream_id, chunk, self._eof, comp_success) message = StreamDataMessage(self._stream_id, chunk, self._eof, comp_success)
self._channel.send(message) self._channel.send(message)
return processed_length return processed_length

View File

@ -136,7 +136,7 @@ class MessageBase(abc.ABC):
MSGTYPE = None MSGTYPE = None
""" """
Defines a unique identifier for a message class. Defines a unique identifier for a message class.
* Must be unique within all classes registered with a ``Channel`` * Must be unique within all classes registered with a ``Channel``
* Must be less than ``0xf000``. Values greater than or equal to ``0xf000`` are reserved. * 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 # The maximum window size for transfers on fast links
WINDOW_MAX_FAST = 48 WINDOW_MAX_FAST = 48
# For calculating maps and guard segments, this # For calculating maps and guard segments, this
# must be set to the global maximum window. # must be set to the global maximum window.
WINDOW_MAX = WINDOW_MAX_FAST WINDOW_MAX = WINDOW_MAX_FAST
# If the fast rate is sustained for this many request # If the fast rate is sustained for this many request
# rounds, the fast link window size will be allowed. # rounds, the fast link window size will be allowed.
FAST_RATE_THRESHOLD = 10 FAST_RATE_THRESHOLD = 10
@ -380,21 +380,21 @@ class Channel(contextlib.AbstractContextManager):
def _emplace_envelope(self, envelope: Envelope, ring: collections.deque[Envelope]) -> bool: def _emplace_envelope(self, envelope: Envelope, ring: collections.deque[Envelope]) -> bool:
with self._lock: with self._lock:
i = 0 i = 0
for existing in ring: for existing in ring:
if envelope.sequence == existing.sequence: if envelope.sequence == existing.sequence:
RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence {envelope.sequence}", RNS.LOG_EXTREME) RNS.log(f"Envelope: Emplacement of duplicate envelope with sequence {envelope.sequence}", RNS.LOG_EXTREME)
return False return False
if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2): if envelope.sequence < existing.sequence and not (self._next_rx_sequence - envelope.sequence) > (Channel.SEQ_MAX//2):
ring.insert(i, envelope) ring.insert(i, envelope)
envelope.tracked = True envelope.tracked = True
return True return True
i += 1 i += 1
envelope.tracked = True envelope.tracked = True
ring.append(envelope) ring.append(envelope)
@ -449,7 +449,7 @@ class Channel(contextlib.AbstractContextManager):
m = e.unpack(self._message_factories) m = e.unpack(self._message_factories)
else: else:
m = e.message m = e.message
self._rx_ring.remove(e) self._rx_ring.remove(e)
self._run_callbacks(m) self._run_callbacks(m)
@ -468,7 +468,7 @@ class Channel(contextlib.AbstractContextManager):
with self._lock: with self._lock:
outstanding = 0 outstanding = 0
for envelope in self._tx_ring: 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: if not envelope.packet or not self._outlet.get_packet_state(envelope.packet) == MessageState.MSGSTATE_DELIVERED:
outstanding += 1 outstanding += 1
@ -508,7 +508,7 @@ class Channel(contextlib.AbstractContextManager):
# TODO: Remove at some point # 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)+" 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) # RNS.log("Increased "+str(self)+" min window to "+str(self.window_min), RNS.LOG_DEBUG)
else: else:
self.fast_rate_rounds += 1 self.fast_rate_rounds += 1
if self.window_max < Channel.WINDOW_MAX_FAST and self.fast_rate_rounds == Channel.FAST_RATE_THRESHOLD: 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: with self._lock:
if not self.is_ready_to_send(): if not self.is_ready_to_send():
raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready") raise ChannelException(CEType.ME_LINK_NOT_READY, f"Link is not ready")
envelope = Envelope(self._outlet, message=message, sequence=self._next_sequence) envelope = Envelope(self._outlet, message=message, sequence=self._next_sequence)
self._next_sequence = (self._next_sequence + 1) % Channel.SEQ_MODULUS self._next_sequence = (self._next_sequence + 1) % Channel.SEQ_MODULUS
self._emplace_envelope(envelope, self._tx_ring) self._emplace_envelope(envelope, self._tx_ring)
@ -592,7 +592,7 @@ class Channel(contextlib.AbstractContextManager):
envelope.pack() envelope.pack()
if len(envelope.raw) > self._outlet.mdu: 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}") 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.packet = self._outlet.send(envelope.raw)
envelope.tries += 1 envelope.tries += 1
self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered) self._outlet.set_packet_delivered_callback(envelope.packet, self._packet_delivered)

View File

@ -25,7 +25,7 @@ import RNS.vendor.platformutils as pu
if cp.PROVIDER == cp.PROVIDER_INTERNAL: if cp.PROVIDER == cp.PROVIDER_INTERNAL:
from .aes import AES from .aes import AES
elif cp.PROVIDER == cp.PROVIDER_PYCA: elif cp.PROVIDER == cp.PROVIDER_PYCA:
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes 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)) cipher = Cipher(algorithms.AES(key), modes.CBC(iv))
else: else:
cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend()) cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=default_backend())
encryptor = cipher.encryptor() encryptor = cipher.encryptor()
ciphertext = encryptor.update(plaintext) + encryptor.finalize() ciphertext = encryptor.update(plaintext) + encryptor.finalize()
return ciphertext return ciphertext

View File

@ -49,7 +49,7 @@ class Fernet():
if len(key) != 32: if len(key) != 32:
raise ValueError(f"Token key must be 32 bytes, not {len(key)}") raise ValueError(f"Token key must be 32 bytes, not {len(key)}")
self._signing_key = key[:16] self._signing_key = key[:16]
self._encryption_key = key[16:] self._encryption_key = key[16:]

View File

@ -48,34 +48,34 @@ class sha256:
_h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, _h = (0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a,
0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19) 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19)
_output_size = 8 _output_size = 8
blocksize = 1 blocksize = 1
block_size = 64 block_size = 64
digest_size = 32 digest_size = 32
def __init__(self, m=None): def __init__(self, m=None):
self._buffer = b"" self._buffer = b""
self._counter = 0 self._counter = 0
if m is not None: if m is not None:
if type(m) is not bytes: if type(m) is not bytes:
raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}') raise TypeError(f'{self.__class__.__name__}() argument 1 must be bytes, not {type(m).__name__}')
self.update(m) self.update(m)
def _rotr(self, x, y): def _rotr(self, x, y):
return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF return ((x >> y) | (x << (32-y))) & 0xFFFFFFFF
def _sha256_process(self, c): def _sha256_process(self, c):
w = [0]*64 w = [0]*64
w[0:16] = struct.unpack('!16L', c) w[0:16] = struct.unpack('!16L', c)
for i in range(16, 64): for i in range(16, 64):
s0 = self._rotr(w[i-15], 7) ^ self._rotr(w[i-15], 18) ^ (w[i-15] >> 3) 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) 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 w[i] = (w[i-16] + s0 + w[i-7] + s1) & 0xFFFFFFFF
a,b,c,d,e,f,g,h = self._h a,b,c,d,e,f,g,h = self._h
for i in range(64): for i in range(64):
s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22) s0 = self._rotr(a, 2) ^ self._rotr(a, 13) ^ self._rotr(a, 22)
maj = (a & b) ^ (a & c) ^ (b & c) 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) s1 = self._rotr(e, 6) ^ self._rotr(e, 11) ^ self._rotr(e, 25)
ch = (e & f) ^ ((~e) & g) ch = (e & f) ^ ((~e) & g)
t1 = h + s1 + ch + self._k[i] + w[i] t1 = h + s1 + ch + self._k[i] + w[i]
h = g h = g
g = f g = f
f = e f = e
@ -92,38 +92,38 @@ class sha256:
c = b c = b
b = a b = a
a = (t1 + t2) & 0xFFFFFFFF a = (t1 + t2) & 0xFFFFFFFF
self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])] self._h = [(x+y) & 0xFFFFFFFF for x,y in zip(self._h, [a,b,c,d,e,f,g,h])]
def update(self, m): def update(self, m):
if not m: if not m:
return return
if type(m) is not bytes: if type(m) is not bytes:
raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}') raise TypeError(f'{sys._getframe().f_code.co_name}() argument 1 must be bytes, not {type(m).__name__}')
self._buffer += m self._buffer += m
self._counter += len(m) self._counter += len(m)
while len(self._buffer) >= 64: while len(self._buffer) >= 64:
self._sha256_process(self._buffer[:64]) self._sha256_process(self._buffer[:64])
self._buffer = self._buffer[64:] self._buffer = self._buffer[64:]
def digest(self): def digest(self):
mdi = self._counter & 0x3F mdi = self._counter & 0x3F
length = struct.pack('!Q', self._counter<<3) length = struct.pack('!Q', self._counter<<3)
if mdi < 56: if mdi < 56:
padlen = 55-mdi padlen = 55-mdi
else: else:
padlen = 119-mdi padlen = 119-mdi
r = self.copy() r = self.copy()
r.update(b'\x80'+(b'\x00'*padlen)+length) r.update(b'\x80'+(b'\x00'*padlen)+length)
return b''.join([struct.pack('!L', i) for i in r._h[:self._output_size]]) return b''.join([struct.pack('!L', i) for i in r._h[:self._output_size]])
def hexdigest(self): def hexdigest(self):
return self.digest().encode('hex') return self.digest().encode('hex')
def copy(self): def copy(self):
return copy.deepcopy(self) return copy.deepcopy(self)

View File

@ -138,9 +138,9 @@ class X25519PrivateKey:
peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key) peer_public_key = X25519PublicKey.from_public_bytes(peer_public_key)
start = time.time() start = time.time()
shared = _pack_number(_raw_curve25519(peer_public_key.x, self.a)) shared = _pack_number(_raw_curve25519(peer_public_key.x, self.a))
end = time.time() end = time.time()
duration = end-start duration = end-start
@ -150,7 +150,7 @@ class X25519PrivateKey:
if end > X25519PrivateKey.T_CLEAR: if end > X25519PrivateKey.T_CLEAR:
X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW X25519PrivateKey.T_CLEAR = end + X25519PrivateKey.DELAY_WINDOW
X25519PrivateKey.T_MAX = 0 X25519PrivateKey.T_MAX = 0
if duration < X25519PrivateKey.T_MAX or duration < X25519PrivateKey.MIN_EXEC_TIME: if duration < X25519PrivateKey.T_MAX or duration < X25519PrivateKey.MIN_EXEC_TIME:
target = start+X25519PrivateKey.T_MAX target = start+X25519PrivateKey.T_MAX

View File

@ -144,7 +144,7 @@ class AES:
return matrix2bytes(state) return matrix2bytes(state)
# will encrypt the entire data # will encrypt the entire data
def encrypt(self, plaintext, iv): def encrypt(self, plaintext, iv):
""" """
Encrypts `plaintext` using CBC mode and PKCS#7 padding, with the given Encrypts `plaintext` using CBC mode and PKCS#7 padding, with the given
@ -173,7 +173,7 @@ class AES:
return b''.join(ciphertext_blocks) return b''.join(ciphertext_blocks)
# will decrypt the entire data # will decrypt the entire data
def decrypt(self, ciphertext, iv): def decrypt(self, ciphertext, iv):
""" """
Decrypts `ciphertext` using CBC mode and PKCS#7 padding, with the given 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): for ciphertext_block in split_blocks(ciphertext):
# in CBC mode every block is XOR'd with the previous block # in CBC mode every block is XOR'd with the previous block
xorred = xor_bytes(previous, self._decrypt_block(ciphertext_block)) xorred = xor_bytes(previous, self._decrypt_block(ciphertext_block))
# append plaintext # append plaintext
plaintext_blocks.append(xorred) plaintext_blocks.append(xorred)
previous = ciphertext_block previous = ciphertext_block
@ -223,7 +223,7 @@ def test():
print("Single Block Tests") print("Single Block Tests")
print("------------------") print("------------------")
print(f"iv: {iv.hex()}") print(f"iv: {iv.hex()}")
print(f"plain text: '{single_block_text.decode()}'") print(f"plain text: '{single_block_text.decode()}'")
ciphertext_block = _aes._encrypt_block(single_block_text) ciphertext_block = _aes._encrypt_block(single_block_text)
plaintext_block = _aes._decrypt_block(ciphertext_block) plaintext_block = _aes._decrypt_block(ciphertext_block)
@ -268,4 +268,4 @@ def test():
if __name__ == "__main__": if __name__ == "__main__":
# test AES class # test AES class
test() test()

View File

@ -140,7 +140,7 @@ class Destination:
def __init__(self, identity, direction, type, app_name, *aspects): def __init__(self, identity, direction, type, app_name, *aspects):
# Check input values and build name string # 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 type in Destination.types: raise ValueError("Unknown destination type")
if not direction in Destination.directions: raise ValueError("Unknown destination direction") if not direction in Destination.directions: raise ValueError("Unknown destination direction")
@ -241,7 +241,7 @@ class Destination:
if self.direction != Destination.IN: if self.direction != Destination.IN:
raise TypeError("Only IN destination types can be announced") raise TypeError("Only IN destination types can be announced")
ratchet = b"" ratchet = b""
now = time.time() now = time.time()
stale_responses = [] stale_responses = []
@ -264,7 +264,7 @@ class Destination:
# multiple available paths, and to choose the best one. # 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) 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] announce_data = self.path_responses[tag][1]
else: else:
destination_hash = self.hash destination_hash = self.hash
random_hash = RNS.Identity.get_random_hash()[0:5]+int(time.time()).to_bytes(5, "big") 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() returned_app_data = self.default_app_data()
if isinstance(returned_app_data, bytes): if isinstance(returned_app_data, bytes):
app_data = returned_app_data app_data = returned_app_data
signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash+ratchet signed_data = self.hash+self.identity.get_public_key()+self.name_hash+random_hash+ratchet
if app_data != None: if app_data != None:
signed_data += app_data signed_data += app_data

View File

@ -137,7 +137,7 @@ class Identity:
# save, but the only changes. It might be possible to # save, but the only changes. It might be possible to
# simply overwrite on exit now that every local client # simply overwrite on exit now that every local client
# disconnect triggers a data persist. # disconnect triggers a data persist.
try: try:
if hasattr(Identity, "saving_known_destinations"): if hasattr(Identity, "saving_known_destinations"):
wait_interval = 0.2 wait_interval = 0.2
@ -279,7 +279,7 @@ class Identity:
ratchet_data = {"ratchet": ratchet, "received": time.time()} ratchet_data = {"ratchet": ratchet, "received": time.time()}
ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets" ratchetdir = f"{RNS.Reticulum.storagepath}/ratchets"
if not os.path.isdir(ratchetdir): if not os.path.isdir(ratchetdir):
os.makedirs(ratchetdir) os.makedirs(ratchetdir)
@ -290,7 +290,7 @@ class Identity:
ratchet_file.close() ratchet_file.close()
os.replace(outpath, finalpath) os.replace(outpath, finalpath)
threading.Thread(target=persist_job, daemon=True).start() threading.Thread(target=persist_job, daemon=True).start()
except Exception as e: except Exception as e:
@ -337,7 +337,7 @@ class Identity:
Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"] Identity.known_ratchets[destination_hash] = ratchet_data["ratchet"]
else: else:
return None return None
except Exception as e: 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"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) 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) RNS.log(f"Received invalid announce for {RNS.prettyhexrep(destination_hash)}: Invalid signature.", RNS.LOG_DEBUG)
del announced_identity del announced_identity
return False return False
except Exception as e: except Exception as e:
RNS.log(f"Error occurred while validating announce. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"Error occurred while validating announce. The contained exception was: {e}", RNS.LOG_ERROR)
return False return False
@ -567,7 +567,7 @@ class Identity:
self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes) self.prv = X25519PrivateKey.from_private_bytes(self.prv_bytes)
self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:] self.sig_prv_bytes = prv_bytes[Identity.KEYSIZE//8//2:]
self.sig_prv = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes) self.sig_prv = Ed25519PrivateKey.from_private_bytes(self.sig_prv_bytes)
self.pub = self.prv.public_key() self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes() self.pub_bytes = self.pub.public_bytes()
@ -640,7 +640,7 @@ class Identity:
target_public_key = self.pub target_public_key = self.pub
shared_key = ephemeral_key.exchange(target_public_key) shared_key = ephemeral_key.exchange(target_public_key)
derived_key = RNS.Cryptography.hkdf( derived_key = RNS.Cryptography.hkdf(
length=32, length=32,
derive_from=shared_key, derive_from=shared_key,
@ -690,9 +690,9 @@ class Identity:
plaintext = fernet.decrypt(ciphertext) plaintext = fernet.decrypt(ciphertext)
if ratchet_id_receiver: if ratchet_id_receiver:
ratchet_id_receiver.latest_ratchet_id = ratchet_id ratchet_id_receiver.latest_ratchet_id = ratchet_id
break break
except Exception as e: except Exception as e:
pass pass
@ -720,7 +720,7 @@ class Identity:
RNS.log(f"Decryption by {RNS.prettyhexrep(self.hash)} failed: {e}", RNS.LOG_DEBUG) RNS.log(f"Decryption by {RNS.prettyhexrep(self.hash)} failed: {e}", RNS.LOG_DEBUG)
if ratchet_id_receiver: if ratchet_id_receiver:
ratchet_id_receiver.latest_ratchet_id = None ratchet_id_receiver.latest_ratchet_id = None
return plaintext; return plaintext;
else: else:
RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG) RNS.log("Decryption failed because the token size was invalid.", RNS.LOG_DEBUG)
@ -739,7 +739,7 @@ class Identity:
""" """
if self.sig_prv != None: if self.sig_prv != None:
try: try:
return self.sig_prv.sign(message) return self.sig_prv.sign(message)
except Exception as e: except Exception as e:
RNS.log(f"The identity {self} could not sign the requested message. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The identity {self} could not sign the requested message. The contained exception was: {e}", RNS.LOG_ERROR)
raise e raise e
@ -770,7 +770,7 @@ class Identity:
proof_data = signature proof_data = signature
else: else:
proof_data = packet.packet_hash + signature proof_data = packet.packet_hash + signature
if destination == None: if destination == None:
destination = packet.generate_proof_destination() destination = packet.generate_proof_destination()

View File

@ -80,7 +80,7 @@ class AX25KISSInterface(Interface):
super().__init__() super().__init__()
self.HW_MTU = 564 self.HW_MTU = 564
self.pyserial = serial self.pyserial = serial
self.serial = None self.serial = None
self.owner = owner self.owner = owner
@ -343,7 +343,7 @@ class AX25KISSInterface(Interface):
self.online = False self.online = False
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) 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) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()

View File

@ -74,7 +74,7 @@ class KISSInterface(Interface):
from usbserial4a import serial4a as serial from usbserial4a import serial4a as serial
self.parity = "N" self.parity = "N"
else: else:
RNS.log("Could not load USB serial module for Android, KISS interface cannot be created.", RNS.LOG_CRITICAL) 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) 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") raise SystemError("Android-specific interface was used on non-Android OS")
super().__init__() super().__init__()
self.HW_MTU = 564 self.HW_MTU = 564
if beacon_data == None: if beacon_data == None:
beacon_data = "" beacon_data = ""
@ -172,7 +172,7 @@ class KISSInterface(Interface):
self.serial.timeout = 0.1 self.serial.timeout = 0.1
elif vid == 0x10C4: elif vid == 0x10C4:
# Hardware parameters for SiLabs CP210x @ 115200 baud # 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.USB_READ_TIMEOUT_MILLIS = 12
self.serial.timeout = 0.012 self.serial.timeout = 0.012
elif vid == 0x1A86 and pid == 0x55D4: elif vid == 0x1A86 and pid == 0x55D4:
@ -352,7 +352,7 @@ class KISSInterface(Interface):
data_buffer = data_buffer+bytes([byte]) data_buffer = data_buffer+bytes([byte])
elif (command == KISS.CMD_READY): elif (command == KISS.CMD_READY):
self.process_queue() self.process_queue()
if got == 0: if got == 0:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: if len(data_buffer) > 0 and time_since_last > self.timeout:
@ -379,7 +379,7 @@ class KISSInterface(Interface):
self.online = False self.online = False
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) 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) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()

View File

@ -42,7 +42,7 @@ class KISS():
FESC = 0xDB FESC = 0xDB
TFEND = 0xDC TFEND = 0xDC
TFESC = 0xDD TFESC = 0xDD
CMD_UNKNOWN = 0xFE CMD_UNKNOWN = 0xFE
CMD_DATA = 0x00 CMD_DATA = 0x00
CMD_FREQUENCY = 0x01 CMD_FREQUENCY = 0x01
@ -78,11 +78,11 @@ class KISS():
DETECT_REQ = 0x73 DETECT_REQ = 0x73
DETECT_RESP = 0x46 DETECT_RESP = 0x46
RADIO_STATE_OFF = 0x00 RADIO_STATE_OFF = 0x00
RADIO_STATE_ON = 0x01 RADIO_STATE_ON = 0x01
RADIO_STATE_ASK = 0xFF RADIO_STATE_ASK = 0xFF
CMD_ERROR = 0x90 CMD_ERROR = 0x90
ERROR_INITRADIO = 0x01 ERROR_INITRADIO = 0x01
ERROR_TXFAILED = 0x02 ERROR_TXFAILED = 0x02
@ -194,7 +194,7 @@ class AndroidBluetoothManager():
if self.rfcomm_reader != None: if self.rfcomm_reader != None:
self.rfcomm_reader.close() self.rfcomm_reader.close()
self.rfcomm_reader = None self.rfcomm_reader = None
if self.rfcomm_writer != None: if self.rfcomm_writer != None:
self.rfcomm_writer.close() self.rfcomm_writer.close()
self.rfcomm_writer = None self.rfcomm_writer = None
@ -371,7 +371,7 @@ class RNodeInterface(Interface):
else: else:
self.bt_manager = None self.bt_manager = None
else: else:
RNS.log("Could not load USB serial module for Android, RNode interface cannot be created.", RNS.LOG_CRITICAL) 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) RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
@ -382,7 +382,7 @@ class RNodeInterface(Interface):
super().__init__() super().__init__()
self.HW_MTU = 508 self.HW_MTU = 508
self.pyserial = serial self.pyserial = serial
self.serial = None self.serial = None
self.owner = owner 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.ble = BLEConnection(owner=self, target_name=self.ble_name, target_bt_addr=self.ble_addr)
# self.serial = self.ble # self.serial = self.ble
# RNS.log(f"New connection instance: "+str(self.ble)) # RNS.log(f"New connection instance: "+str(self.ble))
def open_port(self): def open_port(self):
if not self.use_ble: if not self.use_ble:
if self.port != None: if self.port != None:
@ -602,7 +602,7 @@ class RNodeInterface(Interface):
self.serial.timeout = 0.1 self.serial.timeout = 0.1
elif vid == 0x10C4: elif vid == 0x10C4:
# Hardware parameters for SiLabs CP210x @ 115200 baud # 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.USB_READ_TIMEOUT_MILLIS = 12
self.serial.timeout = 0.012 self.serial.timeout = 0.012
elif vid == 0x1A86 and pid == 0x55D4: 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(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("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
RNS.log("Aborting RNode startup", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
if self.serial != None: if self.serial != None:
self.serial.close() self.serial.close()
if self.bt_manager != None: if self.bt_manager != None:
self.bt_manager.close() self.bt_manager.close()
raise OSError("RNode interface did not pass configuration validation") raise OSError("RNode interface did not pass configuration validation")
def initRadio(self): def initRadio(self):
self.setFrequency() self.setFrequency()
@ -702,22 +702,22 @@ class RNodeInterface(Interface):
self.setBandwidth() self.setBandwidth()
time.sleep(0.15) time.sleep(0.15)
self.setTXPower() self.setTXPower()
time.sleep(0.15) time.sleep(0.15)
self.setSpreadingFactor() self.setSpreadingFactor()
time.sleep(0.15) time.sleep(0.15)
self.setCodingRate() self.setCodingRate()
time.sleep(0.15) time.sleep(0.15)
self.setSTALock() self.setSTALock()
time.sleep(0.15) time.sleep(0.15)
self.setLTALock() self.setLTALock()
time.sleep(0.15) time.sleep(0.15)
self.setRadioState(KISS.RADIO_STATE_ON) self.setRadioState(KISS.RADIO_STATE_ON)
time.sleep(0.15) time.sleep(0.15)
@ -735,7 +735,7 @@ class RNodeInterface(Interface):
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError("An IO error occurred while sending host left command to device") raise OSError("An IO error occurred while sending host left command to device")
def enable_bluetooth(self): def enable_bluetooth(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_BT_CTRL, 0x01, KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
@ -788,7 +788,7 @@ class RNodeInterface(Interface):
data = line_byte+line_data data = line_byte+line_data
escaped_data = KISS.escape(data) escaped_data = KISS.escape(data)
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
written = self.write_mux(kiss_command) written = self.write_mux(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError("An IO error occurred while writing framebuffer data device") 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.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN): if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
self.firmware_ok = True self.firmware_ok = True
if self.firmware_ok: if self.firmware_ok:
return return
@ -1188,7 +1188,7 @@ class RNodeInterface(Interface):
atl = command_buffer[2] << 8 | command_buffer[3] atl = command_buffer[2] << 8 | command_buffer[3]
cus = command_buffer[4] << 8 | command_buffer[5] cus = command_buffer[4] << 8 | command_buffer[5]
cul = command_buffer[6] << 8 | command_buffer[7] cul = command_buffer[6] << 8 | command_buffer[7]
self.r_airtime_short = ats/100.0 self.r_airtime_short = ats/100.0
self.r_airtime_long = atl/100.0 self.r_airtime_long = atl/100.0
self.r_channel_load_short = cus/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: 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) RNS.log(f"Interface {self} is transmitting beacon data: {self.id_callsign.decode('utf-8')}", RNS.LOG_DEBUG)
self.processOutgoing(self.id_callsign) self.processOutgoing(self.id_callsign)
if (time.time() - self.last_port_io > self.port_io_timeout): if (time.time() - self.last_port_io > self.port_io_timeout):
self.detect() self.detect()
if (time.time() - self.last_port_io > self.port_io_timeout*3): if (time.time() - self.last_port_io > self.port_io_timeout*3):
raise OSError(f"Connected port for {self} became unresponsive") raise OSError(f"Connected port for {self} became unresponsive")
@ -1343,7 +1343,7 @@ class RNodeInterface(Interface):
if self.last_imagedata != None: if self.last_imagedata != None:
self.display_image(self.last_imagedata) self.display_image(self.last_imagedata)
self.enable_external_framebuffer() self.enable_external_framebuffer()
elif hasattr(self, "bt_manager") and self.bt_manager != None and self.bt_manager.connected: elif hasattr(self, "bt_manager") and self.bt_manager != None and self.bt_manager.connected:
self.configure_device() self.configure_device()
if self.online: if self.online:
@ -1504,7 +1504,7 @@ class BLEConnection(BluetoothDispatcher):
self.write_characteristic(self.rx_char, data) self.write_characteristic(self.rx_char, data)
else: else:
time.sleep(0.1) time.sleep(0.1)
except Exception as e: except Exception as e:
RNS.log("An error occurred in {self} write loop: {e}", RNS.LOG_ERROR) RNS.log("An error occurred in {self} write loop: {e}", RNS.LOG_ERROR)
RNS.trace_exception(e) 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.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.close()
self.should_run = False self.should_run = False
self.close_gatt() self.close_gatt()
self.connect_job_running = False self.connect_job_running = False
@ -1599,14 +1599,14 @@ class BLEConnection(BluetoothDispatcher):
def on_services(self, status, services): def on_services(self, status, services):
if status == GATT_SUCCESS: if status == GATT_SUCCESS:
self.rx_char = services.search(BLEConnection.UART_RX_CHAR_UUID) self.rx_char = services.search(BLEConnection.UART_RX_CHAR_UUID)
if self.rx_char is not None: if self.rx_char is not None:
self.tx_char = services.search(BLEConnection.UART_TX_CHAR_UUID) 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): if self.enable_notifications(self.tx_char):
RNS.log("Enabled notifications for BLE TX characteristic", RNS.LOG_DEBUG) 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) RNS.log(f"Requesting BLE connection MTU update to {self.target_mtu}", RNS.LOG_DEBUG)
self.mtu_requested_time = time.time() self.mtu_requested_time = time.time()
self.request_mtu(self.target_mtu) self.request_mtu(self.target_mtu)

View File

@ -64,7 +64,7 @@ class SerialInterface(Interface):
from usbserial4a import serial4a as serial from usbserial4a import serial4a as serial
self.parity = "N" self.parity = "N"
else: else:
RNS.log("Could not load USB serial module for Android, Serial interface cannot be created.", RNS.LOG_CRITICAL) 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) RNS.log("You can install this module by issuing: pip install usbserial4a", RNS.LOG_CRITICAL)
@ -75,7 +75,7 @@ class SerialInterface(Interface):
super().__init__() super().__init__()
self.HW_MTU = 564 self.HW_MTU = 564
self.pyserial = serial self.pyserial = serial
self.serial = None self.serial = None
self.owner = owner self.owner = owner
@ -145,7 +145,7 @@ class SerialInterface(Interface):
self.serial.timeout = 0.1 self.serial.timeout = 0.1
elif vid == 0x10C4: elif vid == 0x10C4:
# Hardware parameters for SiLabs CP210x @ 115200 baud # 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.USB_READ_TIMEOUT_MILLIS = 12
self.serial.timeout = 0.012 self.serial.timeout = 0.012
elif vid == 0x1A86 and pid == 0x55D4: elif vid == 0x1A86 and pid == 0x55D4:
@ -182,7 +182,7 @@ class SerialInterface(Interface):
if self.online: if self.online:
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG]) data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
written = self.serial.write(data) written = self.serial.write(data)
self.txb += len(data) self.txb += len(data)
if written != len(data): if written != len(data):
raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}")
@ -217,7 +217,7 @@ class SerialInterface(Interface):
byte = HDLC.ESC byte = HDLC.ESC
escape = False escape = False
data_buffer = data_buffer+bytes([byte]) data_buffer = data_buffer+bytes([byte])
if got == 0: if got == 0:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: if len(data_buffer) > 0 and time_since_last > self.timeout:
@ -225,12 +225,12 @@ class SerialInterface(Interface):
in_frame = False in_frame = False
escape = False escape = False
# sleep(0.08) # sleep(0.08)
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) 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) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()

View File

@ -289,7 +289,7 @@ class AutoInterface(Interface):
udp_server = socketserver.UDPServer(address, self.handler_factory(self.processIncoming)) udp_server = socketserver.UDPServer(address, self.handler_factory(self.processIncoming))
self.interface_servers[ifname] = udp_server self.interface_servers[ifname] = udp_server
thread = threading.Thread(target=udp_server.serve_forever) thread = threading.Thread(target=udp_server.serve_forever)
thread.daemon = True thread.daemon = True
thread.start() thread.start()
@ -306,11 +306,11 @@ class AutoInterface(Interface):
def discovery_handler(self, socket, ifname): def discovery_handler(self, socket, ifname):
def announce_loop(): def announce_loop():
self.announce_handler(ifname) self.announce_handler(ifname)
thread = threading.Thread(target=announce_loop) thread = threading.Thread(target=announce_loop)
thread.daemon = True thread.daemon = True
thread.start() thread.start()
while True: while True:
data, ipv6_src = socket.recvfrom(1024) data, ipv6_src = socket.recvfrom(1024)
expected_hash = RNS.Identity.full_hash(self.group_id+ipv6_src[0].encode("utf-8")) 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 self.carrier_changed = True
RNS.log(f"{self} Carrier recovered on {ifname}", RNS.LOG_WARNING) RNS.log(f"{self} Carrier recovered on {ifname}", RNS.LOG_WARNING)
self.timed_out_interfaces[ifname] = False self.timed_out_interfaces[ifname] = False
def announce_handler(self, ifname): def announce_handler(self, ifname):
while True: while True:
self.peer_announce(ifname) self.peer_announce(ifname)
time.sleep(self.announce_interval) time.sleep(self.announce_interval)
def peer_announce(self, ifname): def peer_announce(self, ifname):
try: try:
link_local_address = self.adopted_interfaces[ifname] 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.setsockopt(socket.IPPROTO_IPV6, socket.IPV6_MULTICAST_IF, ifis)
announce_socket.sendto(discovery_token, addr_info[0][4]) announce_socket.sendto(discovery_token, addr_info[0][4])
announce_socket.close() announce_socket.close()
except Exception as e: 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: 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) 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: except Exception as e:
RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR)
self.txb += len(data) self.txb += len(data)
# Until per-device sub-interfacing is implemented, # Until per-device sub-interfacing is implemented,
# ingress limiting should be disabled on AutoInterface # ingress limiting should be disabled on AutoInterface

View File

@ -143,11 +143,11 @@ class I2PController:
self.loop.ext_owner = self self.loop.ext_owner = self
result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result() result = asyncio.run_coroutine_threadsafe(tunnel_up(), self.loop).result()
if not i2p_destination in self.i2plib_tunnels: if not i2p_destination in self.i2plib_tunnels:
raise OSError("No tunnel control instance was created") raise OSError("No tunnel control instance was created")
else: else:
tn = self.i2plib_tunnels[i2p_destination] tn = self.i2plib_tunnels[i2p_destination]
if tn != None and hasattr(tn, "status"): if tn != None and hasattr(tn, "status"):
@ -183,7 +183,7 @@ class I2PController:
except ConnectionRefusedError as e: except ConnectionRefusedError as e:
raise e raise e
except ConnectionAbortedError as e: except ConnectionAbortedError as e:
raise e raise e
@ -222,13 +222,13 @@ class I2PController:
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.KeyNotFound): 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) 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): 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) 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): elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError):
RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR)
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): 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) 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: elif i2p_exception != None:
RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR) RNS.log("An error ocurred while setting up I2P tunnel", RNS.LOG_ERROR)
if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer): if isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.CantReachPeer):
RNS.log(f"The I2P daemon can't reach peer {i2p_destination}", RNS.LOG_ERROR) 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): 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) 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): 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) 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): elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.I2PError):
RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR) RNS.log("The I2P daemon experienced an unspecified error", RNS.LOG_ERROR)
elif isinstance(i2p_exception, RNS.vendor.i2plib.exceptions.Timeout): 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) 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__() super().__init__()
self.HW_MTU = 1064 self.HW_MTU = 1064
self.IN = True self.IN = True
self.OUT = False self.OUT = False
self.socket = None self.socket = None
@ -492,7 +492,7 @@ class I2PInterfacePeer(Interface):
while self.awaiting_i2p_tunnel: while self.awaiting_i2p_tunnel:
time.sleep(0.25) time.sleep(0.25)
time.sleep(2) time.sleep(2)
if not self.kiss_framing: if not self.kiss_framing:
self.wants_tunnel = True 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.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(I2PInterfacePeer.I2P_PROBE_AFTER)) self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(I2PInterfacePeer.I2P_PROBE_AFTER))
def shutdown_socket(self, target_socket): def shutdown_socket(self, target_socket):
if callable(target_socket.close): if callable(target_socket.close):
try: try:
@ -538,15 +538,15 @@ class I2PInterfacePeer(Interface):
if socket != None: if socket != None:
target_socket.close() target_socket.close()
except Exception as e: 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): def detach(self):
RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
if self.socket != None: if self.socket != None:
if hasattr(self.socket, "close"): if hasattr(self.socket, "close"):
if callable(self.socket.close): if callable(self.socket.close):
self.detached = True self.detached = True
try: try:
self.socket.shutdown(socket.SHUT_RDWR) self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: except Exception as e:
@ -564,7 +564,7 @@ class I2PInterfacePeer(Interface):
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.socket.connect((self.target_ip, self.target_port)) self.socket.connect((self.target_ip, self.target_port))
self.online = True self.online = True
except Exception as e: except Exception as e:
if initial: if initial:
if not self.awaiting_i2p_tunnel: 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) RNS.log(f"Leaving unconnected and retrying connection in {I2PInterfacePeer.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR)
return False return False
else: else:
raise e raise e
@ -580,7 +580,7 @@ class I2PInterfacePeer(Interface):
self.set_timeouts_linux() self.set_timeouts_linux()
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
self.set_timeouts_osx() self.set_timeouts_osx()
self.online = True self.online = True
self.writing = False self.writing = False
self.never_connected = False self.never_connected = False
@ -631,7 +631,7 @@ class I2PInterfacePeer(Interface):
self.rxb += len(data) self.rxb += len(data)
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count: if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
self.parent_interface.rxb += len(data) self.parent_interface.rxb += len(data)
self.owner.inbound(data, self) self.owner.inbound(data, self)
def processOutgoing(self, data): def processOutgoing(self, data):
@ -651,7 +651,7 @@ class I2PInterfacePeer(Interface):
self.writing = False self.writing = False
self.txb += len(data) self.txb += len(data)
self.last_write = time.time() self.last_write = time.time()
if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count: if hasattr(self, "parent_interface") and self.parent_interface != None and self.parent_count:
self.parent_interface.txb += len(data) 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) RNS.log(f"An error ocurred while sending I2P keepalive. The contained exception was: {e}", RNS.LOG_ERROR)
self.shutdown_socket(self.socket) self.shutdown_socket(self.socket)
should_run = False should_run = False
if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT): if (time.time()-self.last_read > I2PInterfacePeer.I2P_READ_TIMEOUT):
RNS.log("I2P socket is unresponsive, restarting...", RNS.LOG_WARNING) RNS.log("I2P socket is unresponsive, restarting...", RNS.LOG_WARNING)
if self.socket != None: if self.socket != None:
@ -790,7 +790,7 @@ class I2PInterfacePeer(Interface):
break break
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) 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): def __init__(self, owner, name, rns_storagepath, peers, connectable = False, ifac_size = 16, ifac_netname = None, ifac_netkey = None):
super().__init__() super().__init__()
self.HW_MTU = 1064 self.HW_MTU = 1064
self.online = False self.online = False
@ -882,7 +882,7 @@ class I2PInterface(Interface):
def createHandler(*args, **keys): def createHandler(*args, **keys):
return I2PInterfaceHandler(callback, *args, **keys) return I2PInterfaceHandler(callback, *args, **keys)
return createHandler return createHandler
ThreadingI2PServer.allow_reuse_address = True ThreadingI2PServer.allow_reuse_address = True
self.server = ThreadingI2PServer(self.address, handlerFactory(self.incoming_connection)) self.server = ThreadingI2PServer(self.address, handlerFactory(self.incoming_connection))

View File

@ -146,7 +146,7 @@ class Interface:
def release(): def release():
RNS.Transport.inbound(selected_announce_packet.raw, selected_announce_packet.receiving_interface) RNS.Transport.inbound(selected_announce_packet.raw, selected_announce_packet.receiving_interface)
threading.Thread(target=release, daemon=True).start() threading.Thread(target=release, daemon=True).start()
except Exception as e: except Exception as e:
RNS.log(f"An error occurred while processing held announces for {self}", RNS.LOG_ERROR) 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) RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
@ -170,7 +170,7 @@ class Interface:
for i in range(1,dq_len): for i in range(1,dq_len):
delta_sum += self.ia_freq_deque[i]-self.ia_freq_deque[i-1] delta_sum += self.ia_freq_deque[i]-self.ia_freq_deque[i-1]
delta_sum += time.time() - self.ia_freq_deque[dq_len-1] delta_sum += time.time() - self.ia_freq_deque[dq_len-1]
if delta_sum == 0: if delta_sum == 0:
avg = 0 avg = 0
else: else:
@ -187,7 +187,7 @@ class Interface:
for i in range(1,dq_len): for i in range(1,dq_len):
delta_sum += self.oa_freq_deque[i]-self.oa_freq_deque[i-1] delta_sum += self.oa_freq_deque[i]-self.oa_freq_deque[i-1]
delta_sum += time.time() - self.oa_freq_deque[dq_len-1] delta_sum += time.time() - self.oa_freq_deque[dq_len-1]
if delta_sum == 0: if delta_sum == 0:
avg = 0 avg = 0
else: else:

View File

@ -71,9 +71,9 @@ class KISSInterface(Interface):
RNS.panic() RNS.panic()
super().__init__() super().__init__()
self.HW_MTU = 564 self.HW_MTU = 564
if beacon_data == None: if beacon_data == None:
beacon_data = "" beacon_data = ""
@ -218,7 +218,7 @@ class KISSInterface(Interface):
def processIncoming(self, data): def processIncoming(self, data):
self.rxb += len(data) self.rxb += len(data)
self.owner.inbound(data, self) self.owner.inbound(data, self)
@ -325,7 +325,7 @@ class KISSInterface(Interface):
self.online = False self.online = False
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) 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) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()

View File

@ -58,11 +58,11 @@ class LocalClientInterface(Interface):
# TODO: Remove at some point # TODO: Remove at some point
# self.rxptime = 0 # self.rxptime = 0
self.HW_MTU = 1064 self.HW_MTU = 1064
self.online = False self.online = False
self.IN = True self.IN = True
self.OUT = False self.OUT = False
self.socket = None self.socket = None
@ -146,7 +146,7 @@ class LocalClientInterface(Interface):
time.sleep(LocalClientInterface.RECONNECT_WAIT+2) time.sleep(LocalClientInterface.RECONNECT_WAIT+2)
RNS.Transport.shared_connection_reappeared() RNS.Transport.shared_connection_reappeared()
threading.Thread(target=job, daemon=True).start() threading.Thread(target=job, daemon=True).start()
else: else:
RNS.log("Attempt to reconnect on a non-initiator shared local interface. This should not happen.", RNS.LOG_ERROR) 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") raise OSError("Attempt to reconnect on a non-initiator local interface")
@ -156,10 +156,10 @@ class LocalClientInterface(Interface):
self.rxb += len(data) self.rxb += len(data)
if hasattr(self, "parent_interface") and self.parent_interface != None: if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.rxb += len(data) self.parent_interface.rxb += len(data)
# TODO: Remove at some point # TODO: Remove at some point
# processing_start = time.time() # processing_start = time.time()
self.owner.inbound(data, self) self.owner.inbound(data, self)
# TODO: Remove at some point # TODO: Remove at some point
@ -234,7 +234,7 @@ class LocalClientInterface(Interface):
break break
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log(f"An interface error occurred, the contained exception was: {e}", RNS.LOG_ERROR) 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): if callable(self.socket.close):
RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
self.detached = True self.detached = True
try: try:
self.socket.shutdown(socket.SHUT_RDWR) self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: except Exception as e:
@ -283,7 +283,7 @@ class LocalClientInterface(Interface):
if self.is_connected_to_shared_instance: if self.is_connected_to_shared_instance:
if nowarning == False: if nowarning == False:
RNS.log("Permanently lost connection to local shared RNS instance. Exiting now.", RNS.LOG_CRITICAL) RNS.log("Permanently lost connection to local shared RNS instance. Exiting now.", RNS.LOG_CRITICAL)
RNS.exit() RNS.exit()
@ -297,7 +297,7 @@ class LocalServerInterface(Interface):
super().__init__() super().__init__()
self.online = False self.online = False
self.clients = 0 self.clients = 0
self.IN = True self.IN = True
self.OUT = False self.OUT = False
self.name = "Reticulum" self.name = "Reticulum"

View File

@ -49,7 +49,7 @@ class PipeInterface(Interface):
owner = None owner = None
command = None command = None
def __init__(self, owner, name, command, respawn_delay): def __init__(self, owner, name, command, respawn_delay):
if respawn_delay == None: if respawn_delay == None:
respawn_delay = 5 respawn_delay = 5
@ -57,7 +57,7 @@ class PipeInterface(Interface):
super().__init__() super().__init__()
self.HW_MTU = 1064 self.HW_MTU = 1064
self.owner = owner self.owner = owner
self.name = name self.name = name
self.command = command self.command = command
@ -83,7 +83,7 @@ class PipeInterface(Interface):
def open_pipe(self): def open_pipe(self):
RNS.log(f"Connecting subprocess pipe for {self}...", RNS.LOG_VERBOSE) RNS.log(f"Connecting subprocess pipe for {self}...", RNS.LOG_VERBOSE)
try: try:
self.process = subprocess.Popen(shlex.split(self.command), stdin=subprocess.PIPE, stdout=subprocess.PIPE) self.process = subprocess.Popen(shlex.split(self.command), stdin=subprocess.PIPE, stdout=subprocess.PIPE)
self.pipe_is_open = True self.pipe_is_open = True
@ -102,7 +102,7 @@ class PipeInterface(Interface):
def processIncoming(self, data): def processIncoming(self, data):
self.rxb += len(data) self.rxb += len(data)
self.owner.inbound(data, self) self.owner.inbound(data, self)
@ -111,7 +111,7 @@ class PipeInterface(Interface):
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG]) data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
written = self.process.stdin.write(data) written = self.process.stdin.write(data)
self.process.stdin.flush() self.process.stdin.flush()
self.txb += len(data) self.txb += len(data)
if written != len(data): if written != len(data):
raise OSError(f"Pipe interface only wrote {written} bytes of {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}") RNS.log(f"Subprocess terminated on {self}")
self.process.kill() self.process.kill()
except Exception as e: except Exception as e:
self.online = False self.online = False
try: 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"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) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()

View File

@ -33,7 +33,7 @@ class KISS():
FESC = 0xDB FESC = 0xDB
TFEND = 0xDC TFEND = 0xDC
TFESC = 0xDD TFESC = 0xDD
CMD_UNKNOWN = 0xFE CMD_UNKNOWN = 0xFE
CMD_DATA = 0x00 CMD_DATA = 0x00
CMD_FREQUENCY = 0x01 CMD_FREQUENCY = 0x01
@ -69,11 +69,11 @@ class KISS():
DETECT_REQ = 0x73 DETECT_REQ = 0x73
DETECT_RESP = 0x46 DETECT_RESP = 0x46
RADIO_STATE_OFF = 0x00 RADIO_STATE_OFF = 0x00
RADIO_STATE_ON = 0x01 RADIO_STATE_ON = 0x01
RADIO_STATE_ASK = 0xFF RADIO_STATE_ASK = 0xFF
CMD_ERROR = 0x90 CMD_ERROR = 0x90
ERROR_INITRADIO = 0x01 ERROR_INITRADIO = 0x01
ERROR_TXFAILED = 0x02 ERROR_TXFAILED = 0x02
@ -91,7 +91,7 @@ class KISS():
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd])) data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc])) data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
return data return data
class RNodeInterface(Interface): class RNodeInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
@ -132,7 +132,7 @@ class RNodeInterface(Interface):
super().__init__() super().__init__()
self.HW_MTU = 508 self.HW_MTU = 508
self.pyserial = serial self.pyserial = serial
self.serial = None self.serial = None
self.owner = owner self.owner = owner
@ -287,7 +287,7 @@ class RNodeInterface(Interface):
write_timeout = None, write_timeout = None,
dsrdtr = False, dsrdtr = False,
) )
else: else:
RNS.log(f"Opening BLE connection for {self}...") RNS.log(f"Opening BLE connection for {self}...")
if self.ble != None and self.ble.running == False: if self.ble != None and self.ble.running == False:
@ -333,7 +333,7 @@ class RNodeInterface(Interface):
detect_time = RNS.prettytime(time.time()-detect_time) detect_time = RNS.prettytime(time.time()-detect_time)
else: else:
RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR) RNS.log(f"RNode detect timed out over {self.port}", RNS.LOG_ERROR)
if not self.detected: if not self.detected:
RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR)
self.serial.close() self.serial.close()
@ -354,7 +354,7 @@ class RNodeInterface(Interface):
RNS.log("Make sure that your hardware actually supports the parameters specified in the 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) RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
self.serial.close() self.serial.close()
def initRadio(self): def initRadio(self):
self.setFrequency() self.setFrequency()
@ -374,13 +374,13 @@ class RNodeInterface(Interface):
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError(f"An IO error occurred while detecting hardware for {self}") raise OSError(f"An IO error occurred while detecting hardware for {self}")
def leave(self): def leave(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError("An IO error occurred while sending host left command to device") raise OSError("An IO error occurred while sending host left command to device")
def enable_external_framebuffer(self): def enable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND])
@ -414,7 +414,7 @@ class RNodeInterface(Interface):
data = line_byte+line_data data = line_byte+line_data
escaped_data = KISS.escape(data) escaped_data = KISS.escape(data)
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError("An IO error occurred while writing framebuffer data device") raise OSError("An IO error occurred while writing framebuffer data device")
@ -509,7 +509,7 @@ class RNodeInterface(Interface):
if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ): if (self.maj_version >= RNodeInterface.REQUIRED_FW_VER_MAJ):
if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN): if (self.min_version >= RNodeInterface.REQUIRED_FW_VER_MIN):
self.firmware_ok = True self.firmware_ok = True
if self.firmware_ok: if self.firmware_ok:
return return
@ -799,7 +799,7 @@ class RNodeInterface(Interface):
atl = command_buffer[2] << 8 | command_buffer[3] atl = command_buffer[2] << 8 | command_buffer[3]
cus = command_buffer[4] << 8 | command_buffer[5] cus = command_buffer[4] << 8 | command_buffer[5]
cul = command_buffer[6] << 8 | command_buffer[7] cul = command_buffer[6] << 8 | command_buffer[7]
self.r_airtime_short = ats/100.0 self.r_airtime_short = ats/100.0
self.r_airtime_long = atl/100.0 self.r_airtime_long = atl/100.0
self.r_channel_load_short = cus/100.0 self.r_channel_load_short = cus/100.0
@ -885,7 +885,7 @@ class RNodeInterface(Interface):
self.detected = True self.detected = True
else: else:
self.detected = False self.detected = False
else: else:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: if len(data_buffer) > 0 and time_since_last > self.timeout:
@ -943,7 +943,7 @@ class RNodeInterface(Interface):
self.disable_external_framebuffer() self.disable_external_framebuffer()
self.setRadioState(KISS.RADIO_STATE_OFF) self.setRadioState(KISS.RADIO_STATE_OFF)
self.leave() self.leave()
if self.use_ble: if self.use_ble:
self.ble.close() self.ble.close()
@ -1038,7 +1038,7 @@ class BLEConnection():
if importlib.util.find_spec("bleak") != None: if importlib.util.find_spec("bleak") != None:
import bleak import bleak
BLEConnection.bleak = bleak BLEConnection.bleak = bleak
import asyncio import asyncio
BLEConnection.asyncio = asyncio BLEConnection.asyncio = asyncio
else: else:
@ -1133,7 +1133,7 @@ class BLEConnection():
else: else:
if self.target_bt_addr != None and device.address == self.target_bt_addr: 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) 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: 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) RNS.log(f"Can't connect to target device {self.target_name} over BLE, device is not bonded", RNS.LOG_ERROR)
@ -1154,7 +1154,7 @@ class BLEConnection():
if "props" in device.details and "Bonded" in device.details["props"]: if "props" in device.details and "Bonded" in device.details["props"]:
if device.details["props"]["Bonded"] == True: if device.details["props"]["Bonded"] == True:
return True return True
except Exception as e: except Exception as e:
RNS.log(f"Error while determining device bond status for {device}, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"Error while determining device bond status for {device}, the contained exception was: {e}", RNS.LOG_ERROR)

View File

@ -33,7 +33,7 @@ class KISS():
FESC = 0xDB FESC = 0xDB
TFEND = 0xDC TFEND = 0xDC
TFESC = 0xDD TFESC = 0xDD
CMD_UNKNOWN = 0xFE CMD_UNKNOWN = 0xFE
CMD_FREQUENCY = 0x01 CMD_FREQUENCY = 0x01
CMD_BANDWIDTH = 0x02 CMD_BANDWIDTH = 0x02
@ -94,11 +94,11 @@ class KISS():
DETECT_REQ = 0x73 DETECT_REQ = 0x73
DETECT_RESP = 0x46 DETECT_RESP = 0x46
RADIO_STATE_OFF = 0x00 RADIO_STATE_OFF = 0x00
RADIO_STATE_ON = 0x01 RADIO_STATE_ON = 0x01
RADIO_STATE_ASK = 0xFF RADIO_STATE_ASK = 0xFF
CMD_ERROR = 0x90 CMD_ERROR = 0x90
ERROR_INITRADIO = 0x01 ERROR_INITRADIO = 0x01
ERROR_TXFAILED = 0x02 ERROR_TXFAILED = 0x02
@ -159,7 +159,7 @@ class KISS():
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd])) data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc])) data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
return data return data
class RNodeMultiInterface(Interface): class RNodeMultiInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
@ -188,7 +188,7 @@ class RNodeMultiInterface(Interface):
super().__init__() super().__init__()
self.HW_MTU = 508 self.HW_MTU = 508
self.clients = 0 self.clients = 0
self.pyserial = serial self.pyserial = serial
self.serial = None self.serial = None
@ -294,7 +294,7 @@ class RNodeMultiInterface(Interface):
self.detect() self.detect()
sleep(0.2) sleep(0.2)
if not self.detected: if not self.detected:
RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR) RNS.log(f"Could not detect device for {self}", RNS.LOG_ERROR)
self.serial.close() self.serial.close()
@ -327,7 +327,7 @@ class RNodeMultiInterface(Interface):
interface.OUT = subint[10] interface.OUT = subint[10]
interface.IN = True interface.IN = True
interface.announce_rate_target = self.announce_rate_target interface.announce_rate_target = self.announce_rate_target
interface.mode = self.mode interface.mode = self.mode
interface.HW_MTU = self.HW_MTU interface.HW_MTU = self.HW_MTU
@ -345,13 +345,13 @@ class RNodeMultiInterface(Interface):
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError(f"An IO error occurred while detecting hardware for {self}") raise OSError(f"An IO error occurred while detecting hardware for {self}")
def leave(self): def leave(self):
kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_LEAVE, 0xFF, KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError("An IO error occurred while sending host left command to device") raise OSError("An IO error occurred while sending host left command to device")
def enable_external_framebuffer(self): def enable_external_framebuffer(self):
if self.display != None: if self.display != None:
kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND]) kiss_command = bytes([KISS.FEND, KISS.CMD_FB_EXT, 0x01, KISS.FEND])
@ -385,7 +385,7 @@ class RNodeMultiInterface(Interface):
data = line_byte+line_data data = line_byte+line_data
escaped_data = KISS.escape(data) escaped_data = KISS.escape(data)
kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND]) kiss_command = bytes([KISS.FEND])+bytes([KISS.CMD_FB_WRITE])+escaped_data+bytes([KISS.FEND])
written = self.serial.write(kiss_command) written = self.serial.write(kiss_command)
if written != len(kiss_command): if written != len(kiss_command):
raise OSError("An IO error occurred while writing framebuffer data device") 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.maj_version >= RNodeMultiInterface.REQUIRED_FW_VER_MAJ):
if (self.min_version >= RNodeMultiInterface.REQUIRED_FW_VER_MIN): if (self.min_version >= RNodeMultiInterface.REQUIRED_FW_VER_MIN):
self.firmware_ok = True self.firmware_ok = True
if self.firmware_ok: if self.firmware_ok:
return return
@ -737,7 +737,7 @@ class RNodeMultiInterface(Interface):
atl = command_buffer[2] << 8 | command_buffer[3] atl = command_buffer[2] << 8 | command_buffer[3]
cus = command_buffer[4] << 8 | command_buffer[5] cus = command_buffer[4] << 8 | command_buffer[5]
cul = command_buffer[6] << 8 | command_buffer[7] cul = command_buffer[6] << 8 | command_buffer[7]
self.r_airtime_short = ats/100.0 self.r_airtime_short = ats/100.0
self.r_airtime_long = atl/100.0 self.r_airtime_long = atl/100.0
self.r_channel_load_short = cus/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 # 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])) self.subinterface_types.append(KISS.interface_type_to_str(command_buffer[1]))
command_buffer = b"" command_buffer = b""
else: else:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: if len(data_buffer) > 0 and time_since_last > self.timeout:
@ -918,7 +918,7 @@ class RNodeSubInterface(Interface):
RNS.panic() RNS.panic()
super().__init__() super().__init__()
if index == 0: if index == 0:
sel_cmd = KISS.CMD_SEL_INT0 sel_cmd = KISS.CMD_SEL_INT0
data_cmd= KISS.CMD_INT0_DATA 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(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("Make sure that your hardware actually supports the parameters specified in the configuration", RNS.LOG_ERROR)
RNS.log("Aborting RNode startup", RNS.LOG_ERROR) RNS.log("Aborting RNode startup", RNS.LOG_ERROR)
def initRadio(self): def initRadio(self):
self.parent_interface.setFrequency(self.frequency, self) self.parent_interface.setFrequency(self.frequency, self)

View File

@ -63,7 +63,7 @@ class SerialInterface(Interface):
super().__init__() super().__init__()
self.HW_MTU = 564 self.HW_MTU = 564
self.pyserial = serial self.pyserial = serial
self.serial = None self.serial = None
self.owner = owner self.owner = owner
@ -122,7 +122,7 @@ class SerialInterface(Interface):
def processIncoming(self, data): def processIncoming(self, data):
self.rxb += len(data) self.rxb += len(data)
self.owner.inbound(data, self) self.owner.inbound(data, self)
@ -130,7 +130,7 @@ class SerialInterface(Interface):
if self.online: if self.online:
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG]) data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
written = self.serial.write(data) written = self.serial.write(data)
self.txb += len(data) self.txb += len(data)
if written != len(data): if written != len(data):
raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}") raise OSError(f"Serial interface only wrote {written} bytes of {len(data)}")
@ -164,7 +164,7 @@ class SerialInterface(Interface):
byte = HDLC.ESC byte = HDLC.ESC
escape = False escape = False
data_buffer = data_buffer+bytes([byte]) data_buffer = data_buffer+bytes([byte])
else: else:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: if len(data_buffer) > 0 and time_since_last > self.timeout:
@ -172,12 +172,12 @@ class SerialInterface(Interface):
in_frame = False in_frame = False
escape = False escape = False
sleep(0.08) sleep(0.08)
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log(f"A serial port error occurred, the contained exception was: {e}", RNS.LOG_ERROR) 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) RNS.log(f"The interface {self} experienced an unrecoverable error and is now offline.", RNS.LOG_ERROR)
if RNS.Reticulum.panic_on_interface_error: if RNS.Reticulum.panic_on_interface_error:
RNS.panic() RNS.panic()

View File

@ -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): 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__() super().__init__()
self.HW_MTU = 1064 self.HW_MTU = 1064
self.IN = True self.IN = True
self.OUT = False self.OUT = False
self.socket = None self.socket = None
@ -99,7 +99,7 @@ class TCPClientInterface(Interface):
self.i2p_tunneled = i2p_tunneled self.i2p_tunneled = i2p_tunneled
self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL
self.bitrate = TCPClientInterface.BITRATE_GUESS self.bitrate = TCPClientInterface.BITRATE_GUESS
if max_reconnect_tries == None: if max_reconnect_tries == None:
self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES
else: else:
@ -128,14 +128,14 @@ class TCPClientInterface(Interface):
self.connect_timeout = connect_timeout self.connect_timeout = connect_timeout
else: else:
self.connect_timeout = TCPClientInterface.INITIAL_CONNECT_TIMEOUT self.connect_timeout = TCPClientInterface.INITIAL_CONNECT_TIMEOUT
if TCPClientInterface.SYNCHRONOUS_START: if TCPClientInterface.SYNCHRONOUS_START:
self.initial_connect() self.initial_connect()
else: else:
thread = threading.Thread(target=self.initial_connect) thread = threading.Thread(target=self.initial_connect)
thread.daemon = True thread.daemon = True
thread.start() thread.start()
def initial_connect(self): def initial_connect(self):
if not self.connect(initial=True): if not self.connect(initial=True):
thread = threading.Thread(target=self.reconnect) thread = threading.Thread(target=self.reconnect)
@ -170,19 +170,19 @@ class TCPClientInterface(Interface):
TCP_KEEPIDLE = 0x10 TCP_KEEPIDLE = 0x10
self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
if not self.i2p_tunneled: if not self.i2p_tunneled:
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER)) self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.TCP_PROBE_AFTER))
else: else:
self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.I2P_PROBE_AFTER)) self.socket.setsockopt(socket.IPPROTO_TCP, TCP_KEEPIDLE, int(TCPClientInterface.I2P_PROBE_AFTER))
def detach(self): def detach(self):
if self.socket != None: if self.socket != None:
if hasattr(self.socket, "close"): if hasattr(self.socket, "close"):
if callable(self.socket.close): if callable(self.socket.close):
RNS.log(f"Detaching {self}", RNS.LOG_DEBUG) RNS.log(f"Detaching {self}", RNS.LOG_DEBUG)
self.detached = True self.detached = True
try: try:
self.socket.shutdown(socket.SHUT_RDWR) self.socket.shutdown(socket.SHUT_RDWR)
except Exception as e: except Exception as e:
@ -209,13 +209,13 @@ class TCPClientInterface(Interface):
if initial: if initial:
RNS.log(f"TCP connection for {self} established", RNS.LOG_DEBUG) RNS.log(f"TCP connection for {self} established", RNS.LOG_DEBUG)
except Exception as e: except Exception as e:
if initial: if initial:
RNS.log(f"Initial connection for {self} could not be established: {e}", RNS.LOG_ERROR) 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) RNS.log(f"Leaving unconnected and retrying connection in {TCPClientInterface.RECONNECT_WAIT} seconds.", RNS.LOG_ERROR)
return False return False
else: else:
raise e raise e
@ -223,7 +223,7 @@ class TCPClientInterface(Interface):
self.set_timeouts_linux() self.set_timeouts_linux()
elif platform.system() == "Darwin": elif platform.system() == "Darwin":
self.set_timeouts_osx() self.set_timeouts_osx()
self.online = True self.online = True
self.writing = False self.writing = False
self.never_connected = False self.never_connected = False
@ -269,7 +269,7 @@ class TCPClientInterface(Interface):
self.rxb += len(data) self.rxb += len(data)
if hasattr(self, "parent_interface") and self.parent_interface != None: if hasattr(self, "parent_interface") and self.parent_interface != None:
self.parent_interface.rxb += len(data) self.parent_interface.rxb += len(data)
self.owner.inbound(data, self) self.owner.inbound(data, self)
def processOutgoing(self, data): def processOutgoing(self, data):
@ -369,7 +369,7 @@ class TCPClientInterface(Interface):
break break
except Exception as e: except Exception as e:
self.online = False self.online = False
RNS.log(f"An interface error occurred for {self}, the contained exception was: {e}", RNS.LOG_WARNING) 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.online = False
self.clients = 0 self.clients = 0
self.IN = True self.IN = True
self.OUT = False self.OUT = False
self.name = name self.name = name
@ -474,7 +474,7 @@ class TCPServerInterface(Interface):
spawned_interface.target_port = str(handler.client_address[1]) spawned_interface.target_port = str(handler.client_address[1])
spawned_interface.parent_interface = self spawned_interface.parent_interface = self
spawned_interface.bitrate = self.bitrate spawned_interface.bitrate = self.bitrate
spawned_interface.ifac_size = self.ifac_size spawned_interface.ifac_size = self.ifac_size
spawned_interface.ifac_netname = self.ifac_netname spawned_interface.ifac_netname = self.ifac_netname
spawned_interface.ifac_netkey = self.ifac_netkey spawned_interface.ifac_netkey = self.ifac_netkey

View File

@ -99,7 +99,7 @@ class UDPInterface(Interface):
udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) udp_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
udp_socket.sendto(data, (self.forward_ip, self.forward_port)) udp_socket.sendto(data, (self.forward_ip, self.forward_port))
self.txb += len(data) self.txb += len(data)
except Exception as e: except Exception as e:
RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"Could not transmit on {self}. The contained exception was: {e}", RNS.LOG_ERROR)

View File

@ -124,7 +124,7 @@ class Link:
RNS.Transport.register_link(link) RNS.Transport.register_link(link)
link.last_inbound = time.time() link.last_inbound = time.time()
link.start_watchdog() link.start_watchdog()
RNS.log(f"Incoming link request {link} accepted on {link.attached_interface}", RNS.LOG_DEBUG) RNS.log(f"Incoming link request {link} accepted on {link.attached_interface}", RNS.LOG_DEBUG)
return link return link
@ -189,7 +189,7 @@ class Link:
self.sig_prv = Ed25519PrivateKey.generate() self.sig_prv = Ed25519PrivateKey.generate()
self.fernet = None self.fernet = None
self.pub = self.prv.public_key() self.pub = self.prv.public_key()
self.pub_bytes = self.pub.public_bytes() self.pub_bytes = self.pub.public_bytes()
@ -288,7 +288,7 @@ class Link:
self.establishment_cost += len(packet.raw) self.establishment_cost += len(packet.raw)
signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes signed_data = self.link_id+self.peer_pub_bytes+self.peer_sig_pub_bytes
signature = packet.data[:RNS.Identity.SIGLENGTH//8] signature = packet.data[:RNS.Identity.SIGLENGTH//8]
if self.destination.identity.validate(signature, signed_data): if self.destination.identity.validate(signature, signed_data):
if self.status != Link.HANDSHAKE: if self.status != Link.HANDSHAKE:
raise OSError(f"Invalid link state for proof validation: {self.status}") raise OSError(f"Invalid link state for proof validation: {self.status}")
@ -301,7 +301,7 @@ class Link:
self.last_proof = self.activated_at self.last_proof = self.activated_at
RNS.Transport.activate_link(self) RNS.Transport.activate_link(self)
RNS.log(f"Link {self} established with {self.destination}, RTT is {round(self.rtt, 3)}s", RNS.LOG_VERBOSE) 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: 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 self.establishment_rate = self.establishment_cost/self.rtt
@ -316,7 +316,7 @@ class Link:
thread.start() thread.start()
else: else:
RNS.log(f"Invalid link proof signature received by {self}. Ignoring.", RNS.LOG_DEBUG) RNS.log(f"Invalid link proof signature received by {self}. Ignoring.", RNS.LOG_DEBUG)
except Exception as e: except Exception as e:
self.status = Link.CLOSED self.status = Link.CLOSED
RNS.log(f"An error ocurred while validating link request proof on {self}.", RNS.LOG_ERROR) RNS.log(f"An error ocurred while validating link request proof on {self}.", RNS.LOG_ERROR)
@ -377,7 +377,7 @@ class Link:
timeout = timeout, timeout = timeout,
request_size = len(packed_request), request_size = len(packed_request),
) )
else: else:
request_id = RNS.Identity.truncated_hash(packed_request) request_id = RNS.Identity.truncated_hash(packed_request)
RNS.log(f"Sending request {RNS.prettyhexrep(request_id)} as resource.", RNS.LOG_DEBUG) RNS.log(f"Sending request {RNS.prettyhexrep(request_id)} as resource.", RNS.LOG_DEBUG)
@ -547,7 +547,7 @@ class Link:
resource.cancel() resource.cancel()
if self._channel: if self._channel:
self._channel._shutdown() self._channel._shutdown()
self.prv = None self.prv = None
self.pub = None self.pub = None
self.pub_bytes = None self.pub_bytes = None
@ -620,7 +620,7 @@ class Link:
self.status = Link.STALE self.status = Link.STALE
else: else:
sleep_time = self.keepalive sleep_time = self.keepalive
else: else:
sleep_time = (last_inbound + self.keepalive) - time.time() sleep_time = (last_inbound + self.keepalive) - time.time()
@ -655,7 +655,7 @@ class Link:
self.snr = packet.snr self.snr = packet.snr
if packet.q != None: if packet.q != None:
self.q = packet.q self.q = packet.q
def send_keepalive(self): def send_keepalive(self):
keepalive_packet = RNS.Packet(self, bytes([0xFF]), context=RNS.Packet.KEEPALIVE) keepalive_packet = RNS.Packet(self, bytes([0xFF]), context=RNS.Packet.KEEPALIVE)
keepalive_packet.send() keepalive_packet.send()
@ -782,7 +782,7 @@ class Link:
thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet)) thread = threading.Thread(target=self.callbacks.packet, args=(plaintext, packet))
thread.daemon = True thread.daemon = True
thread.start() thread.start()
if self.destination.proof_strategy == RNS.Destination.PROVE_ALL: if self.destination.proof_strategy == RNS.Destination.PROVE_ALL:
packet.prove() packet.prove()
should_query = True should_query = True
@ -815,7 +815,7 @@ class Link:
self.callbacks.remote_identified(self, self.__remote_identity) self.callbacks.remote_identified(self, self.__remote_identity)
except Exception as e: except Exception as e:
RNS.log(f"Error while executing remote identified callback from {self}. The contained exception was: {e}", RNS.LOG_ERROR) 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) self.__update_phy_stats(packet, query_shared=True)
elif packet.context == RNS.Packet.REQUEST: elif packet.context == RNS.Packet.REQUEST:
@ -903,7 +903,7 @@ class Link:
if not packet.packet_hash in resource.req_hashlist: if not packet.packet_hash in resource.req_hashlist:
resource.req_hashlist.append(packet.packet_hash) resource.req_hashlist.append(packet.packet_hash)
resource.request(plaintext) resource.request(plaintext)
# TODO: Test and possibly enable this at some point # TODO: Test and possibly enable this at some point
# def request_job(): # def request_job():
# resource.request(plaintext) # resource.request(plaintext)
@ -984,7 +984,7 @@ class Link:
try: try:
if not self.fernet: if not self.fernet:
self.fernet = Fernet(self.derived_key) self.fernet = Fernet(self.derived_key)
return self.fernet.decrypt(ciphertext) return self.fernet.decrypt(ciphertext)
except Exception as e: except Exception as e:
@ -1140,7 +1140,7 @@ class RequestReceipt():
elif self.resource != None: elif self.resource != None:
self.hash = resource.request_id self.hash = resource.request_id
resource.set_callback(self.request_resource_concluded) resource.set_callback(self.request_resource_concluded)
self.link = link self.link = link
self.request_id = self.hash self.request_id = self.hash
self.request_size = request_size self.request_size = request_size
@ -1224,7 +1224,7 @@ class RequestReceipt():
self.packet_receipt.callbacks.delivery(self.packet_receipt) self.packet_receipt.callbacks.delivery(self.packet_receipt)
self.progress = resource.get_progress() self.progress = resource.get_progress()
if self.callbacks.progress != None: if self.callbacks.progress != None:
try: try:
self.callbacks.progress(self) self.callbacks.progress(self)
@ -1233,7 +1233,7 @@ class RequestReceipt():
else: else:
resource.cancel() resource.cancel()
def response_received(self, response): def response_received(self, response):
if not self.status == RequestReceipt.FAILED: if not self.status == RequestReceipt.FAILED:
self.progress = 1.0 self.progress = 1.0

View File

@ -97,7 +97,7 @@ class Packet:
# the below calculation; 383 bytes. # 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 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 PLAIN_MDU = MDU
""" """
@ -256,7 +256,7 @@ class Packet:
def send(self): def send(self):
""" """
Sends the packet. 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. :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: if not self.sent:
@ -278,21 +278,21 @@ class Packet:
self.sent = False self.sent = False
self.receipt = None self.receipt = None
return False return False
else: else:
raise OSError("Packet was already sent") raise OSError("Packet was already sent")
def resend(self): def resend(self):
""" """
Re-sends the packet. 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. :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: if self.sent:
# Re-pack the packet to obtain new ciphertext for # Re-pack the packet to obtain new ciphertext for
# encrypted destinations # encrypted destinations
self.pack() self.pack()
if RNS.Transport.outbound(self): if RNS.Transport.outbound(self):
return self.receipt return self.receipt
else: else:
@ -388,7 +388,7 @@ class PacketReceipt:
def get_status(self): 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 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"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.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
RNS.trace_exception(e) RNS.trace_exception(e)
return True return True
else: else:
return False return False
@ -490,7 +490,7 @@ class PacketReceipt:
self.callbacks.delivery(self) self.callbacks.delivery(self)
except Exception as e: except Exception as e:
RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"Error while executing proof validated callback. The contained exception was: {e}", RNS.LOG_ERROR)
return True return True
else: else:
return False return False
@ -524,7 +524,7 @@ class PacketReceipt:
def set_timeout(self, timeout): def set_timeout(self, timeout):
""" """
Sets a timeout in seconds Sets a timeout in seconds
:param timeout: The timeout in seconds. :param timeout: The timeout in seconds.
""" """
self.timeout = float(timeout) self.timeout = float(timeout)

View File

@ -21,7 +21,7 @@
# SOFTWARE. # SOFTWARE.
class Resolver: class Resolver:
@staticmethod @staticmethod
def resolve_identity(full_name): def resolve_identity(full_name):
pass pass

View File

@ -59,11 +59,11 @@ class Resource:
# The maximum window size for transfers on fast links # The maximum window size for transfers on fast links
WINDOW_MAX_FAST = 75 WINDOW_MAX_FAST = 75
# For calculating maps and guard segments, this # For calculating maps and guard segments, this
# must be set to the global maximum window. # must be set to the global maximum window.
WINDOW_MAX = WINDOW_MAX_FAST WINDOW_MAX = WINDOW_MAX_FAST
# If the fast rate is sustained for this many request # If the fast rate is sustained for this many request
# rounds, the fast link window size will be allowed. # rounds, the fast link window size will be allowed.
FAST_RATE_THRESHOLD = WINDOW_MAX_SLOW - WINDOW - 2 FAST_RATE_THRESHOLD = WINDOW_MAX_SLOW - WINDOW - 2
@ -111,7 +111,7 @@ class Resource:
# fit in 3 bytes in resource advertisements. # fit in 3 bytes in resource advertisements.
MAX_EFFICIENT_SIZE = 16 * 1024 * 1024 - 1 MAX_EFFICIENT_SIZE = 16 * 1024 * 1024 - 1
RESPONSE_MAX_GRACE_TIME = 10 RESPONSE_MAX_GRACE_TIME = 10
# The maximum size to auto-compress with # The maximum size to auto-compress with
# bz2 before sending. # bz2 before sending.
AUTO_COMPRESS_MAX_SIZE = MAX_EFFICIENT_SIZE AUTO_COMPRESS_MAX_SIZE = MAX_EFFICIENT_SIZE
@ -186,7 +186,7 @@ class Resource:
resource.waiting_for_hmu = False resource.waiting_for_hmu = False
resource.receiving_part = False resource.receiving_part = False
resource.consecutive_completed_height = -1 resource.consecutive_completed_height = -1
if not resource.link.has_incoming_resource(resource): if not resource.link.has_incoming_resource(resource):
resource.link.register_incoming_resource(resource) resource.link.register_incoming_resource(resource)
@ -255,7 +255,7 @@ class Resource:
elif isinstance(data, bytes): elif isinstance(data, bytes):
data_size = len(data) data_size = len(data)
self.total_size = data_size self.total_size = data_size
resource_data = data resource_data = data
self.total_segments = 1 self.total_segments = 1
self.segment_index = 1 self.segment_index = 1
@ -322,7 +322,7 @@ class Resource:
self.data = b"" self.data = b""
self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE] self.data += RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE]
self.data += self.compressed_data self.data += self.compressed_data
self.compressed = True self.compressed = True
self.uncompressed_data = None self.uncompressed_data = None
@ -348,7 +348,7 @@ class Resource:
self.sent_parts = 0 self.sent_parts = 0
hashmap_entries = int(math.ceil(self.size/float(Resource.SDU))) hashmap_entries = int(math.ceil(self.size/float(Resource.SDU)))
self.total_parts = hashmap_entries self.total_parts = hashmap_entries
hashmap_ok = False hashmap_ok = False
while not hashmap_ok: while not hashmap_ok:
hashmap_computation_began = time.time() hashmap_computation_began = time.time()
@ -389,12 +389,12 @@ class Resource:
self.parts.append(part) self.parts.append(part)
RNS.log(f"Hashmap computation concluded in {round(time.time() - hashmap_computation_began, 3)} seconds", RNS.LOG_DEBUG) RNS.log(f"Hashmap computation concluded in {round(time.time() - hashmap_computation_began, 3)} seconds", RNS.LOG_DEBUG)
if advertise: if advertise:
self.advertise() self.advertise()
else: else:
self.receive_lock = Lock() self.receive_lock = Lock()
def hashmap_update_packet(self, plaintext): def hashmap_update_packet(self, plaintext):
if not self.status == Resource.FAILED: if not self.status == Resource.FAILED:
@ -489,7 +489,7 @@ class Resource:
except Exception as e: except Exception as e:
RNS.log(f"Could not resend advertisement packet, cancelling resource. The contained exception was: {e}", RNS.LOG_VERBOSE) RNS.log(f"Could not resend advertisement packet, cancelling resource. The contained exception was: {e}", RNS.LOG_VERBOSE)
self.cancel() self.cancel()
elif self.status == Resource.TRANSFERRING: elif self.status == Resource.TRANSFERRING:
if not self.initiator: if not self.initiator:
@ -504,7 +504,7 @@ class Resource:
retries_used = self.max_retries - self.retries_left retries_used = self.max_retries - self.retries_left
extra_wait = retries_used * Resource.PER_RETRY_DELAY 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() 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 sleep_time < 0:
if self.retries_left > 0: if self.retries_left > 0:
ms = "" if self.outstanding_parts == 1 else "s" ms = "" if self.outstanding_parts == 1 else "s"
@ -558,7 +558,7 @@ class Resource:
if sleep_time == None or sleep_time < 0: if sleep_time == None or sleep_time < 0:
RNS.log("Timing error, cancelling resource transfer.", RNS.LOG_ERROR) RNS.log("Timing error, cancelling resource transfer.", RNS.LOG_ERROR)
self.cancel() self.cancel()
if sleep_time != None: if sleep_time != None:
sleep(min(sleep_time, Resource.WATCHDOG_MAX_SLEEP)) sleep(min(sleep_time, Resource.WATCHDOG_MAX_SLEEP))
@ -697,7 +697,7 @@ class Resource:
if self.req_resp == None: if self.req_resp == None:
self.req_resp = self.last_activity self.req_resp = self.last_activity
rtt = self.req_resp-self.req_sent rtt = self.req_resp-self.req_sent
self.part_timeout_factor = Resource.PART_TIMEOUT_FACTOR_AFTER_RTT self.part_timeout_factor = Resource.PART_TIMEOUT_FACTOR_AFTER_RTT
if self.rtt == None: if self.rtt == None:
self.rtt = self.link.rtt self.rtt = self.link.rtt
@ -737,7 +737,7 @@ class Resource:
# Update consecutive completed pointer # Update consecutive completed pointer
if i == self.consecutive_completed_height + 1: if i == self.consecutive_completed_height + 1:
self.consecutive_completed_height = i self.consecutive_completed_height = i
cp = self.consecutive_completed_height + 1 cp = self.consecutive_completed_height + 1
while cp < len(self.parts) and self.parts[cp] != None: while cp < len(self.parts) and self.parts[cp] != None:
self.consecutive_completed_height = cp self.consecutive_completed_height = cp
@ -802,7 +802,7 @@ class Resource:
i = 0; pn = self.consecutive_completed_height+1 i = 0; pn = self.consecutive_completed_height+1
search_start = pn search_start = pn
search_size = self.window search_size = self.window
for part in self.parts[search_start:search_start+search_size]: for part in self.parts[search_start:search_start+search_size]:
if part == None: if part == None:
part_hash = self.hashmap[pn] part_hash = self.hashmap[pn]
@ -883,10 +883,10 @@ class Resource:
RNS.log("Resource could not send parts, cancelling transfer!", RNS.LOG_DEBUG) RNS.log("Resource could not send parts, cancelling transfer!", RNS.LOG_DEBUG)
RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG) RNS.log(f"The contained exception was: {e}", RNS.LOG_DEBUG)
self.cancel() self.cancel()
if wants_more_hashmap: if wants_more_hashmap:
last_map_hash = request_data[1:Resource.MAPHASH_LEN+1] last_map_hash = request_data[1:Resource.MAPHASH_LEN+1]
part_index = self.receiver_min_consecutive_height part_index = self.receiver_min_consecutive_height
search_start = part_index search_start = part_index
search_end = self.receiver_min_consecutive_height+ResourceAdvertisement.COLLISION_GUARD_SIZE search_end = self.receiver_min_consecutive_height+ResourceAdvertisement.COLLISION_GUARD_SIZE
@ -904,7 +904,7 @@ class Resource:
else: else:
segment = part_index // ResourceAdvertisement.HASHMAP_MAX_LEN segment = part_index // ResourceAdvertisement.HASHMAP_MAX_LEN
hashmap_start = segment*ResourceAdvertisement.HASHMAP_MAX_LEN hashmap_start = segment*ResourceAdvertisement.HASHMAP_MAX_LEN
hashmap_end = min((segment+1)*ResourceAdvertisement.HASHMAP_MAX_LEN, len(self.parts)) hashmap_end = min((segment+1)*ResourceAdvertisement.HASHMAP_MAX_LEN, len(self.parts))
@ -949,7 +949,7 @@ class Resource:
self.link.cancel_outgoing_resource(self) self.link.cancel_outgoing_resource(self)
else: else:
self.link.cancel_incoming_resource(self) self.link.cancel_incoming_resource(self)
if self.callback != None: if self.callback != None:
try: try:
self.link.resource_concluded(self) self.link.resource_concluded(self)
@ -969,7 +969,7 @@ class Resource:
""" """
if self.status == RNS.Resource.COMPLETE and self.segment_index == self.total_segments: if self.status == RNS.Resource.COMPLETE and self.segment_index == self.total_segments:
return 1.0 return 1.0
elif self.initiator: elif self.initiator:
if not self.split: if not self.split:
self.processed_parts = self.sent_parts self.processed_parts = self.sent_parts
@ -1194,7 +1194,7 @@ class ResourceAdvertisement:
@staticmethod @staticmethod
def unpack(data): def unpack(data):
dictionary = umsgpack.unpackb(data) dictionary = umsgpack.unpackb(data)
adv = ResourceAdvertisement() adv = ResourceAdvertisement()
adv.t = dictionary["t"] adv.t = dictionary["t"]
adv.d = dictionary["d"] adv.d = dictionary["d"]
@ -1213,4 +1213,4 @@ class ResourceAdvertisement:
adv.u = True if ((adv.f >> 3) & 0x01) == 0x01 else False adv.u = True if ((adv.f >> 3) & 0x01) == 0x01 else False
adv.p = True if ((adv.f >> 4) & 0x01) == 0x01 else False adv.p = True if ((adv.f >> 4) & 0x01) == 0x01 else False
return adv return adv

View File

@ -129,7 +129,7 @@ class Reticulum:
HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2 HEADER_MAXSIZE = 2+1+(TRUNCATED_HASHLENGTH//8)*2
IFAC_MIN_SIZE = 1 IFAC_MIN_SIZE = 1
IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8") IFAC_SALT = bytes.fromhex("adf54d882c9a9b80771eb4995d702d4a3e733391b2a0f53f416d9f907e55cff8")
MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE MDU = MTU - HEADER_MAXSIZE - IFAC_MIN_SIZE
RESOURCE_CACHE = 24*60*60 RESOURCE_CACHE = 24*60*60
@ -140,7 +140,7 @@ class Reticulum:
router = None router = None
config = None config = None
# The default configuration path will be expanded to a directory # The default configuration path will be expanded to a directory
# named ".reticulum" inside the current users home directory # named ".reticulum" inside the current users home directory
userdir = os.path.expanduser("~") userdir = os.path.expanduser("~")
@ -150,7 +150,7 @@ class Reticulum:
cachepath = "" cachepath = ""
__instance = None __instance = None
@staticmethod @staticmethod
def exit_handler(): def exit_handler():
# This exit handler is called whenever Reticulum is asked to # This exit handler is called whenever Reticulum is asked to
@ -212,7 +212,7 @@ class Reticulum:
if logdest == RNS.LOG_FILE: if logdest == RNS.LOG_FILE:
RNS.logdest = RNS.LOG_FILE RNS.logdest = RNS.LOG_FILE
RNS.logfile = f"{Reticulum.configdir}/logfile" RNS.logfile = f"{Reticulum.configdir}/logfile"
Reticulum.configpath = f"{Reticulum.configdir}/config" Reticulum.configpath = f"{Reticulum.configdir}/config"
Reticulum.storagepath = f"{Reticulum.configdir}/storage" Reticulum.storagepath = f"{Reticulum.configdir}/storage"
Reticulum.cachepath = f"{Reticulum.configdir}/storage/cache" Reticulum.cachepath = f"{Reticulum.configdir}/storage/cache"
@ -278,7 +278,7 @@ class Reticulum:
self.__apply_config() self.__apply_config()
RNS.log(f"Configuration loaded from {self.configpath}", RNS.LOG_VERBOSE) RNS.log(f"Configuration loaded from {self.configpath}", RNS.LOG_VERBOSE)
RNS.Identity.load_known_destinations() RNS.Identity.load_known_destinations()
RNS.Transport.start(self) RNS.Transport.start(self)
@ -286,7 +286,7 @@ class Reticulum:
self.rpc_addr = ("127.0.0.1", self.local_control_port) self.rpc_addr = ("127.0.0.1", self.local_control_port)
if self.rpc_key == None: if self.rpc_key == None:
self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key()) self.rpc_key = RNS.Identity.full_hash(RNS.Transport.identity.get_private_key())
if self.is_shared_instance: if self.is_shared_instance:
self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key) self.rpc_listener = multiprocessing.connection.Listener(self.rpc_addr, authkey=self.rpc_key)
thread = threading.Thread(target=self.rpc_loop) thread = threading.Thread(target=self.rpc_loop)
@ -314,7 +314,7 @@ class Reticulum:
if now > self.last_data_persist+Reticulum.PERSIST_INTERVAL: if now > self.last_data_persist+Reticulum.PERSIST_INTERVAL:
self.__persist_data() self.__persist_data()
time.sleep(Reticulum.JOB_INTERVAL) time.sleep(Reticulum.JOB_INTERVAL)
def __start_local_interface(self): def __start_local_interface(self):
@ -330,7 +330,7 @@ class Reticulum:
interface._force_bitrate = Reticulum._force_shared_instance_bitrate interface._force_bitrate = Reticulum._force_shared_instance_bitrate
RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING) RNS.log(f"Forcing shared instance bitrate of {RNS.prettyspeed(interface.bitrate)}", RNS.LOG_WARNING)
RNS.Transport.interfaces.append(interface) RNS.Transport.interfaces.append(interface)
self.is_shared_instance = True self.is_shared_instance = True
RNS.log(f"Started shared instance interface: {interface}", RNS.LOG_DEBUG) RNS.log(f"Started shared instance interface: {interface}", RNS.LOG_DEBUG)
self.__start_jobs() self.__start_jobs()
@ -455,7 +455,7 @@ class Reticulum:
c = self.config["interfaces"][name] c = self.config["interfaces"][name]
interface_mode = Interface.Interface.MODE_FULL interface_mode = Interface.Interface.MODE_FULL
if "interface_mode" in c: if "interface_mode" in c:
c["interface_mode"] = str(c["interface_mode"]).lower() c["interface_mode"] = str(c["interface_mode"]).lower()
if c["interface_mode"] == "full": if c["interface_mode"] == "full":
@ -490,7 +490,7 @@ class Reticulum:
if "ifac_size" in c: if "ifac_size" in c:
if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8: if c.as_int("ifac_size") >= Reticulum.IFAC_MIN_SIZE*8:
ifac_size = c.as_int("ifac_size")//8 ifac_size = c.as_int("ifac_size")//8
ifac_netname = None ifac_netname = None
if "networkname" in c: if "networkname" in c:
if c["networkname"] != "": if c["networkname"] != "":
@ -506,7 +506,7 @@ class Reticulum:
if "pass_phrase" in c: if "pass_phrase" in c:
if c["pass_phrase"] != "": if c["pass_phrase"] != "":
ifac_netkey = c["pass_phrase"] ifac_netkey = c["pass_phrase"]
ingress_control = True ingress_control = True
if "ingress_control" in c: ingress_control = c.as_bool("ingress_control") if "ingress_control" in c: ingress_control = c.as_bool("ingress_control")
ic_max_held_announces = None ic_max_held_announces = None
@ -533,12 +533,12 @@ class Reticulum:
if "announce_rate_target" in c: if "announce_rate_target" in c:
if c.as_int("announce_rate_target") > 0: if c.as_int("announce_rate_target") > 0:
announce_rate_target = c.as_int("announce_rate_target") announce_rate_target = c.as_int("announce_rate_target")
announce_rate_grace = None announce_rate_grace = None
if "announce_rate_grace" in c: if "announce_rate_grace" in c:
if c.as_int("announce_rate_grace") >= 0: if c.as_int("announce_rate_grace") >= 0:
announce_rate_grace = c.as_int("announce_rate_grace") announce_rate_grace = c.as_int("announce_rate_grace")
announce_rate_penalty = None announce_rate_penalty = None
if "announce_rate_penalty" in c: if "announce_rate_penalty" in c:
if c.as_int("announce_rate_penalty") >= 0: if c.as_int("announce_rate_penalty") >= 0:
@ -554,7 +554,7 @@ class Reticulum:
if "announce_cap" in c: if "announce_cap" in c:
if c.as_float("announce_cap") > 0 and c.as_float("announce_cap") <= 100: if c.as_float("announce_cap") > 0 and c.as_float("announce_cap") <= 100:
announce_cap = c.as_float("announce_cap")/100.0 announce_cap = c.as_float("announce_cap")/100.0
try: try:
interface = None interface = None
@ -661,7 +661,7 @@ class Reticulum:
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: 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) 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.Interface.MODE_FULL
interface.mode = interface_mode interface.mode = interface_mode
interface.announce_cap = announce_cap interface.announce_cap = announce_cap
@ -698,7 +698,7 @@ class Reticulum:
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: 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) 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.Interface.MODE_FULL
interface.mode = interface_mode interface.mode = interface_mode
interface.announce_cap = announce_cap interface.announce_cap = announce_cap
@ -735,7 +735,7 @@ class Reticulum:
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: 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) 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.Interface.MODE_FULL
interface.mode = interface_mode interface.mode = interface_mode
interface.announce_cap = announce_cap interface.announce_cap = announce_cap
@ -938,7 +938,7 @@ class Reticulum:
ble_addr = ble_string ble_addr = ble_string
else: else:
ble_name = ble_string ble_name = ble_string
interface = RNodeInterface.RNodeInterface( interface = RNodeInterface.RNodeInterface(
RNS.Transport, RNS.Transport,
name, name,
@ -1012,11 +1012,11 @@ class Reticulum:
txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None
subint_config[subint_index][4] = txpower subint_config[subint_index][4] = txpower
spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None 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 codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None
subint_config[subint_index][6] = codingrate subint_config[subint_index][6] = codingrate
flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False 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 st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None
subint_config[subint_index][8] = st_alock subint_config[subint_index][8] = st_alock
lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None
@ -1038,7 +1038,7 @@ class Reticulum:
id_interval = int(c["id_interval"]) if "id_interval" in c else None 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 id_callsign = c["id_callsign"] if "id_callsign" in c else None
port = c["port"] if "port" in c else None port = c["port"] if "port" in c else None
if port == None: if port == None:
raise ValueError(f"No port specified for {name}") raise ValueError(f"No port specified for {name}")
@ -1122,7 +1122,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): 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 not self.is_connected_to_shared_instance:
if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface): if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface):
if mode == None: if mode == None:
mode = Interface.Interface.MODE_FULL mode = Interface.Interface.MODE_FULL
interface.mode = mode interface.mode = mode
@ -1200,14 +1200,14 @@ class Reticulum:
age = now - mtime age = now - mtime
if age > RNS.Transport.DESTINATION_TIMEOUT: if age > RNS.Transport.DESTINATION_TIMEOUT:
os.unlink(filepath) os.unlink(filepath)
except Exception as e: except Exception as e:
RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"Error while cleaning resources cache, the contained exception was: {e}", RNS.LOG_ERROR)
def __create_default_config(self): def __create_default_config(self):
self.config = ConfigObj(__default_rns_config__) self.config = ConfigObj(__default_rns_config__)
self.config.filename = Reticulum.configpath self.config.filename = Reticulum.configpath
if not os.path.isdir(Reticulum.configdir): if not os.path.isdir(Reticulum.configdir):
os.makedirs(Reticulum.configdir) os.makedirs(Reticulum.configdir)
self.config.write() self.config.write()
@ -1279,7 +1279,7 @@ class Reticulum:
interfaces = [] interfaces = []
for interface in RNS.Transport.interfaces: for interface in RNS.Transport.interfaces:
ifstats = {} ifstats = {}
if hasattr(interface, "clients"): if hasattr(interface, "clients"):
ifstats["clients"] = interface.clients ifstats["clients"] = interface.clients
else: else:

View File

@ -51,7 +51,7 @@ class Transport:
""" """
Maximum amount of hops that Reticulum will transport a packet. Maximum amount of hops that Reticulum will transport a packet.
""" """
PATHFINDER_R = 1 # Retransmit retries PATHFINDER_R = 1 # Retransmit retries
PATHFINDER_G = 5 # Retry grace period PATHFINDER_G = 5 # Retry grace period
PATHFINDER_RW = 0.5 # Random window for announce rebroadcast 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 announce_rate_table = {} # A table for keeping track of announce rates
path_requests = {} # A table for storing path request timestamps path_requests = {} # A table for storing path request timestamps
path_states = {} # A table for keeping track of path states 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_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 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 max_pr_tags = 32000 # Maximum amount of unique path request tags to remember
@ -150,7 +150,7 @@ class Transport:
if Transport.identity == None: if Transport.identity == None:
transport_identity_path = f"{RNS.Reticulum.storagepath}/transport_identity" transport_identity_path = f"{RNS.Reticulum.storagepath}/transport_identity"
if os.path.isfile(transport_identity_path): 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: if Transport.identity == None:
RNS.log("No valid Transport Identity in storage, creating...", RNS.LOG_VERBOSE) 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_destinations.append(Transport.remote_management_destination)
Transport.control_hashes.append(Transport.remote_management_destination.hash) Transport.control_hashes.append(Transport.remote_management_destination.hash)
RNS.log(f"Enabled remote management on {Transport.remote_management_destination}", RNS.LOG_NOTICE) RNS.log(f"Enabled remote management on {Transport.remote_management_destination}", RNS.LOG_NOTICE)
Transport.jobs_running = False Transport.jobs_running = False
thread = threading.Thread(target=Transport.jobloop, daemon=True) thread = threading.Thread(target=Transport.jobloop, daemon=True)
thread.start() thread.start()
@ -405,7 +405,7 @@ class Transport:
announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown"); announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
announce_destination.hash = packet.destination_hash announce_destination.hash = packet.destination_hash
announce_destination.hexhash = announce_destination.hash.hex() announce_destination.hexhash = announce_destination.hash.hex()
new_packet = RNS.Packet( new_packet = RNS.Packet(
announce_destination, announce_destination,
announce_data, 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) RNS.log(f"Rebroadcasting announce as path response for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG)
else: else:
RNS.log(f"Rebroadcasting announce for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG) RNS.log(f"Rebroadcasting announce for {RNS.prettyhexrep(announce_destination.hash)} with hop count {new_packet.hops}", RNS.LOG_DEBUG)
outgoing.append(new_packet) outgoing.append(new_packet)
# This handles an edge case where a peer sends a past # 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_throttle = time.time() - last_path_request < Transport.PATH_REQUEST_MI
path_request_conditions = False path_request_conditions = False
# If the path has been invalidated between the time of # If the path has been invalidated between the time of
# making the link request and now, try to rediscover it # making the link request and now, try to rediscover it
if not Transport.has_path(link_entry[6]): if not Transport.has_path(link_entry[6]):
@ -726,7 +726,7 @@ class Transport:
# Assemble new payload with IFAC # Assemble new payload with IFAC
new_raw = new_header+ifac+raw[2:] new_raw = new_header+ifac+raw[2:]
# Mask payload # Mask payload
i = 0; masked_raw = b"" i = 0; masked_raw = b""
for byte in new_raw: for byte in new_raw:
@ -781,7 +781,7 @@ class Transport:
if generate_receipt: if generate_receipt:
packet.receipt = RNS.PacketReceipt(packet) packet.receipt = RNS.PacketReceipt(packet)
Transport.receipts.append(packet.receipt) Transport.receipts.append(packet.receipt)
# TODO: Enable when caching has been redesigned # TODO: Enable when caching has been redesigned
# Transport.cache(packet) # Transport.cache(packet)
@ -850,7 +850,7 @@ class Transport:
should_transmit = False should_transmit = False
if interface != packet.destination.attached_interface: if interface != packet.destination.attached_interface:
should_transmit = False should_transmit = False
if packet.attached_interface != None and interface != packet.attached_interface: if packet.attached_interface != None and interface != packet.attached_interface:
should_transmit = False should_transmit = False
@ -919,7 +919,7 @@ class Transport:
tx_time = (len(packet.raw)*8) / interface.bitrate tx_time = (len(packet.raw)*8) / interface.bitrate
wait_time = (tx_time / interface.announce_cap) wait_time = (tx_time / interface.announce_cap)
interface.announce_allowed_at = outbound_time + wait_time interface.announce_allowed_at = outbound_time + wait_time
else: else:
should_transmit = False should_transmit = False
if not len(interface.announce_queue) >= RNS.Reticulum.MAX_QUEUED_ANNOUNCES: if not len(interface.announce_queue) >= RNS.Reticulum.MAX_QUEUED_ANNOUNCES:
@ -979,10 +979,10 @@ class Transport:
else: else:
pass pass
else: else:
pass pass
if should_transmit: if should_transmit:
if not stored_hash: if not stored_hash:
Transport.packet_hashlist.append(packet.packet_hash) Transport.packet_hashlist.append(packet.packet_hash)
@ -1134,14 +1134,14 @@ class Transport:
if Transport.identity == None: if Transport.identity == None:
return return
Transport.jobs_locked = True Transport.jobs_locked = True
packet = RNS.Packet(None, raw) packet = RNS.Packet(None, raw)
if not packet.unpack(): if not packet.unpack():
Transport.jobs_locked = False Transport.jobs_locked = False
return return
packet.receiving_interface = interface packet.receiving_interface = interface
packet.hops += 1 packet.hops += 1
@ -1205,7 +1205,7 @@ class Transport:
Transport.packet_hashlist.append(packet.packet_hash) Transport.packet_hashlist.append(packet.packet_hash)
# TODO: Enable when caching has been redesigned # TODO: Enable when caching has been redesigned
# Transport.cache(packet) # Transport.cache(packet)
# Check special conditions for local clients connected # Check special conditions for local clients connected
# through a shared Reticulum instance # through a shared Reticulum instance
from_local_client = (packet.receiving_interface in Transport.local_client_interfaces) 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: if packet.destination_hash in Transport.destination_table:
next_hop = Transport.destination_table[packet.destination_hash][1] next_hop = Transport.destination_table[packet.destination_hash][1]
remaining_hops = Transport.destination_table[packet.destination_hash][2] remaining_hops = Transport.destination_table[packet.destination_hash][2]
if remaining_hops > 1: if remaining_hops > 1:
# Just increase hop count and transmit # Just increase hop count and transmit
new_raw = packet.raw[0:1] new_raw = packet.raw[0:1]
@ -1356,7 +1356,7 @@ class Transport:
new_raw += packet.raw[2:] new_raw += packet.raw[2:]
Transport.transmit(outbound_interface, new_raw) Transport.transmit(outbound_interface, new_raw)
Transport.link_table[packet.destination_hash][0] = time.time() Transport.link_table[packet.destination_hash][0] = time.time()
# TODO: Test and possibly enable this at some point # TODO: Test and possibly enable this at some point
# Transport.jobs_locked = False # Transport.jobs_locked = False
# return # return
@ -1383,13 +1383,13 @@ class Transport:
if local_destination == None and RNS.Identity.validate_announce(packet): if local_destination == None and RNS.Identity.validate_announce(packet):
if packet.transport_id != None: if packet.transport_id != None:
received_from = packet.transport_id received_from = packet.transport_id
# Check if this is a next retransmission from # Check if this is a next retransmission from
# another node. If it is, we're removing the # another node. If it is, we're removing the
# announce in question from our pending table # announce in question from our pending table
if RNS.Reticulum.transport_enabled() and packet.destination_hash in Transport.announce_table: if RNS.Reticulum.transport_enabled() and packet.destination_hash in Transport.announce_table:
announce_entry = Transport.announce_table[packet.destination_hash] announce_entry = Transport.announce_table[packet.destination_hash]
if packet.hops-1 == announce_entry[4]: 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) RNS.log(f"Heard a local rebroadcast of announce for {RNS.prettyhexrep(packet.destination_hash)}", RNS.LOG_DEBUG)
announce_entry[6] += 1 announce_entry[6] += 1
@ -1415,7 +1415,7 @@ class Transport:
# local to this system, and that hops are less than the max # 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): 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) 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_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 = [] random_blobs = []
if packet.destination_hash in Transport.destination_table: if packet.destination_hash in Transport.destination_table:
@ -1442,7 +1442,7 @@ class Transport:
# the emission timestamp is more recent. # the emission timestamp is more recent.
now = time.time() now = time.time()
path_expires = Transport.destination_table[packet.destination_hash][3] path_expires = Transport.destination_table[packet.destination_hash][3]
path_announce_emitted = 0 path_announce_emitted = 0
for path_random_blob in random_blobs: for path_random_blob in random_blobs:
path_announce_emitted = max(path_announce_emitted, int.from_bytes(path_random_blob[5:10], "big")) 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 should_add = True
else: else:
should_add = False should_add = False
# If we have already heard this announce before, # If we have already heard this announce before,
# but the path has been marked as unresponsive # but the path has been marked as unresponsive
# by a failed communications attempt or similar, # by a failed communications attempt or similar,
@ -1527,14 +1527,14 @@ class Transport:
else: else:
rate_blocked = True rate_blocked = True
retries = 0 retries = 0
announce_hops = packet.hops announce_hops = packet.hops
local_rebroadcasts = 0 local_rebroadcasts = 0
block_rebroadcasts = False block_rebroadcasts = False
attached_interface = None attached_interface = None
retransmit_timeout = now + (RNS.rand() * Transport.PATHFINDER_RW) 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: 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 expires = now + Transport.ROAMING_PATH_TIME
else: else:
expires = now + Transport.PATHFINDER_E expires = now + Transport.PATHFINDER_E
random_blobs.append(random_blob) random_blobs.append(random_blob)
random_blobs = random_blobs[-Transport.MAX_RANDOM_BLOBS:] random_blobs = random_blobs[-Transport.MAX_RANDOM_BLOBS:]
@ -1552,7 +1552,7 @@ class Transport:
if rate_blocked: if rate_blocked:
RNS.log(f"Blocking rebroadcast of announce from {RNS.prettyhexrep(packet.destination_hash)} due to excessive announce rate", RNS.LOG_DEBUG) RNS.log(f"Blocking rebroadcast of announce from {RNS.prettyhexrep(packet.destination_hash)} due to excessive announce rate", RNS.LOG_DEBUG)
else: else:
if Transport.from_local_client(packet): if Transport.from_local_client(packet):
# If the announce is from a local client, # If the announce is from a local client,
@ -1619,7 +1619,7 @@ class Transport:
attached_interface = local_interface, attached_interface = local_interface,
context_flag = packet.context_flag, context_flag = packet.context_flag,
) )
new_announce.hops = packet.hops new_announce.hops = packet.hops
new_announce.send() new_announce.send()
@ -1730,7 +1730,7 @@ class Transport:
if destination.hash == packet.destination_hash and destination.type == packet.destination_type: if destination.hash == packet.destination_hash and destination.type == packet.destination_type:
packet.destination = destination packet.destination = destination
destination.receive(packet) destination.receive(packet)
# Handling for local data packets # Handling for local data packets
elif packet.packet_type == RNS.Packet.DATA: elif packet.packet_type == RNS.Packet.DATA:
if packet.destination_type == RNS.Destination.LINK: if packet.destination_type == RNS.Destination.LINK:
@ -1844,7 +1844,7 @@ class Transport:
for link in Transport.active_links: for link in Transport.active_links:
if link.link_id == packet.destination_hash: if link.link_id == packet.destination_hash:
packet.link = link packet.link = link
if len(packet.data) == RNS.PacketReceipt.EXPL_LENGTH: if len(packet.data) == RNS.PacketReceipt.EXPL_LENGTH:
proof_hash = packet.data[:RNS.Identity.HASHLENGTH//8] proof_hash = packet.data[:RNS.Identity.HASHLENGTH//8]
else: else:
@ -1884,13 +1884,13 @@ class Transport:
interface_hash = interface.get_hash() interface_hash = interface.get_hash()
public_key = RNS.Transport.identity.get_public_key() public_key = RNS.Transport.identity.get_public_key()
random_hash = RNS.Identity.get_random_hash() random_hash = RNS.Identity.get_random_hash()
tunnel_id_data = public_key+interface_hash tunnel_id_data = public_key+interface_hash
tunnel_id = RNS.Identity.full_hash(tunnel_id_data) tunnel_id = RNS.Identity.full_hash(tunnel_id_data)
signed_data = tunnel_id_data+random_hash signed_data = tunnel_id_data+random_hash
signature = Transport.identity.sign(signed_data) signature = Transport.identity.sign(signed_data)
data = signed_data+signature data = signed_data+signature
tnl_snth_dst = RNS.Destination(None, RNS.Destination.OUT, RNS.Destination.PLAIN, Transport.APP_NAME, "tunnel", "synthesize") tnl_snth_dst = RNS.Destination(None, RNS.Destination.OUT, RNS.Destination.PLAIN, Transport.APP_NAME, "tunnel", "synthesize")
@ -1910,7 +1910,7 @@ class Transport:
tunnel_id_data = public_key+interface_hash tunnel_id_data = public_key+interface_hash
tunnel_id = RNS.Identity.full_hash(tunnel_id_data) 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] 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] signature = data[RNS.Identity.KEYSIZE//8+RNS.Identity.HASHLENGTH//8+RNS.Reticulum.TRUNCATED_HASHLENGTH//8:expected_length]
signed_data = tunnel_id_data+random_hash signed_data = tunnel_id_data+random_hash
@ -1983,7 +1983,7 @@ class Transport:
for registered_destination in Transport.destinations: for registered_destination in Transport.destinations:
if destination.hash == registered_destination.hash: if destination.hash == registered_destination.hash:
raise KeyError("Attempt to register an already registered destination.") raise KeyError("Attempt to register an already registered destination.")
Transport.destinations.append(destination) Transport.destinations.append(destination)
if Transport.owner.is_connected_to_shared_instance: if Transport.owner.is_connected_to_shared_instance:
@ -2070,7 +2070,7 @@ class Transport:
if packet.receiving_interface != None: if packet.receiving_interface != None:
interface_reference = str(packet.receiving_interface) 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.write(umsgpack.packb([packet.raw, interface_reference]))
file.close() file.close()
@ -2428,11 +2428,11 @@ class Transport:
if len(Transport.local_client_interfaces) > 0: if len(Transport.local_client_interfaces) > 0:
if destination_hash in Transport.destination_table: if destination_hash in Transport.destination_table:
destination_interface = Transport.destination_table[destination_hash][5] destination_interface = Transport.destination_table[destination_hash][5]
if Transport.is_local_client_interface(destination_interface): if Transport.is_local_client_interface(destination_interface):
destination_exists_on_local_client = True destination_exists_on_local_client = True
Transport.pending_local_path_requests[destination_hash] = attached_interface Transport.pending_local_path_requests[destination_hash] = attached_interface
local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None) local_destination = next((d for d in Transport.destinations if d.hash == destination_hash), None)
if local_destination != None: if local_destination != None:
local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface) local_destination.announce(path_response=True, tag=tag, attached_interface=attached_interface)
@ -2445,7 +2445,7 @@ class Transport:
if attached_interface.mode == RNS.Interfaces.Interface.Interface.MODE_ROAMING and attached_interface == received_from: 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) RNS.log("Not answering path request on roaming-mode interface, since next hop is on same roaming-mode interface", RNS.LOG_DEBUG)
else: else:
if requestor_transport_id != None and next_hop == requestor_transport_id: if requestor_transport_id != None and next_hop == requestor_transport_id:
# TODO: Find a bandwidth efficient way to invalidate our # TODO: Find a bandwidth efficient way to invalidate our
@ -2489,7 +2489,7 @@ class Transport:
if packet.destination_hash in Transport.announce_table: if packet.destination_hash in Transport.announce_table:
held_entry = Transport.announce_table[packet.destination_hash] held_entry = Transport.announce_table[packet.destination_hash]
Transport.held_announces[packet.destination_hash] = held_entry 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] 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: elif is_from_local_client:
@ -2563,7 +2563,7 @@ class Transport:
detachable_interfaces.append(interface) detachable_interfaces.append(interface)
else: else:
pass pass
for interface in Transport.local_client_interfaces: for interface in Transport.local_client_interfaces:
# Currently no rules are being applied # Currently no rules are being applied
# here, and all interfaces will be sent # here, and all interfaces will be sent

View File

@ -77,7 +77,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}"
if os.path.isfile(identity_path): if os.path.isfile(identity_path):
identity = RNS.Identity.from_file(identity_path) identity = RNS.Identity.from_file(identity_path)
if identity == None: if identity == None:
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO) RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO)
@ -121,7 +121,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
ms = "y" ms = "y"
else: else:
ms = "ies" ms = "ies"
RNS.log(f"Loaded {len(ali)} allowed identit{ms} from {allowed_file}", RNS.LOG_VERBOSE) RNS.log(f"Loaded {len(ali)} allowed identit{ms} from {allowed_file}", RNS.LOG_VERBOSE)
except Exception as e: except Exception as e:
@ -210,7 +210,7 @@ def listen(configdir, verbosity = 0, quietness = 0, allowed = [], display_identi
destination.announce() destination.announce()
threading.Thread(target=job, daemon=True).start() threading.Thread(target=job, daemon=True).start()
while True: while True:
time.sleep(1) time.sleep(1)
@ -236,7 +236,7 @@ def receive_sender_identified(link, identity):
def receive_resource_callback(resource): def receive_resource_callback(resource):
global allow_all global allow_all
sender_identity = resource.link.get_remote_identity() sender_identity = resource.link.get_remote_identity()
if sender_identity != None: if sender_identity != None:
@ -278,7 +278,7 @@ def receive_resource_concluded(resource):
while os.path.isfile(full_save_path): while os.path.isfile(full_save_path):
counter += 1 counter += 1
full_save_path = f"{saved_filename}.{counter}" full_save_path = f"{saved_filename}.{counter}"
file = open(full_save_path, "wb") file = open(full_save_path, "wb")
file.write(resource.data.read()) file.write(resource.data.read())
file.close() file.close()
@ -599,7 +599,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
print(str(e)) print(str(e))
exit(1) exit(1)
file_path = os.path.expanduser(file) file_path = os.path.expanduser(file)
if not os.path.isfile(file_path): if not os.path.isfile(file_path):
print("File not found") print("File not found")
@ -715,7 +715,7 @@ def send(configdir, verbosity = 0, quietness = 0, destination = None, file = Non
sys.stdout.flush() sys.stdout.flush()
i = (i+1)%len(syms) i = (i+1)%len(syms)
if resource.status > RNS.Resource.COMPLETE: if resource.status > RNS.Resource.COMPLETE:
if silent: if silent:
print(f"File was not accepted by {RNS.prettyhexrep(destination_hash)}") print(f"File was not accepted by {RNS.prettyhexrep(destination_hash)}")
@ -796,7 +796,7 @@ def main():
parser.add_argument('-P', '--phy-rates', action='store_true', default=False, help="display physical layer transfer rates") parser.add_argument('-P', '--phy-rates', action='store_true', default=False, help="display physical layer transfer rates")
# parser.add_argument("--limit", action="store", metavar="files", type=float, help="maximum number of files to accept", default=None) # 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__}") parser.add_argument("--version", action="version", version=f"rncp {__version__}")
args = parser.parse_args() args = parser.parse_args()
if args.listen or args.print_identity: if args.listen or args.print_identity:

View File

@ -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("-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("-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("-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("-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) 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("-B", "--base32", action="store_true", default=False, help="Use base32-encoded input and output")
parser.add_argument("--version", action="version", version=f"rnid {__version__}") parser.add_argument("--version", action="version", version=f"rnid {__version__}")
args = parser.parse_args() args = parser.parse_args()
ops = 0; ops = 0;
for t in [args.encrypt, args.decrypt, args.validate, args.sign]: for t in [args.encrypt, args.decrypt, args.validate, args.sign]:
if t: if t:
ops += 1 ops += 1
if 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) RNS.log("This utility currently only supports one of the encrypt, decrypt, sign or verify operations per invocation", RNS.LOG_ERROR)
exit(1) exit(1)
@ -179,7 +179,7 @@ def main():
quietness = args.quiet quietness = args.quiet
if verbosity != 0 or quietness != 0: if verbosity != 0 or quietness != 0:
targetloglevel = targetloglevel+verbosity-quietness targetloglevel = targetloglevel+verbosity-quietness
# Start Reticulum # Start Reticulum
reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel) reticulum = RNS.Reticulum(configdir=args.config, loglevel=targetloglevel)
RNS.compact_log_fmt = True RNS.compact_log_fmt = True
@ -234,7 +234,7 @@ def main():
RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR) RNS.log("Invalid hexadecimal hash provided", RNS.LOG_ERROR)
exit(7) exit(7)
else: else:
# Try loading Identity from file # Try loading Identity from file
if not os.path.isfile(identity_str): 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("Could not open output file for writing", RNS.LOG_ERROR)
RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR) RNS.log(f"The contained exception was: {e}", RNS.LOG_ERROR)
exit(15) exit(15)
# TODO: Actually expand this to a good solution # TODO: Actually expand this to a good solution
# probably need to create a wrapper that takes # probably need to create a wrapper that takes
# into account not closing stdout when done # into account not closing stdout when done
@ -415,12 +415,12 @@ def main():
if not args.stdout: if not args.stdout:
RNS.log(f"Signing {args.read}") RNS.log(f"Signing {args.read}")
try: try:
data_output.write(identity.sign(data_input.read())) data_output.write(identity.sign(data_input.read()))
data_output.close() data_output.close()
data_input.close() data_input.close()
if not args.stdout: if not args.stdout:
if args.read: if args.read:
RNS.log(f"File {args.read} signed with {identity} to {args.write}") RNS.log(f"File {args.read} signed with {identity} to {args.write}")
@ -448,7 +448,7 @@ def main():
else: else:
# if not args.stdout: # if not args.stdout:
# RNS.log("Verifying "+str(args.validate)+" for "+str(args.read)) # RNS.log("Verifying "+str(args.validate)+" for "+str(args.read))
try: try:
try: try:
sig_input = open(args.validate, "rb") sig_input = open(args.validate, "rb")
@ -498,7 +498,7 @@ def main():
if not args.stdout: if not args.stdout:
RNS.log(f"Encrypting {args.read}") RNS.log(f"Encrypting {args.read}")
try: try:
more_data = True more_data = True
while more_data: while more_data:
@ -545,7 +545,7 @@ def main():
if not args.stdout: if not args.stdout:
RNS.log(f"Decrypting {args.read}...") RNS.log(f"Decrypting {args.read}...")
try: try:
more_data = True more_data = True
while more_data: while more_data:

View File

@ -49,7 +49,7 @@ def main():
parser.add_argument('-q', '--quiet', action='count', default=0) parser.add_argument('-q', '--quiet', action='count', default=0)
parser.add_argument("--exampleconfig", action='store_true', default=False, help="print verbose configuration example to stdout and exit") parser.add_argument("--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__}") parser.add_argument("--version", action="version", version=f"ir {__version__}")
args = parser.parse_args() args = parser.parse_args()
if args.exampleconfig: if args.exampleconfig:

View File

@ -61,7 +61,7 @@ class KISS():
FESC = 0xDB FESC = 0xDB
TFEND = 0xDC TFEND = 0xDC
TFESC = 0xDD TFESC = 0xDD
CMD_UNKNOWN = 0xFE CMD_UNKNOWN = 0xFE
CMD_DATA = 0x00 CMD_DATA = 0x00
CMD_FREQUENCY = 0x01 CMD_FREQUENCY = 0x01
@ -104,11 +104,11 @@ class KISS():
DETECT_REQ = 0x73 DETECT_REQ = 0x73
DETECT_RESP = 0x46 DETECT_RESP = 0x46
RADIO_STATE_OFF = 0x00 RADIO_STATE_OFF = 0x00
RADIO_STATE_ON = 0x01 RADIO_STATE_ON = 0x01
RADIO_STATE_ASK = 0xFF RADIO_STATE_ASK = 0xFF
CMD_ERROR = 0x90 CMD_ERROR = 0x90
ERROR_INITRADIO = 0x01 ERROR_INITRADIO = 0x01
ERROR_TXFAILED = 0x02 ERROR_TXFAILED = 0x02
@ -191,7 +191,7 @@ class ROM():
PRODUCT_TECHO = 0x15 PRODUCT_TECHO = 0x15
MODEL_T4 = 0x16 MODEL_T4 = 0x16
MODEL_T9 = 0x17 MODEL_T9 = 0x17
PRODUCT_HMBRW = 0xF0 PRODUCT_HMBRW = 0xF0
MODEL_FF = 0xFF MODEL_FF = 0xFF
MODEL_FE = 0xFE MODEL_FE = 0xFE
@ -610,7 +610,7 @@ class RNode():
self.detected = True self.detected = True
else: else:
self.detected = False self.detected = False
else: else:
time_since_last = int(time.time()*1000) - last_read_ms time_since_last = int(time.time()*1000) - last_read_ms
if len(data_buffer) > 0 and time_since_last > self.timeout: 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.serialization import load_der_private_key
from cryptography.hazmat.primitives.asymmetric import padding from cryptography.hazmat.primitives.asymmetric import padding
# Try loading local signing key for # Try loading local signing key for
# validation of self-signed devices # validation of self-signed devices
if os.path.isdir(FWD_DIR) and os.path.isfile(FWD_DIR+"/signing.key"): if os.path.isdir(FWD_DIR) and os.path.isfile(FWD_DIR+"/signing.key"):
private_bytes = None private_bytes = None
@ -922,7 +922,7 @@ class RNode():
RNS.log("Could not deserialize local signing key") RNS.log("Could not deserialize local signing key")
RNS.log(str(e)) RNS.log(str(e))
# Try loading trusted signing key for # Try loading trusted signing key for
# validation of devices # validation of devices
if os.path.isdir(TK_DIR): if os.path.isdir(TK_DIR):
for f in os.listdir(TK_DIR): for f in os.listdir(TK_DIR):
@ -1230,11 +1230,11 @@ def rnode_open_serial(port):
write_timeout = None, write_timeout = None,
dsrdtr = False dsrdtr = False
) )
def graceful_exit(C=0): def graceful_exit(C=0):
if RNS.vendor.platformutils.is_windows(): 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: if rnode:
RNS.log("Sending \"Leave\" to Rnode",RNS.LOG_VERBOSE) RNS.log("Sending \"Leave\" to Rnode",RNS.LOG_VERBOSE)
rnode.leave() # Leave has wait built in 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("-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("-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("-S", "--sign", action="store_true", help="Display public part of signing key")
parser.add_argument("-H", "--firmware-hash", action="store", help="Display installed firmware hash") parser.add_argument("-H", "--firmware-hash", action="store", help="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("-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("-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("--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("--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") 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: if args.fw_version != None:
selected_version = args.fw_version selected_version = args.fw_version
try: try:
check_float = float(selected_version) check_float = float(selected_version)
except ValueError: except ValueError:
RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.") RNS.log("Selected version \""+selected_version+"\" does not appear to be a number.")
@ -1368,7 +1368,7 @@ def main():
if args.nocheck: if args.nocheck:
upd_nocheck = True upd_nocheck = True
if args.public or args.key or args.flash or args.rom or args.autoinstall or args.trust_key: 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.primitives import hashes
from cryptography.hazmat.backends import default_backend from cryptography.hazmat.backends import default_backend
@ -1419,8 +1419,8 @@ def main():
ports = list_ports.comports() ports = list_ports.comports()
portlist = [] portlist = []
for port in ports: for port in ports:
portlist.insert(0, port) portlist.insert(0, port)
pi = 1 pi = 1
print("Detected serial ports:") print("Detected serial ports:")
for port in portlist: for port in portlist:
@ -1556,8 +1556,8 @@ def main():
ports = list_ports.comports() ports = list_ports.comports()
portlist = [] portlist = []
for port in ports: for port in ports:
portlist.insert(0, port) portlist.insert(0, port)
pi = 1 pi = 1
print("Detected serial ports:") print("Detected serial ports:")
for port in portlist: for port in portlist:
@ -1638,7 +1638,7 @@ def main():
print("correct firmware and provision it.") print("correct firmware and provision it.")
else: else:
print("\nIt looks like this is a fresh device with no RNode firmware.") print("\nIt looks like this is a fresh device with no RNode firmware.")
print("") print("")
print("What kind of device is this?\n") print("What kind of device is this?\n")
print("[1] A specific kind of RNode") print("[1] A specific kind of RNode")
@ -2224,7 +2224,7 @@ def main():
fw_filename = "rnode_firmware.hex" fw_filename = "rnode_firmware.hex"
elif selected_mcu == ROM.MCU_2560: elif selected_mcu == ROM.MCU_2560:
fw_filename = "rnode_firmware_m2560.hex" fw_filename = "rnode_firmware_m2560.hex"
elif selected_platform == ROM.PLATFORM_ESP32: elif selected_platform == ROM.PLATFORM_ESP32:
fw_filename = None fw_filename = None
print("\nWhat kind of ESP32 board is this?\n") print("\nWhat kind of ESP32 board is this?\n")
@ -2337,7 +2337,7 @@ def main():
except Exception as e: except Exception as e:
RNS.log("Could not load device signing key") RNS.log("Could not load device signing key")
graceful_exit() graceful_exit()
@ -2413,7 +2413,7 @@ def main():
return part_hash return part_hash
else: else:
return None return None
elif platform == ROM.PLATFORM_NRF52: elif platform == ROM.PLATFORM_NRF52:
# Calculate digest manually, as it is not included in the image. # Calculate digest manually, as it is not included in the image.
firmware_data = open(partition_file, "rb") firmware_data = open(partition_file, "rb")
@ -2994,7 +2994,7 @@ def main():
wants_fw_provision = False wants_fw_provision = False
if args.flash: if args.flash:
from subprocess import call from subprocess import call
if fw_filename == None: if fw_filename == None:
fw_filename = "rnode_firmware.hex" fw_filename = "rnode_firmware.hex"
@ -3032,7 +3032,7 @@ def main():
RNS.log("Error while flashing") RNS.log("Error while flashing")
RNS.log(str(e)) RNS.log(str(e))
graceful_exit(1) graceful_exit(1)
else: else:
fw_src = UPD_DIR+"/"+selected_version+"/" fw_src = UPD_DIR+"/"+selected_version+"/"
if os.path.isfile(fw_src+fw_filename): if os.path.isfile(fw_src+fw_filename):
@ -3215,7 +3215,7 @@ def main():
update_full_path = EXT_DIR+"/extracted_rnode_firmware.version" update_full_path = EXT_DIR+"/extracted_rnode_firmware.version"
else: else:
update_full_path = UPD_DIR+"/"+selected_version+"/"+fw_filename update_full_path = UPD_DIR+"/"+selected_version+"/"+fw_filename
if os.path.isfile(update_full_path): if os.path.isfile(update_full_path):
try: try:
args.info = False args.info = False
RNS.log("Updating RNode firmware for device on "+args.port) RNS.log("Updating RNode firmware for device on "+args.port)
@ -3468,7 +3468,7 @@ def main():
if args.autoinstall: if args.autoinstall:
RNS.log("Clearing old EEPROM, this will take about 15 seconds...") RNS.log("Clearing old EEPROM, this will take about 15 seconds...")
rnode.wipe_eeprom() rnode.wipe_eeprom()
if rnode.platform == ROM.PLATFORM_ESP32: if rnode.platform == ROM.PLATFORM_ESP32:
RNS.log("Waiting for ESP32 reset...") RNS.log("Waiting for ESP32 reset...")
time.sleep(6) time.sleep(6)
@ -3849,7 +3849,7 @@ def main():
else: else:
RNS.log("This device has not been provisioned yet, cannot get firmware hash") RNS.log("This device has not been provisioned yet, cannot get firmware hash")
exit(77) exit(77)
if args.get_firmware_hash: if args.get_firmware_hash:
if rnode.provisioned: if rnode.provisioned:
RNS.log(f"The actual firmware hash is: {rnode.firmware_hash.hex()}") RNS.log(f"The actual firmware hash is: {rnode.firmware_hash.hex()}")
@ -3923,7 +3923,7 @@ def main():
except KeyboardInterrupt: except KeyboardInterrupt:
print("") print("")
graceful_exit() graceful_exit()
graceful_exit() graceful_exit()
def extract_recovery_esptool(): def extract_recovery_esptool():

View File

@ -235,7 +235,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
hour_rate = round(len(entry["timestamps"])/span_hours, 3) hour_rate = round(len(entry["timestamps"])/span_hours, 3)
if hour_rate-int(hour_rate) == 0: if hour_rate-int(hour_rate) == 0:
hour_rate = int(hour_rate) hour_rate = int(hour_rate)
if entry["rate_violations"] > 0: if entry["rate_violations"] > 0:
if entry["rate_violations"] == 1: if entry["rate_violations"] == 1:
s_str = "" 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}" rv_str = f", {entry['rate_violations']} active rate violation{s_str}"
else: else:
rv_str = "" rv_str = ""
if entry["blocked_until"] > time.time(): if entry["blocked_until"] > time.time():
bli = time.time()-(int(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))}" bl_str = f", new announces allowed in {pretty_date(int(bli))}"
else: else:
bl_str = "" 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}") 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: 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...") print("Dropping announce queues on all interfaces...")
reticulum.drop_announce_queues() reticulum.drop_announce_queues()
elif drop: elif drop:
if remote_link: if remote_link:
if not no_output: if not no_output:
@ -341,7 +341,7 @@ def program_setup(configdir, table, rates, drop, destination_hexhash, verbosity,
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
sys.exit(1) sys.exit(1)
if not RNS.Transport.has_path(destination_hash): if not RNS.Transport.has_path(destination_hash):
RNS.Transport.request_path(destination_hash) RNS.Transport.request_path(destination_hash)
print(f"Path to {RNS.prettyhexrep(destination_hash)} requested ", end=" ") 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") print("\r \rPath not found")
sys.exit(1) sys.exit(1)
def main(): def main():
try: try:
@ -479,7 +479,7 @@ def main():
help="timeout before giving up on remote queries", help="timeout before giving up on remote queries",
default=RNS.Transport.PATH_REQUEST_TIMEOUT default=RNS.Transport.PATH_REQUEST_TIMEOUT
) )
parser.add_argument( parser.add_argument(
"-j", "-j",
"--json", "--json",
@ -497,7 +497,7 @@ def main():
) )
parser.add_argument('-v', '--verbose', action='count', default=0) parser.add_argument('-v', '--verbose', action='count', default=0)
args = parser.parse_args() args = parser.parse_args()
if args.config: if args.config:

View File

@ -38,7 +38,7 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
if full_name == None: if full_name == None:
print("The full destination name including application name aspects must be specified for the destination") print("The full destination name including application name aspects must be specified for the destination")
exit() exit()
try: try:
app_name, aspects = RNS.Destination.app_and_aspects_from_name(full_name) 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: if time.time() > _timeout:
print("\r \rProbe timed out") print("\r \rProbe timed out")
else: else:
print("\b\b ") print("\b\b ")
sys.stdout.flush() sys.stdout.flush()
@ -162,10 +162,10 @@ def program_setup(configdir, destination_hexhash, size=None, full_name = None, v
if reception_rssi != None: if reception_rssi != None:
reception_stats += f" [RSSI {reception_rssi} dBm]" reception_stats += f" [RSSI {reception_rssi} dBm]"
if reception_snr != None: if reception_snr != None:
reception_stats += f" [SNR {reception_snr} dB]" reception_stats += f" [SNR {reception_snr} dB]"
if reception_q != None: if reception_q != None:
reception_stats += f" [Link Quality {reception_q}%]" 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 != None:
if receipt.proof_packet.rssi != None: if receipt.proof_packet.rssi != None:
reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]" reception_stats += f" [RSSI {receipt.proof_packet.rssi} dBm]"
if receipt.proof_packet.snr != None: if receipt.proof_packet.snr != None:
reception_stats += f" [SNR {receipt.proof_packet.snr} dB]" 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) exit(2)
else: else:
exit(0) exit(0)
def main(): def main():
try: try:

View File

@ -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('-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("--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__}") parser.add_argument("--version", action="version", version=f"rnsd {__version__}")
args = parser.parse_args() args = parser.parse_args()
if args.exampleconfig: if args.exampleconfig:
@ -192,7 +192,7 @@ loglevel = 4
# The following example enables communication with other # The following example enables communication with other
# local Reticulum peers using UDP broadcasts. # local Reticulum peers using UDP broadcasts.
[[UDP Interface]] [[UDP Interface]]
type = UDPInterface type = UDPInterface
enabled = no enabled = no
@ -235,24 +235,24 @@ loglevel = 4
# This example demonstrates a TCP server interface. # This example demonstrates a TCP server interface.
# It will listen for incoming connections on the # It will listen for incoming connections on the
# specified IP address and port number. # specified IP address and port number.
[[TCP Server Interface]] [[TCP Server Interface]]
type = TCPServerInterface type = TCPServerInterface
enabled = no enabled = no
# This configuration will listen on all IP # This configuration will listen on all IP
# interfaces on port 4242 # interfaces on port 4242
listen_ip = 0.0.0.0 listen_ip = 0.0.0.0
listen_port = 4242 listen_port = 4242
# Alternatively you can bind to a specific IP # Alternatively you can bind to a specific IP
# listen_ip = 10.0.0.88 # listen_ip = 10.0.0.88
# listen_port = 4242 # listen_port = 4242
# Or a specific network device # Or a specific network device
# device = eth0 # device = eth0
# port = 4242 # port = 4242
@ -300,7 +300,7 @@ loglevel = 4
# host device before connecting. BLE # host device before connecting. BLE
# devices can be connected by name, # devices can be connected by name,
# BLE MAC address or by any available. # BLE MAC address or by any available.
# Connect to specific device by name # Connect to specific device by name
# port = ble://RNode 3B87 # port = ble://RNode 3B87
@ -320,7 +320,7 @@ loglevel = 4
# Set TX power to 7 dBm (5 mW) # Set TX power to 7 dBm (5 mW)
txpower = 7 txpower = 7
# Select spreading factor 8. Valid # Select spreading factor 8. Valid
# range is 7 through 12, with 7 # range is 7 through 12, with 7
# being the fastest and 12 having # being the fastest and 12 having
# the longest range. # the longest range.
@ -349,8 +349,8 @@ loglevel = 4
# flow control can be useful. By default # flow control can be useful. By default
# it is disabled. # it is disabled.
flow_control = False flow_control = False
# An example KISS modem interface. Useful for running # An example KISS modem interface. Useful for running
# Reticulum over packet radio hardware. # Reticulum over packet radio hardware.
@ -365,7 +365,7 @@ loglevel = 4
# Set the serial baud-rate and other # Set the serial baud-rate and other
# configuration parameters. # configuration parameters.
speed = 115200 speed = 115200
databits = 8 databits = 8
parity = none parity = none
stopbits = 1 stopbits = 1
@ -413,7 +413,7 @@ loglevel = 4
# way, Reticulum will automatically encapsulate it's # way, Reticulum will automatically encapsulate it's
# traffic in AX.25 and also identify your stations # traffic in AX.25 and also identify your stations
# transmissions with your callsign and SSID. # transmissions with your callsign and SSID.
# #
# Only do this if you really need to! Reticulum doesn't # Only do this if you really need to! Reticulum doesn't
# need the AX.25 layer for anything, and it incurs extra # need the AX.25 layer for anything, and it incurs extra
# overhead on every packet to encapsulate in AX.25. # overhead on every packet to encapsulate in AX.25.
@ -436,7 +436,7 @@ loglevel = 4
# Set the serial baud-rate and other # Set the serial baud-rate and other
# configuration parameters. # configuration parameters.
speed = 115200 speed = 115200
databits = 8 databits = 8
parity = none parity = none
stopbits = 1 stopbits = 1

View File

@ -161,7 +161,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
stats, link_count = remote_status stats, link_count = remote_status
except Exception as e: except Exception as e:
raise e raise e
except Exception as e: except Exception as e:
print(str(e)) print(str(e))
exit(20) exit(20)
@ -215,7 +215,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
if sorting == "held": if sorting == "held":
interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse) interfaces.sort(key=lambda i: i["held_announces"], reverse=not sort_reverse)
for ifstat in interfaces: for ifstat in interfaces:
name = ifstat["name"] name = ifstat["name"]
@ -302,10 +302,10 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
if "airtime_short" in ifstat and "airtime_long" in ifstat: 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"]))) 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: if "channel_load_short" in ifstat and "channel_load_long" in ifstat:
print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"]))) print(" Ch.Load : {ats}% (15s), {atl}% (1h)".format(ats=str(ifstat["channel_load_short"]),atl=str(ifstat["channel_load_long"])))
if "peers" in ifstat and ifstat["peers"] != None: if "peers" in ifstat and ifstat["peers"] != None:
print(" Peers : {np} reachable".format(np=ifstat["peers"])) print(" Peers : {np} reachable".format(np=ifstat["peers"]))
@ -315,7 +315,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None: if "ifac_signature" in ifstat and ifstat["ifac_signature"] != None:
sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">" sigstr = "<…"+RNS.hexrep(ifstat["ifac_signature"][-5:], delimit=False)+">"
print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr)) print(" Access : {nb}-bit IFAC by {sig}".format(nb=ifstat["ifac_size"]*8, sig=sigstr))
if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None: if "i2p_b32" in ifstat and ifstat["i2p_b32"] != None:
print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"]))) print(" I2P B32 : {ep}".format(ep=str(ifstat["i2p_b32"])))
@ -325,14 +325,14 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
print(" Queued : {np} announce".format(np=aqn)) print(" Queued : {np} announce".format(np=aqn))
else: else:
print(" Queued : {np} announces".format(np=aqn)) print(" Queued : {np} announces".format(np=aqn))
if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0: if astats and "held_announces" in ifstat and ifstat["held_announces"] != None and ifstat["held_announces"] > 0:
aqn = ifstat["held_announces"] aqn = ifstat["held_announces"]
if aqn == 1: if aqn == 1:
print(" Held : {np} announce".format(np=aqn)) print(" Held : {np} announce".format(np=aqn))
else: else:
print(" Held : {np} announces".format(np=aqn)) print(" Held : {np} announces".format(np=aqn))
if astats and "incoming_announce_frequency" in ifstat and ifstat["incoming_announce_frequency"] != None: 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(" Announces : {iaf}".format(iaf=RNS.prettyfrequency(ifstat["outgoing_announce_frequency"])))
print(" {iaf}".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"]))) print(" {iaf}".format(iaf=RNS.prettyfrequency(ifstat["incoming_announce_frequency"])))
@ -358,7 +358,7 @@ def program_setup(configdir, dispall=False, verbosity=0, name_filter=None, json=
print(f"\n{lstr}") print(f"\n{lstr}")
print("") print("")
else: else:
if not remote: if not remote:
print("Could not get RNS status") print("Could not get RNS status")
@ -379,7 +379,7 @@ def main():
help="show all interfaces", help="show all interfaces",
default=False default=False
) )
parser.add_argument( parser.add_argument(
"-A", "-A",
"--announce-stats", "--announce-stats",
@ -387,7 +387,7 @@ def main():
help="show announce stats", help="show announce stats",
default=False default=False
) )
parser.add_argument( parser.add_argument(
"-l", "-l",
"--link-stats", "--link-stats",
@ -395,7 +395,7 @@ def main():
help="show link stats", help="show link stats",
default=False, default=False,
) )
parser.add_argument( parser.add_argument(
"-s", "-s",
"--sort", "--sort",
@ -404,7 +404,7 @@ def main():
default=None, default=None,
type=str type=str
) )
parser.add_argument( parser.add_argument(
"-r", "-r",
"--reverse", "--reverse",
@ -412,7 +412,7 @@ def main():
help="reverse sorting", help="reverse sorting",
default=False, default=False,
) )
parser.add_argument( parser.add_argument(
"-j", "-j",
"--json", "--json",
@ -451,7 +451,7 @@ def main():
parser.add_argument('-v', '--verbose', action='count', default=0) 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) parser.add_argument("filter", nargs="?", default=None, help="only display interfaces with names including filter", type=str)
args = parser.parse_args() args = parser.parse_args()
if args.config: if args.config:

View File

@ -45,7 +45,7 @@ def prepare_identity(identity_path):
identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}" identity_path = f"{RNS.Reticulum.identitypath}/{APP_NAME}"
if os.path.isfile(identity_path): if os.path.isfile(identity_path):
identity = RNS.Identity.from_file(identity_path) identity = RNS.Identity.from_file(identity_path)
if identity == None: if identity == None:
RNS.log("No valid saved identity found, creating new...", RNS.LOG_INFO) 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 targetloglevel = 3+verbosity-quietness
reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel) reticulum = RNS.Reticulum(configdir=configdir, loglevel=targetloglevel)
prepare_identity(identitypath) prepare_identity(identitypath)
destination = RNS.Destination(identity, RNS.Destination.IN, RNS.Destination.SINGLE, APP_NAME, "execute") 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: if not disable_announce:
destination.announce() destination.announce()
while True: while True:
time.sleep(1) 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: if link == None or link.status == RNS.Link.CLOSED or link.status == RNS.Link.PENDING:
link = RNS.Link(listener_destination) link = RNS.Link(listener_destination)
link.did_identify = False 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): 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)}") print(f"Could not establish link with {RNS.prettyhexrep(destination_hash)}")
exit(243) exit(243)
@ -467,7 +467,7 @@ def execute(configdir, identitypath = None, verbosity = 0, quietness = 0, detail
else: else:
tstr = "" tstr = ""
print(f"Remote wrote {outlen} bytes to stdout{tstr}") print(f"Remote wrote {outlen} bytes to stdout{tstr}")
if errlen != None and stderr != None: if errlen != None and stderr != None:
if len(stderr) < errlen: if len(stderr) < errlen:
tstr = f", {len(stderr)} bytes displayed" 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("--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("--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__}") parser.add_argument("--version", action="version", version=f"rnx {__version__}")
args = parser.parse_args() args = parser.parse_args()
if args.listen or args.print_identity: if args.listen or args.print_identity:
@ -600,8 +600,8 @@ def main():
# while True: # while True:
# ch = sys.stdin.read(1) # ch = sys.stdin.read(1)
# cmdbuf += ch.encode("utf-8") # cmdbuf += ch.encode("utf-8")
# print("\r"+prompt+cmdbuf.decode("utf-8"), end="") # print("\r"+prompt+cmdbuf.decode("utf-8"), end="")
command = input() command = input()
if command.lower() == "exit" or command.lower() == "quit": if command.lower() == "exit" or command.lower() == "quit":
exit(0) exit(0)
@ -676,7 +676,7 @@ def pretty_time(time, verbose=False):
minutes = int(time // 60) minutes = int(time // 60)
time %= 60 time %= 60
seconds = round(time, 2) seconds = round(time, 2)
ss = "" if seconds == 1 else "s" ss = "" if seconds == 1 else "s"
sm = "" if minutes == 1 else "s" sm = "" if minutes == 1 else "s"
sh = "" if hours == 1 else "s" sh = "" if hours == 1 else "s"

View File

@ -90,7 +90,7 @@ def loglevelname(level):
return "Debug" return "Debug"
if (level == LOG_EXTREME): if (level == LOG_EXTREME):
return "Extra" return "Extra"
return "Unknown" return "Unknown"
def version(): def version():
@ -124,7 +124,7 @@ def log(msg, level=3, _override_destination = False):
file = open(logfile, "a") file = open(logfile, "a")
file.write(logstring+"\n") file.write(logstring+"\n")
file.close() file.close()
if os.path.getsize(logfile) > LOG_MAXSIZE: if os.path.getsize(logfile) > LOG_MAXSIZE:
prevfile = logfile+".1" prevfile = logfile+".1"
if os.path.isfile(prevfile): 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("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL)
log("Dumping future log events to console!", LOG_CRITICAL) log("Dumping future log events to console!", LOG_CRITICAL)
log(msg, level) log(msg, level)
def rand(): def rand():
result = instance_random.random() result = instance_random.random()
@ -155,7 +155,7 @@ def hexrep(data, delimit=True):
iter(data) iter(data)
except TypeError: except TypeError:
data = [data] data = [data]
delimiter = ":" delimiter = ":"
if not delimit: if not delimit:
delimiter = "" delimiter = ""
@ -228,7 +228,7 @@ def prettytime(time, verbose=False, compact=False):
seconds = int(time) seconds = int(time)
else: else:
seconds = round(time, 2) seconds = round(time, 2)
ss = "" if seconds == 1 else "s" ss = "" if seconds == 1 else "s"
sm = "" if minutes == 1 else "s" sm = "" if minutes == 1 else "s"
sh = "" if hours == 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): def prettyshorttime(time, verbose=False, compact=False):
time = time*1e6 time = time*1e6
seconds = int(time // 1e6); time %= 1e6 seconds = int(time // 1e6); time %= 1e6
milliseconds = int(time // 1e3); time %= 1e3 milliseconds = int(time // 1e3); time %= 1e3
@ -280,7 +280,7 @@ def prettyshorttime(time, verbose=False, compact=False):
microseconds = int(time) microseconds = int(time)
else: else:
microseconds = round(time, 2) microseconds = round(time, 2)
ss = "" if seconds == 1 else "s" ss = "" if seconds == 1 else "s"
sms = "" if milliseconds == 1 else "s" sms = "" if milliseconds == 1 else "s"
sus = "" if microseconds == 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(): def profiler_results():
from statistics import mean, median, stdev from statistics import mean, median, stdev
results = {} results = {}
for tag in profiler_tags: for tag in profiler_tags:
tag_captures = [] tag_captures = []
tag_entry = profiler_tags[tag] tag_entry = profiler_tags[tag]
for thread_ident in tag_entry["threads"]: for thread_ident in tag_entry["threads"]:
thread_entry = tag_entry["threads"][thread_ident] thread_entry = tag_entry["threads"][thread_ident]
thread_captures = thread_entry["captures"] thread_captures = thread_entry["captures"]
sample_count = len(thread_captures) sample_count = len(thread_captures)
if sample_count > 2: if sample_count > 2:
thread_results = { thread_results = {
"count": sample_count, "count": sample_count,

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
""" """
A modern asynchronous library for building I2P applications. A modern asynchronous library for building I2P applications.
""" """
from .__version__ import ( from .__version__ import (
@ -10,7 +10,7 @@ from .__version__ import (
from .sam import Destination, PrivateKey from .sam import Destination, PrivateKey
from .aiosam import ( from .aiosam import (
get_sam_socket, dest_lookup, new_destination, get_sam_socket, dest_lookup, new_destination,
create_session, stream_connect, stream_accept, create_session, stream_connect, stream_accept,
Session, StreamConnection, StreamAcceptor Session, StreamConnection, StreamAcceptor
) )

View File

@ -34,12 +34,12 @@ async def get_sam_socket(sam_address=sam.DEFAULT_ADDRESS, loop=None):
writer.close() writer.close()
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]() 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): 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. .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. address.
:param sam_address: (optional) SAM API address :param sam_address: (optional) SAM API address
:param loop: (optional) Event loop instance :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, async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None,
sig_type=sam.Destination.default_sig_type): 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. chosen signature type.
:param sam_address: (optional) SAM API address :param sam_address: (optional) SAM API address
@ -70,7 +70,7 @@ async def new_destination(sam_address=sam.DEFAULT_ADDRESS, loop=None,
writer.close() writer.close()
return sam.Destination(reply["PRIV"], has_private_key=True) 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", loop=None, style="STREAM",
signature_type=sam.Destination.default_sig_type, signature_type=sam.Destination.default_sig_type,
destination=None, options={}): 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 sam_address: (optional) SAM API address
:param loop: (optional) Event loop instance :param loop: (optional) Event loop instance
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW :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 signature type is used
:param destination: (optional) Destination to use in this session. Can be :param destination: (optional) Destination to use in this session. Can be
a base64 encoded string, :class:`Destination` a base64 encoded string, :class:`Destination`
instance or None. TRANSIENT destination is used when it instance or None. TRANSIENT destination is used when it
is None. is None.
:param options: (optional) A dict object with i2cp options :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 reply.ok:
if not destination: if not destination:
destination = sam.Destination( destination = sam.Destination(
reply["DESTINATION"], has_private_key=True) reply["DESTINATION"], has_private_key=True)
logger.debug(destination.base32) logger.debug(destination.base32)
logger.debug(f"Session created {session_name}") logger.debug(f"Session created {session_name}")
return (reader, writer) return (reader, writer)
@ -119,7 +119,7 @@ async def create_session(session_name, sam_address=sam.DEFAULT_ADDRESS,
writer.close() writer.close()
raise exceptions.SAM_EXCEPTIONS[reply["RESULT"]]() 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): sam_address=sam.DEFAULT_ADDRESS, loop=None):
"""A coroutine used to connect to a remote I2P destination. """A coroutine used to connect to a remote I2P destination.
@ -173,16 +173,16 @@ class Session:
:param sam_address: (optional) SAM API address :param sam_address: (optional) SAM API address
:param loop: (optional) Event loop instance :param loop: (optional) Event loop instance
:param style: (optional) Session style, can be STREAM, DATAGRAM, RAW :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 signature type is used
:param destination: (optional) Destination to use in this session. Can be :param destination: (optional) Destination to use in this session. Can be
a base64 encoded string, :class:`Destination` a base64 encoded string, :class:`Destination`
instance or None. TRANSIENT destination is used when it instance or None. TRANSIENT destination is used when it
is None. is None.
:param options: (optional) A dict object with i2cp options :param options: (optional) A dict object with i2cp options
:return: :class:`Session` object :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", loop=None, style="STREAM",
signature_type=sam.Destination.default_sig_type, signature_type=sam.Destination.default_sig_type,
destination=None, options={}): destination=None, options={}):
@ -195,9 +195,9 @@ class Session:
self.options = options self.options = options
async def __aenter__(self): async def __aenter__(self):
self.reader, self.writer = await create_session(self.session_name, self.reader, self.writer = await create_session(self.session_name,
sam_address=self.sam_address, loop=self.loop, style=self.style, sam_address=self.sam_address, loop=self.loop, style=self.style,
signature_type=self.signature_type, signature_type=self.signature_type,
destination=self.destination, options=self.options) destination=self.destination, options=self.options)
return self return self
@ -214,7 +214,7 @@ class StreamConnection:
:param loop: (optional) Event loop instance :param loop: (optional) Event loop instance
:return: :class:`StreamConnection` object :return: :class:`StreamConnection` object
""" """
def __init__(self, session_name, destination, def __init__(self, session_name, destination,
sam_address=sam.DEFAULT_ADDRESS, loop=None): sam_address=sam.DEFAULT_ADDRESS, loop=None):
self.session_name = session_name self.session_name = session_name
self.sam_address = sam_address self.sam_address = sam_address
@ -222,7 +222,7 @@ class StreamConnection:
self.destination = destination self.destination = destination
async def __aenter__(self): 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.destination, sam_address=self.sam_address, loop=self.loop)
self.read = self.reader.read self.read = self.reader.read
self.write = self.writer.write self.write = self.writer.write
@ -240,14 +240,14 @@ class StreamAcceptor:
:param loop: (optional) Event loop instance :param loop: (optional) Event loop instance
:return: :class:`StreamAcceptor` object :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): loop=None):
self.session_name = session_name self.session_name = session_name
self.sam_address = sam_address self.sam_address = sam_address
self.loop = loop self.loop = loop
async def __aenter__(self): 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) sam_address=self.sam_address, loop=self.loop)
self.read = self.reader.read self.read = self.reader.read
self.write = self.writer.write self.write = self.writer.write

View File

@ -8,7 +8,7 @@ I2P_B64_CHARS = "-~"
def i2p_b64encode(x): def i2p_b64encode(x):
"""Encode I2P destination""" """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): def i2p_b64decode(x):
"""Decode I2P destination""" """Decode I2P destination"""
@ -79,9 +79,9 @@ class Destination:
https://geti2p.net/spec/common-structures#destination https://geti2p.net/spec/common-structures#destination
:param data: (optional) Base64 encoded data or binary data :param data: (optional) Base64 encoded data or binary data
:param path: (optional) A path to a file with 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 has_private_key: (optional) Does data have a private key?
""" """
ECDSA_SHA256_P256 = 1 ECDSA_SHA256_P256 = 1
@ -97,12 +97,12 @@ class Destination:
def __init__(self, data=None, path=None, has_private_key=False): def __init__(self, data=None, path=None, has_private_key=False):
#: Binary destination #: Binary destination
self.data = b'' self.data = b''
#: Base64 encoded destination #: Base64 encoded destination
self.base64 = "" self.base64 = ""
#: :class:`RNS.vendor.i2plib.PrivateKey` instance or None #: :class:`RNS.vendor.i2plib.PrivateKey` instance or None
self.private_key = None self.private_key = None
if path: if path:
with open(path, "rb") as f: data = f.read() with open(path, "rb") as f: data = f.read()
@ -126,13 +126,13 @@ class Destination:
"""Base32 destination hash of this destination""" """Base32 destination hash of this destination"""
desthash = sha256(self.data).digest() desthash = sha256(self.data).digest()
return b32encode(desthash).decode()[:52].lower() return b32encode(desthash).decode()[:52].lower()
class PrivateKey: class PrivateKey:
"""I2P private key """I2P private key
https://geti2p.net/spec/common-structures#keysandcert 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): def __init__(self, data):

View File

@ -2,7 +2,7 @@ import logging
import asyncio import asyncio
import argparse import argparse
from . import sam from . import sam
from . import aiosam from . import aiosam
from . import utils from . import utils
from .log import logger from .log import logger
@ -29,9 +29,9 @@ async def proxy_data(reader, writer):
class I2PTunnel: class I2PTunnel:
"""Base I2P Tunnel object, not to be used directly """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) 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` a base64 encoded string, :class:`Destination`
instance or None. A new destination is created when it instance or None. A new destination is created when it
is None. is None.
@ -42,7 +42,7 @@ class I2PTunnel:
:param sam_address: (optional) SAM API address :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): options={}, loop=None, sam_address=sam.DEFAULT_ADDRESS):
self.local_address = local_address self.local_address = local_address
self.destination = destination self.destination = destination
@ -57,7 +57,7 @@ class I2PTunnel:
sam_address=self.sam_address, loop=self.loop) sam_address=self.sam_address, loop=self.loop)
_, self.session_writer = await aiosam.create_session( _, self.session_writer = await aiosam.create_session(
self.session_name, style=self.style, options=self.options, 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) loop=self.loop, destination=self.destination)
def stop(self): def stop(self):
@ -68,11 +68,11 @@ class ClientTunnel(I2PTunnel):
"""Client tunnel, a subclass of tunnel.I2PTunnel """Client tunnel, a subclass of tunnel.I2PTunnel
If you run a client tunnel with a local address ("127.0.0.1", 6668) and 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. will be proxied to irc.echelon.i2p.
:param remote_destination: Remote I2P destination, can be either .i2p :param remote_destination: Remote I2P destination, can be either .i2p
domain, .b32.i2p address, base64 destination or domain, .b32.i2p address, base64 destination or
:class:`Destination` instance :class:`Destination` instance
""" """
@ -90,12 +90,12 @@ class ClientTunnel(I2PTunnel):
"""Handle local client connection""" """Handle local client connection"""
try: try:
sc_task = aiosam.stream_connect( 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) sam_address=self.sam_address, loop=self.loop)
self.status["connect_tasks"].append(sc_task) self.status["connect_tasks"].append(sc_task)
remote_reader, remote_writer = await 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) loop=self.loop)
asyncio.ensure_future(proxy_data(client_reader, remote_writer), asyncio.ensure_future(proxy_data(client_reader, remote_writer),
loop=self.loop) loop=self.loop)
@ -123,8 +123,8 @@ class ServerTunnel(I2PTunnel):
"""Server tunnel, a subclass of tunnel.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 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 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 provide a private key or a session name, it will use a TRANSIENT
destination. destination.
""" """
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -139,7 +139,7 @@ class ServerTunnel(I2PTunnel):
async def handle_client(incoming, client_reader, client_writer): async def handle_client(incoming, client_reader, client_writer):
try: try:
# data and dest may come in one chunk # 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()) remote_destination = sam.Destination(dest.decode())
logger.debug(f"{self.session_name} client connected: {remote_destination.base32}.b32.i2p") logger.debug(f"{self.session_name} client connected: {remote_destination.base32}.b32.i2p")
@ -151,7 +151,7 @@ class ServerTunnel(I2PTunnel):
try: try:
sc_task = asyncio.wait_for( sc_task = asyncio.wait_for(
asyncio.open_connection( asyncio.open_connection(
host=self.local_address[0], host=self.local_address[0],
port=self.local_address[1]), port=self.local_address[1]),
timeout=5) timeout=5)
self.status["connect_tasks"].append(sc_task) self.status["connect_tasks"].append(sc_task)
@ -172,7 +172,7 @@ class ServerTunnel(I2PTunnel):
try: try:
while True: while True:
client_reader, client_writer = await aiosam.stream_accept( 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) loop=self.loop)
incoming = await client_reader.read(BUFFER_SIZE) incoming = await client_reader.read(BUFFER_SIZE)
asyncio.ensure_future(handle_client( asyncio.ensure_future(handle_client(
@ -192,13 +192,13 @@ if __name__ == '__main__':
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('type', metavar="TYPE", choices=('server', 'client'), parser.add_argument('type', metavar="TYPE", choices=('server', 'client'),
help="Tunnel type (server or 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)") help="Local address (e.g. 127.0.0.1:8000)")
parser.add_argument('--debug', '-d', action='store_true', parser.add_argument('--debug', '-d', action='store_true',
help='Debugging') help='Debugging')
parser.add_argument('--key', '-k', default='', metavar='PRIVATE_KEY', parser.add_argument('--key', '-k', default='', metavar='PRIVATE_KEY',
help='Path to private key file') help='Path to private key file')
parser.add_argument('--destination', '-D', default='', parser.add_argument('--destination', '-D', default='',
metavar='DESTINATION', help='Remote destination') metavar='DESTINATION', help='Remote destination')
args = parser.parse_args() args = parser.parse_args()
@ -216,10 +216,10 @@ if __name__ == '__main__':
local_address = utils.address_from_string(args.address) local_address = utils.address_from_string(args.address)
if args.type == "client": 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) destination=destination, sam_address=SAM_ADDRESS)
elif args.type == "server": elif args.type == "server":
tunnel = ServerTunnel(local_address, loop=loop, destination=destination, tunnel = ServerTunnel(local_address, loop=loop, destination=destination,
sam_address=SAM_ADDRESS) sam_address=SAM_ADDRESS)
asyncio.ensure_future(tunnel.run(), loop=loop) asyncio.ensure_future(tunnel.run(), loop=loop)

View File

@ -62,7 +62,7 @@ class Packet:
def set_delivered_callback(self, callback: Callable[[Packet], None]): def set_delivered_callback(self, callback: Callable[[Packet], None]):
self.delivered_callback = callback self.delivered_callback = callback
def delivered(self): def delivered(self):
with self.lock: with self.lock:
self.state = MessageState.MSGSTATE_DELIVERED self.state = MessageState.MSGSTATE_DELIVERED

View File

@ -187,7 +187,7 @@ class TestIdentity(unittest.TestCase):
lb = 1 lb = 1
else: else:
lb = 8 lb = 8
for i in range(1, lb): for i in range(1, lb):
msg = os.urandom(mlen) msg = os.urandom(mlen)
b += mlen b += mlen

View File

@ -105,7 +105,7 @@ class TestLink(unittest.TestCase):
dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish") dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
l1 = RNS.Link(dest) l1 = RNS.Link(dest)
time.sleep(0.5) time.sleep(0.5)
self.assertEqual(l1.status, RNS.Link.ACTIVE) 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") dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
l1 = RNS.Link(dest) l1 = RNS.Link(dest)
time.sleep(0.5) time.sleep(0.5)
self.assertEqual(l1.status, RNS.Link.ACTIVE) self.assertEqual(l1.status, RNS.Link.ACTIVE)
@ -176,7 +176,7 @@ class TestLink(unittest.TestCase):
if n_failed > 0: if n_failed > 0:
ns = "s" if n_failed != 1 else "" ns = "s" if n_failed != 1 else ""
print(f"Failed to receive proof for {n_failed} packet{ns}") print(f"Failed to receive proof for {n_failed} packet{ns}")
self.assertEqual(all_ok, True) self.assertEqual(all_ok, True)
print("OK!") print("OK!")
print(f"Single packet and proof round-trip throughput is {self.size_str(b / pduration, 'b')}ps") 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") dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
l1 = RNS.Link(dest) l1 = RNS.Link(dest)
time.sleep(0.5) time.sleep(0.5)
self.assertEqual(l1.status, RNS.Link.ACTIVE) 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") dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
l1 = RNS.Link(dest) l1 = RNS.Link(dest)
time.sleep(0.5) time.sleep(0.5)
self.assertEqual(l1.status, RNS.Link.ACTIVE) 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") dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
l1 = RNS.Link(dest) l1 = RNS.Link(dest)
time.sleep(0.5) time.sleep(0.5)
self.assertEqual(l1.status, RNS.Link.ACTIVE) self.assertEqual(l1.status, RNS.Link.ACTIVE)
@ -310,7 +310,7 @@ class TestLink(unittest.TestCase):
if RNS.Cryptography.backend() == "internal": if RNS.Cryptography.backend() == "internal":
print("Skipping medium resource test...") print("Skipping medium resource test...")
return return
init_rns(self) init_rns(self)
print("") print("")
print("Medium resource test") 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") dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
l1 = RNS.Link(dest) l1 = RNS.Link(dest)
time.sleep(0.5) time.sleep(0.5)
self.assertEqual(l1.status, RNS.Link.ACTIVE) 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") dest = RNS.Destination(id1, RNS.Destination.OUT, RNS.Destination.SINGLE, APP_NAME, "link", "establish")
self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d")) self.assertEqual(dest.hash, bytes.fromhex("fb48da0e82e6e01ba0c014513f74540d"))
l1 = RNS.Link(dest) l1 = RNS.Link(dest)
time.sleep(0.5) time.sleep(0.5)
self.assertEqual(l1.status, RNS.Link.ACTIVE) self.assertEqual(l1.status, RNS.Link.ACTIVE)
@ -553,11 +553,11 @@ class TestLink(unittest.TestCase):
target_bytes = 3000 target_bytes = 3000
else: else:
target_bytes = BUFFER_TEST_TARGET target_bytes = BUFFER_TEST_TARGET
random.seed(154889) random.seed(154889)
message = random.randbytes(target_bytes) message = random.randbytes(target_bytes)
buffer_read_target = len(message) buffer_read_target = len(message)
# the return message will have an appendage string " back at you" # the return message will have an appendage string " back at you"
# for every StreamDataMessage that arrives. To verify, we need # for every StreamDataMessage that arrives. To verify, we need
# to insert that string every MAX_DATA_LEN and also at the end. # 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 # StreamDataMessage, the appended text will end up in a
# separate packet. # separate packet.
print(f"Sending {len(message)} bytes, receiving {len(expected_rx_message)} bytes, ") print(f"Sending {len(message)} bytes, receiving {len(expected_rx_message)} bytes, ")
buffer.write(message) buffer.write(message)
buffer.flush() buffer.flush()
@ -723,7 +723,7 @@ def profile_resource():
resource_profiling() resource_profiling()
def profile_targets(): def profile_targets():
targets_profiling(yp=True) targets_profiling(yp=True)
# cProfile.runctx("entry()", {"entry": targets_profiling, "size_str": size_str}, {}, "profile-targets.data") # cProfile.runctx("entry()", {"entry": targets_profiling, "size_str": size_str}, {}, "profile-targets.data")
# p = pstats.Stats("profile-targets.data") # p = pstats.Stats("profile-targets.data")
@ -749,7 +749,7 @@ def resource_profiling():
import yappi import yappi
yappi.start() yappi.start()
resource = RNS.Resource(data, l1, timeout=resource_timeout) resource = RNS.Resource(data, l1, timeout=resource_timeout)
start = time.time() start = time.time()