Added KISS framing option to TCP client interface

This commit is contained in:
Mark Qvist 2021-12-06 13:07:12 +01:00
parent 8fe7c19c59
commit 2e4fcc659c
2 changed files with 80 additions and 22 deletions

View File

@ -19,6 +19,20 @@ class HDLC():
data = data.replace(bytes([HDLC.FLAG]), bytes([HDLC.ESC, HDLC.FLAG^HDLC.ESC_MASK])) data = data.replace(bytes([HDLC.FLAG]), bytes([HDLC.ESC, HDLC.FLAG^HDLC.ESC_MASK]))
return data return data
class KISS():
FEND = 0xC0
FESC = 0xDB
TFEND = 0xDC
TFESC = 0xDD
CMD_DATA = 0x00
CMD_UNKNOWN = 0xFE
@staticmethod
def escape(data):
data = data.replace(bytes([0xdb]), bytes([0xdb, 0xdd]))
data = data.replace(bytes([0xc0]), bytes([0xdb, 0xdc]))
return data
class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer): class ThreadingTCPServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
pass pass
@ -32,7 +46,7 @@ class TCPClientInterface(Interface):
TCP_PROBE_INTERVAL = 3 TCP_PROBE_INTERVAL = 3
TCP_PROBES = 5 TCP_PROBES = 5
def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None): def __init__(self, owner, name, target_ip=None, target_port=None, connected_socket=None, max_reconnect_tries=None, kiss_framing=False):
self.rxb = 0 self.rxb = 0
self.txb = 0 self.txb = 0
@ -48,6 +62,7 @@ class TCPClientInterface(Interface):
self.writing = False self.writing = False
self.online = False self.online = False
self.detached = False self.detached = False
self.kiss_framing = kiss_framing
if max_reconnect_tries == None: if max_reconnect_tries == None:
self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES self.max_reconnect_tries = TCPClientInterface.RECONNECT_MAX_TRIES
@ -79,7 +94,8 @@ class TCPClientInterface(Interface):
thread = threading.Thread(target=self.read_loop) thread = threading.Thread(target=self.read_loop)
thread.setDaemon(True) thread.setDaemon(True)
thread.start() thread.start()
self.wants_tunnel = True if not self.kiss_framing:
self.wants_tunnel = True
def set_timeouts_linux(self): def set_timeouts_linux(self):
@ -172,7 +188,8 @@ class TCPClientInterface(Interface):
thread = threading.Thread(target=self.read_loop) thread = threading.Thread(target=self.read_loop)
thread.setDaemon(True) thread.setDaemon(True)
thread.start() thread.start()
RNS.Transport.synthesize_tunnel(self) if not self.kiss_framing:
RNS.Transport.synthesize_tunnel(self)
else: else:
RNS.log("Attempt to reconnect on a non-initiator TCP interface. This should not happen.", RNS.LOG_ERROR) RNS.log("Attempt to reconnect on a non-initiator TCP interface. This should not happen.", RNS.LOG_ERROR)
@ -192,7 +209,12 @@ class TCPClientInterface(Interface):
try: try:
self.writing = True self.writing = True
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
if self.kiss_framing:
data = bytes([KISS.FEND])+bytes([KISS.CMD_DATA])+KISS.escape(data)+bytes([KISS.FEND])
else:
data = bytes([HDLC.FLAG])+HDLC.escape(data)+bytes([HDLC.FLAG])
self.socket.sendall(data) self.socket.sendall(data)
self.writing = False self.writing = False
self.txb += len(data) self.txb += len(data)
@ -210,6 +232,7 @@ class TCPClientInterface(Interface):
in_frame = False in_frame = False
escape = False escape = False
data_buffer = b"" data_buffer = b""
command = KISS.CMD_UNKNOWN
while True: while True:
data_in = self.socket.recv(4096) data_in = self.socket.recv(4096)
@ -218,23 +241,53 @@ class TCPClientInterface(Interface):
while pointer < len(data_in): while pointer < len(data_in):
byte = data_in[pointer] byte = data_in[pointer]
pointer += 1 pointer += 1
if (in_frame and byte == HDLC.FLAG):
in_frame = False if self.kiss_framing:
self.processIncoming(data_buffer) # Read loop for KISS framing
elif (byte == HDLC.FLAG): if (in_frame and byte == KISS.FEND and command == KISS.CMD_DATA):
in_frame = True in_frame = False
data_buffer = b"" self.processIncoming(data_buffer)
elif (in_frame and len(data_buffer) < RNS.Reticulum.MTU): elif (byte == KISS.FEND):
if (byte == HDLC.ESC): in_frame = True
escape = True command = KISS.CMD_UNKNOWN
else: data_buffer = b""
if (escape): elif (in_frame and len(data_buffer) < RNS.Reticulum.MTU):
if (byte == HDLC.FLAG ^ HDLC.ESC_MASK): if (len(data_buffer) == 0 and command == KISS.CMD_UNKNOWN):
byte = HDLC.FLAG # We only support one HDLC port for now, so
if (byte == HDLC.ESC ^ HDLC.ESC_MASK): # strip off the port nibble
byte = HDLC.ESC byte = byte & 0x0F
escape = False command = byte
data_buffer = data_buffer+bytes([byte]) elif (command == KISS.CMD_DATA):
if (byte == KISS.FESC):
escape = True
else:
if (escape):
if (byte == KISS.TFEND):
byte = KISS.FEND
if (byte == KISS.TFESC):
byte = KISS.FESC
escape = False
data_buffer = data_buffer+bytes([byte])
else:
# Read loop for HDLC framing
if (in_frame and byte == HDLC.FLAG):
in_frame = False
self.processIncoming(data_buffer)
elif (byte == HDLC.FLAG):
in_frame = True
data_buffer = b""
elif (in_frame and len(data_buffer) < RNS.Reticulum.MTU):
if (byte == HDLC.ESC):
escape = True
else:
if (escape):
if (byte == HDLC.FLAG ^ HDLC.ESC_MASK):
byte = HDLC.FLAG
if (byte == HDLC.ESC ^ HDLC.ESC_MASK):
byte = HDLC.ESC
escape = False
data_buffer = data_buffer+bytes([byte])
else: else:
self.online = False self.online = False
if self.initiator and not self.detached: if self.initiator and not self.detached:

View File

@ -333,11 +333,16 @@ class Reticulum:
if c["type"] == "TCPClientInterface": if c["type"] == "TCPClientInterface":
kiss_framing = False
if "kiss_framing" in c and c.as_bool("kiss_framing") == True:
kiss_framing = True
interface = TCPInterface.TCPClientInterface( interface = TCPInterface.TCPClientInterface(
RNS.Transport, RNS.Transport,
name, name,
c["target_host"], c["target_host"],
int(c["target_port"]) int(c["target_port"]),
kiss_framing = kiss_framing
) )
if "outgoing" in c and c.as_bool("outgoing") == True: if "outgoing" in c and c.as_bool("outgoing") == True: