Added docstrings, refactored method names.
This commit is contained in:
parent
3f1e2bc682
commit
dfb5af5dd1
|
@ -161,7 +161,7 @@ class Identity:
|
|||
announced_identity.load_public_key(public_key)
|
||||
|
||||
if announced_identity.pub != None and announced_identity.validate(signature, signed_data):
|
||||
RNS.Identity.remember(packet.getHash(), destination_hash, public_key, app_data)
|
||||
RNS.Identity.remember(packet.get_hash(), destination_hash, public_key, app_data)
|
||||
RNS.log("Stored valid announce from "+RNS.prettyhexrep(destination_hash), RNS.LOG_DEBUG)
|
||||
del announced_identity
|
||||
return True
|
||||
|
|
85
RNS/Link.py
85
RNS/Link.py
|
@ -19,11 +19,23 @@ class LinkCallbacks:
|
|||
self.link_established = None
|
||||
self.link_closed = None
|
||||
self.packet = None
|
||||
self.resource = None
|
||||
self.resource_started = None
|
||||
self.resource_concluded = None
|
||||
|
||||
class Link:
|
||||
"""
|
||||
This class.
|
||||
|
||||
:param destination: A :ref:`RNS.Destination<api-destination>` instance which to establish a link to.
|
||||
:param owner: Internal use by :ref:`RNS.Transport<api-Transport>`, ignore this argument.
|
||||
:param peer_pub_bytes: Internal use by :ref:`RNS.Transport<api-Transport>`, ignore this argument.
|
||||
"""
|
||||
CURVE = ec.SECP256R1()
|
||||
"""
|
||||
The curve used for Elliptic Curve DH key exchanges
|
||||
"""
|
||||
|
||||
ECPUBSIZE = 91
|
||||
BLOCKSIZE = 16
|
||||
AES_HMAC_OVERHEAD = 58
|
||||
|
@ -33,9 +45,15 @@ class Link:
|
|||
# but calculated from something like
|
||||
# first-hop RTT latency and distance
|
||||
DEFAULT_TIMEOUT = 15.0
|
||||
"""
|
||||
Default timeout for link establishment in seconds.
|
||||
"""
|
||||
TIMEOUT_FACTOR = 3
|
||||
STALE_GRACE = 2
|
||||
KEEPALIVE = 180
|
||||
"""
|
||||
Interval for sending keep-alive packets on established links in seconds.
|
||||
"""
|
||||
|
||||
PENDING = 0x00
|
||||
HANDSHAKE = 0x01
|
||||
|
@ -243,18 +261,31 @@ class Link:
|
|||
return None
|
||||
|
||||
def no_inbound_for(self):
|
||||
"""
|
||||
:returns: The time in seconds since last inbound packet on the link.
|
||||
"""
|
||||
return time.time() - self.last_inbound
|
||||
|
||||
def no_outbound_for(self):
|
||||
"""
|
||||
:returns: The time in seconds since last outbound packet on the link.
|
||||
"""
|
||||
return time.time() - self.last_outbound
|
||||
|
||||
def inactive_for(self):
|
||||
"""
|
||||
:returns: The time in seconds since activity on the link.
|
||||
"""
|
||||
return min(self.no_inbound_for(), self.no_outbound_for())
|
||||
|
||||
def had_outbound(self):
|
||||
self.last_outbound = time.time()
|
||||
|
||||
def teardown(self):
|
||||
"""
|
||||
Closes the link and purges encryption keys. New keys will
|
||||
be used if a new link to the same destination is established.
|
||||
"""
|
||||
if self.status != Link.PENDING and self.status != Link.CLOSED:
|
||||
teardown_packet = RNS.Packet(self, self.link_id, context=RNS.Packet.LINKCLOSE)
|
||||
teardown_packet.send()
|
||||
|
@ -398,9 +429,8 @@ class Link:
|
|||
pass
|
||||
elif self.resource_strategy == Link.ACCEPT_APP:
|
||||
if self.callbacks.resource != None:
|
||||
thread = threading.Thread(target=self.callbacks.resource, args=(packet))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
if self.callbacks.resource(resource):
|
||||
RNS.Resource.accept(packet, self.callbacks.resource_concluded)
|
||||
elif self.resource_strategy == Link.ACCEPT_ALL:
|
||||
RNS.Resource.accept(packet, self.callbacks.resource_concluded)
|
||||
|
||||
|
@ -496,14 +526,41 @@ class Link:
|
|||
self.callbacks.link_closed = callback
|
||||
|
||||
def packet_callback(self, callback):
|
||||
"""
|
||||
Registers a function to be called when a packet has been
|
||||
received over this link.
|
||||
|
||||
:param callback: A function or method with the signature *callback(message, packet)* to be called.
|
||||
"""
|
||||
self.callbacks.packet = callback
|
||||
|
||||
# Called when an incoming resource transfer is started
|
||||
def resource_callback(self, callback):
|
||||
"""
|
||||
Registers a function to be called when a resource has been
|
||||
advertised over this link. If the function returns *True*
|
||||
the resource will be accepted. If it returns *False* it will
|
||||
be ignored.
|
||||
|
||||
:param callback: A function or method with the signature *callback(resource)* to be called.
|
||||
"""
|
||||
self.callbacks.resource = callback
|
||||
|
||||
def resource_started_callback(self, callback):
|
||||
"""
|
||||
Registers a function to be called when a resource has begun
|
||||
transferring over this link.
|
||||
|
||||
:param callback: A function or method with the signature *callback(resource)* to be called.
|
||||
"""
|
||||
self.callbacks.resource_started = callback
|
||||
|
||||
# Called when a resource transfer is concluded
|
||||
def resource_concluded_callback(self, callback):
|
||||
"""
|
||||
Registers a function to be called when a resource has concluded
|
||||
transferring over this link.
|
||||
|
||||
:param callback: A function or method with the signature *callback(resource)* to be called.
|
||||
"""
|
||||
self.callbacks.resource_concluded = callback
|
||||
|
||||
def resource_concluded(self, resource):
|
||||
|
@ -513,6 +570,12 @@ class Link:
|
|||
self.outgoing_resources.remove(resource)
|
||||
|
||||
def set_resource_strategy(self, resource_strategy):
|
||||
"""
|
||||
Sets the resource strategy for the link.
|
||||
|
||||
:param resource_strategy: One of ``RNS.Link.ACCEPT_NONE``, ``RNS.Link.ACCEPT_ALL`` or ``RNS.Link.ACCEPT_APP``. If ``RNS.Link.ACCEPT_APP`` is set, the `resource_callback` will be called to determine whether the resource should be accepted or not.
|
||||
:raises: *TypeError* if the resource strategy is unsupported.
|
||||
"""
|
||||
if not resource_strategy in Link.resource_strategies:
|
||||
raise TypeError("Unsupported resource strategy")
|
||||
else:
|
||||
|
@ -542,7 +605,17 @@ class Link:
|
|||
else:
|
||||
return True
|
||||
|
||||
def disableEncryption(self):
|
||||
def disable_encryption(self):
|
||||
"""
|
||||
HAZARDOUS. This will downgrade the link to encryptionless. All
|
||||
information over the link will be sent in plaintext. Never use
|
||||
this in production applications. Should only be used for debugging
|
||||
purposes, and will disappear in a future version.
|
||||
|
||||
If encryptionless links are not explicitly allowed in the users
|
||||
configuration file, Reticulum will terminate itself along with the
|
||||
client application and throw an error message to the user.
|
||||
"""
|
||||
if (RNS.Reticulum.should_allow_unencrypted()):
|
||||
RNS.log("The link "+str(self)+" was downgraded to an encryptionless link", RNS.LOG_NOTICE)
|
||||
self.__encryption_disabled = True
|
||||
|
|
|
@ -5,6 +5,20 @@ import time
|
|||
import RNS
|
||||
|
||||
class Packet:
|
||||
"""
|
||||
The Packet class is used to create packet instances that can be
|
||||
sent over a Reticulum network.
|
||||
|
||||
:param destination: A :ref:`RNS.Destination<api-destination>` instance to which the packet will be sent.
|
||||
:param data: The data payload to be included in the packet as *bytes*.
|
||||
:param create_receipt: Specifies whether a :ref:`RNS.PacketReceipt<api-packetreceipt>` should be created when instantiating the packet.
|
||||
:param type: Internal use by :ref:`RNS.Transport<api-transport>`. Defaults to ``RNS.Packet.DATA``, and should not be specified.
|
||||
:param context: Internal use by :ref:`RNS.Transport<api-transport>`. Ignore.
|
||||
:param transport_type: Internal use by :ref:`RNS.Transport<api-transport>`. Ignore.
|
||||
:param transport_id: Internal use by :ref:`RNS.Transport<api-transport>`. Ignore.
|
||||
:param attached_interface: Internal use by :ref:`RNS.Transport<api-transport>`. Ignore.
|
||||
"""
|
||||
|
||||
# Packet types
|
||||
DATA = 0x00 # Data packets
|
||||
ANNOUNCE = 0x01 # Announces
|
||||
|
@ -155,7 +169,7 @@ class Packet:
|
|||
raise IOError("Packet size of "+str(len(self.raw))+" exceeds MTU of "+str(self.MTU)+" bytes")
|
||||
|
||||
self.packed = True
|
||||
self.updateHash()
|
||||
self.update_hash()
|
||||
|
||||
def unpack(self):
|
||||
self.flags = self.raw[0]
|
||||
|
@ -178,12 +192,14 @@ class Packet:
|
|||
self.data = self.raw[13:]
|
||||
|
||||
self.packed = False
|
||||
self.updateHash()
|
||||
self.update_hash()
|
||||
|
||||
# Sends the packet. Returns a receipt if one is generated,
|
||||
# or None if no receipt is available. Returns False if the
|
||||
# packet could not be sent.
|
||||
def send(self):
|
||||
"""
|
||||
Sends the packet.
|
||||
|
||||
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
||||
"""
|
||||
if not self.sent:
|
||||
if self.destination.type == RNS.Destination.LINK:
|
||||
if self.destination.status == RNS.Link.CLOSED:
|
||||
|
@ -208,6 +224,11 @@ class Packet:
|
|||
raise IOError("Packet was already sent")
|
||||
|
||||
def resend(self):
|
||||
"""
|
||||
Re-sends the packet.
|
||||
|
||||
:returns: A :ref:`RNS.PacketReceipt<api-packetreceipt>` instance if *create_receipt* was set to *True* when the packet was instantiated, if not returns *None*. If the packet could not be sent *False* is returned.
|
||||
"""
|
||||
if self.sent:
|
||||
if RNS.Transport.outbound(self):
|
||||
return self.receipt
|
||||
|
@ -239,16 +260,16 @@ class Packet:
|
|||
def validate_proof(self, proof):
|
||||
return self.receipt.validate_proof(proof)
|
||||
|
||||
def updateHash(self):
|
||||
self.packet_hash = self.getHash()
|
||||
def update_hash(self):
|
||||
self.packet_hash = self.get_hash()
|
||||
|
||||
def getHash(self):
|
||||
return RNS.Identity.full_hash(self.getHashablePart())
|
||||
def get_hash(self):
|
||||
return RNS.Identity.full_hash(self.get_hashable_part())
|
||||
|
||||
def getTruncatedHash(self):
|
||||
return RNS.Identity.truncated_hash(self.getHashablePart())
|
||||
return RNS.Identity.truncated_hash(self.get_hashable_part())
|
||||
|
||||
def getHashablePart(self):
|
||||
def get_hashable_part(self):
|
||||
hashable_part = bytes([self.raw[0] & 0b00001111])
|
||||
if self.header_type == Packet.HEADER_2:
|
||||
hashable_part += self.raw[12:]
|
||||
|
@ -259,7 +280,7 @@ class Packet:
|
|||
|
||||
class ProofDestination:
|
||||
def __init__(self, packet):
|
||||
self.hash = packet.getHash()[:10];
|
||||
self.hash = packet.get_hash()[:10];
|
||||
self.type = RNS.Destination.SINGLE
|
||||
|
||||
def encrypt(self, plaintext):
|
||||
|
@ -267,6 +288,12 @@ class ProofDestination:
|
|||
|
||||
|
||||
class PacketReceipt:
|
||||
"""
|
||||
The PacketReceipt class is used to receive notifications about
|
||||
:ref:`RNS.Packet<api-packet>` instances sent over the network. Instances
|
||||
of this class should never be created manually, but always returned
|
||||
from a the *send()* method of a :ref:`RNS.Packet<api-packet>` instance.
|
||||
"""
|
||||
# Receipt status constants
|
||||
FAILED = 0x00
|
||||
SENT = 0x01
|
||||
|
@ -279,7 +306,7 @@ class PacketReceipt:
|
|||
|
||||
# Creates a new packet receipt from a sent packet
|
||||
def __init__(self, packet):
|
||||
self.hash = packet.getHash()
|
||||
self.hash = packet.get_hash()
|
||||
self.sent = True
|
||||
self.sent_at = time.time()
|
||||
self.timeout = Packet.TIMEOUT
|
||||
|
@ -289,6 +316,12 @@ class PacketReceipt:
|
|||
self.callbacks = PacketReceiptCallbacks()
|
||||
self.concluded_at = None
|
||||
|
||||
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``.
|
||||
"""
|
||||
return self.status
|
||||
|
||||
# Validate a proof packet
|
||||
def validate_proof_packet(self, proof_packet):
|
||||
if hasattr(proof_packet, "link") and proof_packet.link:
|
||||
|
@ -374,6 +407,9 @@ class PacketReceipt:
|
|||
return False
|
||||
|
||||
def rtt(self):
|
||||
"""
|
||||
:returns: The round-trip-time in seconds
|
||||
"""
|
||||
return self.concluded_at - self.sent_at
|
||||
|
||||
def is_timed_out(self):
|
||||
|
@ -395,18 +431,30 @@ class PacketReceipt:
|
|||
#self.callbacks.timeout(self)
|
||||
|
||||
|
||||
# Set the timeout in seconds
|
||||
def set_timeout(self, timeout):
|
||||
"""
|
||||
Sets a timeout in seconds
|
||||
|
||||
:param timeout: The timeout in seconds.
|
||||
"""
|
||||
self.timeout = float(timeout)
|
||||
|
||||
# Set a function that gets called when
|
||||
# a successfull delivery has been proved
|
||||
def delivery_callback(self, callback):
|
||||
"""
|
||||
Sets a function that gets called if a successfull delivery has been proven.
|
||||
|
||||
:param callback: A *callable* with the signature *callback(packet_receipt)*
|
||||
"""
|
||||
self.callbacks.delivery = callback
|
||||
|
||||
# Set a function that gets called if the
|
||||
# delivery times out
|
||||
def timeout_callback(self, callback):
|
||||
"""
|
||||
Sets a function that gets called if the delivery times out.
|
||||
|
||||
:param callback: A *callable* with the signature *callback(packet_receipt)*
|
||||
"""
|
||||
self.callbacks.timeout = callback
|
||||
|
||||
class PacketReceiptCallbacks:
|
||||
|
|
|
@ -318,7 +318,7 @@ class Transport:
|
|||
|
||||
Transport.jobs_locked = True
|
||||
# TODO: This updateHash call might be redundant
|
||||
packet.updateHash()
|
||||
packet.update_hash()
|
||||
sent = False
|
||||
|
||||
# Check if we have a known path for the destination in the path table
|
||||
|
@ -907,12 +907,22 @@ class Transport:
|
|||
|
||||
@staticmethod
|
||||
def register_announce_handler(handler):
|
||||
"""
|
||||
Registers an announce handler.
|
||||
|
||||
:param handler: Must be an object with an *aspect_filter* attribute and a *received_announce(destination_hash, announced_identity, app_data)* callable. See the :ref:`Announce Example<example-announce>` for more info.
|
||||
"""
|
||||
if hasattr(handler, "received_announce") and callable(handler.received_announce):
|
||||
if hasattr(handler, "aspect_filter"):
|
||||
Transport.announce_handlers.append(handler)
|
||||
|
||||
@staticmethod
|
||||
def deregister_announce_handler(handler):
|
||||
"""
|
||||
Deregisters an announce handler.
|
||||
|
||||
:param handler: The announce handler to be deregistered.
|
||||
"""
|
||||
while handler in Transport.announce_handlers:
|
||||
Transport.announce_handlers.remove(handler)
|
||||
|
||||
|
@ -940,7 +950,7 @@ class Transport:
|
|||
def cache(packet, force_cache=False):
|
||||
if RNS.Transport.should_cache(packet) or force_cache:
|
||||
try:
|
||||
packet_hash = RNS.hexrep(packet.getHash(), delimit=False)
|
||||
packet_hash = RNS.hexrep(packet.get_hash(), delimit=False)
|
||||
interface_reference = None
|
||||
if packet.receiving_interface != None:
|
||||
interface_reference = str(packet.receiving_interface)
|
||||
|
@ -1009,6 +1019,10 @@ class Transport:
|
|||
|
||||
@staticmethod
|
||||
def has_path(destination_hash):
|
||||
"""
|
||||
:param destination_hash: A destination hash as *bytes*.
|
||||
:returns: *True* if a path to the destination is known, otherwise *False*.
|
||||
"""
|
||||
if destination_hash in Transport.destination_table:
|
||||
return True
|
||||
else:
|
||||
|
@ -1016,6 +1030,13 @@ class Transport:
|
|||
|
||||
@staticmethod
|
||||
def request_path(destination_hash):
|
||||
"""
|
||||
Requests a path to the destination from the network. If
|
||||
another reachable peer on the network knows a path, it
|
||||
will announce it.
|
||||
|
||||
:param destination_hash: A destination hash as *bytes*.
|
||||
"""
|
||||
path_request_data = destination_hash + RNS.Identity.get_random_hash()
|
||||
path_request_dst = RNS.Destination(None, RNS.Destination.OUT, RNS.Destination.PLAIN, Transport.APP_NAME, "path", "request")
|
||||
packet = RNS.Packet(path_request_dst, path_request_data, packet_type = RNS.Packet.DATA, transport_type = RNS.Transport.BROADCAST, header_type = RNS.Packet.HEADER_1)
|
||||
|
@ -1147,7 +1168,7 @@ class Transport:
|
|||
hops = de[2]
|
||||
expires = de[3]
|
||||
random_blobs = de[4]
|
||||
packet_hash = de[6].getHash()
|
||||
packet_hash = de[6].get_hash()
|
||||
|
||||
serialised_entry = [
|
||||
destination_hash,
|
||||
|
|
Loading…
Reference in New Issue