Work on BackboneInterface

This commit is contained in:
Mark Qvist 2025-04-06 21:42:54 +02:00
parent b4d1d54ccb
commit df3c2cffb3
2 changed files with 41 additions and 20 deletions

View file

@ -46,6 +46,7 @@ class BackboneInterface(Interface):
DEFAULT_IFAC_SIZE = 16 DEFAULT_IFAC_SIZE = 16
AUTOCONFIGURE_MTU = True AUTOCONFIGURE_MTU = True
epoll = None
listener_filenos = {} listener_filenos = {}
spawned_interface_filenos = {} spawned_interface_filenos = {}
epoll = None epoll = None
@ -130,7 +131,6 @@ class BackboneInterface(Interface):
self.bind_ip = bind_address[0] self.bind_ip = bind_address[0]
self.owner = owner self.owner = owner
if not BackboneInterface.epoll: BackboneInterface.epoll = select.epoll()
self.add_listener(bind_address) self.add_listener(bind_address)
self.bitrate = self.BITRATE_GUESS self.bitrate = self.BITRATE_GUESS
@ -140,16 +140,38 @@ class BackboneInterface(Interface):
else: else:
raise SystemError("Insufficient parameters to create listener") raise SystemError("Insufficient parameters to create listener")
def start(self): @staticmethod
RNS.log(f"Starting {self}") def start():
if not BackboneInterface._job_active: threading.Thread(target=self.__job, daemon=True).start() if not BackboneInterface._job_active: threading.Thread(target=BackboneInterface.__job, daemon=True).start()
@staticmethod
def ensure_epoll():
if not BackboneInterface.epoll: BackboneInterface.epoll = select.epoll()
@staticmethod
def add_client_socket(client_socket, interface):
BackboneInterface.ensure_epoll()
BackboneInterface.spawned_interface_filenos[client_socket.fileno()] = interface
BackboneInterface.epoll.register(client_socket.fileno(), select.EPOLLIN)
@staticmethod
def tx_ready(interface):
if interface.socket:
fileno = interface.socket.fileno()
if fileno in BackboneInterface.spawned_interface_filenos:
try:
BackboneInterface.epoll.modify(interface.socket.fileno(), select.EPOLLOUT)
except Exception as e:
RNS.trace_exception(e)
@staticmethod @staticmethod
def __job(): def __job():
with BackboneInterface._job_lock: with BackboneInterface._job_lock:
if BackboneInterface._job_active: return if BackboneInterface._job_active: return
else: else:
RNS.log(f"Starting BackboneInterface I/O handler") # TODO: Remove debug
BackboneInterface._job_active = True BackboneInterface._job_active = True
BackboneInterface.ensure_epoll()
try: try:
while True: while True:
events = BackboneInterface.epoll.poll(1) events = BackboneInterface.epoll.poll(1)
@ -181,7 +203,8 @@ class BackboneInterface(Interface):
spawned_interface.transmit_buffer = spawned_interface.transmit_buffer[written:] spawned_interface.transmit_buffer = spawned_interface.transmit_buffer[written:]
if len(spawned_interface.transmit_buffer) == 0: BackboneInterface.epoll.modify(fileno, select.EPOLLIN) if len(spawned_interface.transmit_buffer) == 0: BackboneInterface.epoll.modify(fileno, select.EPOLLIN)
spawned_interface.parent_interface.txb += written; spawned_interface.txb += written spawned_interface.txb += written
if spawned_interface.parent_interface: spawned_interface.parent_interface.txb += written
elif fileno == client_socket.fileno() and event & (select.EPOLLHUP): elif fileno == client_socket.fileno() and event & (select.EPOLLHUP):
BackboneInterface.epoll.unregister(fileno) BackboneInterface.epoll.unregister(fileno)
@ -194,10 +217,8 @@ class BackboneInterface(Interface):
if fileno == server_socket.fileno() and (event & select.EPOLLIN): if fileno == server_socket.fileno() and (event & select.EPOLLIN):
client_socket, address = server_socket.accept() client_socket, address = server_socket.accept()
client_socket.setblocking(0) client_socket.setblocking(0)
if owner_interface.incoming_connection(client_socket): if owner_interface.incoming_connection(client_socket): pass
BackboneInterface.epoll.register(client_socket.fileno(), select.EPOLLIN) else: client_socket.close()
else:
client_socket.close()
elif fileno == server_socket.fileno() and (event & select.EPOLLHUP): elif fileno == server_socket.fileno() and (event & select.EPOLLHUP):
try: BackboneInterface.epoll.unregister(fileno) try: BackboneInterface.epoll.unregister(fileno)
@ -217,7 +238,6 @@ class BackboneInterface(Interface):
serversocket.close() serversocket.close()
BackboneInterface.listener_filenos.clear() BackboneInterface.listener_filenos.clear()
BackboneInterface.epoll.close()
def add_listener(self, bind_address, socket_type=socket.AF_INET): def add_listener(self, bind_address, socket_type=socket.AF_INET):
if socket_type == socket.AF_INET: if socket_type == socket.AF_INET:
@ -271,11 +291,11 @@ class BackboneInterface(Interface):
spawned_interface.mode = self.mode spawned_interface.mode = self.mode
spawned_interface.HW_MTU = self.HW_MTU spawned_interface.HW_MTU = self.HW_MTU
spawned_interface.online = True spawned_interface.online = True
RNS.log("Spawned new BackBoneClient Interface: "+str(spawned_interface), RNS.LOG_VERBOSE) RNS.log("Spawned new BackboneClient Interface: "+str(spawned_interface), RNS.LOG_VERBOSE)
RNS.Transport.interfaces.append(spawned_interface) RNS.Transport.interfaces.append(spawned_interface)
while spawned_interface in self.spawned_interfaces: self.spawned_interfaces.remove(spawned_interface) while spawned_interface in self.spawned_interfaces: self.spawned_interfaces.remove(spawned_interface)
self.spawned_interfaces.append(spawned_interface) self.spawned_interfaces.append(spawned_interface)
self.spawned_interface_filenos[socket.fileno()] = spawned_interface BackboneInterface.add_client_socket(client_socket, spawned_interface)
return True return True
@ -393,9 +413,6 @@ class BackboneClientInterface(Interface):
thread.daemon = True thread.daemon = True
thread.start() thread.start()
else: else:
thread = threading.Thread(target=self.read_loop)
thread.daemon = True
thread.start()
self.wants_tunnel = True self.wants_tunnel = True
def set_timeouts_linux(self): def set_timeouts_linux(self):
@ -440,6 +457,10 @@ class BackboneClientInterface(Interface):
self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1) self.socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
self.socket.connect(target_address) self.socket.connect(target_address)
self.socket.settimeout(None) self.socket.settimeout(None)
BackboneInterface.add_client_socket(self.socket, self)
BackboneInterface.start()
self.online = True self.online = True
if initial: if initial:
@ -485,9 +506,6 @@ class BackboneClientInterface(Interface):
RNS.log("Reconnected socket for "+str(self)+".", RNS.LOG_INFO) RNS.log("Reconnected socket for "+str(self)+".", RNS.LOG_INFO)
self.reconnecting = False self.reconnecting = False
thread = threading.Thread(target=self.read_loop)
thread.daemon = True
thread.start()
RNS.Transport.synthesize_tunnel(self) RNS.Transport.synthesize_tunnel(self)
else: else:
@ -506,8 +524,7 @@ class BackboneClientInterface(Interface):
if self.online and not self.detached: if self.online and not self.detached:
try: try:
self.transmit_buffer += bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG]) self.transmit_buffer += bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
if hasattr(self, "parent_interface") and self.parent_interface != None: BackboneInterface.tx_ready(self)
self.parent_interface.epoll.modify(self.socket.fileno(), select.EPOLLOUT)
except Exception as e: except Exception as e:
RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR) RNS.log("Exception occurred while transmitting via "+str(self)+", tearing down interface", RNS.LOG_ERROR)

View file

@ -667,6 +667,10 @@ class Reticulum:
interface = BackboneInterface.BackboneInterface(RNS.Transport, interface_config) interface = BackboneInterface.BackboneInterface(RNS.Transport, interface_config)
interface_post_init(interface) interface_post_init(interface)
if c["type"] == "BackboneClientInterface":
interface = BackboneInterface.BackboneClientInterface(RNS.Transport, interface_config)
interface_post_init(interface)
if c["type"] == "UDPInterface": if c["type"] == "UDPInterface":
interface = UDPInterface.UDPInterface(RNS.Transport, interface_config) interface = UDPInterface.UDPInterface(RNS.Transport, interface_config)
interface_post_init(interface) interface_post_init(interface)