Compare commits

..

25 Commits

Author SHA1 Message Date
jacobeva
d35fe30599
Merge 03f133be43 into a762af035a 2024-11-21 17:17:20 +00:00
Mark Qvist
a762af035a Prepare interface modularity 2024-11-21 14:41:22 +01:00
Mark Qvist
760ab981d0 Prepare interface modularity for Android-specific interfaces 2024-11-21 13:51:34 +01:00
Mark Qvist
7b43ff0cef Cleanup 2024-11-21 13:13:41 +01:00
Mark Qvist
996161e2f4 Internal interface config handling for RNodeMultiInterface 2024-11-21 13:11:17 +01:00
Mark Qvist
bf633bba5d Internal interface config handling for RNodeInterface 2024-11-21 13:03:03 +01:00
Mark Qvist
8337a5945d Internal interface config handling for AX25KISSInterface 2024-11-21 12:30:07 +01:00
Mark Qvist
a736b3adfc Internal interface config handling for KISSInterface 2024-11-21 12:25:59 +01:00
Mark Qvist
25127cd3c9 Internal interface config handling for PipeInterface 2024-11-21 12:22:09 +01:00
Mark Qvist
ebf084cff0 Internal interface config handling for SerialInterface 2024-11-21 12:16:44 +01:00
Mark Qvist
cd8fe95d91 Internal interface config handling for I2PInterface 2024-11-21 12:10:21 +01:00
Mark Qvist
e2efc61208 Added Yggdrasil example to interface documentation 2024-11-20 20:50:08 +01:00
Mark Qvist
5de63d5bf2 Internal interface config handling for TCPClientInterface 2024-11-20 20:39:44 +01:00
Mark Qvist
c9d744f88a Internal interface config handling for TCPServerInterface 2024-11-20 20:27:01 +01:00
Mark Qvist
18e0dbddfa Internal interface config handling for UDPInterface 2024-11-20 20:20:40 +01:00
Mark Qvist
52c816cb27 Cleanup 2024-11-20 20:18:17 +01:00
Mark Qvist
582d2b91f5 Internal interface config handling for AutoInterface 2024-11-20 20:14:02 +01:00
Mark Qvist
28a0dbb0e0 Updated version 2024-11-20 19:56:02 +01:00
Mark Qvist
2895806541 Added IPv6 info to TCP interface documentation 2024-11-20 19:55:18 +01:00
Mark Qvist
5b8de73143 Correctly display IPv6 addresses in interface names 2024-11-20 19:24:06 +01:00
Mark Qvist
212af2f43b Automatically select IPv6 address for IPv6-only interfaces 2024-11-20 19:16:15 +01:00
Mark Qvist
1282061701 Add interface scope for link-local IPv6 addresses 2024-11-20 18:02:50 +01:00
Mark Qvist
49dba483a9 Use address structure according to target address family 2024-11-20 17:10:08 +01:00
Mark Qvist
ebec63487f Added prefer_ipv6 option to TCPServerInterface 2024-11-20 16:53:14 +01:00
Mark Qvist
9373819234 Add ability to bind to AF_INET6 sockets based on both device name and IP addresses 2024-11-20 16:44:39 +01:00
36 changed files with 660 additions and 648 deletions

View File

@ -59,6 +59,7 @@ class AX25():
class AX25KISSInterface(Interface): class AX25KISSInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
BITRATE_GUESS = 1200 BITRATE_GUESS = 1200
DEFAULT_IFAC_SIZE = 8
owner = None owner = None
port = None port = None
@ -68,7 +69,7 @@ class AX25KISSInterface(Interface):
stopbits = None stopbits = None
serial = None serial = None
def __init__(self, owner, name, callsign, ssid, port, speed, databits, parity, stopbits, preamble, txtail, persistence, slottime, flow_control): def __init__(self, owner, configuration):
import importlib import importlib
if importlib.util.find_spec('serial') != None: if importlib.util.find_spec('serial') != None:
import serial import serial
@ -79,6 +80,25 @@ class AX25KISSInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
preamble = int(c["preamble"]) if "preamble" in c else None
txtail = int(c["txtail"]) if "txtail" in c else None
persistence = int(c["persistence"]) if "persistence" in c else None
slottime = int(c["slottime"]) if "slottime" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
callsign = c["callsign"] if "callsign" in c else ""
ssid = int(c["ssid"]) if "ssid" in c else -1
if port == None:
raise ValueError("No port specified for serial interface")
self.HW_MTU = 564 self.HW_MTU = 564
self.pyserial = serial self.pyserial = serial

View File

@ -52,6 +52,7 @@ class KISS():
class KISSInterface(Interface): class KISSInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
BITRATE_GUESS = 1200 BITRATE_GUESS = 1200
DEFAULT_IFAC_SIZE = 8
owner = None owner = None
port = None port = None
@ -61,7 +62,7 @@ class KISSInterface(Interface):
stopbits = None stopbits = None
serial = None serial = None
def __init__(self, owner, name, port, speed, databits, parity, stopbits, preamble, txtail, persistence, slottime, flow_control, beacon_interval, beacon_data): def __init__(self, owner, configuration):
import importlib import importlib
if RNS.vendor.platformutils.is_android(): if RNS.vendor.platformutils.is_android():
self.on_android = True self.on_android = True
@ -84,6 +85,21 @@ class KISSInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
preamble = int(c["preamble"]) if "preamble" in c else None
txtail = int(c["txtail"]) if "txtail" in c else None
persistence = int(c["persistence"]) if "persistence" in c else None
slottime = int(c["slottime"]) if "slottime" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
beacon_interval = int(c["beacon_interval"]) if "beacon_interval" in c else None
beacon_data = c["beacon_data"] if "beacon_data" in c else None
self.HW_MTU = 564 self.HW_MTU = 564
if beacon_data == None: if beacon_data == None:

View File

@ -238,6 +238,7 @@ class AndroidBluetoothManager():
class RNodeInterface(Interface): class RNodeInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
DEFAULT_IFAC_SIZE = 8
FREQ_MIN = 137000000 FREQ_MIN = 137000000
FREQ_MAX = 1020000000 FREQ_MAX = 1020000000
@ -341,12 +342,27 @@ class RNodeInterface(Interface):
serial.close() serial.close()
def __init__( def __init__(self, owner, configuration):
self, owner, name, port, frequency = None, bandwidth = None, txpower = None, c = Interface.get_config_obj(configuration)
sf = None, cr = None, flow_control = False, id_interval = None, name = c["name"]
allow_bluetooth = False, target_device_name = None, allow_bluetooth = c["allow_bluetooth"]
target_device_address = None, id_callsign = None, st_alock = None, lt_alock = None, target_device_name = c["target_device_name"]
ble_addr = None, ble_name = None, force_ble=False): target_device_address = c["target_device_address"]
ble_name = c["ble_name"]
ble_addr = c["ble_addr"]
force_ble = c["force_ble"]
frequency = int(c["frequency"]) if "frequency" in c else None
bandwidth = int(c["bandwidth"]) if "bandwidth" in c else None
txpower = int(c["txpower"]) if "txpower" in c else None
sf = int(c["spreadingfactor"]) if "spreadingfactor" in c else None
cr = int(c["codingrate"]) if "codingrate" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
id_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" in c else None
st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c else None
lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c else None
port = c["port"] if "port" in c else None
import importlib import importlib
if RNS.vendor.platformutils.is_android(): if RNS.vendor.platformutils.is_android():
self.on_android = True self.on_android = True

View File

@ -42,6 +42,7 @@ class HDLC():
class SerialInterface(Interface): class SerialInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
DEFAULT_IFAC_SIZE = 8
owner = None owner = None
port = None port = None
@ -51,7 +52,7 @@ class SerialInterface(Interface):
stopbits = None stopbits = None
serial = None serial = None
def __init__(self, owner, name, port, speed, databits, parity, stopbits): def __init__(self, owner, configuration):
import importlib import importlib
if RNS.vendor.platformutils.is_android(): if RNS.vendor.platformutils.is_android():
self.on_android = True self.on_android = True
@ -74,6 +75,17 @@ class SerialInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
if port == None:
raise ValueError("No port specified for serial interface")
self.HW_MTU = 564 self.HW_MTU = 564
self.pyserial = serial self.pyserial = serial

View File

@ -36,6 +36,7 @@ class AutoInterface(Interface):
DEFAULT_DISCOVERY_PORT = 29716 DEFAULT_DISCOVERY_PORT = 29716
DEFAULT_DATA_PORT = 42671 DEFAULT_DATA_PORT = 42671
DEFAULT_GROUP_ID = "reticulum".encode("utf-8") DEFAULT_GROUP_ID = "reticulum".encode("utf-8")
DEFAULT_IFAC_SIZE = 16
SCOPE_LINK = "2" SCOPE_LINK = "2"
SCOPE_ADMIN = "4" SCOPE_ADMIN = "4"
@ -86,7 +87,18 @@ class AutoInterface(Interface):
return socket.if_nametoindex(ifname) return socket.if_nametoindex(ifname)
def __init__(self, owner, name, group_id=None, discovery_scope=None, discovery_port=None, multicast_address_type=None, data_port=None, allowed_interfaces=None, ignored_interfaces=None, configured_bitrate=None): def __init__(self, owner, configuration):
c = Interface.get_config_obj(configuration)
name = c["name"]
group_id = c["group_id"] if "group_id" in c else None
discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None
discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None
multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None
data_port = int(c["data_port"]) if "data_port" in c else None
allowed_interfaces = c.as_list("devices") if "devices" in c else None
ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None
configured_bitrate = c["configured_bitrate"] if "configured_bitrate" in c else None
from RNS.vendor.ifaddr import niwrapper from RNS.vendor.ifaddr import niwrapper
super().__init__() super().__init__()
self.netinfo = niwrapper self.netinfo = niwrapper

View File

@ -829,10 +829,20 @@ class I2PInterfacePeer(Interface):
class I2PInterface(Interface): class I2PInterface(Interface):
BITRATE_GUESS = 256*1000 BITRATE_GUESS = 256*1000
DEFAULT_IFAC_SIZE = 16
def __init__(self, owner, name, rns_storagepath, peers, connectable = False, ifac_size = 16, ifac_netname = None, ifac_netkey = None): def __init__(self, owner, configuration):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
rns_storagepath = c["storagepath"]
peers = c.as_list("peers") if "peers" in c else None
connectable = c.as_bool("connectable") if "connectable" in c else False
ifac_size = c["ifac_size"] if "ifac_size" in c else None
ifac_netname = c["ifac_netname"] if "ifac_netname" in c else None
ifac_netkey = c["ifac_netkey"] if "ifac_netkey" in c else None
self.HW_MTU = 1064 self.HW_MTU = 1064
self.online = False self.online = False

View File

@ -24,6 +24,7 @@ import RNS
import time import time
import threading import threading
from collections import deque from collections import deque
from RNS.vendor.configobj import ConfigObj
class Interface: class Interface:
IN = False IN = False
@ -239,3 +240,14 @@ class Interface:
def detach(self): def detach(self):
pass pass
@staticmethod
def get_config_obj(config_in):
if type(config_in) == ConfigObj:
return config_in
else:
try:
return ConfigObj(config_in)
except Exception as e:
RNS.log(f"Could not parse supplied configuration data. The contained exception was: {e}", RNS.LOG_ERROR)
raise SystemError("Invalid configuration data supplied")

View File

@ -52,6 +52,7 @@ class KISS():
class KISSInterface(Interface): class KISSInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
BITRATE_GUESS = 1200 BITRATE_GUESS = 1200
DEFAULT_IFAC_SIZE = 8
owner = None owner = None
port = None port = None
@ -61,7 +62,7 @@ class KISSInterface(Interface):
stopbits = None stopbits = None
serial = None serial = None
def __init__(self, owner, name, port, speed, databits, parity, stopbits, preamble, txtail, persistence, slottime, flow_control, beacon_interval, beacon_data): def __init__(self, owner, configuration):
import importlib import importlib
if importlib.util.find_spec('serial') != None: if importlib.util.find_spec('serial') != None:
import serial import serial
@ -72,6 +73,24 @@ class KISSInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
preamble = int(c["preamble"]) if "preamble" in c else None
txtail = int(c["txtail"]) if "txtail" in c else None
persistence = int(c["persistence"]) if "persistence" in c else None
slottime = int(c["slottime"]) if "slottime" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
beacon_interval = int(c["id_interval"]) if "id_interval" in c else None
beacon_data = c["id_callsign"] if "id_callsign" in c else None
if port == None:
raise ValueError("No port specified for serial interface")
self.HW_MTU = 564 self.HW_MTU = 564
if beacon_data == None: if beacon_data == None:

View File

@ -46,16 +46,25 @@ class HDLC():
class PipeInterface(Interface): class PipeInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
BITRATE_GUESS = 1*1000*1000 BITRATE_GUESS = 1*1000*1000
DEFAULT_IFAC_SIZE = 8
owner = None owner = None
command = None command = None
def __init__(self, owner, name, command, respawn_delay): def __init__(self, owner, configuration):
super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
command = c["command"] if "command" in c else None
respawn_delay = c.as_float("respawn_delay") if "respawn_delay" in c else None
if command == None:
raise ValueError("No command specified for PipeInterface")
if respawn_delay == None: if respawn_delay == None:
respawn_delay = 5 respawn_delay = 5
super().__init__()
self.HW_MTU = 1064 self.HW_MTU = 1064
self.owner = owner self.owner = owner

View File

@ -95,6 +95,7 @@ class KISS():
class RNodeInterface(Interface): class RNodeInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
DEFAULT_IFAC_SIZE = 8
FREQ_MIN = 137000000 FREQ_MIN = 137000000
FREQ_MAX = 3000000000 FREQ_MAX = 3000000000
@ -117,7 +118,7 @@ class RNodeInterface(Interface):
BATTERY_STATE_CHARGING = 0x02 BATTERY_STATE_CHARGING = 0x02
BATTERY_STATE_CHARGED = 0x03 BATTERY_STATE_CHARGED = 0x03
def __init__(self, owner, name, port, frequency = None, bandwidth = None, txpower = None, sf = None, cr = None, flow_control = False, id_interval = None, id_callsign = None, st_alock = None, lt_alock = None, ble_addr = None, ble_name = None, force_ble=False): def __init__(self, owner, configuration):
if RNS.vendor.platformutils.is_android(): if RNS.vendor.platformutils.is_android():
raise SystemError("Invalid interface type. The Android-specific RNode interface must be used on Android") raise SystemError("Invalid interface type. The Android-specific RNode interface must be used on Android")
@ -131,6 +132,41 @@ class RNodeInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
frequency = int(c["frequency"]) if "frequency" in c else None
bandwidth = int(c["bandwidth"]) if "bandwidth" in c else None
txpower = int(c["txpower"]) if "txpower" in c else None
sf = int(c["spreadingfactor"]) if "spreadingfactor" in c else None
cr = int(c["codingrate"]) if "codingrate" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
id_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" in c else None
st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c else None
lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c else None
force_ble = False
ble_name = None
ble_addr = None
port = c["port"] if "port" in c else None
if port == None:
raise ValueError("No port specified for RNode interface")
if port != None:
ble_uri_scheme = "ble://"
if port.lower().startswith(ble_uri_scheme):
force_ble = True
ble_string = port[len(ble_uri_scheme):]
port = None
if len(ble_string) == 0:
pass
elif len(ble_string.split(":")) == 6 and len(ble_string) == 17:
ble_addr = ble_string
else:
ble_name = ble_string
self.HW_MTU = 508 self.HW_MTU = 508
self.pyserial = serial self.pyserial = serial

View File

@ -163,6 +163,7 @@ class KISS():
class RNodeMultiInterface(Interface): class RNodeMultiInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
DEFAULT_IFAC_SIZE = 8
CALLSIGN_MAX_LEN = 32 CALLSIGN_MAX_LEN = 32
@ -173,7 +174,7 @@ class RNodeMultiInterface(Interface):
MAX_SUBINTERFACES = 11 MAX_SUBINTERFACES = 11
def __init__(self, owner, name, port, subint_config, id_interval = None, id_callsign = None): def __init__(self, owner, configuration):
if RNS.vendor.platformutils.is_android(): if RNS.vendor.platformutils.is_android():
raise SystemError("Invalid interface type. The Android-specific RNode interface must be used on Android") raise SystemError("Invalid interface type. The Android-specific RNode interface must be used on Android")
@ -187,6 +188,77 @@ class RNodeMultiInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
count = 0
enabled_count = 0
# Count how many interfaces are in the file
for subinterface in c:
# if the retrieved entry is not a string, it must be a dictionary, which is what we want
if not isinstance(c[subinterface], str):
count += 1
# Count how many interfaces are enabled to allow for appropriate matrix sizing
for subinterface in c:
# if the retrieved entry is not a string, it must be a dictionary, which is what we want
if not isinstance(c[subinterface], str):
subinterface_config = self.config["interfaces"][name][subinterface]
if (("interface_enabled" in subinterface_config) and subinterface_config.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True):
enabled_count += 1
# Create an array with a row for each subinterface
subint_config = [[0 for x in range(11)] for y in range(enabled_count)]
subint_index = 0
for subinterface in c:
# If the retrieved entry is not a string, it must be a dictionary, which is what we want
if not isinstance(c[subinterface], str):
subinterface_config = self.config["interfaces"][name][subinterface]
if (("interface_enabled" in subinterface_config) and subinterface_config.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True):
subint_config[subint_index][0] = subinterface
subint_vport = subinterface_config["vport"] if "vport" in subinterface_config else None
subint_config[subint_index][1] = subint_vport
frequency = int(subinterface_config["frequency"]) if "frequency" in subinterface_config else None
subint_config[subint_index][2] = frequency
bandwidth = int(subinterface_config["bandwidth"]) if "bandwidth" in subinterface_config else None
subint_config[subint_index][3] = bandwidth
txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None
subint_config[subint_index][4] = txpower
spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None
subint_config[subint_index][5] = spreadingfactor
codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None
subint_config[subint_index][6] = codingrate
flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False
subint_config[subint_index][7] = flow_control
st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None
subint_config[subint_index][8] = st_alock
lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None
subint_config[subint_index][9] = lt_alock
if "outgoing" in subinterface_config and subinterface_config.as_bool("outgoing") == False:
subint_config[subint_index][10] = False
else:
subint_config[subint_index][10] = True
subint_index += 1
# if no subinterfaces are defined
if count == 0:
raise ValueError("No subinterfaces configured for "+name)
# if no subinterfaces are enabled
elif enabled_count == 0:
raise ValueError("No subinterfaces enabled for "+name)
id_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" in c else None
port = c["port"] if "port" in c else None
if port == None:
raise ValueError("No port specified for "+name)
self.HW_MTU = 508 self.HW_MTU = 508
self.clients = 0 self.clients = 0

View File

@ -42,6 +42,7 @@ class HDLC():
class SerialInterface(Interface): class SerialInterface(Interface):
MAX_CHUNK = 32768 MAX_CHUNK = 32768
DEFAULT_IFAC_SIZE = 8
owner = None owner = None
port = None port = None
@ -51,7 +52,7 @@ class SerialInterface(Interface):
stopbits = None stopbits = None
serial = None serial = None
def __init__(self, owner, name, port, speed, databits, parity, stopbits): def __init__(self, owner, configuration):
import importlib import importlib
if importlib.util.find_spec('serial') != None: if importlib.util.find_spec('serial') != None:
import serial import serial
@ -62,6 +63,17 @@ class SerialInterface(Interface):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
if port == None:
raise ValueError("No port specified for serial interface")
self.HW_MTU = 564 self.HW_MTU = 564
self.pyserial = serial self.pyserial = serial

View File

@ -58,8 +58,12 @@ class KISS():
class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass pass
class ThreadingTCP6Server(socketserver.ThreadingMixIn, socketserver.TCPServer):
address_family = socket.AF_INET6
class TCPClientInterface(Interface): class TCPClientInterface(Interface):
BITRATE_GUESS = 10*1000*1000 BITRATE_GUESS = 10*1000*1000
DEFAULT_IFAC_SIZE = 16
RECONNECT_WAIT = 5 RECONNECT_WAIT = 5
RECONNECT_MAX_TRIES = None RECONNECT_MAX_TRIES = None
@ -78,9 +82,20 @@ class TCPClientInterface(Interface):
I2P_PROBE_INTERVAL = 9 I2P_PROBE_INTERVAL = 9
I2P_PROBES = 5 I2P_PROBES = 5
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None, kiss_framing=False, i2p_tunneled = False, connect_timeout = None): def __init__(self, owner, configuration, connected_socket=None):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
target_ip = c["target_host"] if "target_host" in c else None
target_port = int(c["target_port"]) if "target_port" in c else None
kiss_framing = False
if "kiss_framing" in c and c.as_bool("kiss_framing") == True:
kiss_framing = True
i2p_tunneled = c.as_bool("i2p_tunneled") if "i2p_tunneled" in c else False
connect_timeout = c.as_int("connect_timeout") if "connect_timeout" in c else None
max_reconnect_tries = c.as_int("max_reconnect_tries") if "max_reconnect_tries" in c else None
self.HW_MTU = 1064 self.HW_MTU = 1064
self.IN = True self.IN = True
@ -200,12 +215,14 @@ class TCPClientInterface(Interface):
if initial: if initial:
RNS.log("Establishing TCP connection for "+str(self)+"...", RNS.LOG_DEBUG) RNS.log("Establishing TCP connection for "+str(self)+"...", RNS.LOG_DEBUG)
addrInfo=socket.getaddrinfo(self.target_ip, self.target_port) address_info = socket.getaddrinfo(self.target_ip, self.target_port, proto=socket.IPPROTO_TCP)[0]
addrFam=addrInfo[0] address_family = address_info[0]
self.socket = socket.socket(addrFam, socket.SOCK_STREAM) target_address = address_info[4]
self.socket = socket.socket(address_family, socket.SOCK_STREAM)
self.socket.settimeout(TCPClientInterface.INITIAL_CONNECT_TIMEOUT) self.socket.settimeout(TCPClientInterface.INITIAL_CONNECT_TIMEOUT)
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self.socket.connect((self.target_ip, self.target_port)) self.socket.connect(target_address)
self.socket.settimeout(None) self.socket.settimeout(None)
self.online = True self.online = True
@ -404,32 +421,65 @@ class TCPClientInterface(Interface):
def __str__(self): def __str__(self):
return "TCPInterface["+str(self.name)+"/"+str(self.target_ip)+":"+str(self.target_port)+"]" if ":" in self.target_ip:
ip_str = f"[{self.target_ip}]"
else:
ip_str = f"{self.target_ip}"
return "TCPInterface["+str(self.name)+"/"+ip_str+":"+str(self.target_port)+"]"
class TCPServerInterface(Interface): class TCPServerInterface(Interface):
BITRATE_GUESS = 10*1000*1000 BITRATE_GUESS = 10*1000*1000
DEFAULT_IFAC_SIZE = 16
@staticmethod @staticmethod
def get_address_for_if(name): def get_address_for_if(name, bind_port, prefer_ipv6=False):
import RNS.vendor.ifaddr.niwrapper as netinfo import RNS.vendor.ifaddr.niwrapper as netinfo
ifaddr = netinfo.ifaddresses(name) ifaddr = netinfo.ifaddresses(name)
if len(ifaddr) < 1:
raise SystemError(f"No addresses available on specified kernel interface \"{name}\" for TCPServerInterface to bind to")
# IPv6 preference (if present) if (prefer_ipv6 or not netinfo.AF_INET in ifaddr) and netinfo.AF_INET6 in ifaddr:
if(netinfo.AF_INET6 in ifaddr): bind_ip = ifaddr[netinfo.AF_INET6][0]["addr"]
return ifaddr[netinfo.AF_INET6][0]["addr"] if bind_ip.lower().startswith("fe80::"):
# We'll need to add the interface as scope for link-local addresses
return ifaddr[netinfo.AF_INET][0]["addr"] return TCPServerInterface.get_address_for_host(f"{bind_ip}%{name}", bind_port)
else:
return TCPServerInterface.get_address_for_host(bind_ip, bind_port)
elif netinfo.AF_INET in ifaddr:
bind_ip = ifaddr[netinfo.AF_INET][0]["addr"]
return (bind_ip, bind_port)
else:
raise SystemError(f"No addresses available on specified kernel interface \"{name}\" for TCPServerInterface to bind to")
@staticmethod @staticmethod
def get_broadcast_for_if(name): def get_address_for_host(name, bind_port):
import RNS.vendor.ifaddr.niwrapper as netinfo address_info = socket.getaddrinfo(name, bind_port, proto=socket.IPPROTO_TCP)[0]
ifaddr = netinfo.ifaddresses(name) if address_info[0] == socket.AF_INET6:
return ifaddr[netinfo.AF_INET][0]["broadcast"] return (name, bind_port, address_info[4][2], address_info[4][3])
elif address_info[0] == socket.AF_INET:
return (name, bind_port)
else:
raise SystemError(f"No suitable kernel interface available for address \"{name}\" for TCPServerInterface to bind to")
def __init__(self, owner, name, device=None, bindip=None, bindport=None, i2p_tunneled=False):
# def __init__(self, owner, name, device=None, bindip=None, bindport=None, i2p_tunneled=False, prefer_ipv6=False):
def __init__(self, owner, configuration):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
device = c["device"] if "device" in c else None
port = int(c["port"]) if "port" in c else None
bindip = c["listen_ip"] if "listen_ip" in c else None
bindport = int(c["listen_port"]) if "listen_port" in c else None
i2p_tunneled = c.as_bool("i2p_tunneled") if "i2p_tunneled" in c else False
prefer_ipv6 = c.as_bool("prefer_ipv6") if "prefer_ipv6" in c else False
if port != None:
bindport = port
self.HW_MTU = 1064 self.HW_MTU = 1064
self.online = False self.online = False
@ -443,24 +493,40 @@ class TCPServerInterface(Interface):
self.i2p_tunneled = i2p_tunneled self.i2p_tunneled = i2p_tunneled
self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL self.mode = RNS.Interfaces.Interface.Interface.MODE_FULL
if device != None: if bindport == None:
bindip = TCPServerInterface.get_address_for_if(device) raise SystemError(f"No TCP port configured for interface \"{name}\"")
else:
if (bindip != None and bindport != None):
self.receives = True
self.bind_ip = bindip
self.bind_port = bindport self.bind_port = bindport
bind_address = None
if device != None:
bind_address = TCPServerInterface.get_address_for_if(device, self.bind_port, prefer_ipv6)
else:
if bindip == None:
raise SystemError(f"No TCP bind IP configured for interface \"{name}\"")
bind_address = TCPServerInterface.get_address_for_host(bindip, self.bind_port)
if bind_address != None:
self.receives = True
self.bind_ip = bind_address[0]
def handlerFactory(callback): def handlerFactory(callback):
def createHandler(*args, **keys): def createHandler(*args, **keys):
return TCPInterfaceHandler(callback, *args, **keys) return TCPInterfaceHandler(callback, *args, **keys)
return createHandler return createHandler
self.owner = owner self.owner = owner
address = (self.bind_ip, self.bind_port)
ThreadingTCPServer.allow_reuse_address = True if len(bind_address) == 4:
self.server = ThreadingTCPServer(address, handlerFactory(self.incoming_connection)) try:
ThreadingTCP6Server.allow_reuse_address = True
self.server = ThreadingTCP6Server(bind_address, handlerFactory(self.incoming_connection))
except Exception as e:
RNS.log(f"Error while binding IPv6 socket for interface, the contained exception was: {e}", RNS.LOG_ERROR)
raise SystemError("Could not bind IPv6 socket for interface. Please check the specified \"listen_ip\" configuration option")
else:
ThreadingTCPServer.allow_reuse_address = True
self.server = ThreadingTCPServer(bind_address, handlerFactory(self.incoming_connection))
self.bitrate = TCPServerInterface.BITRATE_GUESS self.bitrate = TCPServerInterface.BITRATE_GUESS
@ -470,11 +536,13 @@ class TCPServerInterface(Interface):
self.online = True self.online = True
else:
raise SystemError("Insufficient parameters to create TCP listener")
def incoming_connection(self, handler): def incoming_connection(self, handler):
RNS.log("Accepting incoming TCP connection", RNS.LOG_VERBOSE) RNS.log("Accepting incoming TCP connection", RNS.LOG_VERBOSE)
interface_name = "Client on "+self.name spawned_configuration = {"name": "Client on "+self.name, "target_host": None, "target_port": None, "i2p_tunneled": self.i2p_tunneled}
spawned_interface = TCPClientInterface(self.owner, interface_name, target_ip=None, target_port=None, connected_socket=handler.request, i2p_tunneled=self.i2p_tunneled) spawned_interface = TCPClientInterface(self.owner, spawned_configuration, connected_socket=handler.request)
spawned_interface.OUT = self.OUT spawned_interface.OUT = self.OUT
spawned_interface.IN = self.IN spawned_interface.IN = self.IN
spawned_interface.target_ip = handler.client_address[0] spawned_interface.target_ip = handler.client_address[0]
@ -538,7 +606,12 @@ class TCPServerInterface(Interface):
def __str__(self): def __str__(self):
return "TCPServerInterface["+self.name+"/"+self.bind_ip+":"+str(self.bind_port)+"]" if ":" in self.bind_ip:
ip_str = f"[{self.bind_ip}]"
else:
ip_str = f"{self.bind_ip}"
return "TCPServerInterface["+self.name+"/"+ip_str+":"+str(self.bind_port)+"]"
class TCPInterfaceHandler(socketserver.BaseRequestHandler): class TCPInterfaceHandler(socketserver.BaseRequestHandler):

View File

@ -31,6 +31,7 @@ import RNS
class UDPInterface(Interface): class UDPInterface(Interface):
BITRATE_GUESS = 10*1000*1000 BITRATE_GUESS = 10*1000*1000
DEFAULT_IFAC_SIZE = 16
@staticmethod @staticmethod
def get_address_for_if(name): def get_address_for_if(name):
@ -44,9 +45,24 @@ class UDPInterface(Interface):
ifaddr = netinfo.ifaddresses(name) ifaddr = netinfo.ifaddresses(name)
return ifaddr[netinfo.AF_INET][0]["broadcast"] return ifaddr[netinfo.AF_INET][0]["broadcast"]
def __init__(self, owner, name, device=None, bindip=None, bindport=None, forwardip=None, forwardport=None): def __init__(self, owner, configuration):
super().__init__() super().__init__()
c = Interface.get_config_obj(configuration)
name = c["name"]
device = c["device"] if "device" in c else None
port = int(c["port"]) if "port" in c else None
bindip = c["listen_ip"] if "listen_ip" in c else None
bindport = int(c["listen_port"]) if "listen_port" in c else None
forwardip = c["forward_ip"] if "forward_ip" in c else None
forwardport = int(c["forward_port"]) if "forward_port" in c else None
if port != None:
if bindport == None:
bindport = port
if forwardport == None:
forwardport = port
self.HW_MTU = 1064 self.HW_MTU = 1064
self.IN = True self.IN = True

View File

@ -446,14 +446,7 @@ class Reticulum:
if "interfaces" in self.config: if "interfaces" in self.config:
for name in self.config["interfaces"]: for name in self.config["interfaces"]:
if not name in interface_names: if not name in interface_names:
# TODO: We really need to generalise this way of instantiating
# and configuring interfaces. Ideally, interfaces should just
# have a conrfig dict passed to their init method, and return
# a ready interface, onto which this routine can configure any
# generic or extra parameters.
c = self.config["interfaces"][name] c = self.config["interfaces"][name]
interface_mode = Interface.Interface.MODE_FULL interface_mode = Interface.Interface.MODE_FULL
if "interface_mode" in c: if "interface_mode" in c:
@ -556,514 +549,87 @@ class Reticulum:
announce_cap = c.as_float("announce_cap")/100.0 announce_cap = c.as_float("announce_cap")/100.0
try: try:
def interface_post_init(interface):
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = interface.DEFAULT_IFAC_SIZE
interface = None interface = None
if (("interface_enabled" in c) and c.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True): if (("interface_enabled" in c) and c.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True):
interface_config = c
interface_config["name"] = name
interface_config["configured_bitrate"] = configured_bitrate
if c["type"] == "AutoInterface": if c["type"] == "AutoInterface":
group_id = c["group_id"] if "group_id" in c else None interface = AutoInterface.AutoInterface(RNS.Transport, interface_config)
discovery_scope = c["discovery_scope"] if "discovery_scope" in c else None interface_post_init(interface)
discovery_port = int(c["discovery_port"]) if "discovery_port" in c else None
multicast_address_type = c["multicast_address_type"] if "multicast_address_type" in c else None
data_port = int(c["data_port"]) if "data_port" in c else None
allowed_interfaces = c.as_list("devices") if "devices" in c else None
ignored_interfaces = c.as_list("ignored_devices") if "ignored_devices" in c else None
interface = AutoInterface.AutoInterface(
RNS.Transport,
name,
group_id,
discovery_scope,
discovery_port,
multicast_address_type,
data_port,
allowed_interfaces,
ignored_interfaces
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 16
if c["type"] == "UDPInterface": if c["type"] == "UDPInterface":
device = c["device"] if "device" in c else None interface = UDPInterface.UDPInterface(RNS.Transport, interface_config)
port = int(c["port"]) if "port" in c else None interface_post_init(interface)
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,
device,
listen_ip,
listen_port,
forward_ip,
forward_port
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 16
if c["type"] == "TCPServerInterface": 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
i2p_tunneled = c.as_bool("i2p_tunneled") if "i2p_tunneled" in c else False
if port != None:
listen_port = port
interface = TCPInterface.TCPServerInterface(
RNS.Transport,
name,
device,
listen_ip,
listen_port,
i2p_tunneled
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: if interface_mode == Interface.Interface.MODE_ACCESS_POINT:
RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING)
interface_mode = Interface.Interface.MODE_FULL interface_mode = Interface.Interface.MODE_FULL
interface.mode = interface_mode interface = TCPInterface.TCPServerInterface(RNS.Transport, interface_config)
interface_post_init(interface)
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 16
if c["type"] == "TCPClientInterface": if c["type"] == "TCPClientInterface":
kiss_framing = False
if "kiss_framing" in c and c.as_bool("kiss_framing") == True:
kiss_framing = True
i2p_tunneled = c.as_bool("i2p_tunneled") if "i2p_tunneled" in c else False
tcp_connect_timeout = c.as_int("connect_timeout") if "connect_timeout" in c else None
interface = TCPInterface.TCPClientInterface(
RNS.Transport,
name,
c["target_host"],
int(c["target_port"]),
kiss_framing = kiss_framing,
i2p_tunneled = i2p_tunneled,
connect_timeout = tcp_connect_timeout,
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: if interface_mode == Interface.Interface.MODE_ACCESS_POINT:
RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING)
interface_mode = Interface.Interface.MODE_FULL interface_mode = Interface.Interface.MODE_FULL
interface.mode = interface_mode interface = TCPInterface.TCPClientInterface(RNS.Transport, interface_config)
interface_post_init(interface)
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 16
if c["type"] == "I2PInterface": if c["type"] == "I2PInterface":
i2p_peers = c.as_list("peers") if "peers" in c else None
connectable = c.as_bool("connectable") if "connectable" in c else False
if ifac_size == None:
ifac_size = 16
interface = I2PInterface.I2PInterface(
RNS.Transport,
name,
Reticulum.storagepath,
i2p_peers,
connectable = connectable,
ifac_size = ifac_size,
ifac_netname = ifac_netname,
ifac_netkey = ifac_netkey,
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
if interface_mode == Interface.Interface.MODE_ACCESS_POINT: if interface_mode == Interface.Interface.MODE_ACCESS_POINT:
RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING) RNS.log(str(interface)+" does not support Access Point mode, reverting to default mode: Full", RNS.LOG_WARNING)
interface_mode = Interface.Interface.MODE_FULL interface_mode = Interface.Interface.MODE_FULL
interface.mode = interface_mode interface_config["storagepath"] = Reticulum.storagepath
interface_config["ifac_netname"] = ifac_netname
interface_config["ifac_netkey"] = ifac_netkey
interface_config["ifac_size"] = ifac_size
interface.announce_cap = announce_cap interface = I2PInterface.I2PInterface(RNS.Transport, interface_config)
if configured_bitrate: interface_post_init(interface)
interface.bitrate = configured_bitrate
if c["type"] == "SerialInterface": if c["type"] == "SerialInterface":
port = c["port"] if "port" in c else None interface = SerialInterface.SerialInterface(RNS.Transport, interface_config)
speed = int(c["speed"]) if "speed" in c else 9600 interface_post_init(interface)
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
if port == None:
raise ValueError("No port specified for serial interface")
interface = SerialInterface.SerialInterface(
RNS.Transport,
name,
port,
speed,
databits,
parity,
stopbits
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 8
if c["type"] == "PipeInterface": if c["type"] == "PipeInterface":
command = c["command"] if "command" in c else None interface = PipeInterface.PipeInterface(RNS.Transport, interface_config)
respawn_delay = c.as_float("respawn_delay") if "respawn_delay" in c else None interface_post_init(interface)
if command == None:
raise ValueError("No command specified for PipeInterface")
interface = PipeInterface.PipeInterface(
RNS.Transport,
name,
command,
respawn_delay,
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 8
if c["type"] == "KISSInterface": if c["type"] == "KISSInterface":
preamble = int(c["preamble"]) if "preamble" in c else None interface = KISSInterface.KISSInterface(RNS.Transport, interface_config)
txtail = int(c["txtail"]) if "txtail" in c else None interface_post_init(interface)
persistence = int(c["persistence"]) if "persistence" in c else None
slottime = int(c["slottime"]) if "slottime" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
beacon_interval = int(c["id_interval"]) if "id_interval" in c else None
beacon_data = c["id_callsign"] if "id_callsign" in c else None
if port == None:
raise ValueError("No port specified for serial interface")
interface = KISSInterface.KISSInterface(
RNS.Transport,
name,
port,
speed,
databits,
parity,
stopbits,
preamble,
txtail,
persistence,
slottime,
flow_control,
beacon_interval,
beacon_data
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 8
if c["type"] == "AX25KISSInterface": if c["type"] == "AX25KISSInterface":
preamble = int(c["preamble"]) if "preamble" in c else None interface = AX25KISSInterface.AX25KISSInterface(RNS.Transport, interface_config)
txtail = int(c["txtail"]) if "txtail" in c else None interface_post_init(interface)
persistence = int(c["persistence"]) if "persistence" in c else None
slottime = int(c["slottime"]) if "slottime" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
port = c["port"] if "port" in c else None
speed = int(c["speed"]) if "speed" in c else 9600
databits = int(c["databits"]) if "databits" in c else 8
parity = c["parity"] if "parity" in c else "N"
stopbits = int(c["stopbits"]) if "stopbits" in c else 1
callsign = c["callsign"] if "callsign" in c else ""
ssid = int(c["ssid"]) if "ssid" in c else -1
if port == None:
raise ValueError("No port specified for serial interface")
interface = AX25KISSInterface.AX25KISSInterface(
RNS.Transport,
name,
callsign,
ssid,
port,
speed,
databits,
parity,
stopbits,
preamble,
txtail,
persistence,
slottime,
flow_control
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 8
if c["type"] == "RNodeInterface": if c["type"] == "RNodeInterface":
frequency = int(c["frequency"]) if "frequency" in c else None interface = RNodeInterface.RNodeInterface(RNS.Transport, interface_config)
bandwidth = int(c["bandwidth"]) if "bandwidth" in c else None interface_post_init(interface)
txpower = int(c["txpower"]) if "txpower" in c else None
spreadingfactor = int(c["spreadingfactor"]) if "spreadingfactor" in c else None
codingrate = int(c["codingrate"]) if "codingrate" in c else None
flow_control = c.as_bool("flow_control") if "flow_control" in c else False
id_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" in c else None
st_alock = float(c["airtime_limit_short"]) if "airtime_limit_short" in c else None
lt_alock = float(c["airtime_limit_long"]) if "airtime_limit_long" in c else None
force_ble = False
ble_name = None
ble_addr = None
port = c["port"] if "port" in c else None
if port == None:
raise ValueError("No port specified for RNode interface")
if port != None:
ble_uri_scheme = "ble://"
if port.lower().startswith(ble_uri_scheme):
force_ble = True
ble_string = port[len(ble_uri_scheme):]
port = None
if len(ble_string) == 0:
pass
elif len(ble_string.split(":")) == 6 and len(ble_string) == 17:
ble_addr = ble_string
else:
ble_name = ble_string
interface = RNodeInterface.RNodeInterface(
RNS.Transport,
name,
port,
frequency = frequency,
bandwidth = bandwidth,
txpower = txpower,
sf = spreadingfactor,
cr = codingrate,
flow_control = flow_control,
id_interval = id_interval,
id_callsign = id_callsign,
st_alock = st_alock,
lt_alock = lt_alock,
ble_addr = ble_addr,
ble_name = ble_name,
force_ble = force_ble,
)
if "outgoing" in c and c.as_bool("outgoing") == False:
interface.OUT = False
else:
interface.OUT = True
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 8
if c["type"] == "RNodeMultiInterface": if c["type"] == "RNodeMultiInterface":
count = 0 interface = RNodeMultiInterface.RNodeMultiInterface(RNS.Transport, interface_config)
enabled_count = 0 interface_post_init(interface)
# Count how many interfaces are in the file
for subinterface in c:
# if the retrieved entry is not a string, it must be a dictionary, which is what we want
if not isinstance(c[subinterface], str):
count += 1
# Count how many interfaces are enabled to allow for appropriate matrix sizing
for subinterface in c:
# if the retrieved entry is not a string, it must be a dictionary, which is what we want
if not isinstance(c[subinterface], str):
subinterface_config = self.config["interfaces"][name][subinterface]
if (("interface_enabled" in subinterface_config) and subinterface_config.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True):
enabled_count += 1
# Create an array with a row for each subinterface
subint_config = [[0 for x in range(11)] for y in range(enabled_count)]
subint_index = 0
for subinterface in c:
# If the retrieved entry is not a string, it must be a dictionary, which is what we want
if not isinstance(c[subinterface], str):
subinterface_config = self.config["interfaces"][name][subinterface]
if (("interface_enabled" in subinterface_config) and subinterface_config.as_bool("interface_enabled") == True) or (("enabled" in c) and c.as_bool("enabled") == True):
subint_config[subint_index][0] = subinterface
subint_vport = subinterface_config["vport"] if "vport" in subinterface_config else None
subint_config[subint_index][1] = subint_vport
frequency = int(subinterface_config["frequency"]) if "frequency" in subinterface_config else None
subint_config[subint_index][2] = frequency
bandwidth = int(subinterface_config["bandwidth"]) if "bandwidth" in subinterface_config else None
subint_config[subint_index][3] = bandwidth
txpower = int(subinterface_config["txpower"]) if "txpower" in subinterface_config else None
subint_config[subint_index][4] = txpower
spreadingfactor = int(subinterface_config["spreadingfactor"]) if "spreadingfactor" in subinterface_config else None
subint_config[subint_index][5] = spreadingfactor
codingrate = int(subinterface_config["codingrate"]) if "codingrate" in subinterface_config else None
subint_config[subint_index][6] = codingrate
flow_control = subinterface_config.as_bool("flow_control") if "flow_control" in subinterface_config else False
subint_config[subint_index][7] = flow_control
st_alock = float(subinterface_config["airtime_limit_short"]) if "airtime_limit_short" in subinterface_config else None
subint_config[subint_index][8] = st_alock
lt_alock = float(subinterface_config["airtime_limit_long"]) if "airtime_limit_long" in subinterface_config else None
subint_config[subint_index][9] = lt_alock
if "outgoing" in subinterface_config and subinterface_config.as_bool("outgoing") == False:
subint_config[subint_index][10] = False
else:
subint_config[subint_index][10] = True
subint_index += 1
# if no subinterfaces are defined
if count == 0:
raise ValueError("No subinterfaces configured for "+name)
# if no subinterfaces are enabled
elif enabled_count == 0:
raise ValueError("No subinterfaces enabled for "+name)
id_interval = int(c["id_interval"]) if "id_interval" in c else None
id_callsign = c["id_callsign"] if "id_callsign" in c else None
port = c["port"] if "port" in c else None
if port == None:
raise ValueError("No port specified for "+name)
interface = RNodeMultiInterface.RNodeMultiInterface(
RNS.Transport,
name,
port,
subint_config,
id_interval = id_interval,
id_callsign = id_callsign
)
interface.IN = False
interface.OUT = False
interface.mode = interface_mode
interface.announce_cap = announce_cap
if configured_bitrate:
interface.bitrate = configured_bitrate
if ifac_size != None:
interface.ifac_size = ifac_size
else:
interface.ifac_size = 8
if interface != None: if interface != None:
interface.announce_rate_target = announce_rate_target interface.announce_rate_target = announce_rate_target
@ -1119,7 +685,7 @@ class Reticulum:
RNS.log("System interfaces are ready", RNS.LOG_VERBOSE) RNS.log("System interfaces are ready", RNS.LOG_VERBOSE)
def _add_interface(self,interface, mode = None, configured_bitrate=None, ifac_size=None, ifac_netname=None, ifac_netkey=None, announce_cap=None, announce_rate_target=None, announce_rate_grace=None, announce_rate_penalty=None): def _add_interface(self, interface, mode = None, configured_bitrate=None, ifac_size=None, ifac_netname=None, ifac_netkey=None, announce_cap=None, announce_rate_target=None, announce_rate_grace=None, announce_rate_penalty=None):
if not self.is_connected_to_shared_instance: if not self.is_connected_to_shared_instance:
if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface): if interface != None and issubclass(type(interface), RNS.Interfaces.Interface.Interface):

View File

@ -1 +1 @@
__version__ = "0.8.5" __version__ = "0.8.6"

View File

@ -1,4 +1,4 @@
# Sphinx build info version 1 # 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. # This file hashes the configuration used when building these files. When it is not found, a full rebuild will be done.
config: 068d3fe32e7f0c111ab64548184dd063 config: a6abb7db1df16737cc5d923272a50d50
tags: 645f666f9bcd5a90fca523b33c5a78b7 tags: 645f666f9bcd5a90fca523b33c5a78b7

View File

@ -171,7 +171,7 @@ TCP Server Interface
==================== ====================
The TCP Server interface is suitable for allowing other peers to connect over The TCP Server interface is suitable for allowing other peers to connect over
the Internet or private IP networks. When a TCP server interface has been the Internet or private IPv4 and IPv6 networks. When a TCP server interface has been
configured, other Reticulum peers can connect to it with a TCP Client interface. configured, other Reticulum peers can connect to it with a TCP Client interface.
.. code:: .. code::
@ -200,6 +200,34 @@ configured, other Reticulum peers can connect to it with a TCP Client interface.
# device = eth0 # device = eth0
# port = 4242 # port = 4242
If you are using the interface on a device which has both IPv4 and IPv6 addresses available,
you can use the ``prefer_ipv6`` option to bind to the IPv6 address:
.. code::
# This example demonstrates a TCP server interface.
# It will listen for incoming connections on the
# specified IP address and port number.
[[TCP Server Interface]]
type = TCPServerInterface
interface_enabled = True
device = eth0
port = 4242
prefer_ipv6 = True
To use the TCP Server Interface over `Yggdrasil <https://yggdrasil-network.github.io/>`_, you
can simply specify the Yggdrasil ``tun`` device and a listening port, like so:
.. code::
[[Yggdrasil TCP Server Interface]]
type = TCPServerInterface
interface_enabled = yes
device = tun0
listen_port = 4343
**Please Note!** The TCP interfaces support tunneling over I2P, but to do so reliably, **Please Note!** The TCP interfaces support tunneling over I2P, but to do so reliably,
you must use the i2p_tunneled option: you must use the i2p_tunneled option:
@ -231,7 +259,7 @@ and restore connectivity after a failure, once the other end of a TCP interface
.. code:: .. code::
# Here's an example of a TCP Client interface. The # Here's an example of a TCP Client interface. The
# target_host can either be an IP address or a hostname. # target_host can be a hostname or an IPv4 or IPv6 address.
[[TCP Client Interface]] [[TCP Client Interface]]
type = TCPClientInterface type = TCPClientInterface
@ -239,6 +267,17 @@ and restore connectivity after a failure, once the other end of a TCP interface
target_host = 127.0.0.1 target_host = 127.0.0.1
target_port = 4242 target_port = 4242
To use the TCP Client Interface over `Yggdrasil <https://yggdrasil-network.github.io/>`_, simply
specify the target Yggdrasil IPv6 address and port, like so:
.. code::
[[Yggdrasil TCP Client Interface]]
type = TCPClientInterface
interface_enabled = yes
target_host = 201:5d78:af73:5caf:a4de:a79f:3278:71e5
target_port = 4343
It is also possible to use this interface type to connect via other programs It is also possible to use this interface type to connect via other programs
or hardware devices that expose a KISS interface on a TCP port, for example or hardware devices that expose a KISS interface on a TCP port, for example
software-based soundmodems. To do this, use the ``kiss_framing`` option: software-based soundmodems. To do this, use the ``kiss_framing`` option:

View File

@ -1,6 +1,6 @@
var DOCUMENTATION_OPTIONS = { var DOCUMENTATION_OPTIONS = {
URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'), URL_ROOT: document.getElementById("documentation_options").getAttribute('data-url_root'),
VERSION: '0.8.5 beta', VERSION: '0.8.6 beta',
LANGUAGE: 'en', LANGUAGE: 'en',
COLLAPSE_INDEX: false, COLLAPSE_INDEX: false,
BUILDER: 'html', BUILDER: 'html',

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Support Reticulum" href="support.html" /><link rel="prev" title="Building Networks" href="networks.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Support Reticulum" href="support.html" /><link rel="prev" title="Building Networks" href="networks.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Code Examples - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Code Examples - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 0.8.5 beta documentation</title> <title>An Explanation of Reticulum for Human Beings - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/> <meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" /> <meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="#" /><link rel="search" title="Search" href="search.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Index - Reticulum Network Stack 0.8.5 beta documentation</title> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Index - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -139,7 +139,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -165,7 +165,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Using Reticulum on Your System" href="using.html" /><link rel="prev" title="What is Reticulum?" href="whatis.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Using Reticulum on Your System" href="using.html" /><link rel="prev" title="What is Reticulum?" href="whatis.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Getting Started Fast - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Getting Started Fast - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Configuring Interfaces" href="interfaces.html" /><link rel="prev" title="Understanding Reticulum" href="understanding.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Configuring Interfaces" href="interfaces.html" /><link rel="prev" title="Understanding Reticulum" href="understanding.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Communications Hardware - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Communications Hardware - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="What is Reticulum?" href="whatis.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="What is Reticulum?" href="whatis.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Reticulum Network Stack 0.8.5 beta documentation</title> <title>Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="#"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="#"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Building Networks" href="networks.html" /><link rel="prev" title="Communications Hardware" href="hardware.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Building Networks" href="networks.html" /><link rel="prev" title="Communications Hardware" href="hardware.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Configuring Interfaces - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Configuring Interfaces - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">
@ -360,7 +360,7 @@ use-cases.</p>
<section id="tcp-server-interface"> <section id="tcp-server-interface">
<span id="interfaces-tcps"></span><h2>TCP Server Interface<a class="headerlink" href="#tcp-server-interface" title="Permalink to this heading">#</a></h2> <span id="interfaces-tcps"></span><h2>TCP Server Interface<a class="headerlink" href="#tcp-server-interface" title="Permalink to this heading">#</a></h2>
<p>The TCP Server interface is suitable for allowing other peers to connect over <p>The TCP Server interface is suitable for allowing other peers to connect over
the Internet or private IP networks. When a TCP server interface has been the Internet or private IPv4 and IPv6 networks. When a TCP server interface has been
configured, other Reticulum peers can connect to it with a TCP Client interface.</p> configured, other Reticulum peers can connect to it with a TCP Client interface.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example demonstrates a TCP server interface.</span> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example demonstrates a TCP server interface.</span>
<span class="c1"># It will listen for incoming connections on the</span> <span class="c1"># It will listen for incoming connections on the</span>
@ -387,6 +387,30 @@ configured, other Reticulum peers can connect to it with a TCP Client interface.
<span class="c1"># port = 4242</span> <span class="c1"># port = 4242</span>
</pre></div> </pre></div>
</div> </div>
<p>If you are using the interface on a device which has both IPv4 and IPv6 addresses available,
you can use the <code class="docutils literal notranslate"><span class="pre">prefer_ipv6</span></code> option to bind to the IPv6 address:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># This example demonstrates a TCP server interface.</span>
<span class="c1"># It will listen for incoming connections on the</span>
<span class="c1"># specified IP address and port number.</span>
<span class="p">[[</span><span class="n">TCP</span> <span class="n">Server</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">TCPServerInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="kc">True</span>
<span class="n">device</span> <span class="o">=</span> <span class="n">eth0</span>
<span class="n">port</span> <span class="o">=</span> <span class="mi">4242</span>
<span class="n">prefer_ipv6</span> <span class="o">=</span> <span class="kc">True</span>
</pre></div>
</div>
<p>To use the TCP Server Interface over <a class="reference external" href="https://yggdrasil-network.github.io/">Yggdrasil</a>, you
can simply specify the Yggdrasil <code class="docutils literal notranslate"><span class="pre">tun</span></code> device and a listening port, like so:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span><span class="n">Yggdrasil</span> <span class="n">TCP</span> <span class="n">Server</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">TCPServerInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="n">yes</span>
<span class="n">device</span> <span class="o">=</span> <span class="n">tun0</span>
<span class="n">listen_port</span> <span class="o">=</span> <span class="mi">4343</span>
</pre></div>
</div>
<p><strong>Please Note!</strong> The TCP interfaces support tunneling over I2P, but to do so reliably, <p><strong>Please Note!</strong> The TCP interfaces support tunneling over I2P, but to do so reliably,
you must use the i2p_tunneled option:</p> you must use the i2p_tunneled option:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span><span class="n">TCP</span> <span class="n">Server</span> <span class="n">on</span> <span class="n">I2P</span><span class="p">]]</span> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span><span class="n">TCP</span> <span class="n">Server</span> <span class="n">on</span> <span class="n">I2P</span><span class="p">]]</span>
@ -409,7 +433,7 @@ same TCP Server interface at the same time.</p>
This means that Reticulum will gracefully handle IP links that go up and down, This means that Reticulum will gracefully handle IP links that go up and down,
and restore connectivity after a failure, once the other end of a TCP interface reappears.</p> and restore connectivity after a failure, once the other end of a TCP interface reappears.</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Here&#39;s an example of a TCP Client interface. The</span> <div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="c1"># Here&#39;s an example of a TCP Client interface. The</span>
<span class="c1"># target_host can either be an IP address or a hostname.</span> <span class="c1"># target_host can be a hostname or an IPv4 or IPv6 address.</span>
<span class="p">[[</span><span class="n">TCP</span> <span class="n">Client</span> <span class="n">Interface</span><span class="p">]]</span> <span class="p">[[</span><span class="n">TCP</span> <span class="n">Client</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">TCPClientInterface</span> <span class="nb">type</span> <span class="o">=</span> <span class="n">TCPClientInterface</span>
@ -418,6 +442,15 @@ and restore connectivity after a failure, once the other end of a TCP interface
<span class="n">target_port</span> <span class="o">=</span> <span class="mi">4242</span> <span class="n">target_port</span> <span class="o">=</span> <span class="mi">4242</span>
</pre></div> </pre></div>
</div> </div>
<p>To use the TCP Client Interface over <a class="reference external" href="https://yggdrasil-network.github.io/">Yggdrasil</a>, simply
specify the target Yggdrasil IPv6 address and port, like so:</p>
<div class="highlight-default notranslate"><div class="highlight"><pre><span></span><span class="p">[[</span><span class="n">Yggdrasil</span> <span class="n">TCP</span> <span class="n">Client</span> <span class="n">Interface</span><span class="p">]]</span>
<span class="nb">type</span> <span class="o">=</span> <span class="n">TCPClientInterface</span>
<span class="n">interface_enabled</span> <span class="o">=</span> <span class="n">yes</span>
<span class="n">target_host</span> <span class="o">=</span> <span class="mi">201</span><span class="p">:</span><span class="mi">5</span><span class="n">d78</span><span class="p">:</span><span class="n">af73</span><span class="p">:</span><span class="mi">5</span><span class="n">caf</span><span class="p">:</span><span class="n">a4de</span><span class="p">:</span><span class="n">a79f</span><span class="p">:</span><span class="mi">3278</span><span class="p">:</span><span class="mf">71e5</span>
<span class="n">target_port</span> <span class="o">=</span> <span class="mi">4343</span>
</pre></div>
</div>
<p>It is also possible to use this interface type to connect via other programs <p>It is also possible to use this interface type to connect via other programs
or hardware devices that expose a KISS interface on a TCP port, for example or hardware devices that expose a KISS interface on a TCP port, for example
software-based soundmodems. To do this, use the <code class="docutils literal notranslate"><span class="pre">kiss_framing</span></code> option:</p> software-based soundmodems. To do this, use the <code class="docutils literal notranslate"><span class="pre">kiss_framing</span></code> option:</p>

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Code Examples" href="examples.html" /><link rel="prev" title="Configuring Interfaces" href="interfaces.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Code Examples" href="examples.html" /><link rel="prev" title="Configuring Interfaces" href="interfaces.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Building Networks - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Building Networks - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

Binary file not shown.

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="Support Reticulum" href="support.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="prev" title="Support Reticulum" href="support.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>API Reference - Reticulum Network Stack 0.8.5 beta documentation</title> <title>API Reference - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -4,7 +4,7 @@
<meta name="viewport" content="width=device-width,initial-scale=1"/> <meta name="viewport" content="width=device-width,initial-scale=1"/>
<meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="#" /> <meta name="color-scheme" content="light dark"><link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="#" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Search - Reticulum Network Stack 0.8.5 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/><title>Search - Reticulum Network Stack 0.8.6 beta documentation</title><link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo-extensions.css?digest=30d1aed668e5c3a91c3e3bf6a60b675221979f0e" />
@ -138,7 +138,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -164,7 +164,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="#" role="search"> </a><form class="sidebar-search-container" method="get" action="#" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

File diff suppressed because one or more lines are too long

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="API Reference" href="reference.html" /><link rel="prev" title="Code Examples" href="examples.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="API Reference" href="reference.html" /><link rel="prev" title="Code Examples" href="examples.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Support Reticulum - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Support Reticulum - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Communications Hardware" href="hardware.html" /><link rel="prev" title="Using Reticulum on Your System" href="using.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Communications Hardware" href="hardware.html" /><link rel="prev" title="Using Reticulum on Your System" href="using.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Understanding Reticulum - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Understanding Reticulum - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Understanding Reticulum" href="understanding.html" /><link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Understanding Reticulum" href="understanding.html" /><link rel="prev" title="Getting Started Fast" href="gettingstartedfast.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>Using Reticulum on Your System - Reticulum Network Stack 0.8.5 beta documentation</title> <title>Using Reticulum on Your System - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -6,7 +6,7 @@
<link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Getting Started Fast" href="gettingstartedfast.html" /><link rel="prev" title="Reticulum Network Stack Manual" href="index.html" /> <link rel="index" title="Index" href="genindex.html" /><link rel="search" title="Search" href="search.html" /><link rel="next" title="Getting Started Fast" href="gettingstartedfast.html" /><link rel="prev" title="Reticulum Network Stack Manual" href="index.html" />
<meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/> <meta name="generator" content="sphinx-5.3.0, furo 2022.09.29.dev1"/>
<title>What is Reticulum? - Reticulum Network Stack 0.8.5 beta documentation</title> <title>What is Reticulum? - Reticulum Network Stack 0.8.6 beta documentation</title>
<link rel="stylesheet" type="text/css" href="_static/pygments.css" /> <link rel="stylesheet" type="text/css" href="_static/pygments.css" />
<link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" /> <link rel="stylesheet" type="text/css" href="_static/styles/furo.css?digest=189ec851f9bb375a2509b67be1f64f0cf212b702" />
<link rel="stylesheet" type="text/css" href="_static/copybutton.css" /> <link rel="stylesheet" type="text/css" href="_static/copybutton.css" />
@ -141,7 +141,7 @@
</label> </label>
</div> </div>
<div class="header-center"> <div class="header-center">
<a href="index.html"><div class="brand">Reticulum Network Stack 0.8.5 beta documentation</div></a> <a href="index.html"><div class="brand">Reticulum Network Stack 0.8.6 beta documentation</div></a>
</div> </div>
<div class="header-right"> <div class="header-right">
<div class="theme-toggle-container theme-toggle-header"> <div class="theme-toggle-container theme-toggle-header">
@ -167,7 +167,7 @@
<img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/> <img class="sidebar-logo" src="_static/rns_logo_512.png" alt="Logo"/>
</div> </div>
<span class="sidebar-brand-text">Reticulum Network Stack 0.8.5 beta documentation</span> <span class="sidebar-brand-text">Reticulum Network Stack 0.8.6 beta documentation</span>
</a><form class="sidebar-search-container" method="get" action="search.html" role="search"> </a><form class="sidebar-search-container" method="get" action="search.html" role="search">
<input class="sidebar-search" placeholder="Search" name="q" aria-label="Search"> <input class="sidebar-search" placeholder="Search" name="q" aria-label="Search">

View File

@ -171,7 +171,7 @@ TCP Server Interface
==================== ====================
The TCP Server interface is suitable for allowing other peers to connect over The TCP Server interface is suitable for allowing other peers to connect over
the Internet or private IP networks. When a TCP server interface has been the Internet or private IPv4 and IPv6 networks. When a TCP server interface has been
configured, other Reticulum peers can connect to it with a TCP Client interface. configured, other Reticulum peers can connect to it with a TCP Client interface.
.. code:: .. code::
@ -200,6 +200,34 @@ configured, other Reticulum peers can connect to it with a TCP Client interface.
# device = eth0 # device = eth0
# port = 4242 # port = 4242
If you are using the interface on a device which has both IPv4 and IPv6 addresses available,
you can use the ``prefer_ipv6`` option to bind to the IPv6 address:
.. code::
# This example demonstrates a TCP server interface.
# It will listen for incoming connections on the
# specified IP address and port number.
[[TCP Server Interface]]
type = TCPServerInterface
interface_enabled = True
device = eth0
port = 4242
prefer_ipv6 = True
To use the TCP Server Interface over `Yggdrasil <https://yggdrasil-network.github.io/>`_, you
can simply specify the Yggdrasil ``tun`` device and a listening port, like so:
.. code::
[[Yggdrasil TCP Server Interface]]
type = TCPServerInterface
interface_enabled = yes
device = tun0
listen_port = 4343
**Please Note!** The TCP interfaces support tunneling over I2P, but to do so reliably, **Please Note!** The TCP interfaces support tunneling over I2P, but to do so reliably,
you must use the i2p_tunneled option: you must use the i2p_tunneled option:
@ -231,7 +259,7 @@ and restore connectivity after a failure, once the other end of a TCP interface
.. code:: .. code::
# Here's an example of a TCP Client interface. The # Here's an example of a TCP Client interface. The
# target_host can either be an IP address or a hostname. # target_host can be a hostname or an IPv4 or IPv6 address.
[[TCP Client Interface]] [[TCP Client Interface]]
type = TCPClientInterface type = TCPClientInterface
@ -239,6 +267,17 @@ and restore connectivity after a failure, once the other end of a TCP interface
target_host = 127.0.0.1 target_host = 127.0.0.1
target_port = 4242 target_port = 4242
To use the TCP Client Interface over `Yggdrasil <https://yggdrasil-network.github.io/>`_, simply
specify the target Yggdrasil IPv6 address and port, like so:
.. code::
[[Yggdrasil TCP Client Interface]]
type = TCPClientInterface
interface_enabled = yes
target_host = 201:5d78:af73:5caf:a4de:a79f:3278:71e5
target_port = 4343
It is also possible to use this interface type to connect via other programs It is also possible to use this interface type to connect via other programs
or hardware devices that expose a KISS interface on a TCP port, for example or hardware devices that expose a KISS interface on a TCP port, for example
software-based soundmodems. To do this, use the ``kiss_framing`` option: software-based soundmodems. To do this, use the ``kiss_framing`` option:
@ -454,89 +493,89 @@ Multi interface can be used to configure sub-interfaces individually.
# id_interval = 600 # id_interval = 600
# A subinterface # A subinterface
[[[HIGHDATARATE]]] [[[High Datarate]]]
# Subinterfaces can be enabled and disabled in of themselves # Subinterfaces can be enabled and disabled in of themselves
interface_enabled = True interface_enabled = True
# Set frequency to 2.4GHz # Set frequency to 2.4GHz
frequency = 2400000000 frequency = 2400000000
# Set LoRa bandwidth to 1625 KHz # Set LoRa bandwidth to 1625 KHz
bandwidth = 1625000 bandwidth = 1625000
# Set TX power to 0 dBm (0.12 mW) # Set TX power to 0 dBm (0.12 mW)
txpower = 0 txpower = 0
# The virtual port, only the manufacturer # The virtual port, only the manufacturer
# or the person who wrote the board config # or the person who wrote the board config
# can tell you what it will be for which # can tell you what it will be for which
# physical hardware interface # physical hardware interface
vport = 1 vport = 1
# Select spreading factor 5. Valid # Select spreading factor 5. Valid
# range is 5 through 12, with 5 # range is 5 through 12, with 5
# being the fastest and 12 having # being the fastest and 12 having
# the longest range. # the longest range.
spreadingfactor = 5 spreadingfactor = 5
# Select coding rate 5. Valid range # Select coding rate 5. Valid range
# is 5 throough 8, with 5 being the # is 5 throough 8, with 5 being the
# fastest, and 8 the longest range. # fastest, and 8 the longest range.
codingrate = 5 codingrate = 5
# It is possible to limit the airtime # It is possible to limit the airtime
# utilisation of an RNode by using the # utilisation of an RNode by using the
# following two configuration options. # following two configuration options.
# The short-term limit is applied in a # The short-term limit is applied in a
# window of approximately 15 seconds, # window of approximately 15 seconds,
# and the long-term limit is enforced # and the long-term limit is enforced
# over a rolling 60 minute window. Both # over a rolling 60 minute window. Both
# options are specified in percent. # options are specified in percent.
# airtime_limit_long = 100 # airtime_limit_long = 100
# airtime_limit_short = 100 # airtime_limit_short = 100
[[[LOWDATARATE]]] [[[Low Datarate]]]
# Subinterfaces can be enabled and disabled in of themselves # Subinterfaces can be enabled and disabled in of themselves
interface_enabled = True interface_enabled = True
# Set frequency to 865.6 MHz # Set frequency to 865.6 MHz
frequency = 865600000 frequency = 865600000
# The virtual port, only the manufacturer # The virtual port, only the manufacturer
# or the person who wrote the board config # or the person who wrote the board config
# can tell you what it will be for which # can tell you what it will be for which
# physical hardware interface # physical hardware interface
vport = 0 vport = 0
# Set LoRa bandwidth to 125 KHz # Set LoRa bandwidth to 125 KHz
bandwidth = 125000 bandwidth = 125000
# Set TX power to 0 dBm (0.12 mW) # Set TX power to 0 dBm (0.12 mW)
txpower = 0 txpower = 0
# Select spreading factor 7. Valid # Select spreading factor 7. Valid
# range is 5 through 12, with 5 # range is 5 through 12, with 5
# being the fastest and 12 having # being the fastest and 12 having
# the longest range. # the longest range.
spreadingfactor = 7 spreadingfactor = 7
# Select coding rate 5. Valid range # Select coding rate 5. Valid range
# is 5 throough 8, with 5 being the # is 5 throough 8, with 5 being the
# fastest, and 8 the longest range. # fastest, and 8 the longest range.
codingrate = 5 codingrate = 5
# It is possible to limit the airtime # It is possible to limit the airtime
# utilisation of an RNode by using the # utilisation of an RNode by using the
# following two configuration options. # following two configuration options.
# The short-term limit is applied in a # The short-term limit is applied in a
# window of approximately 15 seconds, # window of approximately 15 seconds,
# and the long-term limit is enforced # and the long-term limit is enforced
# over a rolling 60 minute window. Both # over a rolling 60 minute window. Both
# options are specified in percent. # options are specified in percent.
# airtime_limit_long = 100 # airtime_limit_long = 100
# airtime_limit_short = 100 # airtime_limit_short = 100
.. _interfaces-serial: .. _interfaces-serial: