This repository has been archived by the owner on Sep 15, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
connection.py
81 lines (74 loc) · 3.07 KB
/
connection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import logging
class Connection:
def __init__(self, sock, address, name, events, context):
self.sock = sock
self.address = address
self.name = name
self.events = events
self.context = context
self.interceptor = None
self.redirect_conn = None
self.out_bytes = b''
self.in_bytes = b''
self.init_status = False
def parse_length(self, length_bytes):
return int.from_bytes(length_bytes, 'big')
def encode_length(self, length):
return length.to_bytes(4, byteorder='big')
def received(self, in_bytes):
self.in_bytes += in_bytes
# Read packet from byte array while there are enough bytes to make up a packet.
# Otherwise wait for more bytes to be received (break and exit)
error_count = 0
while True:
ptype = self.in_bytes[0:1]
if ptype == b'\x00':
if len(self.in_bytes) < 4:
break
header_length = 4
body_length = self.parse_length(self.in_bytes[0:4]) - 4
elif ptype == b'N':
header_length = 1
body_length = 0
elif ptype == b'S':
if len(self.in_bytes) < 5:
if self.init_status == False:
logging.error("SSL connections are not supported")
# TODO: implement polite backoff (currently crashes)
break
header_length = 5
body_length = self.parse_length(self.in_bytes[1:5]) - 4
else:
if len(self.in_bytes) < 5:
break
header_length = 5
body_length = self.parse_length(self.in_bytes[1:5]) - 4
length = header_length + body_length
if len(self.in_bytes) < length:
break
header = self.in_bytes[0:header_length]
body = self.in_bytes[header_length:length]
if self.process_inbound_packet(header, body) == False:
error_count += 1
if error_count > 100:
break
else:
error_count = 0
self.in_bytes = self.in_bytes[length:]
self.init_status = True
def process_inbound_packet(self, header, body):
message_nonempty = True
if header != b'N':
packet_type = header[0:-4]
if not packet_type:
logging.warning(f"malformed message from {self.name}")
message_nonempty = False
logging.info("intercepting packet of type '%s' from %s", packet_type, self.name)
body = self.interceptor.intercept(packet_type, body)
header = packet_type + self.encode_length(len(body) + 4)
message = header + body
logging.debug("Received message. Relaying. Speaker: %s, message:\n%s", self.name, message)
self.redirect_conn.out_bytes += message
return message_nonempty
def sent(self, num_bytes):
self.out_bytes = self.out_bytes[num_bytes:]