mirror of
https://github.com/markqvist/Reticulum.git
synced 2024-11-04 21:30:14 +00:00
Resource transfer and receipt management optimisation
This commit is contained in:
parent
9a00bd2704
commit
be1ff8ec21
@ -55,7 +55,8 @@ def server(configpath, path):
|
||||
|
||||
def announceLoop(destination):
|
||||
# Let the user know that everything is ready
|
||||
RNS.log("File server "+RNS.prettyhexrep(destination.hash)+" running, hit enter to manually send an announce (Ctrl-C to quit)")
|
||||
RNS.log("File server "+RNS.prettyhexrep(destination.hash)+" running")
|
||||
RNS.log("Hit enter to manually send an announce (Ctrl-C to quit)")
|
||||
|
||||
# We enter a loop that runs until the users exits.
|
||||
# If the user hits enter, we will announce our server
|
||||
@ -238,8 +239,9 @@ def download(filename):
|
||||
|
||||
# We just create a packet containing the
|
||||
# requested filename, and send it down the
|
||||
# link.
|
||||
request_packet = RNS.Packet(server_link, filename.encode("utf-8"))
|
||||
# link. We also specify we don't need a
|
||||
# packet receipt.
|
||||
request_packet = RNS.Packet(server_link, filename.encode("utf-8"), create_receipt=False)
|
||||
request_packet.send()
|
||||
|
||||
print("")
|
||||
|
@ -24,32 +24,30 @@ class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
||||
class TCPClientInterface(Interface):
|
||||
|
||||
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None):
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.socket = None
|
||||
self.IN = True
|
||||
self.OUT = False
|
||||
self.socket = None
|
||||
self.parent_interface = None
|
||||
self.name = name
|
||||
|
||||
# TODO: Optimise so this is not needed
|
||||
self.transmit_delay = 0.001
|
||||
self.name = name
|
||||
|
||||
if connected_socket != None:
|
||||
self.receives = True
|
||||
self.target_ip = None
|
||||
self.receives = True
|
||||
self.target_ip = None
|
||||
self.target_port = None
|
||||
self.socket = connected_socket
|
||||
self.socket = connected_socket
|
||||
|
||||
elif target_ip != None and target_port != None:
|
||||
self.receives = True
|
||||
self.target_ip = target_ip
|
||||
self.receives = True
|
||||
self.target_ip = target_ip
|
||||
self.target_port = target_port
|
||||
|
||||
RNS.log("Client init: "+str(self))
|
||||
self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
|
||||
self.socket.connect((self.target_ip, self.target_port))
|
||||
|
||||
self.owner = owner
|
||||
self.online = True
|
||||
self.owner = owner
|
||||
self.online = True
|
||||
self.writing = False
|
||||
|
||||
if connected_socket == None:
|
||||
thread = threading.Thread(target=self.read_loop)
|
||||
@ -61,10 +59,14 @@ class TCPClientInterface(Interface):
|
||||
|
||||
def processOutgoing(self, data):
|
||||
if self.online:
|
||||
while self.writing:
|
||||
time.sleep(0.01)
|
||||
|
||||
try:
|
||||
time.sleep(self.transmit_delay)
|
||||
self.writing = True
|
||||
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
|
||||
self.socket.sendall(data)
|
||||
self.writing = False
|
||||
except Exception as e:
|
||||
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR)
|
||||
RNS.log("The contained exception was: "+str(e), RNS.LOG_ERROR)
|
||||
@ -78,8 +80,7 @@ class TCPClientInterface(Interface):
|
||||
data_buffer = b""
|
||||
|
||||
while True:
|
||||
data_in = self.socket.recv(1024)
|
||||
|
||||
data_in = self.socket.recv(4096)
|
||||
if len(data_in) > 0:
|
||||
pointer = 0
|
||||
while pointer < len(data_in):
|
||||
|
@ -1,3 +1,4 @@
|
||||
import threading
|
||||
import struct
|
||||
import math
|
||||
import time
|
||||
@ -55,7 +56,7 @@ class Packet:
|
||||
# Default packet timeout
|
||||
TIMEOUT = 60
|
||||
|
||||
def __init__(self, destination, data, packet_type = DATA, context = NONE, transport_type = RNS.Transport.BROADCAST, header_type = HEADER_1, transport_id = None, attached_interface = None):
|
||||
def __init__(self, destination, data, packet_type = DATA, context = NONE, transport_type = RNS.Transport.BROADCAST, header_type = HEADER_1, transport_id = None, attached_interface = None, create_receipt = True):
|
||||
if destination != None:
|
||||
if transport_type == None:
|
||||
transport_type = RNS.Transport.BROADCAST
|
||||
@ -65,17 +66,18 @@ class Packet:
|
||||
self.transport_type = transport_type
|
||||
self.context = context
|
||||
|
||||
self.hops = 0;
|
||||
self.hops = 0;
|
||||
self.destination = destination
|
||||
self.transport_id = transport_id
|
||||
self.data = data
|
||||
self.flags = self.getPackedFlags()
|
||||
self.data = data
|
||||
self.flags = self.getPackedFlags()
|
||||
|
||||
self.raw = None
|
||||
self.packed = False
|
||||
self.sent = False
|
||||
self.receipt = None
|
||||
self.fromPacked = False
|
||||
self.raw = None
|
||||
self.packed = False
|
||||
self.sent = False
|
||||
self.create_receipt = create_receipt
|
||||
self.receipt = None
|
||||
self.fromPacked = False
|
||||
else:
|
||||
self.raw = data
|
||||
self.packed = True
|
||||
@ -257,6 +259,7 @@ class PacketReceipt:
|
||||
FAILED = 0x00
|
||||
SENT = 0x01
|
||||
DELIVERED = 0x02
|
||||
CULLED = 0xFF
|
||||
|
||||
|
||||
EXPL_LENGTH = RNS.Identity.HASHLENGTH//8+RNS.Identity.SIGLENGTH//8
|
||||
@ -366,10 +369,18 @@ class PacketReceipt:
|
||||
|
||||
def check_timeout(self):
|
||||
if self.is_timed_out():
|
||||
self.status = PacketReceipt.FAILED
|
||||
if self.timeout == -1:
|
||||
self.status = PacketReceipt.CULLED
|
||||
else:
|
||||
self.status = PacketReceipt.FAILED
|
||||
|
||||
self.concluded_at = time.time()
|
||||
|
||||
if self.callbacks.timeout:
|
||||
self.callbacks.timeout(self)
|
||||
thread = threading.Thread(target=self.callbacks.timeout, args=(self,))
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
#self.callbacks.timeout(self)
|
||||
|
||||
|
||||
# Set the timeout in seconds
|
||||
|
@ -548,8 +548,10 @@ class Resource:
|
||||
if wants_more_hashmap:
|
||||
last_map_hash = request_data[1:Resource.MAPHASH_LEN+1]
|
||||
|
||||
part_index = self.receiver_min_consecutive_height
|
||||
for part in self.parts[self.receiver_min_consecutive_height:]:
|
||||
part_index = self.receiver_min_consecutive_height
|
||||
search_start = part_index
|
||||
search_end = self.receiver_min_consecutive_height+ResourceAdvertisement.COLLISION_GUARD_SIZE
|
||||
for part in self.parts[search_start:search_end]:
|
||||
part_index += 1
|
||||
if part.map_hash == last_map_hash:
|
||||
break
|
||||
|
@ -41,6 +41,7 @@ class Transport:
|
||||
LINK_TIMEOUT = RNS.Link.KEEPALIVE * 2
|
||||
REVERSE_TIMEOUT = 30*60 # Reverse table entries are removed after max 30 minutes
|
||||
DESTINATION_TIMEOUT = 60*60*24*7 # Destination table entries are removed if unused for one week
|
||||
MAX_RECEIPTS = 1024 # Maximum number of receipts to keep track of
|
||||
|
||||
interfaces = [] # All active interfaces
|
||||
destinations = [] # All active destinations
|
||||
@ -49,6 +50,7 @@ class Transport:
|
||||
packet_hashlist = [] # A list of packet hashes for duplicate detection
|
||||
receipts = [] # Receipts of all outgoing packets for proof processing
|
||||
|
||||
# TODO: "destination_table" should really be renamed to "path_table"
|
||||
announce_table = {} # A table for storing announces currently waiting to be retransmitted
|
||||
destination_table = {} # A lookup table containing the next hop to a given destination
|
||||
reverse_table = {} # A lookup table for storing packet hashes used to return proofs and replies
|
||||
@ -154,10 +156,13 @@ class Transport:
|
||||
if not Transport.jobs_locked:
|
||||
# Process receipts list for timed-out packets
|
||||
if time.time() > Transport.receipts_last_checked+Transport.receipts_check_interval:
|
||||
while len(Transport.receipts) > Transport.MAX_RECEIPTS:
|
||||
culled_receipt = Transport.receipts.pop(0)
|
||||
culled_receipt.timeout = -1
|
||||
receipt.check_timeout()
|
||||
|
||||
for receipt in Transport.receipts:
|
||||
thread = threading.Thread(target=receipt.check_timeout)
|
||||
thread.setDaemon(True)
|
||||
thread.start()
|
||||
receipt.check_timeout()
|
||||
if receipt.status != RNS.PacketReceipt.SENT:
|
||||
Transport.receipts.remove(receipt)
|
||||
|
||||
@ -211,11 +216,30 @@ class Transport:
|
||||
if time.time() > link_entry[0] + Transport.LINK_TIMEOUT:
|
||||
Transport.link_table.pop(link_id)
|
||||
|
||||
# Cull the destination table
|
||||
# Cull the path table
|
||||
stale_paths = []
|
||||
for destination_hash in Transport.destination_table:
|
||||
destination_entry = Transport.destination_table[destination_hash]
|
||||
attached_interface = destination_entry[5]
|
||||
|
||||
if time.time() > destination_entry[0] + Transport.DESTINATION_TIMEOUT:
|
||||
Transport.destination_table.pop(destination_hash)
|
||||
stale_paths.append(destination_hash)
|
||||
RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" timed out and was removed", RNS.LOG_DEBUG)
|
||||
|
||||
if not attached_interface in Transport.interfaces:
|
||||
stale_paths.append(destination_hash)
|
||||
RNS.log("Path to "+RNS.prettyhexrep(destination_hash)+" was removed since the attached interface no longer exists", RNS.LOG_DEBUG)
|
||||
|
||||
i = 0
|
||||
for destination_hash in stale_paths:
|
||||
Transport.destination_table.pop(destination_hash)
|
||||
i += 1
|
||||
|
||||
if i > 0:
|
||||
if i == 1:
|
||||
RNS.log("Removed "+str(i)+" path", RNS.LOG_DEBUG)
|
||||
else:
|
||||
RNS.log("Removed "+str(i)+" paths", RNS.LOG_DEBUG)
|
||||
|
||||
Transport.tables_last_culled = time.time()
|
||||
|
||||
@ -266,7 +290,7 @@ class Transport:
|
||||
|
||||
else:
|
||||
# Broadcast packet on all outgoing interfaces, or relevant
|
||||
# interface, if packet is for a link or has an attachede interface
|
||||
# interface, if packet is for a link or has an attached interface
|
||||
for interface in Transport.interfaces:
|
||||
if interface.OUT:
|
||||
should_transmit = True
|
||||
@ -288,7 +312,17 @@ class Transport:
|
||||
packet.sent = True
|
||||
packet.sent_at = time.time()
|
||||
|
||||
if (packet.packet_type == RNS.Packet.DATA and packet.destination.type != RNS.Destination.PLAIN):
|
||||
# Don't generate receipt if it has been explicitly disabled
|
||||
if (packet.create_receipt == True and
|
||||
# Only generate receipts for DATA packets
|
||||
packet.packet_type == RNS.Packet.DATA and
|
||||
# Don't generate receipts for PLAIN destinations
|
||||
packet.destination.type != RNS.Destination.PLAIN and
|
||||
# Don't generate receipts for link-related packets
|
||||
not (packet.context >= RNS.Packet.KEEPALIVE and packet.context <= RNS.Packet.LRPROOF) and
|
||||
# Don't generate receipts for resource packets
|
||||
not (packet.context >= RNS.Packet.RESOURCE and packet.context <= RNS.Packet.RESOURCE_RCL)):
|
||||
|
||||
packet.receipt = RNS.PacketReceipt(packet)
|
||||
Transport.receipts.append(packet.receipt)
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user