-
Notifications
You must be signed in to change notification settings - Fork 0
/
server.py
120 lines (89 loc) · 3.99 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
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
import socket
import select
import base64
import os
from cryptography.fernet import Fernet
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives.kdf.pbkdf2 import PBKDF2HMAC
password = b"abhilash"
salt = os.urandom(16)
kdf = PBKDF2HMAC(
algorithm=hashes.SHA512(),
length=32,
salt=salt,
iterations=100000,
backend=default_backend()
)
key = base64.urlsafe_b64encode(kdf.derive(password))
f = Fernet(key)
print(key)
HEADER_LENGTH = 10
IP = "127.0.0.1"
PORT = 1234
server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server_socket.bind((IP, PORT))
server_socket.listen()
sockets_list = [server_socket]
clients = {}
print(f'Listening for connections on {IP}:{PORT}...')
def receive_message(client_socket):
try:
message_header = client_socket.recv(HEADER_LENGTH)
if not len(message_header):
return False
message_length = int(message_header.decode('utf-8').strip())
return {'header': message_header, 'data': client_socket.recv(message_length)}
except:
return False
while True:
read_sockets, _, exception_sockets = select.select(sockets_list, [], sockets_list)
# Iterate over notified sockets
for notified_socket in read_sockets:
# If notified socket is a server socket - new connection, accept it
if notified_socket == server_socket:
# Accept new connection
# That gives us new socket - client socket, connected to this given client only, it's unique for that client
# The other returned object is ip/port set
client_socket, client_address = server_socket.accept()
# Client should send his name right away, receive it
user = receive_message(client_socket)
client_socket.sendall(key)
print("key sent")
# If False - client disconnected before he sent his name
if user is False:
continue
# Add accepted socket to select.select() list
sockets_list.append(client_socket)
# Also save username and username header
clients[client_socket] = user
print('Accepted new connection from {}:{}, username: {}'.format(*client_address, user['data'].decode('utf-8')))
# Else existing socket is sending a message
else:
# Receive message
message = receive_message(notified_socket)
# If False, client disconnected, cleanup
if message is False:
print('Closed connection from: {}'.format(clients[notified_socket]['data'].decode('utf-8')))
# Remove from list for socket.socket()
sockets_list.remove(notified_socket)
# Remove from our list of users
del clients[notified_socket]
continue
# Get user by notified socket, so we will know who sent the message
user = clients[notified_socket]
print(f'Received message from {user["data"].decode("utf-8")}: {message["data"].decode("utf-8")}')
# Iterate over connected clients and broadcast message
for client_socket in clients:
# But don't sent it to sender
if client_socket != notified_socket:
# Send user and message (both with their headers)
# We are reusing here message header sent by sender, and saved username header send by user when he connected
client_socket.send(user['header'] + user['data'] + message['header'] + message['data'])
# It's not really necessary to have this, but will handle some socket exceptions just in case
for notified_socket in exception_sockets:
# Remove from list for socket.socket()
sockets_list.remove(notified_socket)
# Remove from our list of users
del clients[notified_socket]