mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-26 15:30:18 +00:00
Implemented loop detection for pathfinding and congestionn avoidance for announce rebroadcasts.
This commit is contained in:
parent
64c30488c2
commit
8e19d5bd97
@ -19,12 +19,19 @@ class Transport:
|
|||||||
REACHABILITY_DIRECT = 0x01
|
REACHABILITY_DIRECT = 0x01
|
||||||
REACHABILITY_TRANSPORT = 0x02
|
REACHABILITY_TRANSPORT = 0x02
|
||||||
|
|
||||||
|
# TODO: Document the addition of random windows
|
||||||
|
# and max local rebroadcasts.
|
||||||
PATHFINDER_M = 18 # Max hops
|
PATHFINDER_M = 18 # Max hops
|
||||||
PATHFINDER_C = 2.0 # Decay constant
|
PATHFINDER_C = 2.0 # Decay constant
|
||||||
PATHFINDER_R = 2 # Retransmit retries
|
PATHFINDER_R = 2 # Retransmit retries
|
||||||
PATHFINDER_T = 10 # Retry grace period
|
PATHFINDER_T = 10 # Retry grace period
|
||||||
|
PATHFINDER_RW = 10 # Random window for announce rebroadcast
|
||||||
PATHFINDER_E = 60*15 # Path expiration in seconds
|
PATHFINDER_E = 60*15 # Path expiration in seconds
|
||||||
|
|
||||||
|
# TODO: Calculate an optimal number for this in
|
||||||
|
# various situations
|
||||||
|
LOCAL_REBROADCASTS_MAX = 2 # How many local rebroadcasts of an announce is allowed
|
||||||
|
|
||||||
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
|
||||||
@ -32,8 +39,8 @@ 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 = {}
|
announce_table = {} # A table for storing announces currently waiting to be retransmitted
|
||||||
destination_table = {}
|
destination_table = {} # A lookup table containing the next hop to a given destination
|
||||||
|
|
||||||
jobs_locked = False
|
jobs_locked = False
|
||||||
jobs_running = False
|
jobs_running = False
|
||||||
@ -113,8 +120,7 @@ class Transport:
|
|||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
if time.time() > announce_entry[1]:
|
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 + Transport.PATHFINDER_RW
|
||||||
announce_entry[1] = time.time() + math.pow(Transport.PATHFINDER_C, announce_entry[4]) + Transport.PATHFINDER_T
|
|
||||||
announce_entry[2] += 1
|
announce_entry[2] += 1
|
||||||
packet = announce_entry[5]
|
packet = announce_entry[5]
|
||||||
announce_data = packet.data
|
announce_data = packet.data
|
||||||
@ -221,12 +227,21 @@ class Transport:
|
|||||||
|
|
||||||
# Check if this is a next retransmission from
|
# Check if this is a next retransmission from
|
||||||
# another node. If it is, we're removing the
|
# another node. If it is, we're removing the
|
||||||
# announcein question from our pending table
|
# announce in question from our pending table
|
||||||
if packet.destination_hash in Transport.announce_table:
|
if packet.destination_hash in Transport.announce_table:
|
||||||
announce_entry = Transport.announce_table[packet.destination_hash]
|
announce_entry = Transport.announce_table[packet.destination_hash]
|
||||||
|
|
||||||
|
if packet.hops == announce_entry[4]:
|
||||||
|
RNS.log("Heard a local rebroadcast of announce for "+RNS.prettyhexrep(packet.destination_hash), RNS.LOG_DEBUG)
|
||||||
|
announce_entry[6] += 1
|
||||||
|
if announce_entry[6] >= Transport.LOCAL_REBROADCASTS_MAX:
|
||||||
|
RNS.log("Max local rebroadcasts of announce for "+RNS.prettyhexrep(packet.destination_hash)+" reached, dropping announce from our table", RNS.LOG_DEBUG)
|
||||||
|
Transport.announce_table.pop(packet.destination_hash)
|
||||||
|
|
||||||
if packet.hops == announce_entry[4]+1 and announce_entry[2] > 0:
|
if packet.hops == announce_entry[4]+1 and announce_entry[2] > 0:
|
||||||
now = time.time()
|
now = time.time()
|
||||||
if now < announce_entry[1]:
|
if now < announce_entry[1]:
|
||||||
|
RNS.log("Rebroadcasted announce for "+RNS.prettyhexrep(packet.destination_hash)+" has been passed on to next node, no further tries needed", RNS.LOG_DEBUG)
|
||||||
Transport.announce_table.pop(packet.destination_hash)
|
Transport.announce_table.pop(packet.destination_hash)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
@ -236,20 +251,42 @@ class Transport:
|
|||||||
# announce and destination tables
|
# announce and destination tables
|
||||||
should_add = False
|
should_add = False
|
||||||
packet.hops += 1
|
packet.hops += 1
|
||||||
|
# First, check that the announce is not for a destination
|
||||||
|
# local to this system, and that hops are less than the max
|
||||||
if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1):
|
if (not any(packet.destination_hash == d.hash for d in Transport.destinations) and packet.hops < Transport.PATHFINDER_M+1):
|
||||||
|
random_blob = packet.data[RNS.Identity.DERKEYSIZE/8+10:RNS.Identity.DERKEYSIZE/8+20]
|
||||||
|
random_blobs = []
|
||||||
if packet.destination_hash in Transport.destination_table:
|
if packet.destination_hash in Transport.destination_table:
|
||||||
|
random_blobs = Transport.destination_table[packet.destination_hash][4]
|
||||||
|
|
||||||
|
# If we already have a path to the announced
|
||||||
|
# destination, but the hop count is equal or
|
||||||
|
# less, we'll update our tables.
|
||||||
if packet.hops <= Transport.destination_table[packet.destination_hash][2]:
|
if packet.hops <= Transport.destination_table[packet.destination_hash][2]:
|
||||||
# If we already have a path to the announced
|
# Make sure we haven't heard the random
|
||||||
# destination, but the hop count is equal or
|
# blob before, so announces can't be
|
||||||
# less, we'll update our tables.
|
# replayed to forge paths.
|
||||||
should_add = True
|
# TODO: Check whether this approach works
|
||||||
|
# under all circumstances
|
||||||
|
if not random_blob in random_blobs:
|
||||||
|
should_add = True
|
||||||
|
else:
|
||||||
|
should_add = False
|
||||||
else:
|
else:
|
||||||
# If an announce arrives with a larger hop
|
# If an announce arrives with a larger hop
|
||||||
# count than we already have in the table,
|
# count than we already have in the table,
|
||||||
# ignore it, unless the path is expired
|
# ignore it, unless the path is expired
|
||||||
if (time.time() < Transport.destination_table[packet.destination_hash][3]):
|
if (time.time() > Transport.destination_table[packet.destination_hash][3]):
|
||||||
RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce due to expired path", RNS.LOG_DEBUG)
|
# We also check that the announce hash is
|
||||||
should_add = True
|
# different from ones we've already heard,
|
||||||
|
# to avoid loops in the network
|
||||||
|
if not random_blob in random_blobs:
|
||||||
|
# TODO: Check that this ^ approach actually
|
||||||
|
# works under all circumstances
|
||||||
|
RNS.log("Replacing destination table entry for "+str(RNS.prettyhexrep(packet.destination_hash))+" with new announce due to expired path", RNS.LOG_DEBUG)
|
||||||
|
should_add = True
|
||||||
|
else:
|
||||||
|
should_add = False
|
||||||
else:
|
else:
|
||||||
should_add = False
|
should_add = False
|
||||||
else:
|
else:
|
||||||
@ -261,9 +298,11 @@ class Transport:
|
|||||||
now = time.time()
|
now = time.time()
|
||||||
retries = 0
|
retries = 0
|
||||||
expires = now + Transport.PATHFINDER_E
|
expires = now + Transport.PATHFINDER_E
|
||||||
retransmit_timeout = now + math.pow(Transport.PATHFINDER_C, packet.hops)
|
local_rebroadcasts = 0
|
||||||
Transport.announce_table[packet.destination_hash] = [now, retransmit_timeout, retries, received_from, packet.hops, packet]
|
random_blobs.append(random_blob)
|
||||||
Transport.destination_table[packet.destination_hash] = [now, received_from, packet.hops, expires]
|
retransmit_timeout = now + math.pow(Transport.PATHFINDER_C, packet.hops) + (RNS.rand() * Transport.PATHFINDER_RW)
|
||||||
|
Transport.announce_table[packet.destination_hash] = [now, retransmit_timeout, retries, received_from, packet.hops, packet, local_rebroadcasts]
|
||||||
|
Transport.destination_table[packet.destination_hash] = [now, received_from, packet.hops, expires, random_blobs]
|
||||||
|
|
||||||
elif packet.packet_type == RNS.Packet.LINKREQUEST:
|
elif packet.packet_type == RNS.Packet.LINKREQUEST:
|
||||||
for destination in Transport.destinations:
|
for destination in Transport.destinations:
|
||||||
|
@ -2,6 +2,7 @@ import os
|
|||||||
import sys
|
import sys
|
||||||
import glob
|
import glob
|
||||||
import time
|
import time
|
||||||
|
import random
|
||||||
|
|
||||||
from .Reticulum import Reticulum
|
from .Reticulum import Reticulum
|
||||||
from .Identity import Identity
|
from .Identity import Identity
|
||||||
@ -32,6 +33,8 @@ logfile = None
|
|||||||
logdest = LOG_STDOUT
|
logdest = LOG_STDOUT
|
||||||
logtimefmt = "%Y-%m-%d %H:%M:%S"
|
logtimefmt = "%Y-%m-%d %H:%M:%S"
|
||||||
|
|
||||||
|
random.seed(os.urandom(10))
|
||||||
|
|
||||||
def loglevelname(level):
|
def loglevelname(level):
|
||||||
if (level == LOG_CRITICAL):
|
if (level == LOG_CRITICAL):
|
||||||
return "Critical"
|
return "Critical"
|
||||||
@ -66,6 +69,10 @@ def log(msg, level=3):
|
|||||||
file.write(logstring+"\n")
|
file.write(logstring+"\n")
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
def rand():
|
||||||
|
result = random.random()
|
||||||
|
return result
|
||||||
|
|
||||||
def hexprint(data):
|
def hexprint(data):
|
||||||
print(hexrep(hexrep))
|
print(hexrep(hexrep))
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user