-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.py
92 lines (82 loc) · 2.83 KB
/
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
import json
import socket
import threading
import time
import rumps
import prefs
# if we lose beacons from a host for this long, remove it from the list
HOST_TIMEOUT = 20
class Server:
def __init__(
self,
port=prefs.DEFAULT_PORT,
cb=lambda _: print("no callback"),
sh=lambda _: print("no set hosts"),
pw="insecure",
):
self.port = int(port)
self.cb = cb
self.sh = sh
self.pw = pw
self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.server_socket.settimeout(5)
self.beacon_timer = rumps.Timer(lambda _: self.beacon(), 3)
self.beacon_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
self.beacon_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
self.status = [False]
self.hosts = dict()
def start(self):
self.beacon_timer.start()
self.server_socket.bind(("0.0.0.0", self.port))
self.status[0] = True
self.server_thread = threading.Thread(
target=self.loop,
args=(
self.status,
self.hosts,
),
)
self.server_thread.start()
def loop(self, status, hosts):
while True:
if status[0] is False:
break
try:
msg_raw, (ip, pt) = self.server_socket.recvfrom(256)
try:
# TODO: decrypt the encoded payload using self.pw
msg = json.loads(msg_raw)
except json.JSONDecodeError:
continue
# disallow choosing this host from the list and sending messages to itself
# if msg["from"] == socket.gethostname():
# continue
if msg["to"] == "*":
hosts[msg["from"]] = time.time()
continue
if msg["to"] == socket.gethostname():
threading.Thread(target=self.cb, args=(msg,)).start()
except socket.timeout:
pass
def beacon(self):
"""sends a json message to the broadcast address"""
for host in list(self.hosts):
if time.time() - HOST_TIMEOUT > self.hosts[host]:
self.hosts.pop(host)
self.sh(self.hosts)
self.send("*", "none")
def send(self, host: str, key: str):
msg = json.dumps(
{
"from": socket.gethostname(),
"to": host,
"key": key,
}
).encode()
# TODO: encrypt the encoded payload using self.pw
self.beacon_socket.sendto(msg, ("255.255.255.255", self.port))
def stop(self):
self.beacon_timer.stop()
self.status[0] = False
self.server_thread.join()
self.server_socket.close()