mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-05 13:50:14 +00:00
149 lines
5.4 KiB
Python
Executable File
149 lines
5.4 KiB
Python
Executable File
# MIT License
|
|
#
|
|
# Copyright (c) 2016-2022 Mark Qvist / unsigned.io
|
|
#
|
|
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
# of this software and associated documentation files (the "Software"), to deal
|
|
# in the Software without restriction, including without limitation the rights
|
|
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
# copies of the Software, and to permit persons to whom the Software is
|
|
# furnished to do so, subject to the following conditions:
|
|
#
|
|
# The above copyright notice and this permission notice shall be included in all
|
|
# copies or substantial portions of the Software.
|
|
#
|
|
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
# SOFTWARE.
|
|
|
|
import RNS
|
|
import time
|
|
import threading
|
|
from collections import deque
|
|
|
|
class Interface:
|
|
IN = False
|
|
OUT = False
|
|
FWD = False
|
|
RPT = False
|
|
name = None
|
|
|
|
# Interface mode definitions
|
|
MODE_FULL = 0x01
|
|
MODE_POINT_TO_POINT = 0x02
|
|
MODE_ACCESS_POINT = 0x03
|
|
MODE_ROAMING = 0x04
|
|
MODE_BOUNDARY = 0x05
|
|
MODE_GATEWAY = 0x06
|
|
|
|
# Which interface modes a Transport Node
|
|
# should actively discover paths for.
|
|
DISCOVER_PATHS_FOR = [MODE_ACCESS_POINT, MODE_GATEWAY]
|
|
|
|
# How many samples to use for incoming
|
|
# announce frequency calculation
|
|
IA_FREQ_SAMPLES = 6
|
|
OA_FREQ_SAMPLES = 6
|
|
|
|
def __init__(self):
|
|
self.rxb = 0
|
|
self.txb = 0
|
|
self.online = False
|
|
self.ia_freq_deque = deque(maxlen=Interface.IA_FREQ_SAMPLES)
|
|
self.oa_freq_deque = deque(maxlen=Interface.OA_FREQ_SAMPLES)
|
|
|
|
def get_hash(self):
|
|
return RNS.Identity.full_hash(str(self).encode("utf-8"))
|
|
|
|
def received_announce(self):
|
|
self.ia_freq_deque.append(time.time())
|
|
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
|
self.parent_interface.received_announce(from_spawned=True)
|
|
|
|
def sent_announce(self):
|
|
self.oa_freq_deque.append(time.time())
|
|
if hasattr(self, "parent_interface") and self.parent_interface != None:
|
|
self.parent_interface.sent_announce(from_spawned=True)
|
|
|
|
def incoming_announce_frequency(self):
|
|
if not len(self.ia_freq_deque) > 1:
|
|
return 0
|
|
else:
|
|
dq_len = len(self.ia_freq_deque)
|
|
delta_sum = 0
|
|
for i in range(1,dq_len):
|
|
delta_sum += self.ia_freq_deque[i]-self.ia_freq_deque[i-1]
|
|
delta_sum += time.time() - self.ia_freq_deque[dq_len-1]
|
|
|
|
if delta_sum == 0:
|
|
avg = 0
|
|
else:
|
|
avg = 1/(delta_sum/(dq_len))
|
|
|
|
return avg
|
|
|
|
def outgoing_announce_frequency(self):
|
|
if not len(self.oa_freq_deque) > 1:
|
|
return 0
|
|
else:
|
|
dq_len = len(self.oa_freq_deque)
|
|
delta_sum = 0
|
|
for i in range(1,dq_len):
|
|
delta_sum += self.oa_freq_deque[i]-self.oa_freq_deque[i-1]
|
|
delta_sum += time.time() - self.oa_freq_deque[dq_len-1]
|
|
|
|
if delta_sum == 0:
|
|
avg = 0
|
|
else:
|
|
avg = 1/(delta_sum/(dq_len))
|
|
|
|
return avg
|
|
|
|
def process_announce_queue(self):
|
|
if not hasattr(self, "announce_cap"):
|
|
self.announce_cap = RNS.Reticulum.ANNOUNCE_CAP
|
|
|
|
if hasattr(self, "announce_queue"):
|
|
try:
|
|
now = time.time()
|
|
stale = []
|
|
for a in self.announce_queue:
|
|
if now > a["time"]+RNS.Reticulum.QUEUED_ANNOUNCE_LIFE:
|
|
stale.append(a)
|
|
|
|
for s in stale:
|
|
if s in self.announce_queue:
|
|
self.announce_queue.remove(s)
|
|
|
|
if len(self.announce_queue) > 0:
|
|
min_hops = min(entry["hops"] for entry in self.announce_queue)
|
|
entries = list(filter(lambda e: e["hops"] == min_hops, self.announce_queue))
|
|
entries.sort(key=lambda e: e["time"])
|
|
selected = entries[0]
|
|
|
|
now = time.time()
|
|
tx_time = (len(selected["raw"])*8) / self.bitrate
|
|
wait_time = (tx_time / self.announce_cap)
|
|
self.announce_allowed_at = now + wait_time
|
|
|
|
self.processOutgoing(selected["raw"])
|
|
self.sent_announce()
|
|
|
|
if selected in self.announce_queue:
|
|
self.announce_queue.remove(selected)
|
|
|
|
if len(self.announce_queue) > 0:
|
|
timer = threading.Timer(wait_time, self.process_announce_queue)
|
|
timer.start()
|
|
|
|
except Exception as e:
|
|
self.announce_queue = []
|
|
RNS.log("Error while processing announce queue on "+str(self)+". The contained exception was: "+str(e), RNS.LOG_ERROR)
|
|
RNS.log("The announce queue for this interface has been cleared.", RNS.LOG_ERROR)
|
|
|
|
def detach(self):
|
|
pass |