-
Notifications
You must be signed in to change notification settings - Fork 2
/
registry.py
258 lines (228 loc) · 11.3 KB
/
registry.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
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
'''
## Implementation of registry
## 150114822 - Eren Ulaş
'''
from socket import *
import threading
import select
import logging
import db
# This class is used to process the peer messages sent to registry
# for each peer connected to registry, a new client thread is created
class ClientThread(threading.Thread):
# initializations for client thread
def __init__(self, ip, port, tcpClientSocket):
threading.Thread.__init__(self)
# ip of the connected peer
self.ip = ip
# port number of the connected peer
self.port = port
# socket of the peer
self.tcpClientSocket = tcpClientSocket
# username, online status and udp server initializations
self.username = None
self.isOnline = True
self.udpServer = None
print("New thread started for " + ip + ":" + str(port))
# main of the thread
def run(self):
# locks for thread which will be used for thread synchronization
self.lock = threading.Lock()
print("Connection from: " + self.ip + ":" + str(port))
print("IP Connected: " + self.ip)
while True:
try:
# waits for incoming messages from peers
message = self.tcpClientSocket.recv(1024).decode().split()
logging.info("Received from " + self.ip + ":" + str(self.port) + " -> " + " ".join(message))
# JOIN #
if message[0] == "JOIN":
# join-exist is sent to peer,
# if an account with this username already exists
if db.is_account_exist(message[1]):
response = "join-exist"
print("From-> " + self.ip + ":" + str(self.port) + " " + response)
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
# join-success is sent to peer,
# if an account with this username is not exist, and the account is created
else:
db.register(message[1], message[2])
response = "join-success"
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
# LOGIN #
elif message[0] == "LOGIN":
# login-account-not-exist is sent to peer,
# if an account with the username does not exist
if not db.is_account_exist(message[1]):
response = "login-account-not-exist"
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
# login-online is sent to peer,
# if an account with the username already online
elif db.is_account_online(message[1]):
response = "login-online"
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
# login-success is sent to peer,
# if an account with the username exists and not online
else:
# retrieves the account's password, and checks if the one entered by the user is correct
retrievedPass = db.get_password(message[1])
# if password is correct, then peer's thread is added to threads list
# peer is added to db with its username, port number, and ip address
if retrievedPass == message[2]:
self.username = message[1]
self.lock.acquire()
try:
tcpThreads[self.username] = self
finally:
self.lock.release()
db.user_login(message[1], self.ip, message[3])
# login-success is sent to peer,
# and a udp server thread is created for this peer, and thread is started
# timer thread of the udp server is started
response = "login-success"
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
self.udpServer = UDPServer(self.username, self.tcpClientSocket)
self.udpServer.start()
self.udpServer.timer.start()
# if password not matches and then login-wrong-password response is sent
else:
response = "login-wrong-password"
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
# LOGOUT #
elif message[0] == "LOGOUT":
# if user is online,
# removes the user from onlinePeers list
# and removes the thread for this user from tcpThreads
# socket is closed and timer thread of the udp for this
# user is cancelled
if len(message) > 1 and message[1] is not None and db.is_account_online(message[1]):
db.user_logout(message[1])
self.lock.acquire()
try:
if message[1] in tcpThreads:
del tcpThreads[message[1]]
finally:
self.lock.release()
print(self.ip + ":" + str(self.port) + " is logged out")
self.tcpClientSocket.close()
self.udpServer.timer.cancel()
break
else:
self.tcpClientSocket.close()
break
# SEARCH #
elif message[0] == "SEARCH":
# checks if an account with the username exists
if db.is_account_exist(message[1]):
# checks if the account is online
# and sends the related response to peer
if db.is_account_online(message[1]):
peer_info = db.get_peer_ip_port(message[1])
response = "search-success " + peer_info[0] + ":" + peer_info[1]
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
else:
response = "search-user-not-online"
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
# enters if username does not exist
else:
response = "search-user-not-found"
logging.info("Send to " + self.ip + ":" + str(self.port) + " -> " + response)
self.tcpClientSocket.send(response.encode())
except OSError as oErr:
logging.error("OSError: {0}".format(oErr))
# function for resettin the timeout for the udp timer thread
def resetTimeout(self):
self.udpServer.resetTimer()
# implementation of the udp server thread for clients
class UDPServer(threading.Thread):
# udp server thread initializations
def __init__(self, username, clientSocket):
threading.Thread.__init__(self)
self.username = username
# timer thread for the udp server is initialized
self.timer = threading.Timer(3, self.waitHelloMessage)
self.tcpClientSocket = clientSocket
# if hello message is not received before timeout
# then peer is disconnected
def waitHelloMessage(self):
if self.username is not None:
db.user_logout(self.username)
if self.username in tcpThreads:
del tcpThreads[self.username]
self.tcpClientSocket.close()
print("Removed " + self.username + " from online peers")
# resets the timer for udp server
def resetTimer(self):
self.timer.cancel()
self.timer = threading.Timer(3, self.waitHelloMessage)
self.timer.start()
# tcp and udp server port initializations
print("Registy started...")
port = 15600
portUDP = 15500
# db initialization
db = db.DB()
# gets the ip address of this peer
# first checks to get it for windows devices
# if the device that runs this application is not windows
# it checks to get it for macos devices
hostname=gethostname()
try:
host=gethostbyname(hostname)
except gaierror:
import netifaces as ni
host = ni.ifaddresses('en0')[ni.AF_INET][0]['addr']
print("Registry IP address: " + host)
print("Registry port number: " + str(port))
# onlinePeers list for online account
onlinePeers = {}
# accounts list for accounts
accounts = {}
# tcpThreads list for online client's thread
tcpThreads = {}
#tcp and udp socket initializations
tcpSocket = socket(AF_INET, SOCK_STREAM)
udpSocket = socket(AF_INET, SOCK_DGRAM)
tcpSocket.bind((host,port))
udpSocket.bind((host,portUDP))
tcpSocket.listen(5)
# input sockets that are listened
inputs = [tcpSocket, udpSocket]
# log file initialization
logging.basicConfig(filename="registry.log", level=logging.INFO)
# as long as at least a socket exists to listen registry runs
while inputs:
print("Listening for incoming connections...")
# monitors for the incoming connections
readable, writable, exceptional = select.select(inputs, [], [])
for s in readable:
# if the message received comes to the tcp socket
# the connection is accepted and a thread is created for it, and that thread is started
if s is tcpSocket:
tcpClientSocket, addr = tcpSocket.accept()
newThread = ClientThread(addr[0], addr[1], tcpClientSocket)
newThread.start()
# if the message received comes to the udp socket
elif s is udpSocket:
# received the incoming udp message and parses it
message, clientAddress = s.recvfrom(1024)
message = message.decode().split()
# checks if it is a hello message
if message[0] == "HELLO":
# checks if the account that this hello message
# is sent from is online
if message[1] in tcpThreads:
# resets the timeout for that peer since the hello message is received
tcpThreads[message[1]].resetTimeout()
print("Hello is received from " + message[1])
logging.info("Received from " + clientAddress[0] + ":" + str(clientAddress[1]) + " -> " + " ".join(message))
# registry tcp socket is closed
tcpSocket.close()