-
Notifications
You must be signed in to change notification settings - Fork 0
/
w-modem.server.py
171 lines (157 loc) · 6.62 KB
/
w-modem.server.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
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import socket
import serversocket
import threading
import math
from EventManager import EventManager
import time
print("NOT DONE!!!")
exit()
class WModem-server():
"""
A class to create a server using the WModem protocall
Args:
host = '127.0.0.1' (str): IP to connect to
port = 7012 (int): port to connect to
key = b''(int): The encryption key to use
"""
def __init__(self, host = '127.0.0.1', port = None, key = b''):
self.version = [0x0,0x01,0x01]
if type(port) != int and (port != None and "://" not in host):
raise ValueError(f"Port must be an int and not a {type(key)} if host is not an URL")
if "://" not in host and len(host.split('.')) != 4:
raise ValueError(f"Host must be an IP or URL")
if type(key) not in [bytes,int]:
raise ValueError(f"Key must be a byte or an int type variable not a {type(key)}")
self.key = bytes(key)
self.version_txt = "WModem Version: "
if self.version[0] == 0x0:
self.version_txt += "dev"
elif self.version[0] == 0x1:
self.version_txt += "alpha"
elif self.version[0] == 0x2:
self.version_txt += "beta"
elif self.version[0] == 0x3:
self.version_txt += "pre-release"
elif self.version[0] == 0x4:
self.version_txt += "release"
self.version_txt += " "+str(int(self.version[1]))
for num in self.version[2:]:
self.version_txt += "."+str(int(num))
if startxt:
print(self.version_txt)
self.events = EventManager()
self.socket = serversocket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.packet_mods = {
"Data": 0x80,
"DtD": 0x81,
"SEA": 0x8C,
"SOP": 0x8D,
"HED": 0x8E,
"EOP": 0x8F
}
self.commands = {
"ACK": 0x86,
"NAK": 0x87,
"ABO": 0x88,
"OCK": 0x89,
"ERR": 0x8A,
"IGN": 0x8B,
"KAC": 0x90,
}
self.busy = False
self.buffer = bytearray() # Use bytearray to accumulate incoming data
self.packet_size = 1024
self.packet_number = 0
self.packet_number_ack = 0
self.packet_number_err = 0
self.ign_count = 0
self.connected = False
self.receive_thread = threading.Thread(target=self.receive_loop, daemon=True)
self.receive_thread = threading.Thread(target=self.keep_alive_loop, daemon=True)
self.receive_thread.start() # Start the background thread for receiving data
def keep_alive_loop(self):
while True:
try:
self.send_packet("KAC","DtD")
time.sleep(1)
for packet in self.buffer:
payload = packet[packet.index(self.packet_mods["SOP"])+1:packet.index(self.packet_mods["EOP"])-2]
t = packet[packet.index(self.packet_mods["HED"])+1]
if t == self.packet_mods["DtD"] and payoad == self.commands["KAC"]:
break
else:
raise ValueError("KAC not responded to")
except Exception as e:
print(f"KAC error: {e}")
def receive_loop(self):
while True:
try:
data = self.socket.recv(self.packet_size)
if not data:
break
self.handle_received_data(data)
except Exception as e:
print(f"Error in receive_loop: {e}")
break
def packet_template(self,type,payload):
checksum = self.calculate_checksum(payload)
length = len(payload)
if type == "Data":
return bytes([self.packet_mods["HED"],self.packet_mods[type],length,self.packet_mods["SOP"],payload,checksum,self.packet_mods["EOP"]])
elif type == "DtD":
if payload in self.packet_mods:
return bytes([self.packet_mods["HED"],self.packet_mods[type],length,self.packet_mods["SOP"],self.packet_mods[payload],checksum,self.packet_mods["EOP"]])
else:
return bytes([self.packet_mods["HED"],self.packet_mods[type],length,self.packet_mods["SOP"],payload,checksum,self.packet_mods["EOP"]])
def send_packet(self, data, packet_type="data"):
self.socket.send(self.packet_template(packet_type,data))
def calculate_checksum(self, data):
checksum = 0
for i in range(len(data)):
checksum += data[i]
return math.mod(checksum, 256)
def handle_received_data(self, data):
payload = data[data.index(self.packet_mods["SOP"])+1:data.index(self.packet_mods["EOP"])-2]
rec_check = data[data.index(self.packet_mods["EOP"])-1].decode()
calc_check = self.calculate_checksum(payload)
if rec_check != calc_check:
self.send_packet("ERR","DtD")
elif rec_check == calc_check:
self.buffer.extend(data) # Append received data to the buffer
def process_buffer(self):
if self.busy:
self.send_packet("OCK", packet_type="data")
return
decoded = []
for i in range(len(self.buffer),0,-1):
payload = i[i.index(self.packet_mods["SOP"])+1:i.index(self.packet_mods["EOP"])-2]
rec_check = i[i.index(self.packet_mods["EOP"])-1].decode()
type = i[i.index(self.packet_mods["HED"])+1]
event = self.buffer[i-1]
if event in self.commands.values():
if self.ign_count > 0:
self.ign_count -= 1
elif event == self.commands["ACK"]:
self.packet_number_ack += 1
self.events.trigger("ACK")
elif event == self.commands["NAK"]:
self.packet_number_err += 1
self.events.trigger("NAK")
elif event == self.commands["ABO"]:
self.packet_number_err += 1
self.events.trigger("ABO")
elif event == self.commands["OCK"]:
self.events.trigger("OCK")
elif event == self.commands["ERR"]:
self.packet_number_err += 1
self.events.trigger("ERR")
elif event == self.commands["IGN"]:
self.ign_count += 1
self.events.trigger("IGN")
decoded.append({"type":type,"payload":payload,"checksum":rec_check})
return decoded
m = WModem("127.0.0.1","1701")
m.events.listen("ACK",lambda: print("ACK"))
while True:
time.sleep(1)
print("waiting...")