diff --git a/Examples/Request.py b/Examples/Request.py new file mode 100644 index 0000000..228dfae --- /dev/null +++ b/Examples/Request.py @@ -0,0 +1,283 @@ +########################################################## +# This RNS example demonstrates how to set perform # +# requests and receive responses over a link. # +########################################################## + +import os +import sys +import time +import random +import argparse +import RNS + +# Let's define an app name. We'll use this for all +# destinations we create. Since this echo example +# is part of a range of example utilities, we'll put +# them all within the app namespace "example_utilities" +APP_NAME = "example_utilities" + +########################################################## +#### Server Part ######################################### +########################################################## + +# A reference to the latest client link that connected +latest_client_link = None + +def random_text_generator(path, data, request_id, remote_identity_hash, requested_at): + RNS.log("Generating response to request "+RNS.prettyhexrep(request_id)) + texts = ["They looked up", "On each full moon", "Becky was upset", "I’ll stay away from it", "The pet shop stocks everything"] + return texts[random.randint(0, len(texts)-1)] + +# This initialisation is executed when the users chooses +# to run as a server +def server(configpath): + # We must first initialise Reticulum + reticulum = RNS.Reticulum(configpath) + + # Randomly create a new identity for our link example + server_identity = RNS.Identity() + + # We create a destination that clients can connect to. We + # want clients to create links to this destination, so we + # need to create a "single" destination type. + server_destination = RNS.Destination( + server_identity, + RNS.Destination.IN, + RNS.Destination.SINGLE, + APP_NAME, + "requestexample" + ) + + # We configure a function that will get called every time + # a new client creates a link to this destination. + server_destination.set_link_established_callback(client_connected) + + # We register a request handler for handling incoming + # requests over any established links. + server_destination.register_request_handler( + "/random/text", + response_generator = random_text_generator, + allow = RNS.Destination.ALLOW_ALL + ) + + # Everything's ready! + # Let's Wait for client requests or user input + server_loop(server_destination) + +def server_loop(destination): + # Let the user know that everything is ready + RNS.log( + "Request example "+ + RNS.prettyhexrep(destination.hash)+ + " running, waiting for a connection." + ) + + RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)") + + # We enter a loop that runs until the users exits. + # If the user hits enter, we will announce our server + # destination on the network, which will let clients + # know how to create messages directed towards it. + while True: + entered = input() + destination.announce() + RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash)) + +# When a client establishes a link to our server +# destination, this function will be called with +# a reference to the link. +def client_connected(link): + global latest_client_link + + RNS.log("Client connected") + link.set_link_closed_callback(client_disconnected) + latest_client_link = link + +def client_disconnected(link): + RNS.log("Client disconnected") + + +########################################################## +#### Client Part ######################################### +########################################################## + +# A reference to the server link +server_link = None + +# This initialisation is executed when the users chooses +# to run as a client +def client(destination_hexhash, configpath): + # We need a binary representation of the destination + # hash that was entered on the command line + try: + if len(destination_hexhash) != 20: + raise ValueError("Destination length is invalid, must be 20 hexadecimal characters (10 bytes)") + destination_hash = bytes.fromhex(destination_hexhash) + except: + RNS.log("Invalid destination entered. Check your input!\n") + exit() + + # We must first initialise Reticulum + reticulum = RNS.Reticulum(configpath) + + # Check if we know a path to the destination + if not RNS.Transport.has_path(destination_hash): + RNS.log("Destination is not yet known. Requesting path and waiting for announce to arrive...") + RNS.Transport.request_path(destination_hash) + while not RNS.Transport.has_path(destination_hash): + time.sleep(0.1) + + # Recall the server identity + server_identity = RNS.Identity.recall(destination_hash) + + # Inform the user that we'll begin connecting + RNS.log("Establishing link with server...") + + # When the server identity is known, we set + # up a destination + server_destination = RNS.Destination( + server_identity, + RNS.Destination.OUT, + RNS.Destination.SINGLE, + APP_NAME, + "requestexample" + ) + + # And create a link + link = RNS.Link(server_destination) + + # We'll set up functions to inform the + # user when the link is established or closed + link.set_link_established_callback(link_established) + link.set_link_closed_callback(link_closed) + + # Everything is set up, so let's enter a loop + # for the user to interact with the example + client_loop() + +def client_loop(): + global server_link + + # Wait for the link to become active + while not server_link: + time.sleep(0.1) + + should_quit = False + while not should_quit: + try: + print("> ", end=" ") + text = input() + + # Check if we should quit the example + if text == "quit" or text == "q" or text == "exit": + should_quit = True + server_link.teardown() + + else: + server_link.request( + "/random/text", + data = None, + response_callback = got_response, + failed_callback = request_failed + ) + + + except Exception as e: + RNS.log("Error while sending request over the link: "+str(e)) + should_quit = True + server_link.teardown() + +def got_response(request_receipt): + request_id = request_receipt.request_id + response = request_receipt.response + + RNS.log("Got response for request "+RNS.prettyhexrep(request_id)+": "+str(response)) + +def request_received(request_receipt): + RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" was received by the remote peer.") + +def request_failed(request_receipt): + RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" failed.") + + +# This function is called when a link +# has been established with the server +def link_established(link): + # We store a reference to the link + # instance for later use + global server_link + server_link = link + + # Inform the user that the server is + # connected + RNS.log("Link established with server, hit enter to perform a request, or type in \"quit\" to quit") + +# When a link is closed, we'll inform the +# user, and exit the program +def link_closed(link): + if link.teardown_reason == RNS.Link.TIMEOUT: + RNS.log("The link timed out, exiting now") + elif link.teardown_reason == RNS.Link.DESTINATION_CLOSED: + RNS.log("The link was closed by the server, exiting now") + else: + RNS.log("Link closed, exiting now") + + RNS.Reticulum.exit_handler() + time.sleep(1.5) + os._exit(0) + + +########################################################## +#### Program Startup ##################################### +########################################################## + +# This part of the program runs at startup, +# and parses input of from the user, and then +# starts up the desired program mode. +if __name__ == "__main__": + try: + parser = argparse.ArgumentParser(description="Simple request/response example") + + parser.add_argument( + "-s", + "--server", + action="store_true", + help="wait for incoming requests from clients" + ) + + parser.add_argument( + "--config", + action="store", + default=None, + help="path to alternative Reticulum config directory", + type=str + ) + + parser.add_argument( + "destination", + nargs="?", + default=None, + help="hexadecimal hash of the server destination", + type=str + ) + + args = parser.parse_args() + + if args.config: + configarg = args.config + else: + configarg = None + + if args.server: + server(configarg) + else: + if (args.destination == None): + print("") + parser.print_help() + print("") + else: + client(args.destination, configarg) + + except KeyboardInterrupt: + print("") + exit() \ No newline at end of file diff --git a/RNS/Destination.py b/RNS/Destination.py index f8b24b3..cdf4499 100755 --- a/RNS/Destination.py +++ b/RNS/Destination.py @@ -40,6 +40,11 @@ class Destination: PROVE_ALL = 0x23 proof_strategies = [PROVE_NONE, PROVE_APP, PROVE_ALL] + ALLOW_NONE = 0x00 + ALLOW_ALL = 0x01 + ALLOW_LIST = 0x02 + request_policies = [ALLOW_NONE, ALLOW_ALL, ALLOW_LIST] + IN = 0x11; OUT = 0x12; directions = [IN, OUT] @@ -97,6 +102,7 @@ class Destination: if not type in Destination.types: raise ValueError("Unknown destination type") if not direction in Destination.directions: raise ValueError("Unknown destination direction") self.callbacks = Callbacks() + self.request_handlers = {} self.type = type self.direction = direction self.proof_strategy = Destination.PROVE_NONE @@ -208,6 +214,45 @@ class Destination: else: self.proof_strategy = proof_strategy + + def register_request_handler(self, path, response_generator = None, allow = ALLOW_NONE, allowed_list = None): + """ + Registers a request handler. + + :param path: The path for the request handler to be registered. + :param response_generator: A function or method with the signature *response_generator(path, data, request_id, remote_identity_hash, requested_at)* to be called. Whatever this funcion returns will be sent as a response to the requester. If the function returns ``None``, no response will be sent. + :param allow: One of ``RNS.Destination.ALLOW_NONE``, ``RNS.Destination.ALLOW_ALL`` or ``RNS.Destination.ALLOW_LIST``. If ``RNS.Destination.ALLOW_LIST`` is set, the request handler will only respond to requests for identified peers in the supplied list. + :param allowed_list: A list of *bytes-like* :ref:`RNS.Identity` hashes. + :raises: ``ValueError`` if any of the supplied arguments are invalid. + """ + if path == None or path == "": + raise ValueError("Invalid path specified") + elif not callable(response_generator): + raise ValueError("Invalid response generator specified") + elif not allow in Destination.request_policies: + raise ValueError("Invalid request policy") + else: + path_hash = RNS.Identity.truncated_hash(path.encode("utf-8")) + request_handler = [path, response_generator, allow, allowed_list] + self.request_handlers[path_hash] = request_handler + + + def deregister_request_handler(self, path): + """ + Deregisters a request handler. + + :param path: The path for the request handler to be deregistered. + :returns: True if the handler was deregistered, otherwise False. + """ + path_hash = RNS.Identity.truncated_hash(path.encode("utf-8")) + if path_hash in self.request_handlers: + self.request_handlers.pop(path_hash) + return True + else: + return False + + + def receive(self, packet): if packet.packet_type == RNS.Packet.LINKREQUEST: plaintext = packet.data diff --git a/RNS/Link.py b/RNS/Link.py index 5d40854..995dc6e 100644 --- a/RNS/Link.py +++ b/RNS/Link.py @@ -110,6 +110,7 @@ class Link: self.resource_strategy = Link.ACCEPT_NONE self.outgoing_resources = [] self.incoming_resources = [] + self.pending_requests = [] self.last_inbound = 0 self.last_outbound = 0 self.tx = 0 @@ -265,6 +266,26 @@ class Link: self.had_outbound() + def request(self, path, data = None, response_callback = None, failed_callback = None): + """ + Sends a request to the remote peer. + + :param path: The request path. + :param response_callback: A function or method with the signature *response_callback(request_receipt)* to be called when a response is received. See the :ref:`Request Example` for more info. + :param failed_callback: A function or method with the signature *failed_callback(request_receipt)* to be called when a request fails. See the :ref:`Request Example` for more info. + """ + request_path_hash = RNS.Identity.truncated_hash(path.encode("utf-8")) + unpacked_request = [time.time(), request_path_hash, data] + packed_request = umsgpack.packb(unpacked_request) + + if len(packed_request) <= Link.MDU: + request_packet = RNS.Packet(self, packed_request, RNS.Packet.DATA, context = RNS.Packet.REQUEST) + return RequestReceipt(self, request_packet.send(), response_callback, failed_callback) + else: + # TODO: Implement sending requests as Resources + raise IOError("Request size of "+str(len(packed_request))+" exceeds MDU of "+str(Link.MDU)+" bytes") + + def rtt_packet(self, packet): try: # TODO: This is crude, we should use the delta @@ -467,6 +488,70 @@ class Link: if self.callbacks.remote_identified != None: self.callbacks.remote_identified(self.__remote_identity) + elif packet.context == RNS.Packet.REQUEST: + try: + request_id = packet.getTruncatedHash() + packed_request = self.decrypt(packet.data) + unpacked_request = umsgpack.unpackb(packed_request) + requested_at = unpacked_request[0] + path_hash = unpacked_request[1] + request_data = unpacked_request[2] + + if path_hash in self.destination.request_handlers: + request_handler = self.destination.request_handlers[path_hash] + path = request_handler[0] + response_generator = request_handler[1] + allow = request_handler[2] + allowed_list = request_handler[3] + + allowed = False + if not allow == RNS.Destination.ALLOW_NONE: + if allow == RNS.Destination.ALLOW_LIST: + if self.__remote_identity in allowed_list: + allowed = True + elif allow == RNS.Destination.ALLOW_ALL: + allowed = True + + if allowed: + response = response_generator(path, request_data, request_id, self.__remote_identity, requested_at) + if response != None: + packed_response = umsgpack.packb([request_id, True, response]) + + if len(packed_response) <= Link.MDU: + RNS.Packet(self, packed_response, RNS.Packet.DATA, context = RNS.Packet.RESPONSE).send() + else: + # TODO: Implement transfer as resource + packed_response = umsgpack.packb([request_id, False, None]) + raise Exception("Response transfer as resource not implemented") + + except Exception as e: + RNS.log("Error occurred while handling request. The contained exception was: "+str(e), RNS.LOG_ERROR) + + elif packet.context == RNS.Packet.RESPONSE: + packed_response = self.decrypt(packet.data) + unpacked_response = umsgpack.unpackb(packed_response) + request_id = unpacked_response[0] + + if unpacked_response[1] == True: + remove = None + for pending_request in self.pending_requests: + if pending_request.request_id == request_id: + response_data = unpacked_response[2] + remove = pending_request + try: + pending_request.response_received(response_data) + except Exception as e: + RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR) + + break + + if remove != None: + self.pending_requests.remove(remove) + + else: + # TODO: Implement receiving responses as Resources + raise Exception("Response transfer as resource not implemented") + elif packet.context == RNS.Packet.LRRTT: if not self.initiator: self.rtt_packet(packet) @@ -691,4 +776,58 @@ class Link: return self.__encryption_disabled def __str__(self): - return RNS.prettyhexrep(self.link_id) \ No newline at end of file + return RNS.prettyhexrep(self.link_id) + + +class RequestReceipt(): + FAILED = 0x00 + SENT = 0x01 + DELIVERED = 0x02 + READY = 0x03 + + def __init__(self, link, packet_receipt, response_callback = None, failed_callback = None): + self.hash = packet_receipt.truncated_hash + self.link = link + self.request_id = self.hash + + self.response = None + self.status = RequestReceipt.SENT + self.sent_at = time.time() + self.timeout = RNS.Packet.TIMEOUT + self.concluded_at = None + + self.callbacks = RequestReceiptCallbacks() + self.callbacks.response = response_callback + self.callbacks.failed = failed_callback + + self.packet_receipt = packet_receipt + self.packet_receipt.set_timeout_callback(self.request_timed_out) + + self.link.pending_requests.append(self) + + + def request_timed_out(self, packet_receipt): + self.status = RequestReceipt.FAILED + self.concluded_at = time.time() + self.link.pending_requests.remove(self) + + if self.callbacks.failed != None: + self.callbacks.failed(self) + + def response_received(self, response): + self.response = response + + self.packet_receipt.status = RNS.PacketReceipt.DELIVERED + self.packet_receipt.proved = True + self.packet_receipt.concluded_at = time.time() + if self.packet_receipt.callbacks.delivery != None: + self.packet_receipt.callbacks.delivery(self) + + if self.callbacks.response != None: + self.callbacks.response(self) + + +class RequestReceiptCallbacks: + def __init__(self): + self.response = None + self.failed = None \ No newline at end of file diff --git a/RNS/Packet.py b/RNS/Packet.py index 4e9f70d..15cfd0f 100755 --- a/RNS/Packet.py +++ b/RNS/Packet.py @@ -41,7 +41,7 @@ class Packet: HEADER_4 = 0x03 # Reserved header_types = [HEADER_1, HEADER_2, HEADER_3, HEADER_4] - # Data packet context types + # Packet context types NONE = 0x00 # Generic data packet RESOURCE = 0x01 # Packet is part of a resource RESOURCE_ADV = 0x02 # Packet is a resource advertisement @@ -68,7 +68,6 @@ class Packet: HEADER_MAXSIZE = RNS.Reticulum.HEADER_MAXSIZE MDU = RNS.Reticulum.MDU - # TODO: Update this # With an MTU of 500, the maximum of data we can # send in a single encrypted packet is given by # the below calculation; 383 bytes. @@ -326,15 +325,16 @@ class PacketReceipt: # Creates a new packet receipt from a sent packet def __init__(self, packet): - self.hash = packet.get_hash() - self.sent = True - self.sent_at = time.time() - self.timeout = Packet.TIMEOUT - self.proved = False - self.status = PacketReceipt.SENT - self.destination = packet.destination - self.callbacks = PacketReceiptCallbacks() - self.concluded_at = None + self.hash = packet.get_hash() + self.truncated_hash = packet.getTruncatedHash() + self.sent = True + self.sent_at = time.time() + self.timeout = Packet.TIMEOUT + self.proved = False + self.status = PacketReceipt.SENT + self.destination = packet.destination + self.callbacks = PacketReceiptCallbacks() + self.concluded_at = None def get_status(self): """ diff --git a/docs/manual/.buildinfo b/docs/manual/.buildinfo index e75ab37..17e7f72 100644 --- a/docs/manual/.buildinfo +++ b/docs/manual/.buildinfo @@ -1,4 +1,4 @@ # Sphinx build info version 1 # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done. -config: 205a0b937612ce08d1a58b1cbb471256 +config: 966ae7177c1d48c9ee15971994c623b5 tags: 645f666f9bcd5a90fca523b33c5a78b7 diff --git a/docs/manual/_sources/examples.rst.txt b/docs/manual/_sources/examples.rst.txt index 84018b9..ee50df9 100644 --- a/docs/manual/_sources/examples.rst.txt +++ b/docs/manual/_sources/examples.rst.txt @@ -80,6 +80,17 @@ the link has been established. This example can also be found at ``_. +.. _example-request: + +Requests & Responses +==================== + +The *Request* example explores sendig requests and receiving responses. + +.. literalinclude:: ../../Examples/Request.py + +This example can also be found at ``_. + .. _example-filetransfer: Filetransfer diff --git a/docs/manual/_static/documentation_options.js b/docs/manual/_static/documentation_options.js index 5eb22a9..65c3a7b 100644 --- a/docs/manual/_static/documentation_options.js +++ b/docs/manual/_static/documentation_options.js @@ -1,6 +1,6 @@ var DOCUMENTATION_OPTIONS = { URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), - VERSION: '0.2.1 beta', + VERSION: '0.2.2 beta', LANGUAGE: 'None', COLLAPSE_INDEX: false, BUILDER: 'html', diff --git a/docs/manual/examples.html b/docs/manual/examples.html index a83ff5c..6ebac6f 100644 --- a/docs/manual/examples.html +++ b/docs/manual/examples.html @@ -5,7 +5,7 @@ - Examples — Reticulum Network Stack 0.2.1 beta documentation + Examples — Reticulum Network Stack 0.2.2 beta documentation @@ -27,7 +27,7 @@
  • previous |
  • - + @@ -1362,6 +1362,295 @@ the link has been established.

    This example can also be found at https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py.

    +
    +

    Requests & Responses

    +

    The Request example explores sendig requests and receiving responses.

    +
    ##########################################################
    +# This RNS example demonstrates how to set perform       #
    +# requests and receive responses over a link.            #
    +##########################################################
    +
    +import os
    +import sys
    +import time
    +import random
    +import argparse
    +import RNS
    +
    +# Let's define an app name. We'll use this for all
    +# destinations we create. Since this echo example
    +# is part of a range of example utilities, we'll put
    +# them all within the app namespace "example_utilities"
    +APP_NAME = "example_utilities"
    +
    +##########################################################
    +#### Server Part #########################################
    +##########################################################
    +
    +# A reference to the latest client link that connected
    +latest_client_link = None
    +
    +def random_text_generator(path, data, remote_identity_hash, requested_at):
    +    texts = ["They looked up", "On each full moon", "Becky was upset", "I’ll stay away from it", "The pet shop stocks everything"]
    +    return texts[random.randint(0, len(texts)-1)]
    +
    +# This initialisation is executed when the users chooses
    +# to run as a server
    +def server(configpath):
    +    # We must first initialise Reticulum
    +    reticulum = RNS.Reticulum(configpath)
    +    
    +    # Randomly create a new identity for our link example
    +    server_identity = RNS.Identity()
    +
    +    # We create a destination that clients can connect to. We
    +    # want clients to create links to this destination, so we
    +    # need to create a "single" destination type.
    +    server_destination = RNS.Destination(
    +        server_identity,
    +        RNS.Destination.IN,
    +        RNS.Destination.SINGLE,
    +        APP_NAME,
    +        "requestexample"
    +    )
    +
    +    # We configure a function that will get called every time
    +    # a new client creates a link to this destination.
    +    server_destination.set_link_established_callback(client_connected)
    +
    +    # We register a request handler for handling incoming
    +    # requests over any established links.
    +    server_destination.register_request_handler(
    +        "/random/text",
    +        response_generator = random_text_generator,
    +        allow = RNS.Destination.ALLOW_ALL
    +    )
    +
    +    # Everything's ready!
    +    # Let's Wait for client requests or user input
    +    server_loop(server_destination)
    +
    +def server_loop(destination):
    +    # Let the user know that everything is ready
    +    RNS.log(
    +        "Request example "+
    +        RNS.prettyhexrep(destination.hash)+
    +        " running, waiting for a connection."
    +    )
    +
    +    RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
    +
    +    # We enter a loop that runs until the users exits.
    +    # If the user hits enter, we will announce our server
    +    # destination on the network, which will let clients
    +    # know how to create messages directed towards it.
    +    while True:
    +        entered = input()
    +        destination.announce()
    +        RNS.log("Sent announce from "+RNS.prettyhexrep(destination.hash))
    +
    +# When a client establishes a link to our server
    +# destination, this function will be called with
    +# a reference to the link.
    +def client_connected(link):
    +    global latest_client_link
    +
    +    RNS.log("Client connected")
    +    link.set_link_closed_callback(client_disconnected)
    +    latest_client_link = link
    +
    +def client_disconnected(link):
    +    RNS.log("Client disconnected")
    +
    +
    +##########################################################
    +#### Client Part #########################################
    +##########################################################
    +
    +# A reference to the server link
    +server_link = None
    +
    +# This initialisation is executed when the users chooses
    +# to run as a client
    +def client(destination_hexhash, configpath):
    +    # We need a binary representation of the destination
    +    # hash that was entered on the command line
    +    try:
    +        if len(destination_hexhash) != 20:
    +            raise ValueError("Destination length is invalid, must be 20 hexadecimal characters (10 bytes)")
    +        destination_hash = bytes.fromhex(destination_hexhash)
    +    except:
    +        RNS.log("Invalid destination entered. Check your input!\n")
    +        exit()
    +
    +    # We must first initialise Reticulum
    +    reticulum = RNS.Reticulum(configpath)
    +
    +    # Check if we know a path to the destination
    +    if not RNS.Transport.has_path(destination_hash):
    +        RNS.log("Destination is not yet known. Requesting path and waiting for announce to arrive...")
    +        RNS.Transport.request_path(destination_hash)
    +        while not RNS.Transport.has_path(destination_hash):
    +            time.sleep(0.1)
    +
    +    # Recall the server identity
    +    server_identity = RNS.Identity.recall(destination_hash)
    +
    +    # Inform the user that we'll begin connecting
    +    RNS.log("Establishing link with server...")
    +
    +    # When the server identity is known, we set
    +    # up a destination
    +    server_destination = RNS.Destination(
    +        server_identity,
    +        RNS.Destination.OUT,
    +        RNS.Destination.SINGLE,
    +        APP_NAME,
    +        "requestexample"
    +    )
    +
    +    # And create a link
    +    link = RNS.Link(server_destination)
    +
    +    # We'll set up functions to inform the
    +    # user when the link is established or closed
    +    link.set_link_established_callback(link_established)
    +    link.set_link_closed_callback(link_closed)
    +
    +    # Everything is set up, so let's enter a loop
    +    # for the user to interact with the example
    +    client_loop()
    +
    +def client_loop():
    +    global server_link
    +
    +    # Wait for the link to become active
    +    while not server_link:
    +        time.sleep(0.1)
    +
    +    should_quit = False
    +    while not should_quit:
    +        try:
    +            print("> ", end=" ")
    +            text = input()
    +
    +            # Check if we should quit the example
    +            if text == "quit" or text == "q" or text == "exit":
    +                should_quit = True
    +                server_link.teardown()
    +
    +            else:
    +                server_link.request(
    +                    "/random/text",
    +                    data = None,
    +                    response_callback = got_response,
    +                    failed_callback = request_failed
    +                )
    +
    +
    +        except Exception as e:
    +            RNS.log("Error while sending request over the link: "+str(e))
    +            should_quit = True
    +            server_link.teardown()
    +
    +def got_response(request_receipt):
    +    request_id = request_receipt.request_id
    +    response = request_receipt.response
    +
    +    RNS.log("Got response for request "+RNS.prettyhexrep(request_id)+": "+str(response))
    +
    +def request_received(request_receipt):
    +    RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" was received by the remote peer.")
    +
    +def request_failed(request_receipt):
    +    RNS.log("The request "+RNS.prettyhexrep(request_receipt.request_id)+" failed.")
    +
    +
    +# This function is called when a link
    +# has been established with the server
    +def link_established(link):
    +    # We store a reference to the link
    +    # instance for later use
    +    global server_link
    +    server_link = link
    +
    +    # Inform the user that the server is
    +    # connected
    +    RNS.log("Link established with server, hit enter to perform a request, or type in \"quit\" to quit")
    +
    +# When a link is closed, we'll inform the
    +# user, and exit the program
    +def link_closed(link):
    +    if link.teardown_reason == RNS.Link.TIMEOUT:
    +        RNS.log("The link timed out, exiting now")
    +    elif link.teardown_reason == RNS.Link.DESTINATION_CLOSED:
    +        RNS.log("The link was closed by the server, exiting now")
    +    else:
    +        RNS.log("Link closed, exiting now")
    +    
    +    RNS.Reticulum.exit_handler()
    +    time.sleep(1.5)
    +    os._exit(0)
    +
    +
    +##########################################################
    +#### Program Startup #####################################
    +##########################################################
    +
    +# This part of the program runs at startup,
    +# and parses input of from the user, and then
    +# starts up the desired program mode.
    +if __name__ == "__main__":
    +    try:
    +        parser = argparse.ArgumentParser(description="Simple request/response example")
    +
    +        parser.add_argument(
    +            "-s",
    +            "--server",
    +            action="store_true",
    +            help="wait for incoming requests from clients"
    +        )
    +
    +        parser.add_argument(
    +            "--config",
    +            action="store",
    +            default=None,
    +            help="path to alternative Reticulum config directory",
    +            type=str
    +        )
    +
    +        parser.add_argument(
    +            "destination",
    +            nargs="?",
    +            default=None,
    +            help="hexadecimal hash of the server destination",
    +            type=str
    +        )
    +
    +        args = parser.parse_args()
    +
    +        if args.config:
    +            configarg = args.config
    +        else:
    +            configarg = None
    +
    +        if args.server:
    +            server(configarg)
    +        else:
    +            if (args.destination == None):
    +                print("")
    +                parser.print_help()
    +                print("")
    +            else:
    +                client(args.destination, configarg)
    +
    +    except KeyboardInterrupt:
    +        print("")
    +        exit()
    +
    +
    +

    This example can also be found at https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py.

    +
    diff --git a/docs/manual/genindex.html b/docs/manual/genindex.html index e0eeb16..2071a5f 100644 --- a/docs/manual/genindex.html +++ b/docs/manual/genindex.html @@ -5,7 +5,7 @@ - Index — Reticulum Network Stack 0.2.1 beta documentation + Index — Reticulum Network Stack 0.2.2 beta documentation @@ -23,7 +23,7 @@
  • index
  • - + @@ -103,6 +103,8 @@ diff --git a/docs/manual/gettingstartedfast.html b/docs/manual/gettingstartedfast.html index 29e6bb0..9a6e44f 100644 --- a/docs/manual/gettingstartedfast.html +++ b/docs/manual/gettingstartedfast.html @@ -5,7 +5,7 @@ - Getting Started Fast — Reticulum Network Stack 0.2.1 beta documentation + Getting Started Fast — Reticulum Network Stack 0.2.2 beta documentation @@ -31,7 +31,7 @@
  • previous |
  • - + @@ -166,7 +166,7 @@ don’t use pip, but try this recipe:

  • previous |
  • - + diff --git a/docs/manual/index.html b/docs/manual/index.html index 9ebe659..7d427c4 100644 --- a/docs/manual/index.html +++ b/docs/manual/index.html @@ -5,7 +5,7 @@ - Reticulum Network Stack Manual — Reticulum Network Stack 0.2.1 beta documentation + Reticulum Network Stack Manual — Reticulum Network Stack 0.2.2 beta documentation @@ -27,7 +27,7 @@
  • next |
  • - + @@ -104,6 +104,7 @@ the development of Reticulum itself.

  • Echo
  • Link
  • Identification
  • +
  • Requests & Responses
  • Filetransfer
  • @@ -166,7 +167,7 @@ the development of Reticulum itself.

  • next |
  • - + diff --git a/docs/manual/objects.inv b/docs/manual/objects.inv index c0f6217..7b27886 100644 Binary files a/docs/manual/objects.inv and b/docs/manual/objects.inv differ diff --git a/docs/manual/reference.html b/docs/manual/reference.html index 1b375c4..f6f98ab 100644 --- a/docs/manual/reference.html +++ b/docs/manual/reference.html @@ -5,7 +5,7 @@ - API Reference — Reticulum Network Stack 0.2.1 beta documentation + API Reference — Reticulum Network Stack 0.2.2 beta documentation @@ -31,7 +31,7 @@
  • previous |
  • - + @@ -508,6 +508,39 @@ proofs should be returned for received packets.

    +
    +
    +register_request_handler(path, response_generator=None, allow=0, allowed_list=None)
    +

    Registers a request handler.

    +
    +
    Parameters
    +
      +
    • path – The path for the request handler to be registered.

    • +
    • response_generator – A function or method with the signature response_generator(path, data, remote_identity_hash, requested_at) to be called. Whatever this funcion returns will be sent as a response to the requester. If the function returns None, no response will be sent.

    • +
    • allow – One of RNS.Destination.ALLOW_NONE, RNS.Destination.ALLOW_ALL or RNS.Destination.ALLOW_LIST. If RNS.Destination.ALLOW_LIST is set, the request handler will only respond to requests for identified peers in the supplied list.

    • +
    • allowed_list – A list of bytes-like RNS.Identity hashes.

    • +
    +
    +
    Raises
    +

    ValueError if any of the supplied arguments are invalid.

    +
    +
    +
    + +
    +
    +deregister_request_handler(path)
    +

    Deregisters a request handler.

    +
    +
    Parameters
    +

    path – The path for the request handler to be deregistered.

    +
    +
    Returns
    +

    True if the handler was deregistered, otherwise False.

    +
    +
    +
    +
    create_keys()
    @@ -785,6 +818,21 @@ thus preserved. This method can be used for authentication.

    +
    +
    +request(path, data=None, response_callback=None, failed_callback=None)
    +

    Sends a request to the remote peer.

    +
    +
    Parameters
    +
      +
    • path – The request path.

    • +
    • response_callback – A function or method with the signature response_callback(request_receipt) to be called when a response is received. See the Request Example for more info.

    • +
    • failed_callback – A function or method with the signature failed_callback(request_receipt) to be called when a request fails. See the Request Example for more info.

    • +
    +
    +
    +
    +
    no_inbound_for()
    @@ -934,7 +982,7 @@ compression, coordination and checksumming.

    Parameters
    diff --git a/docs/manual/search.html b/docs/manual/search.html index 3971cd0..259c205 100644 --- a/docs/manual/search.html +++ b/docs/manual/search.html @@ -5,7 +5,7 @@ - Search — Reticulum Network Stack 0.2.1 beta documentation + Search — Reticulum Network Stack 0.2.2 beta documentation @@ -29,7 +29,7 @@
  • index
  • - + @@ -85,7 +85,7 @@
  • index
  • - + diff --git a/docs/manual/searchindex.js b/docs/manual/searchindex.js index ad74113..4b61fdb 100644 --- a/docs/manual/searchindex.js +++ b/docs/manual/searchindex.js @@ -1 +1 @@ -Search.setIndex({docnames:["examples","gettingstartedfast","index","reference","understanding","whatis"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["examples.rst","gettingstartedfast.rst","index.rst","reference.rst","understanding.rst","whatis.rst"],objects:{"RNS.Destination":{announce:[3,1,1,""],app_and_aspects_from_name:[3,1,1,""],clear_default_app_data:[3,1,1,""],create_keys:[3,1,1,""],decrypt:[3,1,1,""],encrypt:[3,1,1,""],full_name:[3,1,1,""],get_private_key:[3,1,1,""],hash:[3,1,1,""],hash_from_name_and_identity:[3,1,1,""],load_private_key:[3,1,1,""],set_default_app_data:[3,1,1,""],set_link_established_callback:[3,1,1,""],set_packet_callback:[3,1,1,""],set_proof_requested_callback:[3,1,1,""],set_proof_strategy:[3,1,1,""],sign:[3,1,1,""]},"RNS.Identity":{CURVE:[3,2,1,""],KEYSIZE:[3,2,1,""],TRUNCATED_HASHLENGTH:[3,2,1,""],decrypt:[3,1,1,""],encrypt:[3,1,1,""],from_bytes:[3,1,1,""],from_file:[3,1,1,""],full_hash:[3,1,1,""],get_private_key:[3,1,1,""],get_public_key:[3,1,1,""],get_random_hash:[3,1,1,""],load_private_key:[3,1,1,""],load_public_key:[3,1,1,""],recall:[3,1,1,""],recall_app_data:[3,1,1,""],sign:[3,1,1,""],to_file:[3,1,1,""],truncated_hash:[3,1,1,""],validate:[3,1,1,""]},"RNS.Link":{CURVE:[3,2,1,""],DEFAULT_TIMEOUT:[3,2,1,""],KEEPALIVE:[3,2,1,""],disable_encryption:[3,1,1,""],get_remote_identity:[3,1,1,""],identify:[3,1,1,""],inactive_for:[3,1,1,""],no_inbound_for:[3,1,1,""],no_outbound_for:[3,1,1,""],set_packet_callback:[3,1,1,""],set_remote_identified_callback:[3,1,1,""],set_resource_callback:[3,1,1,""],set_resource_concluded_callback:[3,1,1,""],set_resource_started_callback:[3,1,1,""],set_resource_strategy:[3,1,1,""],teardown:[3,1,1,""]},"RNS.Packet":{ENCRYPTED_MDU:[3,2,1,""],PLAIN_MDU:[3,2,1,""],resend:[3,1,1,""],send:[3,1,1,""]},"RNS.PacketReceipt":{get_rtt:[3,1,1,""],get_status:[3,1,1,""],set_delivery_callback:[3,1,1,""],set_timeout:[3,1,1,""],set_timeout_callback:[3,1,1,""]},"RNS.Resource":{advertise:[3,1,1,""],cancel:[3,1,1,""],progress:[3,1,1,""]},"RNS.Reticulum":{should_allow_unencrypted:[3,1,1,""],should_use_implicit_proof:[3,1,1,""],transport_enabled:[3,1,1,""]},"RNS.Transport":{deregister_announce_handler:[3,1,1,""],has_path:[3,1,1,""],register_announce_handler:[3,1,1,""],request_path:[3,1,1,""]},RNS:{Destination:[3,0,1,""],Identity:[3,0,1,""],Link:[3,0,1,""],Packet:[3,0,1,""],PacketReceipt:[3,0,1,""],Resource:[3,0,1,""],Reticulum:[3,0,1,""],Transport:[3,0,1,""]}},objnames:{"0":["py","class","Python class"],"1":["py","method","Python method"],"2":["py","attribute","Python attribute"]},objtypes:{"0":"py:class","1":"py:method","2":"py:attribute"},terms:{"0":[0,3,4,5],"00":4,"000":[4,5],"00000000":4,"00000100":4,"00000111":4,"01":4,"01010000":4,"05":0,"1":[0,3,4,5],"10":[0,4],"100":[0,4],"1000":[0,4],"1024":0,"11":4,"1200":4,"128":[4,5],"14":4,"141":[],"15":[3,4],"151":4,"18":4,"180":4,"182":[],"2":[0,4],"20":[0,4],"205":[],"240":[4,5],"25":[0,5],"256":[3,4],"270":4,"2f":0,"3":[0,4,5],"323":[],"33":4,"34":4,"360":3,"3600":0,"383":3,"3e12fc71692f8ec47bc5":1,"4":4,"409":[],"430":4,"45":0,"477":[3,4],"5":[0,4],"500":[4,5],"512":3,"60":0,"62":[4,5],"7":4,"77":4,"8":0,"80":[3,4],"80e29bf7cccaf31431b3":4,"86":4,"868":4,"900":4,"95":4,"abstract":4,"break":[4,5],"byte":[0,3,4,5],"case":[1,4],"class":[0,2,5],"default":[0,3,4],"do":[0,1,4,5],"float":[0,3],"function":[0,2,3,5],"import":[0,1,4],"int":0,"long":[0,4],"new":[0,3,4],"public":[0,2,3],"return":[0,3],"short":4,"static":3,"throw":3,"true":[0,3],"try":[0,2],"while":[0,3,4,5],A:[0,3,4,5],And:0,As:[3,4,5],At:4,Be:3,But:4,By:[0,4],For:[3,4],IN:[0,3],If:[0,1,3,4,5],In:[0,1,4,5],It:[0,3,4,5],No:[4,5],One:3,Or:4,That:4,The:[0,1,2,3,5],There:[4,5],These:4,To:[0,4,5],Will:3,With:4,_:4,__:4,______:4,_______:4,________:4,________________:4,__init__:0,__main__:0,__name__:0,_exit:0,ab:0,abl:[0,3,4],about:[0,3,4],abov:[1,4],accept:[3,4],accept_al:[0,3],accept_app:3,accept_non:3,access:[3,4],accord:4,accordingli:0,acheiv:4,achiev:[3,4],acknowledg:5,act:[3,4],action:0,activ:[0,3,4],actor:4,actual:[0,1,4],ad:[0,3,4,5],add:0,add_argu:0,addit:[4,5],addr1:4,addr2:4,address:[0,3,4,5],adress:[0,3,5],advantag:3,advertis:[0,3],advis:4,ae:[4,5],after:[0,4],again:[1,4],against:4,agent:4,agnost:4,agnostic:4,aim:[2,4],aliv:[3,4],all:[0,2,3,4,5],allow:[0,3,4,5],almost:4,along:[3,4],alreadi:[0,4],also:[0,3,4,5],alter:4,altern:0,although:5,alwai:[3,4],amateur:5,amount:[3,4,5],an:[0,1,3,4,5],ani:[0,1,3,4,5],announc:[2,3],announce_handl:0,announced_ident:[0,3],announceloop:0,announcesampl:0,anonym:[3,4],anoth:[1,3,4],answer:4,anyon:[0,3,4],anyth:4,anywher:0,apart:4,api:[1,2,4,5],app:[0,3,4],app_and_aspects_from_nam:3,app_data:[0,3],app_nam:[0,3],app_timeout:0,append:[0,4],appli:4,applic:[0,3,4],approv:4,approxim:4,ar:[0,3,4,5],arbitrari:[3,4],arbritrari:5,area:5,arg:0,argon:0,argpars:0,argument:[0,3],argumentpars:0,around:4,arriv:[0,4],ask:[0,3],aspect:[0,3,4],aspect_filt:[0,3],assign:4,associ:[1,3,4],assum:4,asymmetr:5,attached_interfac:3,attribut:3,audit:5,authent:[3,4,5],author:4,auto:[3,4],auto_compress:3,autoconfigur:5,autom:4,automat:[0,3,4,5],autonom:4,autoomat:0,avail:[0,4,5],averag:4,avoid:4,awai:4,awar:4,ax:5,b:0,back:[0,4,5],band:4,bandwidth:[4,5],bare:0,barrier:4,base:[2,4,5],basi:[3,4,5],basic:[0,1,2],baud:4,becaus:4,becom:0,been:[0,3,4,5],befor:[0,3,4],begin:[0,3],begun:3,behind:4,being:4,belief:4,below:1,best:[1,4,5],beta:5,between:[0,3,4],bgp:4,bi:4,bidirect:4,binari:[0,2],bit:[3,4,5],blob:[0,4],both:[3,4,5],bp:4,briefli:4,broadcast:[2,3,4],broadcast_destin:0,broadcastloop:0,bug:5,build:[0,4,5],built:[1,4,5],bundl:0,c:[0,4],cad:4,calcul:4,call:[0,3,4,5],callabl:3,callback:[0,3],can:[0,1,2,3,4],cancel:3,cannot:0,capac:4,carambola:0,care:[3,4,5],carri:[3,4],carrier:5,caveat:2,cb:4,cbc:5,cd:1,censor:4,censorship:4,central:4,certain:[0,4],challeng:4,chang:[0,1,4,5],channel:[0,4,5],channelarg:0,chapter:[1,4],charact:0,characterist:4,cheap:4,check:0,checksum:[3,5],choos:0,chose:4,chunk:0,ciphertext:3,ciphertext_token:3,cl:0,clear:[0,3,4],clear_default_app_data:3,clear_screen:0,client:[0,1,3],client_connect:0,client_disconnect:0,client_ident:0,client_loop:0,client_packet_receiv:0,client_request:0,clone:1,close:[0,3],closer:4,cluster:4,code:[0,4],com:[0,1],combin:4,come:4,command:[0,1],common:4,commun:[0,1,3,4,5],compat:4,complet:[0,1,3,4,5],compon:4,compos:4,compress:[0,3,4],comput:[1,4],concaten:3,concept:4,conclud:[0,3],concurr:4,condit:4,config:[0,1],configarg:0,configdir:3,configpath:0,configur:[0,3,4,5],confirm:[4,5],connect:[0,3,4,5],consequ:4,consid:[4,5],consist:4,constant:[3,4],construct:4,contact:4,contain:[0,3,4],content:[],context:[3,4],control:[0,3,4],conveni:0,convent:0,coordin:[3,4,5],core:[4,5],correct:[0,4],correctli:0,correspond:4,cost:[4,5],could:[0,3,4,5],count:4,counter:0,cover:5,cpu:0,creat:[0,1,3,4],create_kei:3,create_receipt:[0,3],creation:4,creator:4,critic:4,cryptograph:5,cryptographi:[1,4,5],ctrl:0,cull:3,current:[0,2,3,4],current_download:0,current_filenam:0,curv:[3,4,5],curve25519:[3,4,5],custom:4,d:4,daemon:3,dai:4,data:[0,3,4,5],date:0,debian:4,debug:3,decai:4,decid:[3,4],decod:0,decrypt:[3,4],dedic:4,def:0,default_timeout:3,defin:[0,4],definit:4,delai:4,deliv:[0,3],deliveri:[0,3,5],demand:3,demonstr:0,depend:1,deploi:4,deregist:3,deregister_announce_handl:3,deriv:[4,5],describ:[3,4],descript:0,design:[4,5],desir:[0,4],destin:[0,1,2],destination_1:0,destination_2:0,destination_clos:0,destination_hash:[0,3],destination_hexhash:0,detail:[0,2,3],detect:0,determin:[3,4],develop:[2,4,5],devic:[2,3,4],dh:3,did:0,differ:[0,1,3,4,5],diffi:[4,5],digit:[4,5],dir:0,direct:[0,3,4],directli:[3,4,5],directori:0,disable_encrypt:3,disappear:3,discard:4,disconnect:0,discoveri:4,discuss:4,disk:[0,3],displai:[0,4],distanc:4,distinct:4,distribut:[0,3,4],divmod:0,document:4,doe:[0,2,3,4],don:[0,1],done:[0,4],dot:4,down:0,downgrad:3,download:0,download_began:0,download_conclud:0,download_finish:0,download_start:0,download_tim:0,driver:5,drop:4,duplex:[4,5],e:0,each:[0,4],earlier:4,eas:4,easi:[4,5],easiest:[1,4],easili:[4,5],ecdh:[4,5],echo:[1,2],echo_destin:0,echo_request:0,ed25519:[4,5],effici:[0,4,5],ei:0,either:4,elif:0,ellipt:[3,4,5],els:[0,4],emploi:4,emptor:2,enabl:3,enable_transport:4,encapsul:5,encod:0,encrypt:[0,1,3,4,5],encrypted_mdu:3,encryptionless:3,end:[0,3,4,5],endpoint:[0,3,4],engin:4,ensur:4,enter:0,entir:4,entiti:4,entri:[0,4],enumer:0,environ:4,environment:4,environmentlogg:4,ephemer:[3,4,5],equal:4,equip:4,equl:[],error:[0,3],essenti:4,establish:[0,3,5],ethernet:[4,5],even:[4,5],everi:[0,3,4],everyon:4,everyth:[0,4],exact:4,exactli:[3,4],exampl:[1,2,3,4,5],example_util:0,exampleannouncehandl:0,exce:0,except:[0,4],exchang:[3,4,5],execut:[0,3],exhaust:4,exist:[0,4,5],exit:[0,1,3],exit_handl:0,expand:4,expect:[0,4],experi:[1,4],experiment:5,explain:3,explan:4,explicit:3,explicitli:3,explor:[0,4,5],expos:3,extend:[0,4],extern:[3,5],extrem:5,fa7ddfab5213f916dea:4,face:1,fact:[4,5],fail:[0,3],fals:[0,3],far:4,fast:2,featur:[4,5],feed:3,feedback:0,fernet:5,few:[4,5],field:4,file:[0,1,3,4,5],file_resourc:0,file_s:0,filelist:0,filelist_data:0,filelist_receiv:0,filelist_timeout_job:0,filenam:0,filetransf:[1,2,3],filter:[0,4],find:4,firmwar:4,first:[0,3,4],fit:0,five:0,fix:4,flag:[3,4],flush:0,folder:1,follow:[0,4,5],forcibl:3,foremost:5,form:[3,4],format:[0,2,5],forth:0,forward:[3,4,5],found:[0,1,4],free:5,frequenc:4,friendli:5,from:[0,1,3,4,5],from_byt:3,from_fil:3,fromhex:0,fruit:0,full:[3,4],full_hash:3,full_nam:3,fulli:[4,5],fundament:4,further:[1,2],futur:[3,4],g:0,ga:0,gatekeep:4,gener:[0,3,4,5],generalis:5,get:[0,2,3,5],get_private_kei:3,get_public_kei:3,get_random_hash:[0,3],get_remote_ident:[0,3],get_rtt:[0,3],get_statu:3,gi:0,gigabyt:5,git:1,github:[0,1],give:4,given:4,global:[0,5],go:[0,1,4],goal:2,good:4,got:0,govern:4,grape:0,great:4,greater:4,group:[3,4],guarante:4,guid:[1,3,4],h:[1,4],ha:[0,3,4,5],had:4,half:[4,5],hand:0,handheld:4,handl:[0,3,4,5],handler:[0,3],happen:[0,3],hardwar:[3,4,5],has_path:[0,3],hasattr:0,hash:[0,1,3,4],hash_from_name_and_ident:3,hashmap:0,have:[0,1,3,4],hazard:3,header:4,header_1:4,header_2:4,header_typ:3,hear:4,heard:[3,4],helium:0,hellman:[4,5],help:[0,4,5],here:[0,4],hexadecim:[0,4],high:[4,5],higher:[4,5],highli:4,hint:0,hit:0,hmac:5,hoc:5,hold:[3,4],hop:[4,5],host:[0,4,5],hour:0,how:[0,4,5],howev:4,http:[0,1],human:[0,3],i:0,id:4,idea:4,ident:[0,2],identif:[2,5],identifi:[0,3,4],identify:4,identifyexampl:0,ie:[],ignor:[3,4],immedi:1,impact:4,implement:[0,4,5],implicit:[3,4],inactive_for:3,inbound:3,includ:[0,3,4],incom:[0,3],incompat:[3,4],indefinit:4,independ:3,independt:5,index:[0,2],indirectli:4,individu:4,inevit:4,infer:4,info:[3,4],inform:[0,1,2,3,4],infrastructur:4,ingo:3,initi:[0,3,4],initialis:[0,3],input:0,insert:4,instal:1,instanc:[0,3],instanti:3,instead:[0,4],integr:4,intend:4,intention:4,inter:3,interact:[0,4],interest:4,interfac:[0,2,3,4],intern:[3,4],internet:[4,5],interv:3,intiat:0,introduc:4,introduct:2,intuit:5,invalid:[0,3],investig:4,ip:[4,5],isdir:0,isfil:0,ism:4,its:[3,4],itself:[2,3,4],iv:5,job:0,join:[0,4],just:[0,4,5],k:0,kbp:4,keep:[0,3,4,5],keepal:[3,4],kei:[0,2,3,5],kept:[3,4],kernel:5,keyboardinterrupt:0,keyerror:3,keypair:4,keysiz:3,ki:0,kill:3,kilomet:4,kind:4,know:[0,3,4],knowledg:4,known:[0,3,4],krypton:0,lack:4,laid:4,larg:[0,4],larger:4,last:[0,3],last_unit:0,latenc:[4,5],later:0,latest:[0,1],latest_client_link:0,launch:1,lavg:4,layer:[4,5],lead:4,learn:[0,4],least:[4,5],leav:4,ledger:4,left:4,len:0,length:[0,3],less:[4,5],let:[0,4],level:4,librari:1,licens:4,light:4,like:[1,3,4],limit:4,line:[0,1,4,5],link:[2,5],link_clos:0,link_establish:0,linkexampl:0,linux:4,list:[0,3,4],list_deliv:0,list_fil:0,list_packet:0,list_receipt:0,list_timeout:0,listdir:0,listen:[0,4],littl:4,lki:4,lkr:4,ll:[0,1,5],ln:1,load:[0,3],load_private_kei:3,load_public_kei:3,local:[0,3,4,5],locat:4,log:0,log_error:0,log_info:0,loglevel:0,longer:[0,4],look:[1,4],loop:0,lora:[4,5],lorawan:4,lot:4,low:[4,5],lxmf:1,m:[0,4],mac:4,machin:4,made:4,mai:4,main:0,maintain:4,make:[1,4],malici:4,manag:3,mani:[0,4,5],manipul:4,manual:[0,1,3],mark:4,markqvist:[0,1],master:[0,3],match:0,maximum:[3,4],mcu:4,mdu:0,mean:4,measur:4,mechan:2,medium:[4,5],memori:4,mention:4,menu:0,menu_mod:0,mesh:5,messag:[0,1,3,4],messeng:4,metavar:0,method:[0,3,4],methodolog:4,mhz:4,mi:0,microcontrol:4,microwav:4,might:4,millisecond:0,mind:5,minim:[2,4],minimalsampl:0,minimum:[0,4],minut:[0,4],mode:[0,1,4,5],modem:[3,4,5],modul:[0,4,5],moment:[4,5],monitor:4,more:[3,4,5],most:[1,4,5],motiv:2,move:1,mtu:[4,5],much:4,multi:[4,5],multilater:4,multipl:[0,4],multipoint:4,must:[0,3,4],my:4,n:0,name:[0,3],namespac:0,nano:1,narg:0,necessari:[1,3,4],necessarili:4,need:[0,2,4,5],neglig:4,neither:4,neon:0,network:[0,1,3,4,5],never:3,newer:4,newest:4,newli:4,next:[1,4],nicknam:4,no_inbound_for:3,no_outbound_for:3,nobl:0,noble_ga:0,noble_gas:0,node:[2,5],nomad:1,non:[3,4],none:[0,3,4],normal:0,notat:4,note:[0,4],noth:5,notic:4,notif:[0,3],now:[0,1,4],nt:0,num:0,number:[0,3,4],object:3,obtain:4,occur:5,off:[4,5],offer:[2,3,4],often:4,oganesson:0,old:4,onc:[0,3,4,5],one:[0,3,4,5],onli:[0,3,4,5],onlin:4,open:[0,3,4,5],openmodem:5,oper:[3,4,5],opt:4,optic:5,option:[0,1],orient:4,origin:[0,4],original_hash:3,os:[0,4,5],ospf:4,other:[3,4],otherwis:[3,4],our:[0,4],out:[0,3,4,5],outbound:3,outgo:[0,3,4],outlin:[1,4],outward:4,over:[0,3,4,5],overal:4,overcom:4,overhead:4,overrid:0,overview:4,own:[0,1,3,4],owner:3,p:[0,4],pack:0,packb:0,packet:[0,2,5],packet_callback:0,packet_deliv:0,packet_receipt:[0,3],packet_timed_out:0,packet_typ:3,packetreceipt:[0,3],pad:5,page:[2,4],pair:4,palm:0,paramet:3,pars:0,parse_arg:0,parser:0,part:[0,4],particip:[2,4],pass:[0,3,4],path:[0,1,3,4],path_respons:3,pathfind:[],pattern:4,payload:[3,4],peach:0,peer:[0,3,4],peer_pub_byt:3,peer_sig_pub_byt:3,peopl:4,per:[4,5],percent:0,perfect:4,perform:4,period:4,persecut:4,person:4,philosophi:4,physic:4,pi:[0,4,5],piec:4,ping:1,pip3:1,pip:1,pkcs7:5,place:4,plain:[0,3,4],plain_mdu:3,plaintext:[0,3],platform:4,pleas:[0,5],plenti:4,plu:4,pmr:4,point:4,pomelo:0,port:[4,5],possess:4,possibl:[4,5],potenti:[0,4],practic:[4,5],pre:[3,4],predict:4,prefer:4,prepar:0,presenc:3,preserv:3,press:0,pretend:4,pretti:4,prettyhexrep:0,previou:0,previous:[3,4],primari:4,principl:[4,5],print:0,print_filelist:0,print_help:0,print_menu:0,prioriti:4,prioritis:2,privaci:5,privat:[3,4,5],probabl:[0,4,5],procedur:4,process:[1,3,4],product:3,program:[0,2,3,4],program_setup:0,programm:4,programmat:4,progress:[0,3,5],progress_callback:3,project:1,prompt:0,proof:[0,3,4],proof_requested_callback:3,proof_strategi:3,propag:4,protocol:[1,2,5],prove:[0,4],prove_al:[0,3],prove_app:3,prove_non:3,proven:[3,4],provid:[0,1,2,3,4,5],prv_byte:3,pub_byt:3,public_inform:0,purchas:[4,5],purg:3,purpos:[3,4],purposefulli:4,put:0,py:[0,1],pyseri:1,python3:1,python:[4,5],q:0,queri:0,queue:4,quinc:0,quit:0,r:[0,4],radio:[3,4,5],radiu:4,radon:0,rais:[0,3],rand:4,randint:0,random:[0,3,4],randomli:[0,4],rang:[0,4,5],raspberri:[4,5],rate:0,rb:0,re:[0,3,4],reach:2,reachabl:[0,3,4],read:[0,1,4],readabl:[0,3,4],readi:[0,1],readili:5,real:5,reason:4,reassembl:4,recal:[0,3],recall_app_data:3,recap:4,receipt:[0,2,4],receiv:[0,3,4],received_announc:[0,3],recip:1,recipi:4,recommend:[0,4],reconstruct:4,record:4,recreat:4,refer:[0,1,2],regard:4,regist:[0,3],register_announce_handl:[0,3],rel:[4,5],releas:[1,4],relev:[0,3],reli:4,reliabl:[4,5],rem:0,remain:4,rememb:4,remot:[0,3,5],remote_identifi:0,remote_p:0,remotesensor:4,repeat:1,replac:[1,4],repli:0,replic:4,reply_data:0,reply_text:0,repositori:1,repres:4,represent:[0,4],request:[0,3,4],request_destin:0,request_packet:0,request_path:[0,3],requir:[0,4,5],research:5,resend:3,reserv:4,resili:5,resourc:[0,2],resource_callback:3,resource_sending_conclud:0,resource_strategi:3,respond:[0,3],rest:5,result:[0,4],reticulum:0,retransmiss:4,retransmit:4,retri:4,reveal:[3,4],review:5,right:[],rn:[0,1,3],rnode:[4,5],robot:4,rotat:4,round:[0,3],rout:[3,4,5],rprogress:0,rsa:[],rtt:[0,4],rttstring:0,rule:4,run:[0,1,3,4,5],runtim:4,rw:4,s:[0,1,4,5],said:4,same:[1,3,4],satisfi:4,save:[3,4],save_error:0,saved_filenam:0,scenario:[1,4],screen:0,search:2,second:[0,3,4,5],secreci:[3,4,5],section:4,secur:[4,5],see:[0,3,4],seen:4,segment_index:3,select:0,self:[0,5],send:[0,3,4],sender:[0,4],sensibl:1,sensor:4,sent:[0,3,4],sentiment:4,separ:4,sequenc:[0,3,4,5],serial:[4,5],serv:[0,4],serve_path:0,server:[0,1],server_callback:0,server_destin:0,server_fil:0,server_ident:0,server_link:0,server_loop:0,server_packet_receiv:0,session:4,set:[0,3,4,5],set_default_app_data:3,set_delivery_callback:[0,3],set_link_closed_callback:0,set_link_established_callback:[0,3],set_packet_callback:[0,3],set_proof_requested_callback:3,set_proof_strategi:[0,3],set_remote_identified_callback:[0,3],set_resource_callback:3,set_resource_concluded_callback:[0,3],set_resource_started_callback:[0,3],set_resource_strategi:[0,3],set_timeout:[0,3],set_timeout_callback:[0,3],setdaemon:0,setup:[0,2],sever:3,sha256:5,sha:[3,4],shall:4,share:[1,3,4],shelf:[4,5],shortest:4,should:[0,3,4,5],should_allow_unencrypt:3,should_quit:0,should_use_implicit_proof:3,shown:0,side:5,sign:[3,4],signatur:[3,4,5],similar:5,simpl:[0,4,5],simplest:4,simpli:[0,1,4],simplic:4,sinc:[0,3,4],singl:[0,3,4],singular:4,situat:4,size:[0,3,4],size_str:0,sleep:0,slice:0,slow:[0,4],small:[0,4],so:[0,1,4,5],softwar:[4,5],some:[0,1,4],someth:4,somethign:0,soon:3,sort:4,sourc:[0,1,4,5],space:[0,5],span:4,special:4,specif:[0,2,3,5],specifi:[0,3],spectrum:4,split:0,sponsor:5,stabl:[4,5],stack:[0,1,4,5],stage:4,standard:4,start:[0,2,3,4],startup:0,state:0,station:4,statist:0,statu:[0,2,3,4],stdout:0,step:1,still:[0,4],stop:5,store:[0,4],store_tru:0,str:0,strategi:3,stream:4,strength:5,strictli:4,string:[0,3],structur:4,subject:4,subsequ:4,successful:3,successfulli:0,sucessfulli:4,suffic:4,suffici:4,suffix:0,suit:[1,4],suitabl:[0,4],suppli:[3,4],support:[0,2,4],sy:0,symlink:1,symmetr:[3,4],system:[0,2,3,5],t:[0,1,4],tabl:4,take:[0,1,4,5],taken:[0,4],tangerin:0,target:0,tcp:[4,5],tdata:0,teardown:[0,3],teardown_reason:0,teffect:0,tell:0,temperatur:4,ten:4,term:4,termin:3,terminolog:4,test:4,text:[0,4],tfile:0,than:[0,4],thei:[0,3,4],them:[0,4],thereaft:4,therefor:[4,5],thi:[0,1,2,3,4],though:4,thourough:5,thread:0,three:4,through:[4,5],throughout:4,throughput:[4,5],thu:[3,4],ti:[0,4],time:[0,1,3,4],timeout:[0,3],timeout_callback:[],timeoutarg:0,timestr:0,tnc:[3,5],to_fil:3,todai:4,todo:[],togeth:4,token:[3,4],too:[0,4],tool:5,top:4,topic:4,topolog:4,total:[4,5],total_s:0,touch:5,toward:[0,4],traffic:[0,3,4],tramsit:[],transceiv:[4,5],transfer:[0,3,4,5],transfer_s:0,transmiss:4,transmit:[0,4],transpar:4,transport:[0,2,5],transport_en:3,transport_id:3,transport_typ:3,travers:4,treat:4,tri:0,trip:[0,3],trivial:5,truli:4,truncat:[3,4],truncated_hash:3,truncated_hashlength:3,trust:4,trustless:[4,5],ttime:0,ttransfer:0,tunnel:[4,5],tupl:3,two:[0,4],type:[0,2,3],typeerror:3,udp:[4,5],umsgpack:0,uncencrypt:0,underli:5,understand:[1,2],unencrypt:[0,3,4],unequivoc:4,unforg:5,unidentifi:0,uninterest:0,uniqu:[4,5],unit:0,unknown:[0,3,4],unless:[1,3,4],unlicens:4,unpack:0,unpackb:0,unsupport:3,until:[0,3,4],unwant:4,up:[0,4,5],updat:[0,3],upon:[0,4],urandom:5,us:[0,2,3,4],usabl:4,usag:[],usb:[4,5],useabl:4,user:[0,1,3,4],user_input:0,userland:5,utf:0,util:[0,1,4],utilis:[4,5],valid:[0,3,4],valu:4,valueerror:[0,3],variabl:0,varieti:[4,5],variou:[0,4],ve:1,vendor:0,veri:[3,4,5],verif:[3,4],verifi:[0,4],versa:5,version:3,vhf:4,via:[1,4],vice:5,view:4,visibl:0,wa:[0,3,4,5],wai:[0,1,4],wait:[0,4],want:[0,1,4,5],warrant:5,wb:0,we:[0,4],well:[3,4,5],went:0,what:[0,1,2,3,4],whatev:4,when:[0,1,3,4],whenev:3,where:[2,3,4],whereupon:4,whether:[0,3,4],which:[0,1,3,4],who:4,wide:[4,5],wifi:[4,5],wildcard:0,window:4,wire:[4,5],wish:4,within:[0,3,4],won:0,work:[4,5],world:5,would:4,write:[0,3],written:4,wrong:0,x25519:[3,4,5],x:4,xenon:0,y:0,ye:4,year:4,yet:[0,4],yi:0,you:[0,1,2,3,4,5],your:[0,1,4,5],yourself:[4,5],z:0,zero:3,zi:0},titles:["Examples","Getting Started Fast","Reticulum Network Stack Manual","API Reference","Understanding Reticulum","What is Reticulum?"],titleterms:{"1":[],"2":[],"class":3,"function":4,"public":4,"try":1,The:4,announc:[0,4],api:3,base:1,basic:4,binari:4,broadcast:0,can:5,caveat:5,current:5,deliveri:[],destin:[3,4],detail:4,develop:1,devic:5,doe:5,echo:0,emptor:5,establish:4,exampl:0,fast:1,filetransf:0,format:4,further:4,get:[1,4],goal:4,ident:[3,4],identif:0,indic:2,interfac:5,introduct:4,kei:4,link:[0,3,4],manual:2,mechan:4,minim:0,motiv:4,name:4,network:2,node:4,offer:5,packet:[3,4],particip:1,pathfind:[],prioritis:4,program:1,protocol:4,proven:[],reach:4,receipt:3,refer:[3,4],resourc:[3,4],reticulum:[1,2,3,4,5],setup:4,specif:4,stack:2,start:1,statu:5,step:[],support:5,system:4,tabl:2,transport:[3,4],type:[4,5],understand:4,us:[1,5],what:5,where:5}}) \ No newline at end of file +Search.setIndex({docnames:["examples","gettingstartedfast","index","reference","understanding","whatis"],envversion:{"sphinx.domains.c":2,"sphinx.domains.changeset":1,"sphinx.domains.citation":1,"sphinx.domains.cpp":3,"sphinx.domains.index":1,"sphinx.domains.javascript":2,"sphinx.domains.math":2,"sphinx.domains.python":3,"sphinx.domains.rst":2,"sphinx.domains.std":2,sphinx:56},filenames:["examples.rst","gettingstartedfast.rst","index.rst","reference.rst","understanding.rst","whatis.rst"],objects:{"RNS.Destination":{announce:[3,1,1,""],app_and_aspects_from_name:[3,1,1,""],clear_default_app_data:[3,1,1,""],create_keys:[3,1,1,""],decrypt:[3,1,1,""],deregister_request_handler:[3,1,1,""],encrypt:[3,1,1,""],full_name:[3,1,1,""],get_private_key:[3,1,1,""],hash:[3,1,1,""],hash_from_name_and_identity:[3,1,1,""],load_private_key:[3,1,1,""],register_request_handler:[3,1,1,""],set_default_app_data:[3,1,1,""],set_link_established_callback:[3,1,1,""],set_packet_callback:[3,1,1,""],set_proof_requested_callback:[3,1,1,""],set_proof_strategy:[3,1,1,""],sign:[3,1,1,""]},"RNS.Identity":{CURVE:[3,2,1,""],KEYSIZE:[3,2,1,""],TRUNCATED_HASHLENGTH:[3,2,1,""],decrypt:[3,1,1,""],encrypt:[3,1,1,""],from_bytes:[3,1,1,""],from_file:[3,1,1,""],full_hash:[3,1,1,""],get_private_key:[3,1,1,""],get_public_key:[3,1,1,""],get_random_hash:[3,1,1,""],load_private_key:[3,1,1,""],load_public_key:[3,1,1,""],recall:[3,1,1,""],recall_app_data:[3,1,1,""],sign:[3,1,1,""],to_file:[3,1,1,""],truncated_hash:[3,1,1,""],validate:[3,1,1,""]},"RNS.Link":{CURVE:[3,2,1,""],DEFAULT_TIMEOUT:[3,2,1,""],KEEPALIVE:[3,2,1,""],disable_encryption:[3,1,1,""],get_remote_identity:[3,1,1,""],identify:[3,1,1,""],inactive_for:[3,1,1,""],no_inbound_for:[3,1,1,""],no_outbound_for:[3,1,1,""],request:[3,1,1,""],set_packet_callback:[3,1,1,""],set_remote_identified_callback:[3,1,1,""],set_resource_callback:[3,1,1,""],set_resource_concluded_callback:[3,1,1,""],set_resource_started_callback:[3,1,1,""],set_resource_strategy:[3,1,1,""],teardown:[3,1,1,""]},"RNS.Packet":{ENCRYPTED_MDU:[3,2,1,""],PLAIN_MDU:[3,2,1,""],resend:[3,1,1,""],send:[3,1,1,""]},"RNS.PacketReceipt":{get_rtt:[3,1,1,""],get_status:[3,1,1,""],set_delivery_callback:[3,1,1,""],set_timeout:[3,1,1,""],set_timeout_callback:[3,1,1,""]},"RNS.Resource":{advertise:[3,1,1,""],cancel:[3,1,1,""],progress:[3,1,1,""]},"RNS.Reticulum":{should_allow_unencrypted:[3,1,1,""],should_use_implicit_proof:[3,1,1,""],transport_enabled:[3,1,1,""]},"RNS.Transport":{deregister_announce_handler:[3,1,1,""],has_path:[3,1,1,""],register_announce_handler:[3,1,1,""],request_path:[3,1,1,""]},RNS:{Destination:[3,0,1,""],Identity:[3,0,1,""],Link:[3,0,1,""],Packet:[3,0,1,""],PacketReceipt:[3,0,1,""],Resource:[3,0,1,""],Reticulum:[3,0,1,""],Transport:[3,0,1,""]}},objnames:{"0":["py","class","Python class"],"1":["py","method","Python method"],"2":["py","attribute","Python attribute"]},objtypes:{"0":"py:class","1":"py:method","2":"py:attribute"},terms:{"0":[0,3,4,5],"00":4,"000":[4,5],"00000000":4,"00000100":4,"00000111":4,"01":4,"01010000":4,"05":0,"1":[0,3,4,5],"10":[0,4],"100":[0,4],"1000":[0,4],"1024":0,"11":4,"1200":4,"128":[4,5],"14":4,"141":[],"15":[3,4],"151":4,"18":4,"180":4,"182":[],"2":[0,4],"20":[0,4],"205":[],"240":[4,5],"25":[0,5],"256":[3,4],"270":4,"2f":0,"3":[0,4,5],"323":[],"33":4,"34":4,"360":3,"3600":0,"383":3,"3e12fc71692f8ec47bc5":1,"4":4,"409":[],"430":4,"45":0,"477":[3,4],"5":[0,4],"500":[4,5],"512":3,"60":0,"62":[4,5],"7":4,"77":4,"8":0,"80":[3,4],"80e29bf7cccaf31431b3":4,"86":4,"868":4,"900":4,"95":4,"abstract":4,"break":[4,5],"byte":[0,3,4,5],"case":[1,4],"class":[0,2,5],"default":[0,3,4],"do":[0,1,4,5],"float":[0,3],"function":[0,2,3,5],"import":[0,1,4],"int":0,"long":[0,4],"new":[0,3,4],"public":[0,2,3],"return":[0,3],"short":4,"static":3,"throw":3,"true":[0,3],"try":[0,2],"while":[0,3,4,5],A:[0,3,4,5],And:0,As:[3,4,5],At:4,Be:3,But:4,By:[0,4],For:[3,4],IN:[0,3],If:[0,1,3,4,5],In:[0,1,4,5],It:[0,3,4,5],No:[4,5],On:0,One:3,Or:4,That:4,The:[0,1,2,3,5],There:[4,5],These:4,To:[0,4,5],Will:3,With:4,_:4,__:4,______:4,_______:4,________:4,________________:4,__init__:0,__main__:0,__name__:0,_exit:0,ab:0,abl:[0,3,4],about:[0,3,4],abov:[1,4],accept:[3,4],accept_al:[0,3],accept_app:3,accept_non:3,access:[3,4],accord:4,accordingli:0,acheiv:4,achiev:[3,4],acknowledg:5,act:[3,4],action:0,activ:[0,3,4],actor:4,actual:[0,1,4],ad:[0,3,4,5],add:0,add_argu:0,addit:[4,5],addr1:4,addr2:4,address:[0,3,4,5],adress:[0,3,5],advantag:3,advertis:[0,3],advis:4,ae:[4,5],after:[0,4],again:[1,4],against:4,agent:4,agnost:4,agnostic:4,aim:[2,4],aliv:[3,4],all:[0,2,3,4,5],allow:[0,3,4,5],allow_al:[0,3],allow_list:3,allow_non:3,allowed_list:3,almost:4,along:[3,4],alreadi:[0,4],also:[0,3,4,5],alter:4,altern:0,although:5,alwai:[3,4],amateur:5,amount:[3,4,5],an:[0,1,3,4,5],ani:[0,1,3,4,5],announc:[2,3],announce_handl:0,announced_ident:[0,3],announceloop:0,announcesampl:0,anonym:[3,4],anoth:[1,3,4],answer:4,anyon:[0,3,4],anyth:4,anywher:0,apart:4,api:[1,2,4,5],app:[0,3,4],app_and_aspects_from_nam:3,app_data:[0,3],app_nam:[0,3],app_timeout:0,append:[0,4],appli:4,applic:[0,3,4],approv:4,approxim:4,ar:[0,3,4,5],arbitrari:[3,4],arbritrari:5,area:5,arg:0,argon:0,argpars:0,argument:[0,3],argumentpars:0,around:4,arriv:[0,4],ask:[0,3],aspect:[0,3,4],aspect_filt:[0,3],assign:4,associ:[1,3,4],assum:4,asymmetr:5,attached_interfac:3,attribut:3,audit:5,authent:[3,4,5],author:4,auto:[3,4],auto_compress:3,autoconfigur:5,autom:4,automat:[0,3,4,5],autonom:4,autoomat:0,avail:[0,4,5],averag:4,avoid:4,awai:[0,4],awar:4,ax:5,b:0,back:[0,4,5],band:4,bandwidth:[4,5],bare:0,barrier:4,base:[2,4,5],basi:[3,4,5],basic:[0,1,2],baud:4,becaus:4,becki:0,becom:0,been:[0,3,4,5],befor:[0,3,4],begin:[0,3],begun:3,behind:4,being:4,belief:4,below:1,best:[1,4,5],beta:5,between:[0,3,4],bgp:4,bi:4,bidirect:4,binari:[0,2],bit:[3,4,5],blob:[0,4],both:[3,4,5],bp:4,briefli:4,broadcast:[2,3,4],broadcast_destin:0,broadcastloop:0,bug:5,build:[0,4,5],built:[1,4,5],bundl:0,c:[0,4],cad:4,calcul:4,call:[0,3,4,5],callabl:3,callback:[0,3],can:[0,1,2,3,4],cancel:3,cannot:0,capac:4,carambola:0,care:[3,4,5],carri:[3,4],carrier:5,caveat:2,cb:4,cbc:5,cd:1,censor:4,censorship:4,central:4,certain:[0,4],challeng:4,chang:[0,1,4,5],channel:[0,4,5],channelarg:0,chapter:[1,4],charact:0,characterist:4,cheap:4,check:0,checksum:[3,5],choos:0,chose:4,chunk:0,ciphertext:3,ciphertext_token:3,cl:0,clear:[0,3,4],clear_default_app_data:3,clear_screen:0,client:[0,1,3],client_connect:0,client_disconnect:0,client_ident:0,client_loop:0,client_packet_receiv:0,client_request:0,clone:1,close:[0,3],closer:4,cluster:4,code:[0,4],com:[0,1],combin:4,come:4,command:[0,1],common:4,commun:[0,1,3,4,5],compat:4,complet:[0,1,3,4,5],compon:4,compos:4,compress:[0,3,4],comput:[1,4],concaten:3,concept:4,conclud:[0,3],concurr:4,condit:4,config:[0,1],configarg:0,configdir:3,configpath:0,configur:[0,3,4,5],confirm:[4,5],connect:[0,3,4,5],consequ:4,consid:[4,5],consist:4,constant:[3,4],construct:4,contact:4,contain:[0,3,4],content:[],context:[3,4],control:[0,3,4],conveni:0,convent:0,coordin:[3,4,5],core:[4,5],correct:[0,4],correctli:0,correspond:4,cost:[4,5],could:[0,3,4,5],count:4,counter:0,cover:5,cpu:0,creat:[0,1,3,4],create_kei:3,create_receipt:[0,3],creation:4,creator:4,critic:4,cryptograph:5,cryptographi:[1,4,5],ctrl:0,cull:3,current:[0,2,3,4],current_download:0,current_filenam:0,curv:[3,4,5],curve25519:[3,4,5],custom:4,d:4,daemon:3,dai:4,data:[0,3,4,5],date:0,debian:4,debug:3,decai:4,decid:[3,4],decod:0,decrypt:[3,4],dedic:4,def:0,default_timeout:3,defin:[0,4],definit:4,delai:4,deliv:[0,3],deliveri:[0,3,5],demand:3,demonstr:0,depend:1,deploi:4,deregist:3,deregister_announce_handl:3,deregister_request_handl:3,deriv:[4,5],describ:[3,4],descript:0,design:[4,5],desir:[0,4],destin:[0,1,2],destination_1:0,destination_2:0,destination_clos:0,destination_hash:[0,3],destination_hexhash:0,detail:[0,2,3],detect:0,determin:[3,4],develop:[2,4,5],devic:[2,3,4],dh:3,did:0,differ:[0,1,3,4,5],diffi:[4,5],digit:[4,5],dir:0,direct:[0,3,4],directli:[3,4,5],directori:0,disable_encrypt:3,disappear:3,discard:4,disconnect:0,discoveri:4,discuss:4,disk:[0,3],displai:[0,4],distanc:4,distinct:4,distribut:[0,3,4],divmod:0,document:4,doe:[0,2,3,4],don:[0,1],done:[0,4],dot:4,down:0,downgrad:3,download:0,download_began:0,download_conclud:0,download_finish:0,download_start:0,download_tim:0,driver:5,drop:4,duplex:[4,5],e:0,each:[0,4],earlier:4,eas:4,easi:[4,5],easiest:[1,4],easili:[4,5],ecdh:[4,5],echo:[1,2],echo_destin:0,echo_request:0,ed25519:[4,5],effici:[0,4,5],ei:0,either:4,elif:0,ellipt:[3,4,5],els:[0,4],emploi:4,emptor:2,enabl:3,enable_transport:4,encapsul:5,encod:0,encrypt:[0,1,3,4,5],encrypted_mdu:3,encryptionless:3,end:[0,3,4,5],endpoint:[0,3,4],engin:4,ensur:4,enter:0,entir:4,entiti:4,entri:[0,4],enumer:0,environ:4,environment:4,environmentlogg:4,ephemer:[3,4,5],equal:4,equip:4,equl:[],error:[0,3],essenti:4,establish:[0,3,5],ethernet:[4,5],even:[4,5],everi:[0,3,4],everyon:4,everyth:[0,4],exact:4,exactli:[3,4],exampl:[1,2,3,4,5],example_util:0,exampleannouncehandl:0,exce:0,except:[0,4],exchang:[3,4,5],execut:[0,3],exhaust:4,exist:[0,4,5],exit:[0,1,3],exit_handl:0,expand:4,expect:[0,4],experi:[1,4],experiment:5,explain:3,explan:4,explicit:3,explicitli:3,explor:[0,4,5],expos:3,extend:[0,4],extern:[3,5],extrem:5,fa7ddfab5213f916dea:4,face:1,fact:[4,5],fail:[0,3],failed_callback:[0,3],fals:[0,3],far:4,fast:2,featur:[4,5],feed:3,feedback:0,fernet:5,few:[4,5],field:4,file:[0,1,3,4,5],file_resourc:0,file_s:0,filelist:0,filelist_data:0,filelist_receiv:0,filelist_timeout_job:0,filenam:0,filetransf:[1,2,3],filter:[0,4],find:4,firmwar:4,first:[0,3,4],fit:0,five:0,fix:4,flag:[3,4],flush:0,folder:1,follow:[0,4,5],forcibl:3,foremost:5,form:[3,4],format:[0,2,5],forth:0,forward:[3,4,5],found:[0,1,4],free:5,frequenc:4,friendli:5,from:[0,1,3,4,5],from_byt:3,from_fil:3,fromhex:0,fruit:0,full:[0,3,4],full_hash:3,full_nam:3,fulli:[4,5],funcion:3,fundament:4,further:[1,2],futur:[3,4],g:0,ga:0,gatekeep:4,gener:[0,3,4,5],generalis:5,get:[0,2,3,5],get_private_kei:3,get_public_kei:3,get_random_hash:[0,3],get_remote_ident:[0,3],get_rtt:[0,3],get_statu:3,gi:0,gigabyt:5,git:1,github:[0,1],give:4,given:4,global:[0,5],go:[0,1,4],goal:2,good:4,got:0,got_respons:0,govern:4,grape:0,great:4,greater:4,group:[3,4],guarante:4,guid:[1,3,4],h:[1,4],ha:[0,3,4,5],had:4,half:[4,5],hand:0,handheld:4,handl:[0,3,4,5],handler:[0,3],happen:[0,3],hardwar:[3,4,5],has_path:[0,3],hasattr:0,hash:[0,1,3,4],hash_from_name_and_ident:3,hashmap:0,have:[0,1,3,4],hazard:3,header:4,header_1:4,header_2:4,header_typ:3,hear:4,heard:[3,4],helium:0,hellman:[4,5],help:[0,4,5],here:[0,4],hexadecim:[0,4],high:[4,5],higher:[4,5],highli:4,hint:0,hit:0,hmac:5,hoc:5,hold:[3,4],hop:[4,5],host:[0,4,5],hour:0,how:[0,4,5],howev:4,http:[0,1],human:[0,3],i:0,id:4,idea:4,ident:[0,2],identif:[2,5],identifi:[0,3,4],identify:4,identifyexampl:0,ie:[],ignor:[3,4],immedi:1,impact:4,implement:[0,4,5],implicit:[3,4],inactive_for:3,inbound:3,includ:[0,3,4],incom:[0,3],incompat:[3,4],indefinit:4,independ:3,independt:5,index:[0,2],indirectli:4,individu:4,inevit:4,infer:4,info:[3,4],inform:[0,1,2,3,4],infrastructur:4,ingo:3,initi:[0,3,4],initialis:[0,3],input:0,insert:4,instal:1,instanc:[0,3],instanti:3,instead:[0,4],integr:4,intend:4,intention:4,inter:3,interact:[0,4],interest:4,interfac:[0,2,3,4],intern:[3,4],internet:[4,5],interv:3,intiat:0,introduc:4,introduct:2,intuit:5,invalid:[0,3],investig:4,ip:[4,5],isdir:0,isfil:0,ism:4,its:[3,4],itself:[2,3,4],iv:5,job:0,join:[0,4],just:[0,4,5],k:0,kbp:4,keep:[0,3,4,5],keepal:[3,4],kei:[0,2,3,5],kept:[3,4],kernel:5,keyboardinterrupt:0,keyerror:3,keypair:4,keysiz:3,ki:0,kill:3,kilomet:4,kind:4,know:[0,3,4],knowledg:4,known:[0,3,4],krypton:0,lack:4,laid:4,larg:[0,4],larger:4,last:[0,3],last_unit:0,latenc:[4,5],later:0,latest:[0,1],latest_client_link:0,launch:1,lavg:4,layer:[4,5],lead:4,learn:[0,4],least:[4,5],leav:4,ledger:4,left:4,len:0,length:[0,3],less:[4,5],let:[0,4],level:4,librari:1,licens:4,light:4,like:[1,3,4],limit:4,line:[0,1,4,5],link:[2,5],link_clos:0,link_establish:0,linkexampl:0,linux:4,list:[0,3,4],list_deliv:0,list_fil:0,list_packet:0,list_receipt:0,list_timeout:0,listdir:0,listen:[0,4],littl:4,lki:4,lkr:4,ll:[0,1,5],ln:1,load:[0,3],load_private_kei:3,load_public_kei:3,local:[0,3,4,5],locat:4,log:0,log_error:0,log_info:0,loglevel:0,longer:[0,4],look:[0,1,4],loop:0,lora:[4,5],lorawan:4,lot:4,low:[4,5],lxmf:1,m:[0,4],mac:4,machin:4,made:4,mai:4,main:0,maintain:4,make:[1,4],malici:4,manag:3,mani:[0,4,5],manipul:4,manual:[0,1,3],mark:4,markqvist:[0,1],master:[0,3],match:0,maximum:[3,4],mcu:4,mdu:0,mean:4,measur:4,mechan:2,medium:[4,5],memori:4,mention:4,menu:0,menu_mod:0,mesh:5,messag:[0,1,3,4],messeng:4,metavar:0,method:[0,3,4],methodolog:4,mhz:4,mi:0,microcontrol:4,microwav:4,might:4,millisecond:0,mind:5,minim:[2,4],minimalsampl:0,minimum:[0,4],minut:[0,4],mode:[0,1,4,5],modem:[3,4,5],modul:[0,4,5],moment:[4,5],monitor:4,moon:0,more:[3,4,5],most:[1,4,5],motiv:2,move:1,mtu:[4,5],much:4,multi:[4,5],multilater:4,multipl:[0,4],multipoint:4,must:[0,3,4],my:4,n:0,name:[0,3],namespac:0,nano:1,narg:0,necessari:[1,3,4],necessarili:4,need:[0,2,4,5],neglig:4,neither:4,neon:0,network:[0,1,3,4,5],never:3,newer:4,newest:4,newli:4,next:[1,4],nicknam:4,no_inbound_for:3,no_outbound_for:3,nobl:0,noble_ga:0,noble_gas:0,node:[2,5],nomad:1,non:[3,4],none:[0,3,4],normal:0,notat:4,note:[0,4],noth:5,notic:4,notif:[0,3],now:[0,1,4],nt:0,num:0,number:[0,3,4],object:3,obtain:4,occur:5,off:[4,5],offer:[2,3,4],often:4,oganesson:0,old:4,onc:[0,3,4,5],one:[0,3,4,5],onli:[0,3,4,5],onlin:4,open:[0,3,4,5],openmodem:5,oper:[3,4,5],opt:4,optic:5,option:[0,1],orient:4,origin:[0,4],original_hash:3,os:[0,4,5],ospf:4,other:[3,4],otherwis:[3,4],our:[0,4],out:[0,3,4,5],outbound:3,outgo:[0,3,4],outlin:[1,4],outward:4,over:[0,3,4,5],overal:4,overcom:4,overhead:4,overrid:0,overview:4,own:[0,1,3,4],owner:3,p:[0,4],pack:0,packb:0,packet:[0,2,5],packet_callback:0,packet_deliv:0,packet_receipt:[0,3],packet_timed_out:0,packet_typ:3,packetreceipt:[0,3],pad:5,page:[2,4],pair:4,palm:0,paramet:3,pars:0,parse_arg:0,parser:0,part:[0,4],particip:[2,4],pass:[0,3,4],path:[0,1,3,4],path_respons:3,pathfind:[],pattern:4,payload:[3,4],peach:0,peer:[0,3,4],peer_pub_byt:3,peer_sig_pub_byt:3,peopl:4,per:[4,5],percent:0,perfect:4,perform:[0,4],period:4,persecut:4,person:4,pet:0,philosophi:4,physic:4,pi:[0,4,5],piec:4,ping:1,pip3:1,pip:1,pkcs7:5,place:4,plain:[0,3,4],plain_mdu:3,plaintext:[0,3],platform:4,pleas:[0,5],plenti:4,plu:4,pmr:4,point:4,pomelo:0,port:[4,5],possess:4,possibl:[4,5],potenti:[0,4],practic:[4,5],pre:[3,4],predict:4,prefer:4,prepar:0,presenc:3,preserv:3,press:0,pretend:4,pretti:4,prettyhexrep:0,previou:0,previous:[3,4],primari:4,principl:[4,5],print:0,print_filelist:0,print_help:0,print_menu:0,prioriti:4,prioritis:2,privaci:5,privat:[3,4,5],probabl:[0,4,5],procedur:4,process:[1,3,4],product:3,program:[0,2,3,4],program_setup:0,programm:4,programmat:4,progress:[0,3,5],progress_callback:3,project:1,prompt:0,proof:[0,3,4],proof_requested_callback:3,proof_strategi:3,propag:4,protocol:[1,2,5],prove:[0,4],prove_al:[0,3],prove_app:3,prove_non:3,proven:[3,4],provid:[0,1,2,3,4,5],prv_byte:3,pub_byt:3,public_inform:0,purchas:[4,5],purg:3,purpos:[3,4],purposefulli:4,put:0,py:[0,1],pyseri:1,python3:1,python:[4,5],q:0,queri:0,queue:4,quinc:0,quit:0,r:[0,4],radio:[3,4,5],radiu:4,radon:0,rais:[0,3],rand:4,randint:0,random:[0,3,4],random_text_gener:0,randomli:[0,4],rang:[0,4,5],raspberri:[4,5],rate:0,rb:0,re:[0,3,4],reach:2,reachabl:[0,3,4],read:[0,1,4],readabl:[0,3,4],readi:[0,1],readili:5,real:5,reason:4,reassembl:4,recal:[0,3],recall_app_data:3,recap:4,receipt:[0,2,4],receiv:[0,3,4],received_announc:[0,3],recip:1,recipi:4,recommend:[0,4],reconstruct:4,record:4,recreat:4,refer:[0,1,2],regard:4,regist:[0,3],register_announce_handl:[0,3],register_request_handl:[0,3],rel:[4,5],releas:[1,4],relev:[0,3],reli:4,reliabl:[4,5],rem:0,remain:4,rememb:4,remot:[0,3,5],remote_identifi:0,remote_identity_hash:[0,3],remote_p:0,remotesensor:4,repeat:1,replac:[1,4],repli:0,replic:4,reply_data:0,reply_text:0,repositori:1,repres:4,represent:[0,4],request:[2,3,4],request_destin:0,request_fail:0,request_id:0,request_packet:0,request_path:[0,3],request_receipt:[0,3],request_receiv:0,requested_at:[0,3],requestexampl:0,requir:[0,4,5],research:5,resend:3,reserv:4,resili:5,resourc:[0,2],resource_callback:3,resource_sending_conclud:0,resource_strategi:3,respond:[0,3],respons:[2,3],response_callback:[0,3],response_gener:[0,3],rest:5,result:[0,4],reticulum:0,retransmiss:4,retransmit:4,retri:4,reveal:[3,4],review:5,right:[],rn:[0,1,3],rnode:[4,5],robot:4,rotat:4,round:[0,3],rout:[3,4,5],rprogress:0,rsa:[],rtt:[0,4],rttstring:0,rule:4,run:[0,1,3,4,5],runtim:4,rw:4,s:[0,1,4,5],said:4,same:[1,3,4],satisfi:4,save:[3,4],save_error:0,saved_filenam:0,scenario:[1,4],screen:0,search:2,second:[0,3,4,5],secreci:[3,4,5],section:4,secur:[4,5],see:[0,3,4],seen:4,segment_index:3,select:0,self:[0,5],send:[0,3,4],sender:[0,4],sendig:0,sensibl:1,sensor:4,sent:[0,3,4],sentiment:4,separ:4,sequenc:[0,3,4,5],serial:[4,5],serv:[0,4],serve_path:0,server:[0,1],server_callback:0,server_destin:0,server_fil:0,server_ident:0,server_link:0,server_loop:0,server_packet_receiv:0,session:4,set:[0,3,4,5],set_default_app_data:3,set_delivery_callback:[0,3],set_link_closed_callback:0,set_link_established_callback:[0,3],set_packet_callback:[0,3],set_proof_requested_callback:3,set_proof_strategi:[0,3],set_remote_identified_callback:[0,3],set_resource_callback:3,set_resource_concluded_callback:[0,3],set_resource_started_callback:[0,3],set_resource_strategi:[0,3],set_timeout:[0,3],set_timeout_callback:[0,3],setdaemon:0,setup:[0,2],sever:3,sha256:5,sha:[3,4],shall:4,share:[1,3,4],shelf:[4,5],shop:0,shortest:4,should:[0,3,4,5],should_allow_unencrypt:3,should_quit:0,should_use_implicit_proof:3,shown:0,side:5,sign:[3,4],signatur:[3,4,5],similar:5,simpl:[0,4,5],simplest:4,simpli:[0,1,4],simplic:4,sinc:[0,3,4],singl:[0,3,4],singular:4,situat:4,size:[0,3,4],size_str:0,sleep:0,slice:0,slow:[0,4],small:[0,4],so:[0,1,4,5],softwar:[4,5],some:[0,1,4],someth:4,somethign:0,soon:3,sort:4,sourc:[0,1,4,5],space:[0,5],span:4,special:4,specif:[0,2,3,5],specifi:[0,3],spectrum:4,split:0,sponsor:5,stabl:[4,5],stack:[0,1,4,5],stage:4,stai:0,standard:4,start:[0,2,3,4],startup:0,state:0,station:4,statist:0,statu:[0,2,3,4],stdout:0,step:1,still:[0,4],stock:0,stop:5,store:[0,4],store_tru:0,str:0,strategi:3,stream:4,strength:5,strictli:4,string:[0,3],structur:4,subject:4,subsequ:4,successful:3,successfulli:0,sucessfulli:4,suffic:4,suffici:4,suffix:0,suit:[1,4],suitabl:[0,4],suppli:[3,4],support:[0,2,4],sy:0,symlink:1,symmetr:[3,4],system:[0,2,3,5],t:[0,1,4],tabl:4,take:[0,1,4,5],taken:[0,4],tangerin:0,target:0,tcp:[4,5],tdata:0,teardown:[0,3],teardown_reason:0,teffect:0,tell:0,temperatur:4,ten:4,term:4,termin:3,terminolog:4,test:4,text:[0,4],tfile:0,than:[0,4],thei:[0,3,4],them:[0,4],thereaft:4,therefor:[4,5],thi:[0,1,2,3,4],though:4,thourough:5,thread:0,three:4,through:[4,5],throughout:4,throughput:[4,5],thu:[3,4],ti:[0,4],time:[0,1,3,4],timeout:[0,3],timeout_callback:[],timeoutarg:0,timestr:0,tnc:[3,5],to_fil:3,todai:4,todo:[],togeth:4,token:[3,4],too:[0,4],tool:5,top:4,topic:4,topolog:4,total:[4,5],total_s:0,touch:5,toward:[0,4],traffic:[0,3,4],tramsit:[],transceiv:[4,5],transfer:[0,3,4,5],transfer_s:0,transmiss:4,transmit:[0,4],transpar:4,transport:[0,2,5],transport_en:3,transport_id:3,transport_typ:3,travers:4,treat:4,tri:0,trip:[0,3],trivial:5,truli:4,truncat:[3,4],truncated_hash:3,truncated_hashlength:3,trust:4,trustless:[4,5],ttime:0,ttransfer:0,tunnel:[4,5],tupl:3,two:[0,4],type:[0,2,3],typeerror:3,udp:[4,5],umsgpack:0,uncencrypt:0,underli:5,understand:[1,2],unencrypt:[0,3,4],unequivoc:4,unforg:5,unidentifi:0,uninterest:0,uniqu:[4,5],unit:0,unknown:[0,3,4],unless:[1,3,4],unlicens:4,unpack:0,unpackb:0,unsupport:3,until:[0,3,4],unwant:4,up:[0,4,5],updat:[0,3],upon:[0,4],upset:0,urandom:5,us:[0,2,3,4],usabl:4,usag:[],usb:[4,5],useabl:4,user:[0,1,3,4],user_input:0,userland:5,utf:0,util:[0,1,4],utilis:[4,5],valid:[0,3,4],valu:4,valueerror:[0,3],variabl:0,varieti:[4,5],variou:[0,4],ve:1,vendor:0,veri:[3,4,5],verif:[3,4],verifi:[0,4],versa:5,version:3,vhf:4,via:[1,4],vice:5,view:4,visibl:0,wa:[0,3,4,5],wai:[0,1,4],wait:[0,4],want:[0,1,4,5],warrant:5,wb:0,we:[0,4],well:[3,4,5],went:0,what:[0,1,2,3,4],whatev:[3,4],when:[0,1,3,4],whenev:3,where:[2,3,4],whereupon:4,whether:[0,3,4],which:[0,1,3,4],who:4,wide:[4,5],wifi:[4,5],wildcard:0,window:4,wire:[4,5],wish:4,within:[0,3,4],won:0,work:[4,5],world:5,would:4,write:[0,3],written:4,wrong:0,x25519:[3,4,5],x:4,xenon:0,y:0,ye:4,year:4,yet:[0,4],yi:0,you:[0,1,2,3,4,5],your:[0,1,4,5],yourself:[4,5],z:0,zero:3,zi:0},titles:["Examples","Getting Started Fast","Reticulum Network Stack Manual","API Reference","Understanding Reticulum","What is Reticulum?"],titleterms:{"1":[],"2":[],"class":3,"function":4,"public":4,"try":1,The:4,announc:[0,4],api:3,base:1,basic:4,binari:4,broadcast:0,can:5,caveat:5,current:5,deliveri:[],destin:[3,4],detail:4,develop:1,devic:5,doe:5,echo:0,emptor:5,establish:4,exampl:0,fast:1,filetransf:0,format:4,further:4,get:[1,4],goal:4,ident:[3,4],identif:0,indic:2,interfac:5,introduct:4,kei:4,link:[0,3,4],manual:2,mechan:4,minim:0,motiv:4,name:4,network:2,node:4,offer:5,packet:[3,4],particip:1,pathfind:[],prioritis:4,program:1,protocol:4,proven:[],reach:4,receipt:3,refer:[3,4],request:0,resourc:[3,4],respons:0,reticulum:[1,2,3,4,5],setup:4,specif:4,stack:2,start:1,statu:5,step:[],support:5,system:4,tabl:2,transport:[3,4],type:[4,5],understand:4,us:[1,5],what:5,where:5}}) \ No newline at end of file diff --git a/docs/manual/understanding.html b/docs/manual/understanding.html index 443694e..da7b378 100644 --- a/docs/manual/understanding.html +++ b/docs/manual/understanding.html @@ -5,7 +5,7 @@ - Understanding Reticulum — Reticulum Network Stack 0.2.1 beta documentation + Understanding Reticulum — Reticulum Network Stack 0.2.2 beta documentation @@ -31,7 +31,7 @@
  • previous |
  • - + @@ -853,7 +853,7 @@ proof 11
  • previous |
  • - + diff --git a/docs/manual/whatis.html b/docs/manual/whatis.html index f0850ed..46879a7 100644 --- a/docs/manual/whatis.html +++ b/docs/manual/whatis.html @@ -5,7 +5,7 @@ - What is Reticulum? — Reticulum Network Stack 0.2.1 beta documentation + What is Reticulum? — Reticulum Network Stack 0.2.2 beta documentation @@ -31,7 +31,7 @@
  • previous |
  • - + @@ -182,7 +182,7 @@ network, and vice versa.

  • previous |
  • - + diff --git a/docs/source/conf.py b/docs/source/conf.py index f74593e..cf462a0 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -22,7 +22,7 @@ copyright = '2021, Mark Qvist' author = 'Mark Qvist' # The full version, including alpha/beta/rc tags -release = '0.2.1 beta' +release = '0.2.2 beta' # -- General configuration --------------------------------------------------- diff --git a/docs/source/examples.rst b/docs/source/examples.rst index 84018b9..ee50df9 100644 --- a/docs/source/examples.rst +++ b/docs/source/examples.rst @@ -80,6 +80,17 @@ the link has been established. This example can also be found at ``_. +.. _example-request: + +Requests & Responses +==================== + +The *Request* example explores sendig requests and receiving responses. + +.. literalinclude:: ../../Examples/Request.py + +This example can also be found at ``_. + .. _example-filetransfer: Filetransfer