Compare commits

..

4 Commits

Author SHA1 Message Date
Mark Qvist f242abcf75 Version bump 2021-05-13 16:42:36 +02:00
Mark Qvist 51ab2d3488 Implemented app_data recall from announces, better destination registration handling and link inactivity querying. 2021-05-13 16:41:23 +02:00
Mark Qvist 54206d9101 Added thread locking to log output. Various housekeeping. 2021-05-03 20:24:44 +02:00
Mark Qvist 178c69e361 Updated readme 2020-08-13 15:41:54 +02:00
10 changed files with 64 additions and 27 deletions
+1 -1
View File
@@ -73,7 +73,7 @@ if __name__ == "__main__":
try:
parser = argparse.ArgumentParser(description="Reticulum example that demonstrates sending and receiving unencrypted broadcasts")
parser.add_argument("--config", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
parser.add_argument("--channel", action="store", default=None, help="path to alternative Reticulum config directory", type=str)
parser.add_argument("--channel", action="store", default=None, help="broadcast channel name", type=str)
args = parser.parse_args()
if args.config:
+1 -2
View File
@@ -787,10 +787,9 @@ pre {
<h2>
<a id="user-content-what-is-currently-being-worked-on" class="anchor" href="#what-is-currently-being-worked-on" aria-hidden="true"><span aria-hidden="true" class="octicon octicon-link"></span></a>What is currently being worked on?</h2>
<ul>
<li>Delay/disruption tolerance</li>
<li>API documentation</li>
<li>Useful example programs and utilities</li>
<li>A generic message transfer protocol built on Reticulum, see <a href="https://github.com/markqvist/lxmf">LXMF</a>
<li>A delay and disruption tolerant message transfer protocol built on Reticulum, see <a href="https://github.com/markqvist/lxmf">LXMF</a>
</li>
<li>A few useful-in-the-real-world apps built with Reticulum</li>
</ul>
+1 -2
View File
@@ -54,10 +54,9 @@ Reticulum implements a range of generalised interface types that covers most of
- UDP over IP networks
## What is currently being worked on?
- Delay/disruption tolerance
- API documentation
- Useful example programs and utilities
- A generic message transfer protocol built on Reticulum, see [LXMF](https://github.com/markqvist/lxmf)
- A delay and disruption tolerant message transfer protocol built on Reticulum, see [LXMF](https://github.com/markqvist/lxmf)
- A few useful-in-the-real-world apps built with Reticulum
## Can I use Reticulum on amateur radio spectrum?
+17 -6
View File
@@ -43,12 +43,24 @@ class Identity:
identity_data = Identity.known_destinations[destination_hash]
identity = Identity(public_only=True)
identity.loadPublicKey(identity_data[2])
identity.app_data = identity_data[3]
RNS.log("Found "+RNS.prettyhexrep(destination_hash)+" in known destinations", RNS.LOG_EXTREME)
return identity
else:
RNS.log("Could not find "+RNS.prettyhexrep(destination_hash)+" in known destinations", RNS.LOG_EXTREME)
return None
@staticmethod
def recall_app_data(destination_hash):
RNS.log("Searching for app_data for "+RNS.prettyhexrep(destination_hash)+"...", RNS.LOG_EXTREME)
if destination_hash in Identity.known_destinations:
app_data = Identity.known_destinations[destination_hash][3]
RNS.log("Found "+RNS.prettyhexrep(destination_hash)+" app_data in known destinations", RNS.LOG_EXTREME)
return app_data
else:
RNS.log("Could not find "+RNS.prettyhexrep(destination_hash)+" app_data in known destinations", RNS.LOG_EXTREME)
return None
@staticmethod
def saveKnownDestinations():
RNS.log("Saving known destinations to storage...", RNS.LOG_VERBOSE)
@@ -79,10 +91,6 @@ class Identity:
@staticmethod
def truncatedHash(data):
# TODO: Remove
# digest = hashes.Hash(hashes.SHA256(), backend=default_backend())
# digest.update(data)
return Identity.fullHash(data)[:(Identity.TRUNCATED_HASHLENGTH//8)]
@staticmethod
@@ -103,11 +111,14 @@ class Identity:
signed_data = destination_hash+public_key+random_hash+app_data
if not len(packet.data) > Identity.DERKEYSIZE//8+20+Identity.KEYSIZE//8:
app_data = None
announced_identity = Identity(public_only=True)
announced_identity.loadPublicKey(public_key)
if announced_identity.pub != None and announced_identity.validate(signature, signed_data):
RNS.Identity.remember(packet.getHash(), destination_hash, public_key)
RNS.Identity.remember(packet.getHash(), destination_hash, public_key, app_data)
RNS.log("Stored valid announce from "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG)
del announced_identity
return True
@@ -188,7 +199,7 @@ class Identity:
except Exception as e:
RNS.log("Failed to load identity key", RNS.LOG_ERROR)
RNS.log("The contained exception was: "+str(e))
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
return False
def loadPublicKey(self, key):
+8 -1
View File
@@ -238,6 +238,9 @@ class Link:
def getContext(self):
return None
def inactive_for(self):
return min(time.time() - self.last_inbound, time.time() - self.last_outbound)
def teardown(self):
if self.status != Link.PENDING and self.status != Link.CLOSED:
teardown_packet = RNS.Packet(self, self.link_id, context=RNS.Packet.LINKCLOSE)
@@ -331,6 +334,7 @@ class Link:
if sleep_time == None or sleep_time < 0:
RNS.log("Timing error! Tearing down link "+str(self)+" now.", RNS.LOG_ERROR)
self.teardown()
sleep_time = 0.1
sleep(sleep_time)
@@ -454,7 +458,10 @@ class Link:
return plaintext
except Exception as e:
RNS.log("Decryption failed on link "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
traceback.print_exc()
RNS.log(traceback.format_exc(), RNS.LOG_ERROR)
# TODO: Do we really need to do this? Or can we recover somehow?
self.teardown()
def sign(self, message):
return self.prv.sign(message, ec.ECDSA(hashes.SHA256()))
+5 -7
View File
@@ -42,15 +42,15 @@ class Resource:
HASHMAP_IS_EXHAUSTED = 0xFF
# Status constants
NONE = 0x00
QUEUED = 0x01
ADVERTISED = 0x02
NONE = 0x00
QUEUED = 0x01
ADVERTISED = 0x02
TRANSFERRING = 0x03
AWAITING_PROOF = 0x04
ASSEMBLING = 0x05
COMPLETE = 0x06
FAILED = 0x07
CORRUPT = 0x08
FAILED = 0x07
CORRUPT = 0x08
@staticmethod
def accept(advertisement_packet, callback=None, progress_callback = None):
@@ -111,8 +111,6 @@ class Resource:
return resource
except Exception as e:
RNS.log("Could not decode resource advertisement, dropping resource", RNS.LOG_DEBUG)
# TODO: Remove
raise e
return None
# Create a resource for transmission to a remote destination
+4
View File
@@ -446,6 +446,7 @@ class Transport:
@staticmethod
def inbound(raw, interface=None):
while (Transport.jobs_running):
# TODO: Decrease this for performance
sleep(0.1)
Transport.jobs_locked = True
@@ -849,6 +850,9 @@ class Transport:
def registerDestination(destination):
destination.MTU = RNS.Reticulum.MTU
if destination.direction == RNS.Destination.IN:
for registered_destination in Transport.destinations:
if destination.hash == registered_destination.hash:
raise KeyError("Attempt to register an already registered destination.")
Transport.destinations.append(destination)
@staticmethod
+24 -7
View File
@@ -3,6 +3,7 @@ import sys
import glob
import time
import random
import threading
from .Reticulum import Reticulum
from .Identity import Identity
@@ -35,6 +36,10 @@ logtimefmt = "%Y-%m-%d %H:%M:%S"
random.seed(os.urandom(10))
_always_override_destination = False
logging_lock = threading.Lock()
def loglevelname(level):
if (level == LOG_CRITICAL):
return "Critical"
@@ -55,19 +60,31 @@ def loglevelname(level):
return "Unknown"
def log(msg, level=3):
# TODO: not thread safe
def log(msg, level=3, _override_destination = False):
global _always_override_destination
if loglevel >= level:
timestamp = time.time()
logstring = "["+time.strftime(logtimefmt)+"] ["+loglevelname(level)+"] "+msg
logging_lock.acquire()
if (logdest == LOG_STDOUT):
if (logdest == LOG_STDOUT or _always_override_destination):
print(logstring)
logging_lock.release()
if (logdest == LOG_FILE and logfile != None):
file = open(logfile, "a")
file.write(logstring+"\n")
file.close()
elif (logdest == LOG_FILE and logfile != None):
try:
file = open(logfile, "a")
file.write(logstring+"\n")
file.close()
logging_lock.release()
except Exception as e:
logging_lock.release()
_always_override_destination = True
log("Exception occurred while writing log message to log file: "+str(e), LOG_CRITICAL)
log("Dumping future log events to console!", LOG_CRITICAL)
log(msg, level)
def rand():
result = random.random()
+2
View File
@@ -1,5 +1,7 @@
import os
import glob
__version__ = "0.1.9"
modules = glob.glob(os.path.dirname(__file__)+"/*.py")
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
+1 -1
View File
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
setuptools.setup(
name="rns",
version="0.1.8",
version="0.1.9",
author="Mark Qvist",
author_email="mark@unsigned.io",
description="Self-configuring, encrypted and resilient mesh networking stack for LoRa, packet radio, WiFi and everything in between",