-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsephiroth.py
More file actions
141 lines (117 loc) · 3.94 KB
/
sephiroth.py
File metadata and controls
141 lines (117 loc) · 3.94 KB
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
import socket
import select
import errno
import threading
import logging
log = logging.getLogger('sephiroth')
MSG_SEPARATOR = '\n'
log.setLevel(logging.INFO)
# Exceptions for flow control
class WrongUID(Exception):
pass
class EndpointExists(Exception):
pass
class SephirothReadError(Exception):
pass
class STATE:
CONNECTED = '0'
ENDPOINT_EXISTS = '1'
WRONG_UID = '2'
# Read all method to read from socket
def readall(sock, timeout=None):
sock.setblocking(0)
msg = []
read_ready, _, _ = select.select([sock], [], [], timeout)
if sock in read_ready:
while True:
try:
chunk = sock.recv(1)
if not chunk or chunk == MSG_SEPARATOR:
break
msg.append(chunk)
except socket.error as e:
if e.errno != errno.EWOULDBLOCK:
raise SephirothReadError
# No more data
break
return ''.join(msg)
# Endpoint class
# ---------------
class endpoint:
''' Endpoint class '''
def __init__(self, uid, timeout=None):
self.uid = uid
self.alive = False
self.endpoints = []
self.handlers = {'*': []}
self.timeout = timeout
self.sock = socket.socket(
socket.AF_INET, socket.SOCK_STREAM)
self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
def __handle_conn(self, conn, addr):
def handle_thread(conn, addr):
# Check for uid
uid = readall(conn, self.timeout)
if uid in self.endpoints:
log.error('uid exists :(')
conn.sendall(STATE.ENDPOINT_EXISTS)
conn.close()
return
if not uid or uid=='*':
log.error('Wrong uid :(')
conn.sendall(STATE.WRONG_UID)
conn.close()
return
self.endpoints.append(uid)
conn.sendall(STATE.CONNECTED)
log.info('Client %s connected' % uid)
handlers = self.handlers.get(uid, None)
global_handlers = self.handlers.get('*')
while True:
msg = readall(conn, self.timeout)
if not msg: break
if global_handlers:
for fn in global_handlers:
fn(conn, uid, msg)
if handlers:
for fn in handlers:
fn(conn, uid, msg)
else:
# This was added to avoid a possible race condition with
# method add_handler
handlers = self.handlers.get(uid, None)
log.info('Removing %s' % uid)
self.endpoints.remove(uid)
conn.close()
t = threading.Thread(target=handle_thread, args=(conn, addr))
t.start()
return t
def bind(self, host, port):
self.sock.bind((host, port))
self.sock.listen(1)
self.alive = True
while True:
conn, addr = self.sock.accept()
self.__handle_conn(conn, addr)
self.alive = False
def connect(self, host, port):
self.sock.connect((host, port))
self.send(self.uid)
response = readall(self.sock, self.timeout)
if(response == STATE.CONNECTED):
self.alive = True
return
if(response == STATE.ENDPOINT_EXISTS):
raise EndpointExists
if(response == STATE.WRONG_UID):
raise WrongUID
def remove_handler(self, uid, handler):
handlers = self.handlers.get(uid, None)
handlers.remove(handler)
def add_handler(self, uid, handler):
handlers = self.handlers.get(uid, None)
if handlers is None:
handlers = self.handlers[uid] = []
handlers.append(handler)
def send(self, msg):
self.sock.sendall(msg + '\n')