mirror of
https://github.com/markqvist/Reticulum.git
synced 2026-06-23 04:16:12 -07:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| da13ee9cb9 | |||
| f719d44db5 | |||
| af890d91d2 | |||
| 242941fec4 | |||
| 0f79197945 | |||
| 212518a345 | |||
| 1dc6655017 | |||
| 69930e5652 | |||
| 2b8b95da2b | |||
| 6382409194 | |||
| 4fd3d26714 | |||
| 8b6870fad8 | |||
| 384a7db974 | |||
| 772ae44ab8 | |||
| d326df6c5a | |||
| 4269c48293 |
@@ -135,7 +135,12 @@ def client_disconnected(link):
|
||||
|
||||
def client_request(message, packet):
|
||||
global serve_path
|
||||
filename = message.decode("utf-8")
|
||||
|
||||
try:
|
||||
filename = message.decode("utf-8")
|
||||
except Exception as e:
|
||||
filename = None
|
||||
|
||||
if filename in list_files():
|
||||
try:
|
||||
# If we have the requested file, we'll
|
||||
@@ -497,7 +502,6 @@ def download_concluded(resource):
|
||||
|
||||
saved_filename = current_filename
|
||||
|
||||
|
||||
if resource.status == RNS.Resource.COMPLETE:
|
||||
counter = 0
|
||||
while os.path.isfile(saved_filename):
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
##########################################################
|
||||
# This RNS example demonstrates how to set up a link to #
|
||||
# a destination, and identify the initiator to it's peer #
|
||||
##########################################################
|
||||
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
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
|
||||
|
||||
# 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,
|
||||
"identifyexample"
|
||||
)
|
||||
|
||||
# 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)
|
||||
|
||||
# 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(
|
||||
"Link identification 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)
|
||||
link.set_packet_callback(server_packet_received)
|
||||
link.set_remote_identified_callback(remote_identified)
|
||||
latest_client_link = link
|
||||
|
||||
def client_disconnected(link):
|
||||
RNS.log("Client disconnected")
|
||||
|
||||
def remote_identified(identity):
|
||||
RNS.log("Remote identified as: "+str(identity))
|
||||
|
||||
def server_packet_received(message, packet):
|
||||
global latest_client_link
|
||||
|
||||
# Get the originating identity for display
|
||||
remote_peer = "unidentified peer"
|
||||
if packet.link.get_remote_identity() != None:
|
||||
remote_peer = str(packet.link.get_remote_identity())
|
||||
|
||||
# When data is received over any active link,
|
||||
# it will all be directed to the last client
|
||||
# that connected.
|
||||
text = message.decode("utf-8")
|
||||
|
||||
RNS.log("Received data from "+remote_peer+": "+text)
|
||||
|
||||
reply_text = "I received \""+text+"\" over the link from "+remote_peer
|
||||
reply_data = reply_text.encode("utf-8")
|
||||
RNS.Packet(latest_client_link, reply_data).send()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### Client Part #########################################
|
||||
##########################################################
|
||||
|
||||
# A reference to the server link
|
||||
server_link = None
|
||||
|
||||
# A reference to the client identity
|
||||
client_identity = None
|
||||
|
||||
# This initialisation is executed when the users chooses
|
||||
# to run as a client
|
||||
def client(destination_hexhash, configpath):
|
||||
global client_identity
|
||||
# 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)
|
||||
|
||||
# Create a new client identity
|
||||
client_identity = RNS.Identity()
|
||||
RNS.log(
|
||||
"Client created new identity "+
|
||||
str(client_identity)
|
||||
)
|
||||
|
||||
# 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,
|
||||
"identifyexample"
|
||||
)
|
||||
|
||||
# And create a link
|
||||
link = RNS.Link(server_destination)
|
||||
|
||||
# We set a callback that will get executed
|
||||
# every time a packet is received over the
|
||||
# link
|
||||
link.set_packet_callback(client_packet_received)
|
||||
|
||||
# We'll also 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()
|
||||
|
||||
# If not, send the entered text over the link
|
||||
if text != "":
|
||||
data = text.encode("utf-8")
|
||||
if len(data) <= RNS.Link.MDU:
|
||||
RNS.Packet(server_link, data).send()
|
||||
else:
|
||||
RNS.log(
|
||||
"Cannot send this packet, the data size of "+
|
||||
str(len(data))+" bytes exceeds the link packet MDU of "+
|
||||
str(RNS.Link.MDU)+" bytes",
|
||||
RNS.LOG_ERROR
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Error while sending data over the link: "+str(e))
|
||||
should_quit = True
|
||||
server_link.teardown()
|
||||
|
||||
# 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, client_identity
|
||||
server_link = link
|
||||
|
||||
# Inform the user that the server is
|
||||
# connected
|
||||
RNS.log("Link established with server, identifying to remote peer...")
|
||||
|
||||
link.identify(client_identity)
|
||||
|
||||
# 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)
|
||||
|
||||
# When a packet is received over the link, we
|
||||
# simply print out the data.
|
||||
def client_packet_received(message, packet):
|
||||
text = message.decode("utf-8")
|
||||
RNS.log("Received data on the link: "+text)
|
||||
print("> ", end=" ")
|
||||
sys.stdout.flush()
|
||||
|
||||
|
||||
##########################################################
|
||||
#### 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 link example")
|
||||
|
||||
parser.add_argument(
|
||||
"-s",
|
||||
"--server",
|
||||
action="store_true",
|
||||
help="wait for incoming link 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()
|
||||
@@ -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, 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()
|
||||
@@ -1,54 +0,0 @@
|
||||
Reticulum Wire Format
|
||||
|
||||
Header Types
|
||||
-----------------
|
||||
type 1 00 Two byte header, one 10 byte address field
|
||||
type 2 01 Two byte header, two 10 byte address fields
|
||||
type 3 10 Reserved
|
||||
type 4 11 Reserved
|
||||
|
||||
|
||||
Propagation Types
|
||||
-----------------
|
||||
broadcast 00
|
||||
transport 01
|
||||
reserved 10
|
||||
reserved 11
|
||||
|
||||
|
||||
Destination Types
|
||||
-----------------
|
||||
single 00
|
||||
group 01
|
||||
plain 10
|
||||
link 11
|
||||
|
||||
|
||||
Packet Types
|
||||
-----------------
|
||||
data 00
|
||||
announce 01
|
||||
link request 10
|
||||
proof 11
|
||||
|
||||
|
||||
+- Packet Example -+
|
||||
|
||||
01010000 00000100 [ADDR1, 10 bytes] [ADDR2, 10 bytes] [CONTEXT, 1 byte] [DATA]
|
||||
| | | | |
|
||||
| | | | +-- Hops = 4
|
||||
| | | +------- DATA packet
|
||||
| | +--------- SINGLE destination
|
||||
| +----------- TRANSPORT propagation type
|
||||
+------------- HEADER_2, two byte header, two address fields
|
||||
|
||||
|
||||
+- Packet Example -+
|
||||
|
||||
00000000 00000111 [ADDR1, 10 bytes] [CONTEXT, 1 byte] [DATA]
|
||||
| | | | |
|
||||
| | | | +-- Hops = 7
|
||||
| | | +------- DATA packet
|
||||
| | +--------- SINGLE destination
|
||||
| +----------- BROADCAST propagation type
|
||||
+------------- HEADER_1, two byte header, one address field
|
||||
@@ -32,6 +32,7 @@ For more info, see [unsigned.io/projects/reticulum](https://unsigned.io/projects
|
||||
- Reticulum can handle a few bytes of data or files of many gigabytes
|
||||
- Sequencing, transfer coordination and checksumming is automatic
|
||||
- The API is very easy to use, and provides transfer progress
|
||||
- Lightweight, flexible and expandable Request/Response mechanism
|
||||
- Efficient link establishment
|
||||
- Total bandwidth cost of setting up a link is 3 packets totalling 240 bytes
|
||||
- Low cost of keeping links open at only 0.62 bits per second
|
||||
@@ -74,49 +75,15 @@ Some countries still ban the use of encryption when operating under an amateur r
|
||||
- pyserial
|
||||
|
||||
## How do I get started?
|
||||
Full documentation and tutorials are coming with the stable alpha release. Until then, you are mostly on your own. If you want to experiment already, you could take a look in the "Examples" folder, for some well-documented example programs. The default configuration file created by Reticulum on the first run is also worth reading. Be sure to also read the [Reticulum Overview Document](http://unsigned.io/wp-content/uploads/2018/04/Reticulum_Overview_v0.4.pdf).
|
||||
The best way to get started with the Reticulum Network Stack depends on what
|
||||
you want to do. For full details and examples, have a look at the [Getting Started Fast](https://markqvist.github.io/Reticulum/manual/gettingstartedfast.html) section of the [Reticulum Manual](https://markqvist.github.io/Reticulum/manual/).
|
||||
|
||||
If you just need Reticulum as a dependency for another application, the easiest way is probably via pip:
|
||||
If you just need Reticulum as a dependency for another application, the easiest way is via pip:
|
||||
|
||||
```bash
|
||||
pip3 install rns
|
||||
```
|
||||
|
||||
For Reticulum development, you might want to get the latest source from GitHub. In that case, don't use pip, but try this recipe:
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pip3 install cryptography pyserial
|
||||
|
||||
# Clone repository
|
||||
git clone https://github.com/markqvist/Reticulum.git
|
||||
|
||||
# Move into Reticulum folder and symlink library to examples folder
|
||||
cd Reticulum
|
||||
ln -s ../RNS ./Examples/
|
||||
|
||||
# Run an example
|
||||
python3 Examples/Echo.py -s
|
||||
|
||||
# Unless you've manually created a config file, Reticulum will do so now,
|
||||
# and immediately exit. Make any necessary changes to the file:
|
||||
nano ~/.reticulum/config
|
||||
|
||||
# ... and launch the example again.
|
||||
python3 Examples/Echo.py -s
|
||||
|
||||
# You can now repeat the process on another computer,
|
||||
# and run the same example with -h to get command line options.
|
||||
python3 Examples/Echo.py -h
|
||||
|
||||
# Run the example in client mode to "ping" the server.
|
||||
# Replace the hash below with the actual destination hash of your server.
|
||||
python3 Examples/Echo.py 3e12fc71692f8ec47bc5
|
||||
|
||||
# Have a look at another example
|
||||
python3 Examples/Filetransfer.py -h
|
||||
```
|
||||
|
||||
The default config file contains examples for using Reticulum with LoRa transceivers (specifically [RNode](https://unsigned.io/projects/rnode/)), packet radio TNCs/modems and UDP. By default a UDP interface is already enabled in the default config, which will enable Reticulum communication in your local ethernet broadcast domain.
|
||||
|
||||
You can use the examples in the config file to expand communication over other mediums such as packet radio or LoRa, or over fast IP links using the UDP interface. I'll add in-depth tutorials and explanations on these topics later. For now, the included examples will hopefully be enough to get started.
|
||||
|
||||
@@ -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, 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<api-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
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
from .Interface import Interface
|
||||
import socketserver
|
||||
import threading
|
||||
import netifaces
|
||||
import socket
|
||||
import time
|
||||
import sys
|
||||
@@ -127,12 +128,21 @@ class TCPClientInterface(Interface):
|
||||
|
||||
|
||||
class TCPServerInterface(Interface):
|
||||
@staticmethod
|
||||
def get_address_for_if(name):
|
||||
return netifaces.ifaddresses(name)[netifaces.AF_INET][0]['addr']
|
||||
|
||||
def __init__(self, owner, name, bindip=None, bindport=None):
|
||||
def get_broadcast_for_if(name):
|
||||
return netifaces.ifaddresses(name)[netifaces.AF_INET][0]['broadcast']
|
||||
|
||||
def __init__(self, owner, name, device=None, bindip=None, bindport=None):
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.name = name
|
||||
|
||||
if device != None:
|
||||
bindip = TCPServerInterface.get_address_for_if(device)
|
||||
|
||||
if (bindip != None and bindport != None):
|
||||
self.receives = True
|
||||
self.bind_ip = bindip
|
||||
|
||||
@@ -1,18 +1,34 @@
|
||||
from .Interface import Interface
|
||||
import socketserver
|
||||
import threading
|
||||
import netifaces
|
||||
import socket
|
||||
import time
|
||||
import sys
|
||||
import RNS
|
||||
|
||||
|
||||
class UDPInterface(Interface):
|
||||
|
||||
def __init__(self, owner, name, bindip=None, bindport=None, forwardip=None, forwardport=None):
|
||||
@staticmethod
|
||||
def get_address_for_if(name):
|
||||
return netifaces.ifaddresses(name)[netifaces.AF_INET][0]['addr']
|
||||
|
||||
def get_broadcast_for_if(name):
|
||||
return netifaces.ifaddresses(name)[netifaces.AF_INET][0]['broadcast']
|
||||
|
||||
def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None):
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.name = name
|
||||
|
||||
if device != None:
|
||||
if bindip == None:
|
||||
bindip = UDPInterface.get_broadcast_for_if(device)
|
||||
if forwardip == None:
|
||||
forwardip = UDPInterface.get_broadcast_for_if(device)
|
||||
|
||||
|
||||
if (bindip != None and bindport != None):
|
||||
self.receives = True
|
||||
self.bind_ip = bindip
|
||||
|
||||
+258
-2
@@ -23,6 +23,7 @@ class LinkCallbacks:
|
||||
self.resource = None
|
||||
self.resource_started = None
|
||||
self.resource_concluded = None
|
||||
self.remote_identified = None
|
||||
|
||||
class Link:
|
||||
"""
|
||||
@@ -109,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
|
||||
@@ -125,6 +127,7 @@ class Link:
|
||||
self.owner = owner
|
||||
self.destination = destination
|
||||
self.attached_interface = None
|
||||
self.__remote_identity = None
|
||||
self.__encryption_disabled = False
|
||||
if self.destination == None:
|
||||
self.initiator = False
|
||||
@@ -226,6 +229,7 @@ class Link:
|
||||
if self.destination.identity.validate(signature, signed_data):
|
||||
self.rtt = time.time() - self.request_time
|
||||
self.attached_interface = packet.receiving_interface
|
||||
self.__remote_identity = self.destination.identity
|
||||
RNS.Transport.activate_link(self)
|
||||
RNS.log("Link "+str(self)+" established with "+str(self.destination)+", RTT is "+str(self.rtt), RNS.LOG_VERBOSE)
|
||||
rtt_data = umsgpack.packb(self.rtt)
|
||||
@@ -243,6 +247,60 @@ class Link:
|
||||
RNS.log("Invalid link proof signature received by "+str(self)+". Ignoring.", RNS.LOG_DEBUG)
|
||||
|
||||
|
||||
def identify(self, identity):
|
||||
"""
|
||||
Identifies the initiator of the link to the remote peer. This can only happen
|
||||
once the link has been established, and is carried out over the encrypted link.
|
||||
The identity is only revealed to the remote peer, and initiator anonymity is
|
||||
thus preserved. This method can be used for authentication.
|
||||
|
||||
:param identity: An RNS.Identity instance to identify as.
|
||||
"""
|
||||
if self.initiator:
|
||||
signed_data = self.link_id + identity.get_public_key()
|
||||
signature = identity.sign(signed_data)
|
||||
proof_data = identity.get_public_key() + signature
|
||||
|
||||
proof = RNS.Packet(self, proof_data, RNS.Packet.DATA, context = RNS.Packet.LINKIDENTIFY)
|
||||
proof.send()
|
||||
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<example-request>` 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<example-request>` 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,
|
||||
packet_receipt = request_packet.send(),
|
||||
response_callback = response_callback,
|
||||
failed_callback = failed_callback
|
||||
)
|
||||
|
||||
else:
|
||||
request_id = RNS.Identity.truncated_hash(packed_request)
|
||||
RNS.log("Sending request "+RNS.prettyhexrep(request_id)+" as resource.", RNS.LOG_DEBUG)
|
||||
request_resource = RNS.Resource(packed_request, self, request_id = request_id, is_response = False)
|
||||
|
||||
return RequestReceipt(
|
||||
self,
|
||||
resource = request_resource,
|
||||
response_callback = response_callback,
|
||||
failed_callback = failed_callback
|
||||
)
|
||||
|
||||
|
||||
def rtt_packet(self, packet):
|
||||
try:
|
||||
# TODO: This is crude, we should use the delta
|
||||
@@ -286,6 +344,12 @@ class Link:
|
||||
"""
|
||||
return min(self.no_inbound_for(), self.no_outbound_for())
|
||||
|
||||
def get_remote_identity(self):
|
||||
"""
|
||||
:returns: The identity of the remote peer, if it is known
|
||||
"""
|
||||
return self.__remote_identity
|
||||
|
||||
def had_outbound(self):
|
||||
self.last_outbound = time.time()
|
||||
|
||||
@@ -397,6 +461,77 @@ class Link:
|
||||
keepalive_packet.send()
|
||||
self.had_outbound()
|
||||
|
||||
def handle_request(self, request_id, unpacked_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.hash in allowed_list:
|
||||
allowed = True
|
||||
elif allow == RNS.Destination.ALLOW_ALL:
|
||||
allowed = True
|
||||
|
||||
if allowed:
|
||||
RNS.log("Handling request "+RNS.prettyhexrep(request_id)+" for: "+str(path), RNS.LOG_DEBUG)
|
||||
response = response_generator(path, request_data, request_id, self.__remote_identity, requested_at)
|
||||
if response != None:
|
||||
packed_response = umsgpack.packb([request_id, response])
|
||||
|
||||
if len(packed_response) <= Link.MDU:
|
||||
RNS.Packet(self, packed_response, RNS.Packet.DATA, context = RNS.Packet.RESPONSE).send()
|
||||
else:
|
||||
response_resource = RNS.Resource(packed_response, self, request_id = request_id, is_response = True)
|
||||
else:
|
||||
identity_string = RNS.prettyhexrep(self.get_remote_identity()) if self.get_remote_identity() != None else "<Unknown>"
|
||||
RNS.log("Request "+RNS.prettyhexrep(request_id)+" from "+identity_string+" not allowed for: "+str(path), RNS.LOG_DEBUG)
|
||||
|
||||
def handle_response(self, request_id, response_data):
|
||||
remove = None
|
||||
for pending_request in self.pending_requests:
|
||||
if pending_request.request_id == request_id:
|
||||
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)
|
||||
|
||||
def request_resource_concluded(self, resource):
|
||||
if resource.status == RNS.Resource.COMPLETE:
|
||||
packed_request = resource.data.read()
|
||||
unpacked_request = umsgpack.unpackb(packed_request)
|
||||
request_id = RNS.Identity.truncated_hash(packed_request)
|
||||
request_data = unpacked_request
|
||||
|
||||
self.handle_request(request_id, request_data)
|
||||
else:
|
||||
RNS.log("Incoming request resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG)
|
||||
|
||||
def response_resource_concluded(self, resource):
|
||||
if resource.status == RNS.Resource.COMPLETE:
|
||||
packed_response = resource.data.read()
|
||||
unpacked_response = umsgpack.unpackb(packed_response)
|
||||
request_id = unpacked_response[0]
|
||||
response_data = unpacked_response[1]
|
||||
|
||||
self.handle_response(request_id, response_data)
|
||||
else:
|
||||
RNS.log("Incoming response resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG)
|
||||
|
||||
def receive(self, packet):
|
||||
self.watchdog_lock = True
|
||||
if not self.status == Link.CLOSED and not (self.initiator and packet.context == RNS.Packet.KEEPALIVE and packet.data == bytes([0xFF])):
|
||||
@@ -424,6 +559,40 @@ class Link:
|
||||
if self.destination.callbacks.proof_requested:
|
||||
self.destination.callbacks.proof_requested(packet)
|
||||
|
||||
elif packet.context == RNS.Packet.LINKIDENTIFY:
|
||||
plaintext = self.decrypt(packet.data)
|
||||
|
||||
if not self.initiator and len(plaintext) == RNS.Identity.KEYSIZE//8 + RNS.Identity.SIGLENGTH//8:
|
||||
public_key = plaintext[:RNS.Identity.KEYSIZE//8]
|
||||
signed_data = self.link_id+public_key
|
||||
signature = plaintext[RNS.Identity.KEYSIZE//8:RNS.Identity.KEYSIZE//8+RNS.Identity.SIGLENGTH//8]
|
||||
identity = RNS.Identity(create_keys=False)
|
||||
identity.load_public_key(public_key)
|
||||
|
||||
if identity.validate(signature, signed_data):
|
||||
self.__remote_identity = identity
|
||||
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)
|
||||
self.handle_request(request_id, unpacked_request)
|
||||
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:
|
||||
try:
|
||||
packed_response = self.decrypt(packet.data)
|
||||
unpacked_response = umsgpack.unpackb(packed_response)
|
||||
request_id = unpacked_response[0]
|
||||
response_data = unpacked_response[1]
|
||||
self.handle_response(request_id, response_data)
|
||||
except Exception as e:
|
||||
RNS.log("Error occurred while handling response. The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
elif packet.context == RNS.Packet.LRRTT:
|
||||
if not self.initiator:
|
||||
self.rtt_packet(packet)
|
||||
@@ -433,7 +602,12 @@ class Link:
|
||||
|
||||
elif packet.context == RNS.Packet.RESOURCE_ADV:
|
||||
packet.plaintext = self.decrypt(packet.data)
|
||||
if self.resource_strategy == Link.ACCEPT_NONE:
|
||||
|
||||
if RNS.ResourceAdvertisement.is_request(packet):
|
||||
RNS.Resource.accept(packet, callback=self.request_resource_concluded)
|
||||
elif RNS.ResourceAdvertisement.is_response(packet):
|
||||
RNS.Resource.accept(packet, callback=self.response_resource_concluded)
|
||||
elif self.resource_strategy == Link.ACCEPT_NONE:
|
||||
pass
|
||||
elif self.resource_strategy == Link.ACCEPT_APP:
|
||||
if self.callbacks.resource != None:
|
||||
@@ -574,6 +748,15 @@ class Link:
|
||||
"""
|
||||
self.callbacks.resource_concluded = callback
|
||||
|
||||
def set_remote_identified_callback(self, callback):
|
||||
"""
|
||||
Registers a function to be called when an initiating peer has
|
||||
identified over this link.
|
||||
|
||||
:param callback: A function or method with the signature *callback(identity)* to be called.
|
||||
"""
|
||||
self.callbacks.remote_identified = callback
|
||||
|
||||
def resource_concluded(self, resource):
|
||||
if resource in self.incoming_resources:
|
||||
self.incoming_resources.remove(resource)
|
||||
@@ -639,4 +822,77 @@ class Link:
|
||||
return self.__encryption_disabled
|
||||
|
||||
def __str__(self):
|
||||
return RNS.prettyhexrep(self.link_id)
|
||||
return RNS.prettyhexrep(self.link_id)
|
||||
|
||||
|
||||
class RequestReceipt():
|
||||
FAILED = 0x00
|
||||
SENT = 0x01
|
||||
DELIVERED = 0x02
|
||||
READY = 0x03
|
||||
|
||||
def __init__(self, link, packet_receipt = None, resource = None, response_callback = None, failed_callback = None):
|
||||
self.packet_receipt = packet_receipt
|
||||
self.resource = resource
|
||||
|
||||
if self.packet_receipt != None:
|
||||
self.hash = packet_receipt.truncated_hash
|
||||
self.packet_receipt.set_timeout_callback(self.request_timed_out)
|
||||
|
||||
elif self.resource != None:
|
||||
self.hash = resource.request_id
|
||||
resource.set_callback(self.request_resource_concluded)
|
||||
|
||||
self.link = link
|
||||
self.request_id = self.hash
|
||||
|
||||
self.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.link.pending_requests.append(self)
|
||||
|
||||
def request_resource_concluded(self, resource):
|
||||
if resource.status == RNS.Resource.COMPLETE:
|
||||
RNS.log("Request "+RNS.prettyhexrep(self.request_id)+" successfully sent as resource.", RNS.LOG_DEBUG)
|
||||
else:
|
||||
RNS.log("Sending request "+RNS.prettyhexrep(self.request_id)+" as resource failed with status: "+RNS.hexrep([resource.status]), RNS.LOG_DEBUG)
|
||||
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 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
|
||||
|
||||
if self.packet_receipt != None:
|
||||
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
|
||||
+13
-12
@@ -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
|
||||
@@ -56,7 +56,8 @@ class Packet:
|
||||
PATH_RESPONSE = 0x0B # Packet is a response to a path request
|
||||
COMMAND = 0x0C # Packet is a command
|
||||
COMMAND_STATUS = 0x0D # Packet is a status of an executed command
|
||||
KEEPALIVE = 0xFB # Packet is a keepalive packet
|
||||
KEEPALIVE = 0xFA # Packet is a keepalive packet
|
||||
LINKIDENTIFY = 0xFB # Packet is a link peer identification proof
|
||||
LINKCLOSE = 0xFC # Packet is a link close message
|
||||
LINKPROOF = 0xFD # Packet is a link packet proof
|
||||
LRRTT = 0xFE # Packet is a link request round-trip time measurement
|
||||
@@ -67,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.
|
||||
@@ -325,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):
|
||||
"""
|
||||
|
||||
+70
-17
@@ -21,6 +21,8 @@ class Resource:
|
||||
:param progress_callback: A *callable* with the signature *callback(resource)*. Will be called whenever the resource transfer progress is updated.
|
||||
:param segment_index: Internal use, ignore.
|
||||
:param original_hash: Internal use, ignore.
|
||||
:param is_request: Internal use, ignore.
|
||||
:param is_response: Internal use, ignore.
|
||||
"""
|
||||
WINDOW_FLEXIBILITY = 4
|
||||
WINDOW_MIN = 1
|
||||
@@ -119,7 +121,8 @@ class Resource:
|
||||
resource.link.register_incoming_resource(resource)
|
||||
|
||||
RNS.log("Accepting resource advertisement for "+RNS.prettyhexrep(resource.hash), RNS.LOG_DEBUG)
|
||||
resource.link.callbacks.resource_started(resource)
|
||||
if resource.link.callbacks.resource_started != None:
|
||||
resource.link.callbacks.resource_started(resource)
|
||||
|
||||
resource.hashmap_update(0, resource.hashmap_raw)
|
||||
|
||||
@@ -133,7 +136,7 @@ class Resource:
|
||||
# Create a resource for transmission to a remote destination
|
||||
# The data passed can be either a bytes-array or a file opened
|
||||
# in binary read mode.
|
||||
def __init__(self, data, link, advertise=True, auto_compress=True, callback=None, progress_callback=None, segment_index = 1, original_hash = None):
|
||||
def __init__(self, data, link, advertise=True, auto_compress=True, callback=None, progress_callback=None, segment_index = 1, original_hash = None, request_id = None, is_response = False):
|
||||
data_size = None
|
||||
resource_data = None
|
||||
if hasattr(data, "read"):
|
||||
@@ -188,6 +191,8 @@ class Resource:
|
||||
self.__watchdog_job_id = 0
|
||||
self.__progress_callback = progress_callback
|
||||
self.rtt = None
|
||||
self.request_id = request_id
|
||||
self.is_response = is_response
|
||||
|
||||
self.receiver_min_consecutive_height = 0
|
||||
|
||||
@@ -250,6 +255,7 @@ class Resource:
|
||||
|
||||
self.random_hash = RNS.Identity.get_random_hash()[:Resource.RANDOM_HASH_SIZE]
|
||||
self.hash = RNS.Identity.full_hash(data+self.random_hash)
|
||||
self.truncated_hash = RNS.Identity.truncated_hash(data+self.random_hash)
|
||||
self.expected_proof = RNS.Identity.full_hash(data+self.hash)
|
||||
|
||||
if original_hash == None:
|
||||
@@ -739,6 +745,9 @@ class Resource:
|
||||
self.link.resource_concluded(self)
|
||||
self.callback(self)
|
||||
|
||||
def set_callback(self, callback):
|
||||
self.callback = callback
|
||||
|
||||
def progress_callback(self, callback):
|
||||
self.__progress_callback = callback
|
||||
|
||||
@@ -767,24 +776,63 @@ class Resource:
|
||||
|
||||
|
||||
class ResourceAdvertisement:
|
||||
HASHMAP_MAX_LEN = 73
|
||||
HASHMAP_MAX_LEN = 70
|
||||
COLLISION_GUARD_SIZE = 2*Resource.WINDOW_MAX+HASHMAP_MAX_LEN
|
||||
|
||||
def __init__(self, resource=None):
|
||||
@staticmethod
|
||||
def is_request(advertisement_packet):
|
||||
adv = ResourceAdvertisement.unpack(advertisement_packet.plaintext)
|
||||
if adv.q != None and adv.u:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
@staticmethod
|
||||
def is_response(advertisement_packet):
|
||||
adv = ResourceAdvertisement.unpack(advertisement_packet.plaintext)
|
||||
|
||||
if adv.q != None and adv.p:
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
@staticmethod
|
||||
def get_request_id(advertisement_packet):
|
||||
adv = ResourceAdvertisement.unpack(advertisement_packet.plaintext)
|
||||
return adv.q
|
||||
|
||||
|
||||
def __init__(self, resource=None, request_id=None, is_response=False):
|
||||
if resource != None:
|
||||
self.t = resource.size # Transfer size
|
||||
self.d = resource.total_size # Total uncompressed data size
|
||||
self.n = len(resource.parts) # Number of parts
|
||||
self.h = resource.hash # Resource hash
|
||||
self.r = resource.random_hash # Resource random hash
|
||||
self.o = resource.original_hash # First-segment hash
|
||||
self.m = resource.hashmap # Resource hashmap
|
||||
self.c = resource.compressed # Compression flag
|
||||
self.e = resource.encrypted # Encryption flag
|
||||
self.s = resource.split # Split flag
|
||||
self.i = resource.segment_index # Segment index
|
||||
self.l = resource.total_segments # Total segments
|
||||
self.f = 0x00 | self.s << 2 | self.c << 1 | self.e # Flags
|
||||
self.t = resource.size # Transfer size
|
||||
self.d = resource.total_size # Total uncompressed data size
|
||||
self.n = len(resource.parts) # Number of parts
|
||||
self.h = resource.hash # Resource hash
|
||||
self.r = resource.random_hash # Resource random hash
|
||||
self.o = resource.original_hash # First-segment hash
|
||||
self.m = resource.hashmap # Resource hashmap
|
||||
self.c = resource.compressed # Compression flag
|
||||
self.e = resource.encrypted # Encryption flag
|
||||
self.s = resource.split # Split flag
|
||||
self.i = resource.segment_index # Segment index
|
||||
self.l = resource.total_segments # Total segments
|
||||
self.q = resource.request_id # ID of associated request
|
||||
self.u = False # Is request flag
|
||||
self.p = False # Is response flag
|
||||
|
||||
if self.q != None:
|
||||
if not resource.is_response:
|
||||
self.u = True
|
||||
self.p = False
|
||||
else:
|
||||
self.u = False
|
||||
self.p = True
|
||||
|
||||
# Flags
|
||||
self.f = 0x00 | self.p << 4 | self.u << 3 | self.s << 2 | self.c << 1 | self.e
|
||||
|
||||
|
||||
def pack(self, segment=0):
|
||||
hashmap_start = segment*ResourceAdvertisement.HASHMAP_MAX_LEN
|
||||
@@ -803,12 +851,14 @@ class ResourceAdvertisement:
|
||||
"o": self.o, # Original hash
|
||||
"i": self.i, # Segment index
|
||||
"l": self.l, # Total segments
|
||||
"q": self.q, # Request ID
|
||||
"f": self.f, # Resource flags
|
||||
"m": hashmap
|
||||
}
|
||||
|
||||
return umsgpack.packb(dictionary)
|
||||
|
||||
|
||||
@staticmethod
|
||||
def unpack(data):
|
||||
dictionary = umsgpack.unpackb(data)
|
||||
@@ -824,8 +874,11 @@ class ResourceAdvertisement:
|
||||
adv.f = dictionary["f"]
|
||||
adv.i = dictionary["i"]
|
||||
adv.l = dictionary["l"]
|
||||
adv.q = dictionary["q"]
|
||||
adv.e = True if (adv.f & 0x01) == 0x01 else False
|
||||
adv.c = True if ((adv.f >> 1) & 0x01) == 0x01 else False
|
||||
adv.s = True if ((adv.f >> 2) & 0x01) == 0x01 else False
|
||||
adv.u = True if ((adv.f >> 3) & 0x01) == 0x01 else False
|
||||
adv.p = True if ((adv.f >> 4) & 0x01) == 0x01 else False
|
||||
|
||||
return adv
|
||||
+73
-19
@@ -217,13 +217,27 @@ class Reticulum:
|
||||
try:
|
||||
if ("interface_enabled" in c) and c.as_bool("interface_enabled") == True:
|
||||
if c["type"] == "UDPInterface":
|
||||
device = c["device"] if "device" in c else None
|
||||
port = int(c["port"]) if "port" in c else None
|
||||
listen_ip = c["listen_ip"] if "listen_ip" in c else None
|
||||
listen_port = int(c["listen_port"]) if "listen_port" in c else None
|
||||
forward_ip = c["forward_ip"] if "forward_ip" in c else None
|
||||
forward_port = int(c["forward_port"]) if "forward_port" in c else None
|
||||
|
||||
if port != None:
|
||||
if listen_port == None:
|
||||
listen_port = port
|
||||
if forward_port == None:
|
||||
forward_port = port
|
||||
|
||||
interface = UDPInterface.UDPInterface(
|
||||
RNS.Transport,
|
||||
name,
|
||||
c["listen_ip"],
|
||||
int(c["listen_port"]),
|
||||
c["forward_ip"],
|
||||
int(c["forward_port"])
|
||||
device,
|
||||
listen_ip,
|
||||
listen_port,
|
||||
forward_ip,
|
||||
forward_port
|
||||
)
|
||||
|
||||
if "outgoing" in c and c.as_bool("outgoing") == True:
|
||||
@@ -235,11 +249,20 @@ class Reticulum:
|
||||
|
||||
|
||||
if c["type"] == "TCPServerInterface":
|
||||
device = c["device"] if "device" in c else None
|
||||
port = int(c["port"]) if "port" in c else None
|
||||
listen_ip = c["listen_ip"] if "listen_ip" in c else None
|
||||
listen_port = int(c["listen_port"]) if "listen_port" in c else None
|
||||
|
||||
if port != None:
|
||||
listen_port = port
|
||||
|
||||
interface = TCPInterface.TCPServerInterface(
|
||||
RNS.Transport,
|
||||
name,
|
||||
c["listen_ip"],
|
||||
int(c["listen_port"])
|
||||
device,
|
||||
listen_ip,
|
||||
listen_port
|
||||
)
|
||||
|
||||
if "outgoing" in c and c.as_bool("outgoing") == True:
|
||||
@@ -482,10 +505,10 @@ allow_unencrypted = False
|
||||
|
||||
# If you enable Transport, your system will route traffic
|
||||
# for other peers, pass announces and serve path requests.
|
||||
# Unless you really know what you're doing, this should be
|
||||
# done only for systems that are suited to act as transport
|
||||
# nodes, ie. if they are stationary and always-on. This
|
||||
# directive is optional and can be removed for brevity.
|
||||
# This should be done for systems that are suited to act
|
||||
# as transport nodes, ie. if they are stationary and
|
||||
# always-on. This directive is optional and can be removed
|
||||
# for brevity.
|
||||
|
||||
enable_transport = False
|
||||
|
||||
@@ -533,20 +556,37 @@ loglevel = 4
|
||||
[interfaces]
|
||||
|
||||
# This interface enables communication with other
|
||||
# Reticulum nodes on your local ethernet networks.
|
||||
# It's enabled by default, and provides basic
|
||||
# connectivity to other peers in your local ethernet
|
||||
# broadcast domain. You can modify it to suit your
|
||||
# needs or turn it off completely.
|
||||
# local Reticulum nodes over UDP. You can modify it
|
||||
# to suit your needs or turn it off completely.
|
||||
# As a minimum, you should probably specify the
|
||||
# network device you want to communicate on, such
|
||||
# as eth0 or wlan0.
|
||||
|
||||
[[Default UDP Interface]]
|
||||
type = UDPInterface
|
||||
interface_enabled = True
|
||||
outgoing = True
|
||||
listen_ip = 0.0.0.0
|
||||
listen_port = 4242
|
||||
forward_ip = 255.255.255.255
|
||||
forward_port = 4242
|
||||
device = eth0
|
||||
port = 4242
|
||||
|
||||
# Assuming the eth0 device has the address
|
||||
# 10.55.0.72/24, the above configuration would
|
||||
# be equivalent to the following manual setup.
|
||||
# Note that we are both listening and forwarding
|
||||
# to the network segments broadcast address.
|
||||
|
||||
# listen_ip = 10.55.0.255
|
||||
# listen_port = 4242
|
||||
# forward_ip = 10.55.0.255
|
||||
# forward_port = 4242
|
||||
|
||||
# You can of course also communicate only with
|
||||
# a single IP address
|
||||
|
||||
# listen_ip = 10.55.0.15
|
||||
# listen_port = 4242
|
||||
# forward_ip = 10.55.0.16
|
||||
# forward_port = 4242
|
||||
|
||||
|
||||
# This example demonstrates a TCP server interface.
|
||||
@@ -557,9 +597,23 @@ loglevel = 4
|
||||
type = TCPServerInterface
|
||||
interface_enabled = False
|
||||
outgoing = True
|
||||
|
||||
# This configuration will listen on all IP
|
||||
# interfaces on port 4242
|
||||
|
||||
listen_ip = 0.0.0.0
|
||||
listen_port = 4242
|
||||
|
||||
# Alternatively you can bind to a specific IP
|
||||
|
||||
# listen_ip = 10.0.0.88
|
||||
# listen_port = 4242
|
||||
|
||||
# Or a specific network device
|
||||
|
||||
# device = eth0
|
||||
# port = 4242
|
||||
|
||||
|
||||
# To connect to a TCP server interface, you would
|
||||
# naturally use the TCP client interface. Here's
|
||||
|
||||
+14
-3
@@ -49,6 +49,8 @@ class Transport:
|
||||
receipts = [] # Receipts of all outgoing packets for proof processing
|
||||
|
||||
# TODO: "destination_table" should really be renamed to "path_table"
|
||||
# Notes on memory usage: 1 megabyte of memory can store approximately
|
||||
# 55.100 path table entries or approximately 22.300 link table entries.
|
||||
announce_table = {} # A table for storing announces currently waiting to be retransmitted
|
||||
destination_table = {} # A lookup table containing the next hop to a given destination
|
||||
reverse_table = {} # A lookup table for storing packet hashes used to return proofs and replies
|
||||
@@ -375,6 +377,7 @@ class Transport:
|
||||
# just the relevant interface if the packet has an attached
|
||||
# interface, or belongs to a link.
|
||||
else:
|
||||
stored_hash = False
|
||||
for interface in Transport.interfaces:
|
||||
if interface.OUT:
|
||||
should_transmit = True
|
||||
@@ -389,6 +392,10 @@ class Transport:
|
||||
if should_transmit:
|
||||
RNS.log("Transmitting "+str(len(packet.raw))+" bytes on: "+str(interface), RNS.LOG_EXTREME)
|
||||
RNS.log("Hash is "+RNS.prettyhexrep(packet.packet_hash), RNS.LOG_EXTREME)
|
||||
|
||||
if not stored_hash:
|
||||
Transport.packet_hashlist.append(packet.packet_hash)
|
||||
|
||||
interface.processOutgoing(packet.raw)
|
||||
sent = True
|
||||
|
||||
@@ -396,7 +403,7 @@ class Transport:
|
||||
packet.sent = True
|
||||
packet.sent_at = time.time()
|
||||
|
||||
# Don't generate receipt if it has been explicitly disabled
|
||||
# Don't generate receipt if it has been explicitly disabled
|
||||
if (packet.create_receipt == True and
|
||||
# Only generate receipts for DATA packets
|
||||
packet.packet_type == RNS.Packet.DATA and
|
||||
@@ -1136,13 +1143,17 @@ class Transport:
|
||||
|
||||
@staticmethod
|
||||
def exit_handler():
|
||||
RNS.log("Saving packet hashlist to storage...", RNS.LOG_VERBOSE)
|
||||
try:
|
||||
if not RNS.Reticulum.transport_enabled():
|
||||
Transport.packet_hashlist = []
|
||||
else:
|
||||
RNS.log("Saving packet hashlist to storage...", RNS.LOG_VERBOSE)
|
||||
|
||||
packet_hashlist_path = RNS.Reticulum.storagepath+"/packet_hashlist"
|
||||
file = open(packet_hashlist_path, "wb")
|
||||
file.write(umsgpack.packb(Transport.packet_hashlist))
|
||||
file.close()
|
||||
RNS.log("Done packet hashlist to storage", RNS.LOG_VERBOSE)
|
||||
|
||||
except Exception as e:
|
||||
RNS.log("Could not save packet hashlist to storage, the contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
|
||||
|
||||
+7
-2
@@ -5,6 +5,8 @@ import time
|
||||
import random
|
||||
import threading
|
||||
|
||||
from ._version import __version__
|
||||
|
||||
from .Reticulum import Reticulum
|
||||
from .Identity import Identity
|
||||
from .Link import Link
|
||||
@@ -12,7 +14,7 @@ from .Transport import Transport
|
||||
from .Destination import Destination
|
||||
from .Packet import Packet
|
||||
from .Packet import PacketReceipt
|
||||
from .Resource import Resource
|
||||
from .Resource import Resource, ResourceAdvertisement
|
||||
|
||||
modules = glob.glob(os.path.dirname(__file__)+"/*.py")
|
||||
__all__ = [ os.path.basename(f)[:-3] for f in modules if not f.endswith('__init__.py')]
|
||||
@@ -60,6 +62,9 @@ def loglevelname(level):
|
||||
|
||||
return "Unknown"
|
||||
|
||||
def version():
|
||||
return __version__
|
||||
|
||||
def log(msg, level=3, _override_destination = False):
|
||||
global _always_override_destination
|
||||
|
||||
@@ -68,7 +73,7 @@ def log(msg, level=3, _override_destination = False):
|
||||
logstring = "["+time.strftime(logtimefmt)+"] ["+loglevelname(level)+"] "+msg
|
||||
logging_lock.acquire()
|
||||
|
||||
if (logdest == LOG_STDOUT or _always_override_destination):
|
||||
if (logdest == LOG_STDOUT or _always_override_destination or _override_destination):
|
||||
print(logstring)
|
||||
logging_lock.release()
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
__version__ = "0.2.2"
|
||||
Binary file not shown.
@@ -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
|
||||
|
||||
@@ -68,6 +68,29 @@ destination, and passing traffic back and forth over the link.
|
||||
|
||||
This example can also be found at `<https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py>`_.
|
||||
|
||||
.. _example-identify:
|
||||
|
||||
Identification
|
||||
==============
|
||||
|
||||
The *Identify* example explores identifying an intiator of a link, once
|
||||
the link has been established.
|
||||
|
||||
.. literalinclude:: ../../Examples/Identify.py
|
||||
|
||||
This example can also be found at `<https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py>`_.
|
||||
|
||||
.. _example-request:
|
||||
|
||||
Requests & Responses
|
||||
====================
|
||||
|
||||
The *Request* example explores sendig requests and receiving responses.
|
||||
|
||||
.. literalinclude:: ../../Examples/Request.py
|
||||
|
||||
This example can also be found at `<https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py>`_.
|
||||
|
||||
.. _example-filetransfer:
|
||||
|
||||
Filetransfer
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
What is Reticulum?
|
||||
******************
|
||||
|
||||
Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth. Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
|
||||
Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth.
|
||||
|
||||
Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
|
||||
|
||||
Reticulum is a complete networking stack, and does not use IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.
|
||||
|
||||
@@ -43,7 +45,7 @@ What does Reticulum Offer?
|
||||
|
||||
* A variety of supported interface types
|
||||
|
||||
* An intuitive and easy-to-use API
|
||||
* An intuitive and developer-friendly API
|
||||
|
||||
* Reliable and efficient transfer of arbritrary amounts of data
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
+619
-5
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Examples — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>Examples — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<li class="right" >
|
||||
<a href="reference.html" title="API Reference"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Examples</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -1044,6 +1044,614 @@ destination, and passing traffic back and forth over the link.</p>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="example-identify">
|
||||
<span id="identification"></span><h2>Identification<a class="headerlink" href="#example-identify" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <em>Identify</em> example explores identifying an intiator of a link, once
|
||||
the link has been established.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates how to set up a link to #</span>
|
||||
<span class="c1"># a destination, and identify the initiator to it's peer #</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">os</span>
|
||||
<span class="kn">import</span> <span class="nn">sys</span>
|
||||
<span class="kn">import</span> <span class="nn">time</span>
|
||||
<span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="kn">import</span> <span class="nn">RNS</span>
|
||||
|
||||
<span class="c1"># Let's define an app name. We'll use this for all</span>
|
||||
<span class="c1"># destinations we create. Since this echo example</span>
|
||||
<span class="c1"># is part of a range of example utilities, we'll put</span>
|
||||
<span class="c1"># them all within the app namespace "example_utilities"</span>
|
||||
<span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span>
|
||||
|
||||
<span class="c1">##########################################################</span>
|
||||
<span class="c1">#### Server Part #########################################</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="c1"># A reference to the latest client link that connected</span>
|
||||
<span class="n">latest_client_link</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># This initialisation is executed when the users chooses</span>
|
||||
<span class="c1"># to run as a server</span>
|
||||
<span class="k">def</span> <span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span>
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Randomly create a new identity for our link example</span>
|
||||
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># We create a destination that clients can connect to. We</span>
|
||||
<span class="c1"># want clients to create links to this destination, so we</span>
|
||||
<span class="c1"># need to create a "single" destination type.</span>
|
||||
<span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span>
|
||||
<span class="n">server_identity</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span>
|
||||
<span class="n">APP_NAME</span><span class="p">,</span>
|
||||
<span class="s2">"identifyexample"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># We configure a function that will get called every time</span>
|
||||
<span class="c1"># a new client creates a link to this destination.</span>
|
||||
<span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Everything's ready!</span>
|
||||
<span class="c1"># Let's Wait for client requests or user input</span>
|
||||
<span class="n">server_loop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span>
|
||||
<span class="c1"># Let the user know that everything is ready</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
|
||||
<span class="s2">"Link identification example "</span><span class="o">+</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span>
|
||||
<span class="s2">" running, waiting for a connection."</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We enter a loop that runs until the users exits.</span>
|
||||
<span class="c1"># If the user hits enter, we will announce our server</span>
|
||||
<span class="c1"># destination on the network, which will let clients</span>
|
||||
<span class="c1"># know how to create messages directed towards it.</span>
|
||||
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||||
<span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span>
|
||||
<span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span>
|
||||
|
||||
<span class="c1"># When a client establishes a link to our server</span>
|
||||
<span class="c1"># destination, this function will be called with</span>
|
||||
<span class="c1"># a reference to the link.</span>
|
||||
<span class="k">def</span> <span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="k">global</span> <span class="n">latest_client_link</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected"</span><span class="p">)</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">server_packet_received</span><span class="p">)</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_remote_identified_callback</span><span class="p">(</span><span class="n">remote_identified</span><span class="p">)</span>
|
||||
<span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">remote_identified</span><span class="p">(</span><span class="n">identity</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Remote identified as: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">identity</span><span class="p">))</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">server_packet_received</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span>
|
||||
<span class="k">global</span> <span class="n">latest_client_link</span>
|
||||
|
||||
<span class="c1"># Get the originating identity for display</span>
|
||||
<span class="n">remote_peer</span> <span class="o">=</span> <span class="s2">"unidentified peer"</span>
|
||||
<span class="k">if</span> <span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="o">.</span><span class="n">get_remote_identity</span><span class="p">()</span> <span class="o">!=</span> <span class="kc">None</span><span class="p">:</span>
|
||||
<span class="n">remote_peer</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">packet</span><span class="o">.</span><span class="n">link</span><span class="o">.</span><span class="n">get_remote_identity</span><span class="p">())</span>
|
||||
|
||||
<span class="c1"># When data is received over any active link,</span>
|
||||
<span class="c1"># it will all be directed to the last client</span>
|
||||
<span class="c1"># that connected.</span>
|
||||
<span class="n">text</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data from "</span><span class="o">+</span><span class="n">remote_peer</span><span class="o">+</span><span class="s2">": "</span><span class="o">+</span><span class="n">text</span><span class="p">)</span>
|
||||
|
||||
<span class="n">reply_text</span> <span class="o">=</span> <span class="s2">"I received </span><span class="se">\"</span><span class="s2">"</span><span class="o">+</span><span class="n">text</span><span class="o">+</span><span class="s2">"</span><span class="se">\"</span><span class="s2"> over the link from "</span><span class="o">+</span><span class="n">remote_peer</span>
|
||||
<span class="n">reply_data</span> <span class="o">=</span> <span class="n">reply_text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">latest_client_link</span><span class="p">,</span> <span class="n">reply_data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span>
|
||||
|
||||
|
||||
<span class="c1">##########################################################</span>
|
||||
<span class="c1">#### Client Part #########################################</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="c1"># A reference to the server link</span>
|
||||
<span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># A reference to the client identity</span>
|
||||
<span class="n">client_identity</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># This initialisation is executed when the users chooses</span>
|
||||
<span class="c1"># to run as a client</span>
|
||||
<span class="k">def</span> <span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span>
|
||||
<span class="k">global</span> <span class="n">client_identity</span>
|
||||
<span class="c1"># We need a binary representation of the destination</span>
|
||||
<span class="c1"># hash that was entered on the command line</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">20</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"Destination length is invalid, must be 20 hexadecimal characters (10 bytes)"</span><span class="p">)</span>
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Create a new client identity</span>
|
||||
<span class="n">client_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
|
||||
<span class="s2">"Client created new identity "</span><span class="o">+</span>
|
||||
<span class="nb">str</span><span class="p">(</span><span class="n">client_identity</span><span class="p">)</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># Check if we know a path to the destination</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span>
|
||||
<span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Recall the server identity</span>
|
||||
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Inform the user that we'll begin connecting</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When the server identity is known, we set</span>
|
||||
<span class="c1"># up a destination</span>
|
||||
<span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span>
|
||||
<span class="n">server_identity</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span>
|
||||
<span class="n">APP_NAME</span><span class="p">,</span>
|
||||
<span class="s2">"identifyexample"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># And create a link</span>
|
||||
<span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We set a callback that will get executed</span>
|
||||
<span class="c1"># every time a packet is received over the</span>
|
||||
<span class="c1"># link</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_packet_callback</span><span class="p">(</span><span class="n">client_packet_received</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We'll also set up functions to inform the</span>
|
||||
<span class="c1"># user when the link is established or closed</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Everything is set up, so let's enter a loop</span>
|
||||
<span class="c1"># for the user to interact with the example</span>
|
||||
<span class="n">client_loop</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">client_loop</span><span class="p">():</span>
|
||||
<span class="k">global</span> <span class="n">server_link</span>
|
||||
|
||||
<span class="c1"># Wait for the link to become active</span>
|
||||
<span class="k">while</span> <span class="ow">not</span> <span class="n">server_link</span><span class="p">:</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
|
||||
|
||||
<span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="k">while</span> <span class="ow">not</span> <span class="n">should_quit</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span>
|
||||
<span class="n">text</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># Check if we should quit the example</span>
|
||||
<span class="k">if</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span>
|
||||
<span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># If not, send the entered text over the link</span>
|
||||
<span class="k">if</span> <span class="n">text</span> <span class="o">!=</span> <span class="s2">""</span><span class="p">:</span>
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">)</span> <span class="o"><=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Packet</span><span class="p">(</span><span class="n">server_link</span><span class="p">,</span> <span class="n">data</span><span class="p">)</span><span class="o">.</span><span class="n">send</span><span class="p">()</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
|
||||
<span class="s2">"Cannot send this packet, the data size of "</span><span class="o">+</span>
|
||||
<span class="nb">str</span><span class="p">(</span><span class="nb">len</span><span class="p">(</span><span class="n">data</span><span class="p">))</span><span class="o">+</span><span class="s2">" bytes exceeds the link packet MDU of "</span><span class="o">+</span>
|
||||
<span class="nb">str</span><span class="p">(</span><span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">MDU</span><span class="p">)</span><span class="o">+</span><span class="s2">" bytes"</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">LOG_ERROR</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while sending data over the link: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
|
||||
<span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># This function is called when a link</span>
|
||||
<span class="c1"># has been established with the server</span>
|
||||
<span class="k">def</span> <span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="c1"># We store a reference to the link</span>
|
||||
<span class="c1"># instance for later use</span>
|
||||
<span class="k">global</span> <span class="n">server_link</span><span class="p">,</span> <span class="n">client_identity</span>
|
||||
<span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span>
|
||||
|
||||
<span class="c1"># Inform the user that the server is</span>
|
||||
<span class="c1"># connected</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server, identifying to remote peer..."</span><span class="p">)</span>
|
||||
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">identify</span><span class="p">(</span><span class="n">client_identity</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When a link is closed, we'll inform the</span>
|
||||
<span class="c1"># user, and exit the program</span>
|
||||
<span class="k">def</span> <span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When a packet is received over the link, we</span>
|
||||
<span class="c1"># simply print out the data.</span>
|
||||
<span class="k">def</span> <span class="nf">client_packet_received</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span>
|
||||
<span class="n">text</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Received data on the link: "</span><span class="o">+</span><span class="n">text</span><span class="p">)</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span>
|
||||
<span class="n">sys</span><span class="o">.</span><span class="n">stdout</span><span class="o">.</span><span class="n">flush</span><span class="p">()</span>
|
||||
|
||||
|
||||
<span class="c1">##########################################################</span>
|
||||
<span class="c1">#### Program Startup #####################################</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="c1"># This part of the program runs at startup,</span>
|
||||
<span class="c1"># and parses input of from the user, and then</span>
|
||||
<span class="c1"># starts up the desired program mode.</span>
|
||||
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple link example"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span>
|
||||
<span class="s2">"-s"</span><span class="p">,</span>
|
||||
<span class="s2">"--server"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming link requests from clients"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span>
|
||||
<span class="s2">"--config"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span>
|
||||
<span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span>
|
||||
<span class="nb">type</span><span class="o">=</span><span class="nb">str</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span>
|
||||
<span class="s2">"destination"</span><span class="p">,</span>
|
||||
<span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span>
|
||||
<span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span>
|
||||
<span class="nb">type</span><span class="o">=</span><span class="nb">str</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
|
||||
<span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span>
|
||||
<span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="requests-responses">
|
||||
<span id="example-request"></span><h2>Requests & Responses<a class="headerlink" href="#requests-responses" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <em>Request</em> example explores sendig requests and receiving responses.</p>
|
||||
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1">##########################################################</span>
|
||||
<span class="c1"># This RNS example demonstrates how to set perform #</span>
|
||||
<span class="c1"># requests and receive responses over a link. #</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="kn">import</span> <span class="nn">os</span>
|
||||
<span class="kn">import</span> <span class="nn">sys</span>
|
||||
<span class="kn">import</span> <span class="nn">time</span>
|
||||
<span class="kn">import</span> <span class="nn">random</span>
|
||||
<span class="kn">import</span> <span class="nn">argparse</span>
|
||||
<span class="kn">import</span> <span class="nn">RNS</span>
|
||||
|
||||
<span class="c1"># Let's define an app name. We'll use this for all</span>
|
||||
<span class="c1"># destinations we create. Since this echo example</span>
|
||||
<span class="c1"># is part of a range of example utilities, we'll put</span>
|
||||
<span class="c1"># them all within the app namespace "example_utilities"</span>
|
||||
<span class="n">APP_NAME</span> <span class="o">=</span> <span class="s2">"example_utilities"</span>
|
||||
|
||||
<span class="c1">##########################################################</span>
|
||||
<span class="c1">#### Server Part #########################################</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="c1"># A reference to the latest client link that connected</span>
|
||||
<span class="n">latest_client_link</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">random_text_generator</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">request_id</span><span class="p">,</span> <span class="n">remote_identity</span><span class="p">,</span> <span class="n">requested_at</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Generating response to request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_id</span><span class="p">))</span>
|
||||
<span class="n">texts</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"They looked up"</span><span class="p">,</span> <span class="s2">"On each full moon"</span><span class="p">,</span> <span class="s2">"Becky was upset"</span><span class="p">,</span> <span class="s2">"I’ll stay away from it"</span><span class="p">,</span> <span class="s2">"The pet shop stocks everything"</span><span class="p">]</span>
|
||||
<span class="k">return</span> <span class="n">texts</span><span class="p">[</span><span class="n">random</span><span class="o">.</span><span class="n">randint</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="nb">len</span><span class="p">(</span><span class="n">texts</span><span class="p">)</span><span class="o">-</span><span class="mi">1</span><span class="p">)]</span>
|
||||
|
||||
<span class="c1"># This initialisation is executed when the users chooses</span>
|
||||
<span class="c1"># to run as a server</span>
|
||||
<span class="k">def</span> <span class="nf">server</span><span class="p">(</span><span class="n">configpath</span><span class="p">):</span>
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Randomly create a new identity for our link example</span>
|
||||
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># We create a destination that clients can connect to. We</span>
|
||||
<span class="c1"># want clients to create links to this destination, so we</span>
|
||||
<span class="c1"># need to create a "single" destination type.</span>
|
||||
<span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span>
|
||||
<span class="n">server_identity</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">IN</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span>
|
||||
<span class="n">APP_NAME</span><span class="p">,</span>
|
||||
<span class="s2">"requestexample"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># We configure a function that will get called every time</span>
|
||||
<span class="c1"># a new client creates a link to this destination.</span>
|
||||
<span class="n">server_destination</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">client_connected</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We register a request handler for handling incoming</span>
|
||||
<span class="c1"># requests over any established links.</span>
|
||||
<span class="n">server_destination</span><span class="o">.</span><span class="n">register_request_handler</span><span class="p">(</span>
|
||||
<span class="s2">"/random/text"</span><span class="p">,</span>
|
||||
<span class="n">response_generator</span> <span class="o">=</span> <span class="n">random_text_generator</span><span class="p">,</span>
|
||||
<span class="n">allow</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">ALLOW_ALL</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># Everything's ready!</span>
|
||||
<span class="c1"># Let's Wait for client requests or user input</span>
|
||||
<span class="n">server_loop</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">server_loop</span><span class="p">(</span><span class="n">destination</span><span class="p">):</span>
|
||||
<span class="c1"># Let the user know that everything is ready</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
|
||||
<span class="s2">"Request example "</span><span class="o">+</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">)</span><span class="o">+</span>
|
||||
<span class="s2">" running, waiting for a connection."</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Hit enter to manually send an announce (Ctrl-C to quit)"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We enter a loop that runs until the users exits.</span>
|
||||
<span class="c1"># If the user hits enter, we will announce our server</span>
|
||||
<span class="c1"># destination on the network, which will let clients</span>
|
||||
<span class="c1"># know how to create messages directed towards it.</span>
|
||||
<span class="k">while</span> <span class="kc">True</span><span class="p">:</span>
|
||||
<span class="n">entered</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span>
|
||||
<span class="n">destination</span><span class="o">.</span><span class="n">announce</span><span class="p">()</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Sent announce from "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">destination</span><span class="o">.</span><span class="n">hash</span><span class="p">))</span>
|
||||
|
||||
<span class="c1"># When a client establishes a link to our server</span>
|
||||
<span class="c1"># destination, this function will be called with</span>
|
||||
<span class="c1"># a reference to the link.</span>
|
||||
<span class="k">def</span> <span class="nf">client_connected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="k">global</span> <span class="n">latest_client_link</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client connected"</span><span class="p">)</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">client_disconnected</span><span class="p">)</span>
|
||||
<span class="n">latest_client_link</span> <span class="o">=</span> <span class="n">link</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">client_disconnected</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Client disconnected"</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c1">##########################################################</span>
|
||||
<span class="c1">#### Client Part #########################################</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="c1"># A reference to the server link</span>
|
||||
<span class="n">server_link</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="c1"># This initialisation is executed when the users chooses</span>
|
||||
<span class="c1"># to run as a client</span>
|
||||
<span class="k">def</span> <span class="nf">client</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">,</span> <span class="n">configpath</span><span class="p">):</span>
|
||||
<span class="c1"># We need a binary representation of the destination</span>
|
||||
<span class="c1"># hash that was entered on the command line</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">20</span><span class="p">:</span>
|
||||
<span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="s2">"Destination length is invalid, must be 20 hexadecimal characters (10 bytes)"</span><span class="p">)</span>
|
||||
<span class="n">destination_hash</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="n">destination_hexhash</span><span class="p">)</span>
|
||||
<span class="k">except</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Invalid destination entered. Check your input!</span><span class="se">\n</span><span class="s2">"</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># We must first initialise Reticulum</span>
|
||||
<span class="n">reticulum</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="p">(</span><span class="n">configpath</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Check if we know a path to the destination</span>
|
||||
<span class="k">if</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Destination is not yet known. Requesting path and waiting for announce to arrive..."</span><span class="p">)</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">request_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span>
|
||||
<span class="k">while</span> <span class="ow">not</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Transport</span><span class="o">.</span><span class="n">has_path</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">):</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Recall the server identity</span>
|
||||
<span class="n">server_identity</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Identity</span><span class="o">.</span><span class="n">recall</span><span class="p">(</span><span class="n">destination_hash</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Inform the user that we'll begin connecting</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Establishing link with server..."</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When the server identity is known, we set</span>
|
||||
<span class="c1"># up a destination</span>
|
||||
<span class="n">server_destination</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="p">(</span>
|
||||
<span class="n">server_identity</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">OUT</span><span class="p">,</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Destination</span><span class="o">.</span><span class="n">SINGLE</span><span class="p">,</span>
|
||||
<span class="n">APP_NAME</span><span class="p">,</span>
|
||||
<span class="s2">"requestexample"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="c1"># And create a link</span>
|
||||
<span class="n">link</span> <span class="o">=</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="p">(</span><span class="n">server_destination</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># We'll set up functions to inform the</span>
|
||||
<span class="c1"># user when the link is established or closed</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_link_established_callback</span><span class="p">(</span><span class="n">link_established</span><span class="p">)</span>
|
||||
<span class="n">link</span><span class="o">.</span><span class="n">set_link_closed_callback</span><span class="p">(</span><span class="n">link_closed</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># Everything is set up, so let's enter a loop</span>
|
||||
<span class="c1"># for the user to interact with the example</span>
|
||||
<span class="n">client_loop</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">client_loop</span><span class="p">():</span>
|
||||
<span class="k">global</span> <span class="n">server_link</span>
|
||||
|
||||
<span class="c1"># Wait for the link to become active</span>
|
||||
<span class="k">while</span> <span class="ow">not</span> <span class="n">server_link</span><span class="p">:</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">0.1</span><span class="p">)</span>
|
||||
|
||||
<span class="n">should_quit</span> <span class="o">=</span> <span class="kc">False</span>
|
||||
<span class="k">while</span> <span class="ow">not</span> <span class="n">should_quit</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">"> "</span><span class="p">,</span> <span class="n">end</span><span class="o">=</span><span class="s2">" "</span><span class="p">)</span>
|
||||
<span class="n">text</span> <span class="o">=</span> <span class="nb">input</span><span class="p">()</span>
|
||||
|
||||
<span class="c1"># Check if we should quit the example</span>
|
||||
<span class="k">if</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"quit"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"q"</span> <span class="ow">or</span> <span class="n">text</span> <span class="o">==</span> <span class="s2">"exit"</span><span class="p">:</span>
|
||||
<span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span>
|
||||
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">server_link</span><span class="o">.</span><span class="n">request</span><span class="p">(</span>
|
||||
<span class="s2">"/random/text"</span><span class="p">,</span>
|
||||
<span class="n">data</span> <span class="o">=</span> <span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">response_callback</span> <span class="o">=</span> <span class="n">got_response</span><span class="p">,</span>
|
||||
<span class="n">failed_callback</span> <span class="o">=</span> <span class="n">request_failed</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Error while sending request over the link: "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">e</span><span class="p">))</span>
|
||||
<span class="n">should_quit</span> <span class="o">=</span> <span class="kc">True</span>
|
||||
<span class="n">server_link</span><span class="o">.</span><span class="n">teardown</span><span class="p">()</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">got_response</span><span class="p">(</span><span class="n">request_receipt</span><span class="p">):</span>
|
||||
<span class="n">request_id</span> <span class="o">=</span> <span class="n">request_receipt</span><span class="o">.</span><span class="n">request_id</span>
|
||||
<span class="n">response</span> <span class="o">=</span> <span class="n">request_receipt</span><span class="o">.</span><span class="n">response</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Got response for request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_id</span><span class="p">)</span><span class="o">+</span><span class="s2">": "</span><span class="o">+</span><span class="nb">str</span><span class="p">(</span><span class="n">response</span><span class="p">))</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">request_received</span><span class="p">(</span><span class="n">request_receipt</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_receipt</span><span class="o">.</span><span class="n">request_id</span><span class="p">)</span><span class="o">+</span><span class="s2">" was received by the remote peer."</span><span class="p">)</span>
|
||||
|
||||
<span class="k">def</span> <span class="nf">request_failed</span><span class="p">(</span><span class="n">request_receipt</span><span class="p">):</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The request "</span><span class="o">+</span><span class="n">RNS</span><span class="o">.</span><span class="n">prettyhexrep</span><span class="p">(</span><span class="n">request_receipt</span><span class="o">.</span><span class="n">request_id</span><span class="p">)</span><span class="o">+</span><span class="s2">" failed."</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c1"># This function is called when a link</span>
|
||||
<span class="c1"># has been established with the server</span>
|
||||
<span class="k">def</span> <span class="nf">link_established</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="c1"># We store a reference to the link</span>
|
||||
<span class="c1"># instance for later use</span>
|
||||
<span class="k">global</span> <span class="n">server_link</span>
|
||||
<span class="n">server_link</span> <span class="o">=</span> <span class="n">link</span>
|
||||
|
||||
<span class="c1"># Inform the user that the server is</span>
|
||||
<span class="c1"># connected</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link established with server, hit enter to perform a request, or type in </span><span class="se">\"</span><span class="s2">quit</span><span class="se">\"</span><span class="s2"> to quit"</span><span class="p">)</span>
|
||||
|
||||
<span class="c1"># When a link is closed, we'll inform the</span>
|
||||
<span class="c1"># user, and exit the program</span>
|
||||
<span class="k">def</span> <span class="nf">link_closed</span><span class="p">(</span><span class="n">link</span><span class="p">):</span>
|
||||
<span class="k">if</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">TIMEOUT</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link timed out, exiting now"</span><span class="p">)</span>
|
||||
<span class="k">elif</span> <span class="n">link</span><span class="o">.</span><span class="n">teardown_reason</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Link</span><span class="o">.</span><span class="n">DESTINATION_CLOSED</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"The link was closed by the server, exiting now"</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">log</span><span class="p">(</span><span class="s2">"Link closed, exiting now"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">RNS</span><span class="o">.</span><span class="n">Reticulum</span><span class="o">.</span><span class="n">exit_handler</span><span class="p">()</span>
|
||||
<span class="n">time</span><span class="o">.</span><span class="n">sleep</span><span class="p">(</span><span class="mf">1.5</span><span class="p">)</span>
|
||||
<span class="n">os</span><span class="o">.</span><span class="n">_exit</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span>
|
||||
|
||||
|
||||
<span class="c1">##########################################################</span>
|
||||
<span class="c1">#### Program Startup #####################################</span>
|
||||
<span class="c1">##########################################################</span>
|
||||
|
||||
<span class="c1"># This part of the program runs at startup,</span>
|
||||
<span class="c1"># and parses input of from the user, and then</span>
|
||||
<span class="c1"># starts up the desired program mode.</span>
|
||||
<span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">parser</span> <span class="o">=</span> <span class="n">argparse</span><span class="o">.</span><span class="n">ArgumentParser</span><span class="p">(</span><span class="n">description</span><span class="o">=</span><span class="s2">"Simple request/response example"</span><span class="p">)</span>
|
||||
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span>
|
||||
<span class="s2">"-s"</span><span class="p">,</span>
|
||||
<span class="s2">"--server"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store_true"</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"wait for incoming requests from clients"</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span>
|
||||
<span class="s2">"--config"</span><span class="p">,</span>
|
||||
<span class="n">action</span><span class="o">=</span><span class="s2">"store"</span><span class="p">,</span>
|
||||
<span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"path to alternative Reticulum config directory"</span><span class="p">,</span>
|
||||
<span class="nb">type</span><span class="o">=</span><span class="nb">str</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">add_argument</span><span class="p">(</span>
|
||||
<span class="s2">"destination"</span><span class="p">,</span>
|
||||
<span class="n">nargs</span><span class="o">=</span><span class="s2">"?"</span><span class="p">,</span>
|
||||
<span class="n">default</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span>
|
||||
<span class="n">help</span><span class="o">=</span><span class="s2">"hexadecimal hash of the server destination"</span><span class="p">,</span>
|
||||
<span class="nb">type</span><span class="o">=</span><span class="nb">str</span>
|
||||
<span class="p">)</span>
|
||||
|
||||
<span class="n">args</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span><span class="p">:</span>
|
||||
<span class="n">configarg</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">config</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">configarg</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">server</span><span class="p">:</span>
|
||||
<span class="n">server</span><span class="p">(</span><span class="n">configarg</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="k">if</span> <span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span> <span class="o">==</span> <span class="kc">None</span><span class="p">):</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">parser</span><span class="o">.</span><span class="n">print_help</span><span class="p">()</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="k">else</span><span class="p">:</span>
|
||||
<span class="n">client</span><span class="p">(</span><span class="n">args</span><span class="o">.</span><span class="n">destination</span><span class="p">,</span> <span class="n">configarg</span><span class="p">)</span>
|
||||
|
||||
<span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
|
||||
<span class="nb">print</span><span class="p">(</span><span class="s2">""</span><span class="p">)</span>
|
||||
<span class="n">exit</span><span class="p">()</span>
|
||||
</pre></div>
|
||||
</div>
|
||||
<p>This example can also be found at <a class="reference external" href="https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py">https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py</a>.</p>
|
||||
</div>
|
||||
<div class="section" id="filetransfer">
|
||||
<span id="example-filetransfer"></span><h2>Filetransfer<a class="headerlink" href="#filetransfer" title="Permalink to this headline">¶</a></h2>
|
||||
<p>The <em>Filetransfer</em> example implements a basic file-server program that
|
||||
@@ -1186,7 +1794,12 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
|
||||
<span class="k">def</span> <span class="nf">client_request</span><span class="p">(</span><span class="n">message</span><span class="p">,</span> <span class="n">packet</span><span class="p">):</span>
|
||||
<span class="k">global</span> <span class="n">serve_path</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s2">"utf-8"</span><span class="p">)</span>
|
||||
<span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
|
||||
<span class="n">filename</span> <span class="o">=</span> <span class="kc">None</span>
|
||||
|
||||
<span class="k">if</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">list_files</span><span class="p">():</span>
|
||||
<span class="k">try</span><span class="p">:</span>
|
||||
<span class="c1"># If we have the requested file, we'll</span>
|
||||
@@ -1548,7 +2161,6 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
|
||||
<span class="n">saved_filename</span> <span class="o">=</span> <span class="n">current_filename</span>
|
||||
|
||||
|
||||
<span class="k">if</span> <span class="n">resource</span><span class="o">.</span><span class="n">status</span> <span class="o">==</span> <span class="n">RNS</span><span class="o">.</span><span class="n">Resource</span><span class="o">.</span><span class="n">COMPLETE</span><span class="p">:</span>
|
||||
<span class="n">counter</span> <span class="o">=</span> <span class="mi">0</span>
|
||||
<span class="k">while</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">isfile</span><span class="p">(</span><span class="n">saved_filename</span><span class="p">):</span>
|
||||
@@ -1667,6 +2279,8 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
<li><a class="reference internal" href="#broadcast">Broadcast</a></li>
|
||||
<li><a class="reference internal" href="#echo">Echo</a></li>
|
||||
<li><a class="reference internal" href="#link">Link</a></li>
|
||||
<li><a class="reference internal" href="#example-identify">Identification</a></li>
|
||||
<li><a class="reference internal" href="#requests-responses">Requests & Responses</a></li>
|
||||
<li><a class="reference internal" href="#filetransfer">Filetransfer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -1705,7 +2319,7 @@ interface to efficiently pass files of any size over a Reticulum <a class="refer
|
||||
<li class="right" >
|
||||
<a href="reference.html" title="API Reference"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Examples</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Index — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>Index — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="#" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Index</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -103,6 +103,8 @@
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Transport.deregister_announce_handler">deregister_announce_handler() (RNS.Transport static method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Destination.deregister_request_handler">deregister_request_handler() (RNS.Destination method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Destination">Destination (class in RNS)</a>
|
||||
</li>
|
||||
@@ -157,6 +159,8 @@
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Identity.get_random_hash">get_random_hash() (RNS.Identity static method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Link.get_remote_identity">get_remote_identity() (RNS.Link method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.PacketReceipt.get_rtt">get_rtt() (RNS.PacketReceipt method)</a>
|
||||
</li>
|
||||
@@ -182,10 +186,12 @@
|
||||
<h2 id="I">I</h2>
|
||||
<table style="width: 100%" class="indextable genindextable"><tr>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Identity">Identity (class in RNS)</a>
|
||||
<li><a href="reference.html#RNS.Link.identify">identify() (RNS.Link method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Identity">Identity (class in RNS)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Link.inactive_for">inactive_for() (RNS.Link method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
@@ -257,9 +263,13 @@
|
||||
<li><a href="reference.html#RNS.Identity.recall_app_data">recall_app_data() (RNS.Identity static method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Transport.register_announce_handler">register_announce_handler() (RNS.Transport static method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Destination.register_request_handler">register_request_handler() (RNS.Destination method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Link.request">request() (RNS.Link method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Transport.request_path">request_path() (RNS.Transport static method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Packet.resend">resend() (RNS.Packet method)</a>
|
||||
@@ -292,10 +302,12 @@
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Destination.set_proof_strategy">set_proof_strategy() (RNS.Destination method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Link.set_resource_callback">set_resource_callback() (RNS.Link method)</a>
|
||||
<li><a href="reference.html#RNS.Link.set_remote_identified_callback">set_remote_identified_callback() (RNS.Link method)</a>
|
||||
</li>
|
||||
</ul></td>
|
||||
<td style="width: 33%; vertical-align: top;"><ul>
|
||||
<li><a href="reference.html#RNS.Link.set_resource_callback">set_resource_callback() (RNS.Link method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Link.set_resource_concluded_callback">set_resource_concluded_callback() (RNS.Link method)</a>
|
||||
</li>
|
||||
<li><a href="reference.html#RNS.Link.set_resource_started_callback">set_resource_started_callback() (RNS.Link method)</a>
|
||||
@@ -375,7 +387,7 @@
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="#" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Index</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Getting Started Fast — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>Getting Started Fast — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
|
||||
<link rel="index" title="Index" href="genindex.html" />
|
||||
<link rel="search" title="Search" href="search.html" />
|
||||
<link rel="next" title="Examples" href="examples.html" />
|
||||
<link rel="next" title="Understanding Reticulum" href="understanding.html" />
|
||||
<link rel="prev" title="What is Reticulum?" href="whatis.html" />
|
||||
</head><body>
|
||||
<div class="related" role="navigation" aria-label="related navigation">
|
||||
@@ -26,12 +26,12 @@
|
||||
<a href="genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="right" >
|
||||
<a href="examples.html" title="Examples"
|
||||
<a href="understanding.html" title="Understanding Reticulum"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="whatis.html" title="What is Reticulum?"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -131,8 +131,8 @@ don’t use pip, but try this recipe:</p>
|
||||
<p class="topless"><a href="whatis.html"
|
||||
title="previous chapter">What is Reticulum?</a></p>
|
||||
<h4>Next topic</h4>
|
||||
<p class="topless"><a href="examples.html"
|
||||
title="next chapter">Examples</a></p>
|
||||
<p class="topless"><a href="understanding.html"
|
||||
title="next chapter">Understanding Reticulum</a></p>
|
||||
<div role="note" aria-label="source link">
|
||||
<h3>This Page</h3>
|
||||
<ul class="this-page-menu">
|
||||
@@ -161,12 +161,12 @@ don’t use pip, but try this recipe:</p>
|
||||
<a href="genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="right" >
|
||||
<a href="examples.html" title="Examples"
|
||||
<a href="understanding.html" title="Understanding Reticulum"
|
||||
>next</a> |</li>
|
||||
<li class="right" >
|
||||
<a href="whatis.html" title="What is Reticulum?"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Getting Started Fast</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Reticulum Network Stack Manual — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>Reticulum Network Stack Manual — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
<li class="right" >
|
||||
<a href="whatis.html" title="What is Reticulum?"
|
||||
accesskey="N">next</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -103,6 +103,8 @@ the development of Reticulum itself.</p>
|
||||
<li class="toctree-l2"><a class="reference internal" href="examples.html#broadcast">Broadcast</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="examples.html#echo">Echo</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="examples.html#link">Link</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="examples.html#example-identify">Identification</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="examples.html#requests-responses">Requests & Responses</a></li>
|
||||
<li class="toctree-l2"><a class="reference internal" href="examples.html#filetransfer">Filetransfer</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -165,7 +167,7 @@ the development of Reticulum itself.</p>
|
||||
<li class="right" >
|
||||
<a href="whatis.html" title="What is Reticulum?"
|
||||
>next</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="#">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Reticulum Network Stack Manual</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
Binary file not shown.
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>API Reference — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>API Reference — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<li class="right" >
|
||||
<a href="understanding.html" title="Understanding Reticulum"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">API Reference</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -508,6 +508,39 @@ proofs should be returned for received packets.</p>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Destination.register_request_handler">
|
||||
<span class="sig-name descname"><span class="pre">register_request_handler</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">path</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">response_generator</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">allow</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">0</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">allowed_list</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.register_request_handler" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Registers a request handler.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><ul class="simple">
|
||||
<li><p><strong>path</strong> – The path for the request handler to be registered.</p></li>
|
||||
<li><p><strong>response_generator</strong> – A function or method with the signature <em>response_generator(path, data, request_id, remote_identity, requested_at)</em> to be called. Whatever this funcion returns will be sent as a response to the requester. If the function returns <code class="docutils literal notranslate"><span class="pre">None</span></code>, no response will be sent.</p></li>
|
||||
<li><p><strong>allow</strong> – One of <code class="docutils literal notranslate"><span class="pre">RNS.Destination.ALLOW_NONE</span></code>, <code class="docutils literal notranslate"><span class="pre">RNS.Destination.ALLOW_ALL</span></code> or <code class="docutils literal notranslate"><span class="pre">RNS.Destination.ALLOW_LIST</span></code>. If <code class="docutils literal notranslate"><span class="pre">RNS.Destination.ALLOW_LIST</span></code> is set, the request handler will only respond to requests for identified peers in the supplied list.</p></li>
|
||||
<li><p><strong>allowed_list</strong> – A list of <em>bytes-like</em> <a class="reference internal" href="#api-identity"><span class="std std-ref">RNS.Identity</span></a> hashes.</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
<dt class="field-even">Raises</dt>
|
||||
<dd class="field-even"><p><code class="docutils literal notranslate"><span class="pre">ValueError</span></code> if any of the supplied arguments are invalid.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Destination.deregister_request_handler">
|
||||
<span class="sig-name descname"><span class="pre">deregister_request_handler</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">path</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.deregister_request_handler" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Deregisters a request handler.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><p><strong>path</strong> – The path for the request handler to be deregistered.</p>
|
||||
</dd>
|
||||
<dt class="field-even">Returns</dt>
|
||||
<dd class="field-even"><p>True if the handler was deregistered, otherwise False.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Destination.create_keys">
|
||||
<span class="sig-name descname"><span class="pre">create_keys</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Destination.create_keys" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -771,6 +804,35 @@ from a the <em>send()</em> method of a <a class="reference internal" href="#api-
|
||||
<dd><p>Interval for sending keep-alive packets on established links in seconds.</p>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Link.identify">
|
||||
<span class="sig-name descname"><span class="pre">identify</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">identity</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.identify" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Identifies the initiator of the link to the remote peer. This can only happen
|
||||
once the link has been established, and is carried out over the encrypted link.
|
||||
The identity is only revealed to the remote peer, and initiator anonymity is
|
||||
thus preserved. This method can be used for authentication.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><p><strong>identity</strong> – An RNS.Identity instance to identify as.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Link.request">
|
||||
<span class="sig-name descname"><span class="pre">request</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">path</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">data</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">response_callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">failed_callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.request" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Sends a request to the remote peer.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><ul class="simple">
|
||||
<li><p><strong>path</strong> – The request path.</p></li>
|
||||
<li><p><strong>response_callback</strong> – A function or method with the signature <em>response_callback(request_receipt)</em> to be called when a response is received. See the <a class="reference internal" href="examples.html#example-request"><span class="std std-ref">Request Example</span></a> for more info.</p></li>
|
||||
<li><p><strong>failed_callback</strong> – A function or method with the signature <em>failed_callback(request_receipt)</em> to be called when a request fails. See the <a class="reference internal" href="examples.html#example-request"><span class="std std-ref">Request Example</span></a> for more info.</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Link.no_inbound_for">
|
||||
<span class="sig-name descname"><span class="pre">no_inbound_for</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.no_inbound_for" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -801,6 +863,16 @@ from a the <em>send()</em> method of a <a class="reference internal" href="#api-
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Link.get_remote_identity">
|
||||
<span class="sig-name descname"><span class="pre">get_remote_identity</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.get_remote_identity" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><dl class="field-list simple">
|
||||
<dt class="field-odd">Returns</dt>
|
||||
<dd class="field-odd"><p>The identity of the remote peer, if it is known</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Link.teardown">
|
||||
<span class="sig-name descname"><span class="pre">teardown</span></span><span class="sig-paren">(</span><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.teardown" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -858,6 +930,18 @@ transferring over this link.</p>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Link.set_remote_identified_callback">
|
||||
<span class="sig-name descname"><span class="pre">set_remote_identified_callback</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">callback</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.set_remote_identified_callback" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>Registers a function to be called when an initiating peer has
|
||||
identified over this link.</p>
|
||||
<dl class="field-list simple">
|
||||
<dt class="field-odd">Parameters</dt>
|
||||
<dd class="field-odd"><p><strong>callback</strong> – A function or method with the signature <em>callback(identity)</em> to be called.</p>
|
||||
</dd>
|
||||
</dl>
|
||||
</dd></dl>
|
||||
|
||||
<dl class="py method">
|
||||
<dt class="sig sig-object py" id="RNS.Link.set_resource_strategy">
|
||||
<span class="sig-name descname"><span class="pre">set_resource_strategy</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">resource_strategy</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Link.set_resource_strategy" title="Permalink to this definition">¶</a></dt>
|
||||
@@ -891,7 +975,7 @@ client application and throw an error message to the user.</p>
|
||||
<span id="api-resource"></span><h3>Resource<a class="headerlink" href="#resource" title="Permalink to this headline">¶</a></h3>
|
||||
<dl class="py class">
|
||||
<dt class="sig sig-object py" id="RNS.Resource">
|
||||
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Resource</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">link</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">advertise</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">auto_compress</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">progress_callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">segment_index</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">original_hash</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Resource" title="Permalink to this definition">¶</a></dt>
|
||||
<em class="property"><span class="pre">class</span> </em><span class="sig-prename descclassname"><span class="pre">RNS.</span></span><span class="sig-name descname"><span class="pre">Resource</span></span><span class="sig-paren">(</span><em class="sig-param"><span class="n"><span class="pre">data</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">link</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">advertise</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">auto_compress</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">True</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">progress_callback</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">segment_index</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">1</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">original_hash</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">request_id</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">None</span></span></em>, <em class="sig-param"><span class="n"><span class="pre">is_response</span></span><span class="o"><span class="pre">=</span></span><span class="default_value"><span class="pre">False</span></span></em><span class="sig-paren">)</span><a class="headerlink" href="#RNS.Resource" title="Permalink to this definition">¶</a></dt>
|
||||
<dd><p>The Resource class allows transferring arbitrary amounts
|
||||
of data over a link. It will automatically handle sequencing,
|
||||
compression, coordination and checksumming.</p>
|
||||
@@ -906,6 +990,8 @@ compression, coordination and checksumming.</p>
|
||||
<li><p><strong>progress_callback</strong> – A <em>callable</em> with the signature <em>callback(resource)</em>. Will be called whenever the resource transfer progress is updated.</p></li>
|
||||
<li><p><strong>segment_index</strong> – Internal use, ignore.</p></li>
|
||||
<li><p><strong>original_hash</strong> – Internal use, ignore.</p></li>
|
||||
<li><p><strong>is_request</strong> – Internal use, ignore.</p></li>
|
||||
<li><p><strong>is_response</strong> – Internal use, ignore.</p></li>
|
||||
</ul>
|
||||
</dd>
|
||||
</dl>
|
||||
@@ -1058,7 +1144,7 @@ will announce it.</p>
|
||||
<li class="right" >
|
||||
<a href="understanding.html" title="Understanding Reticulum"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">API Reference</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Search — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>Search — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="genindex.html" title="General Index"
|
||||
accesskey="I">index</a></li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Search</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -85,7 +85,7 @@
|
||||
<li class="right" style="margin-right: 10px">
|
||||
<a href="genindex.html" title="General Index"
|
||||
>index</a></li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Search</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Understanding Reticulum — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>Understanding Reticulum — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<li class="right" >
|
||||
<a href="gettingstartedfast.html" title="Getting Started Fast"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -853,7 +853,7 @@ proof 11
|
||||
<li class="right" >
|
||||
<a href="gettingstartedfast.html" title="Getting Started Fast"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">Understanding Reticulum</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>What is Reticulum? — Reticulum Network Stack 0.2.1 beta documentation</title>
|
||||
<title>What is Reticulum? — Reticulum Network Stack 0.2.2 beta documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="_static/pygments.css" />
|
||||
<link rel="stylesheet" type="text/css" href="_static/classic.css" />
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
<li class="right" >
|
||||
<a href="index.html" title="Reticulum Network Stack Manual"
|
||||
accesskey="P">previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
@@ -43,7 +43,8 @@
|
||||
|
||||
<div class="section" id="what-is-reticulum">
|
||||
<h1>What is Reticulum?<a class="headerlink" href="#what-is-reticulum" title="Permalink to this headline">¶</a></h1>
|
||||
<p>Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth. Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.</p>
|
||||
<p>Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth.</p>
|
||||
<p>Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.</p>
|
||||
<p>Reticulum is a complete networking stack, and does not use IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.</p>
|
||||
<p>No kernel modules or drivers are required. Reticulum runs completely in userland, and can run on practically any system that runs Python 3.</p>
|
||||
<div class="section" id="current-status">
|
||||
@@ -71,7 +72,7 @@
|
||||
</li>
|
||||
<li><p>Unforgeable packet delivery confirmations</p></li>
|
||||
<li><p>A variety of supported interface types</p></li>
|
||||
<li><p>An intuitive and easy-to-use API</p></li>
|
||||
<li><p>An intuitive and developer-friendly API</p></li>
|
||||
<li><p>Reliable and efficient transfer of arbritrary amounts of data</p>
|
||||
<ul>
|
||||
<li><p>Reticulum can handle a few bytes of data or files of many gigabytes</p></li>
|
||||
@@ -181,7 +182,7 @@ network, and vice versa.</p>
|
||||
<li class="right" >
|
||||
<a href="index.html" title="Reticulum Network Stack Manual"
|
||||
>previous</a> |</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.1 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-0"><a href="index.html">Reticulum Network Stack 0.2.2 beta documentation</a> »</li>
|
||||
<li class="nav-item nav-item-this"><a href="">What is Reticulum?</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
+1
-1
@@ -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 ---------------------------------------------------
|
||||
|
||||
@@ -68,6 +68,29 @@ destination, and passing traffic back and forth over the link.
|
||||
|
||||
This example can also be found at `<https://github.com/markqvist/Reticulum/blob/master/Examples/Link.py>`_.
|
||||
|
||||
.. _example-identify:
|
||||
|
||||
Identification
|
||||
==============
|
||||
|
||||
The *Identify* example explores identifying an intiator of a link, once
|
||||
the link has been established.
|
||||
|
||||
.. literalinclude:: ../../Examples/Identify.py
|
||||
|
||||
This example can also be found at `<https://github.com/markqvist/Reticulum/blob/master/Examples/Identify.py>`_.
|
||||
|
||||
.. _example-request:
|
||||
|
||||
Requests & Responses
|
||||
====================
|
||||
|
||||
The *Request* example explores sendig requests and receiving responses.
|
||||
|
||||
.. literalinclude:: ../../Examples/Request.py
|
||||
|
||||
This example can also be found at `<https://github.com/markqvist/Reticulum/blob/master/Examples/Request.py>`_.
|
||||
|
||||
.. _example-filetransfer:
|
||||
|
||||
Filetransfer
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
What is Reticulum?
|
||||
******************
|
||||
|
||||
Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth. Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
|
||||
Reticulum is a cryptography-based networking stack for wide-area networks built on readily available hardware, and can operate even with very high latency and extremely low bandwidth.
|
||||
|
||||
Reticulum allows you to build very wide-area networks with off-the-shelf tools, and offers end-to-end encryption, autoconfiguring cryptographically backed multi-hop transport, efficient addressing, unforgeable packet acknowledgements and more.
|
||||
|
||||
Reticulum is a complete networking stack, and does not use IP or higher layers, although it is easy to utilise IP (with TCP or UDP) as the underlying carrier for Reticulum. It is therefore trivial to tunnel Reticulum over the Internet or private IP networks. Reticulum is built directly on cryptographic principles, allowing resilience and stable functionality in open and trustless networks.
|
||||
|
||||
@@ -43,7 +45,7 @@ What does Reticulum Offer?
|
||||
|
||||
* A variety of supported interface types
|
||||
|
||||
* An intuitive and easy-to-use API
|
||||
* An intuitive and developer-friendly API
|
||||
|
||||
* Reliable and efficient transfer of arbritrary amounts of data
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import setuptools
|
||||
|
||||
exec(open("RNS/_version.py", "r").read())
|
||||
|
||||
with open("README.md", "r") as fh:
|
||||
long_description = fh.read()
|
||||
|
||||
setuptools.setup(
|
||||
name="rns",
|
||||
version="0.2.1",
|
||||
version=__version__,
|
||||
author="Mark Qvist",
|
||||
author_email="mark@unsigned.io",
|
||||
description="Self-configuring, encrypted and resilient mesh networking stack for LoRa, packet radio, WiFi and everything in between",
|
||||
@@ -18,6 +20,6 @@ setuptools.setup(
|
||||
"License :: OSI Approved :: MIT License",
|
||||
"Operating System :: OS Independent",
|
||||
],
|
||||
install_requires=['cryptography>=3.4.7', 'pyserial'],
|
||||
install_requires=['cryptography>=3.4.7', 'pyserial', 'netifaces>=0.10.4'],
|
||||
python_requires='>=3.5',
|
||||
)
|
||||
Reference in New Issue
Block a user