mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-26 23:40:18 +00:00
Work on announce routing
This commit is contained in:
parent
fe1642664c
commit
6cdbab7e31
@ -208,7 +208,11 @@ class Destination:
|
|||||||
|
|
||||||
signature = self.identity.sign(signed_data)
|
signature = self.identity.sign(signed_data)
|
||||||
|
|
||||||
|
# TODO: Check if this could be optimised by only
|
||||||
|
# carrying the hash in the destination field, not
|
||||||
|
# also redundantly inside the signed blob as here
|
||||||
announce_data = self.hash+self.identity.getPublicKey()+random_hash+signature
|
announce_data = self.hash+self.identity.getPublicKey()+random_hash+signature
|
||||||
|
|
||||||
if app_data != None:
|
if app_data != None:
|
||||||
announce_data += app_data
|
announce_data += app_data
|
||||||
|
|
||||||
|
@ -62,7 +62,6 @@ class Packet:
|
|||||||
self.transport_id = transport_id
|
self.transport_id = transport_id
|
||||||
self.data = data
|
self.data = data
|
||||||
self.flags = self.getPackedFlags()
|
self.flags = self.getPackedFlags()
|
||||||
self.MTU = RNS.Reticulum.MTU
|
|
||||||
|
|
||||||
self.raw = None
|
self.raw = None
|
||||||
self.packed = False
|
self.packed = False
|
||||||
@ -74,6 +73,7 @@ class Packet:
|
|||||||
self.packed = True
|
self.packed = True
|
||||||
self.fromPacked = True
|
self.fromPacked = True
|
||||||
|
|
||||||
|
self.MTU = RNS.Reticulum.MTU
|
||||||
self.sent_at = None
|
self.sent_at = None
|
||||||
self.packet_hash = None
|
self.packet_hash = None
|
||||||
|
|
||||||
@ -120,8 +120,13 @@ class Packet:
|
|||||||
self.ciphertext = self.destination.encrypt(self.data)
|
self.ciphertext = self.destination.encrypt(self.data)
|
||||||
|
|
||||||
if self.header_type == Packet.HEADER_2:
|
if self.header_type == Packet.HEADER_2:
|
||||||
if t_destination != None:
|
if self.transport_id != None:
|
||||||
self.header += self.t_destination
|
self.header += self.transport_id
|
||||||
|
self.header += self.destination.hash
|
||||||
|
|
||||||
|
if self.packet_type == Packet.ANNOUNCE:
|
||||||
|
# Announce packets are not encrypted
|
||||||
|
self.ciphertext = self.data
|
||||||
else:
|
else:
|
||||||
raise IOError("Packet with header type 2 must have a transport ID")
|
raise IOError("Packet with header type 2 must have a transport ID")
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import RNS
|
import RNS
|
||||||
import time
|
import time
|
||||||
|
import math
|
||||||
import threading
|
import threading
|
||||||
import traceback
|
import traceback
|
||||||
from time import sleep
|
from time import sleep
|
||||||
@ -14,6 +15,15 @@ class Transport:
|
|||||||
TUNNEL = 0x03;
|
TUNNEL = 0x03;
|
||||||
types = [BROADCAST, TRANSPORT, RELAY, TUNNEL]
|
types = [BROADCAST, TRANSPORT, RELAY, TUNNEL]
|
||||||
|
|
||||||
|
REACHABILITY_UNREACHABLE = 0x00
|
||||||
|
REACHABILITY_DIRECT = 0x01
|
||||||
|
REACHABILITY_TRANSPORT = 0x02
|
||||||
|
|
||||||
|
PATHFINDER_M = 18 # Max hops
|
||||||
|
PATHFINDER_C = 2.0 # Decay constant
|
||||||
|
PATHFINDER_R = 2 # Retransmit retries
|
||||||
|
PATHFINDER_T = 10 # Retry grace period
|
||||||
|
|
||||||
interfaces = [] # All active interfaces
|
interfaces = [] # All active interfaces
|
||||||
destinations = [] # All active destinations
|
destinations = [] # All active destinations
|
||||||
pending_links = [] # Links that are being established
|
pending_links = [] # Links that are being established
|
||||||
@ -21,11 +31,16 @@ class Transport:
|
|||||||
packet_hashlist = [] # A list of packet hashes for duplicate detection
|
packet_hashlist = [] # A list of packet hashes for duplicate detection
|
||||||
receipts = [] # Receipts of all outgoing packets for proof processing
|
receipts = [] # Receipts of all outgoing packets for proof processing
|
||||||
|
|
||||||
|
announce_table = {}
|
||||||
|
destination_table = {}
|
||||||
|
|
||||||
jobs_locked = False
|
jobs_locked = False
|
||||||
jobs_running = False
|
jobs_running = False
|
||||||
job_interval = 0.250
|
job_interval = 0.250
|
||||||
receipts_last_checked = 0.0
|
receipts_last_checked = 0.0
|
||||||
receipts_check_interval = 1.0
|
receipts_check_interval = 1.0
|
||||||
|
announces_last_checked = 0.0
|
||||||
|
announces_check_interval = 1.0
|
||||||
hashlist_maxsize = 1000000
|
hashlist_maxsize = 1000000
|
||||||
|
|
||||||
identity = None
|
identity = None
|
||||||
@ -68,11 +83,12 @@ class Transport:
|
|||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def jobs():
|
def jobs():
|
||||||
|
outgoing = []
|
||||||
Transport.jobs_running = True
|
Transport.jobs_running = True
|
||||||
try:
|
try:
|
||||||
if not Transport.jobs_locked:
|
if not Transport.jobs_locked:
|
||||||
# Process receipts list for timed-out packets
|
# Process receipts list for timed-out packets
|
||||||
if Transport.receipts_last_checked+Transport.receipts_check_interval < time.time():
|
if time.time() > Transport.receipts_last_checked+Transport.receipts_check_interval:
|
||||||
for receipt in Transport.receipts:
|
for receipt in Transport.receipts:
|
||||||
thread = threading.Thread(target=receipt.check_timeout)
|
thread = threading.Thread(target=receipt.check_timeout)
|
||||||
thread.setDaemon(True)
|
thread.setDaemon(True)
|
||||||
@ -82,6 +98,37 @@ class Transport:
|
|||||||
|
|
||||||
Transport.receipts_last_checked = time.time()
|
Transport.receipts_last_checked = time.time()
|
||||||
|
|
||||||
|
# Process announces needing retransmission
|
||||||
|
if time.time() > Transport.announces_last_checked+Transport.announces_check_interval:
|
||||||
|
for destination_hash in Transport.announce_table:
|
||||||
|
announce_entry = Transport.announce_table[destination_hash]
|
||||||
|
# TODO: remove comment and log output
|
||||||
|
# [time_heard, retransmit_timeout, retries, received_from, packet.hops, packet]
|
||||||
|
# RNS.log("Announce entry retries: "+str(announce_entry[2]), RNS.LOG_INFO)
|
||||||
|
# RNS.log("Max retries: "+str(Transport.PATHFINDER_R), RNS.LOG_INFO)
|
||||||
|
if announce_entry[2] > Transport.PATHFINDER_R:
|
||||||
|
# RNS.log("Removing due to exceeded retries", RNS.LOG_INFO)
|
||||||
|
Transport.announce_table.pop(destination_hash)
|
||||||
|
break
|
||||||
|
else:
|
||||||
|
if time.time() > announce_entry[1]:
|
||||||
|
# RNS.log("Rebroadcasting announce", RNS.LOG_INFO)
|
||||||
|
announce_entry[1] = time.time() + math.pow(Transport.PATHFINDER_C, announce_entry[4]) + Transport.PATHFINDER_T
|
||||||
|
announce_entry[2] += 1
|
||||||
|
packet = announce_entry[5]
|
||||||
|
announce_data = packet.data
|
||||||
|
announce_identity = RNS.Identity.recall(packet.destination_hash)
|
||||||
|
announce_destination = RNS.Destination(announce_identity, RNS.Destination.OUT, RNS.Destination.SINGLE, "unknown", "unknown");
|
||||||
|
announce_destination.hash = packet.destination_hash
|
||||||
|
announce_destination.hexhash = announce_destination.hash.encode("hex_codec")
|
||||||
|
new_packet = RNS.Packet(announce_destination, announce_data, RNS.Packet.ANNOUNCE, header_type = RNS.Packet.HEADER_2, transport_type = Transport.TRANSPORT, transport_id = Transport.identity.hash)
|
||||||
|
new_packet.hops = announce_entry[4]
|
||||||
|
RNS.log("Rebroadcasting announce for "+RNS.prettyhexrep(announce_destination.hash)+" with hop count "+str(new_packet.hops), RNS.LOG_INFO)
|
||||||
|
outgoing.append(new_packet)
|
||||||
|
|
||||||
|
Transport.announces_last_checked = time.time()
|
||||||
|
|
||||||
|
|
||||||
# Cull the packet hashlist if it has reached max size
|
# Cull the packet hashlist if it has reached max size
|
||||||
while (len(Transport.packet_hashlist) > Transport.hashlist_maxsize):
|
while (len(Transport.packet_hashlist) > Transport.hashlist_maxsize):
|
||||||
Transport.packet_hashlist.pop(0)
|
Transport.packet_hashlist.pop(0)
|
||||||
@ -93,6 +140,9 @@ class Transport:
|
|||||||
|
|
||||||
Transport.jobs_running = False
|
Transport.jobs_running = False
|
||||||
|
|
||||||
|
for packet in outgoing:
|
||||||
|
packet.send()
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def outbound(packet):
|
def outbound(packet):
|
||||||
while (Transport.jobs_running):
|
while (Transport.jobs_running):
|
||||||
@ -165,7 +215,33 @@ class Transport:
|
|||||||
|
|
||||||
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
if packet.packet_type == RNS.Packet.ANNOUNCE:
|
||||||
if RNS.Identity.validateAnnounce(packet):
|
if RNS.Identity.validateAnnounce(packet):
|
||||||
Transport.cache(packet)
|
if (packet.transport_id != None):
|
||||||
|
received_from = packet.transport_id
|
||||||
|
|
||||||
|
# Check if this is a next retransmission from
|
||||||
|
# another node. If it is, we're removing the
|
||||||
|
# announcein question from our pending table
|
||||||
|
if packet.destination_hash in Transport.announce_table:
|
||||||
|
announce_entry = Transport.announce_table[packet.destination_hash]
|
||||||
|
if packet.hops == announce_entry[4]+1 and announce_entry[2] > 0:
|
||||||
|
now = time.time()
|
||||||
|
if now < announce_entry[2]:
|
||||||
|
# TODO: Remove
|
||||||
|
RNS.log("Another node retransmitted our transported announce for "+RNS.prettyhexrep(packet.destination_hash)+", removing it from pending table", RNS.LOG_DEBUG)
|
||||||
|
Transport.announce_table.pop(announce_entry)
|
||||||
|
|
||||||
|
else:
|
||||||
|
received_from = packet.destination_hash
|
||||||
|
|
||||||
|
# If the announce has not reached the retransmission
|
||||||
|
# limit, insert it into our pending table
|
||||||
|
packet.hops += 1
|
||||||
|
if (packet.hops < Transport.PATHFINDER_M+1):
|
||||||
|
now = time.time()
|
||||||
|
retransmit_timeout = now + math.pow(Transport.PATHFINDER_C, packet.hops)
|
||||||
|
retries = 0
|
||||||
|
Transport.announce_table[packet.destination_hash] = [now, retransmit_timeout, retries, received_from, packet.hops, packet]
|
||||||
|
Transport.destination_table[packet.destination_hash] = [now, received_from, packet.hops]
|
||||||
|
|
||||||
elif packet.packet_type == RNS.Packet.LINKREQUEST:
|
elif packet.packet_type == RNS.Packet.LINKREQUEST:
|
||||||
for destination in Transport.destinations:
|
for destination in Transport.destinations:
|
||||||
@ -288,6 +364,8 @@ class Transport:
|
|||||||
def cache_request_packet(packet):
|
def cache_request_packet(packet):
|
||||||
if len(packet.data) == RNS.Identity.HASHLENGTH/8:
|
if len(packet.data) == RNS.Identity.HASHLENGTH/8:
|
||||||
packet_hash = RNS.hexrep(packet.data, delimit=False)
|
packet_hash = RNS.hexrep(packet.data, delimit=False)
|
||||||
|
# TODO: There's some pretty obvious file access
|
||||||
|
# issues here. Make sure this can't happen
|
||||||
path = RNS.Reticulum.cachepath+"/"+packet_hash
|
path = RNS.Reticulum.cachepath+"/"+packet_hash
|
||||||
if os.path.isfile(path):
|
if os.path.isfile(path):
|
||||||
file = open(path, "r")
|
file = open(path, "r")
|
||||||
|
Loading…
Reference in New Issue
Block a user