def login(username): while True: # username = input("Username: "******"Connection closed1.") return False password = getpass("Password: "******"Connection closed2.") return False response = m2proto.recv(client) if not response: print("Connection closed3.") return False elif response[0] == 10: print("Login successful.") return True elif response[0] == 12: print("New user registered.") return True elif response[0] == 11: print("Login failed.") else: print(f"Unexpected message type: {response[0]}") return False
def receive_login(connection, client_commonName): while True: if client_commonName: print(client_commonName) username_msg = m2proto.recv(connection) if not username_msg or username_msg[0] != 8: return None print(username_msg[1]) if(username_msg[1] != client_commonName): return None else: print("Client's username is verified against certificate's common name..!!") else: username_msg = m2proto.recv(connection) if not username_msg or username_msg[0] != 8: return None password_msg = m2proto.recv(connection) if not password_msg or password_msg[0] != 9: return None result = check_user_credentials_in_auth_thread(auth_queue, username_msg[1], password_msg[1]) if result == 10 or result == 12: m2proto.send(connection, result) print(username_msg[1]) return username_msg[1] else: m2proto.send(connection, 11)
def send_file(fd): with fd: b = fd.read(4096) while b: time.sleep(1.0) # just to simulate slow file transfer with client_lock: m2proto.send(client, 4, b) b = fd.read(4096) m2proto.send(client, 18) ui.add_output(None, "Finished sending file.")
def receive(): global file_to_send prefix = None file_sender = None file_to_receive = None response = m2proto.recv(client) while response is not None: # receive and print responses from the server (can be many) (msg_type, payload) = response if msg_type == 13: prefix = payload elif msg_type == 0: ui.add_output(prefix, payload) prefix = None elif msg_type == 14: file_sender = payload elif msg_type == 15: incoming_filename = payload try: file_to_receive = open(incoming_filename, "xb") except: # likely either FileExistsError or PermissionError, but we don't really care ui.add_output( None, "Unable to receive file from " + file_sender + ": " + incoming_filename) file_sender = None file_to_receive = None with client_lock: m2proto.send(client, 17) else: with client_lock: m2proto.send(client, 16) ui.add_output( None, "Receiving file from " + file_sender + ": " + incoming_filename) elif msg_type == 4: file_to_receive.write(payload) elif msg_type == 18: file_to_receive.close() ui.add_output(None, "Finished receiving file.") elif msg_type == 16: ui.add_output(None, "Sending file...") with client_lock: fd = file_to_send file_to_send = None Thread(target=send_file, daemon=True, args=(fd, )).start() elif msg_type == 17: ui.add_output(None, "Cannot send file.") with client_lock: if file_to_send is not None: file_to_send.close() file_to_send = None response = m2proto.recv(client) ui.send_exit_signals()
def handle_command(command): global file_to_send parts = command.split() if len(parts) == 1 and (parts[0] == "q" or parts[0] == "quit"): raise KeyboardInterrupt elif len(parts) == 3 and parts[0] == "send": recipient = parts[1] filename = parts[2] try: fd = open(filename, "rb") except PermissionError: ui.add_output(None, "Cannot open file.") else: file_to_send = fd m2proto.send(client, 14, recipient) m2proto.send(client, 15, filename) else: ui.add_output(None, "Unrecognized command.")
def test_send_error_with_partial_payload(self): socket = FakeWritableSocket(4) self.assertFalse(m2proto.send(socket, 0, 'abcde'))
def test_send_error_after_second_byte(self): socket = FakeWritableSocket(2) self.assertFalse(m2proto.send(socket, 0, 'abcde'))
def test_send_error(self): socket = FakeWritableSocket(0) self.assertFalse(m2proto.send(socket, 0, 'abcde'))
def __test_send(self, type, payload, expected_data): socket = FakeWritableSocket() self.assertTrue(m2proto.send(socket, type, payload)) self.assertEqual(socket.fake_data(), expected_data)
def __test_send_raises(self, type, payload, expected_exception): socket = FakeWritableSocket() with self.assertRaises(expected_exception): m2proto.send(socket, type, payload) self.assertEqual(socket.fake_data(), b'')
file_to_send = fd m2proto.send(client, 14, recipient) m2proto.send(client, 15, filename) else: ui.add_output(None, "Unrecognized command.") try: if login(username): with ChatUI() as ui: receive_thread = Thread(target=receive, daemon=True) receive_thread.start() # start the receive thread message = ui.get_input() # get input from user while message is not None: with client_lock: if message[0] == "/": handle_command(message[1:]) elif not m2proto.send( client, 0, message): # send msgs from user to the server break message = ui.get_input() except KeyboardInterrupt: pass finally: try: client.shutdown(socket.SHUT_RDWR) client.close() except: pass
def client_thread(connection, address, threadNumber, client_commonName): global file_transfer_source_connection, file_transfer_target_connection try: if not client_commonName: username = receive_login(connection, '') else: print("Client's commonName : " + client_commonName) username = receive_login(connection, client_commonName) if username is not None: with clients_lock: clients[threadNumber] = (connection, username) while True: data = m2proto.recv(connection) if data is not None: (msg_type, payload) = data if msg_type == 0: print(f"From connected Client {address}): " + str(payload)) with clients_lock: # broadcast msg to all clients for target_connection, target_username in clients.values(): m2proto.send(target_connection, 13, username) m2proto.send(target_connection, 0, payload) elif msg_type == 14: with clients_lock: if file_transfer_source_connection is None: file_transfer_source_connection = connection file_transfer_target_connection = None for target_connection, target_username in clients.values(): if payload == target_username: file_transfer_target_connection = target_connection break if file_transfer_target_connection is None: file_transfer_source_connection = None elif msg_type == 15: with clients_lock: if file_transfer_source_connection != connection or file_transfer_target_connection is None: m2proto.send(connection, 17) else: m2proto.send(file_transfer_target_connection, 14, username) m2proto.send(file_transfer_target_connection, 15, payload) elif msg_type == 16: with clients_lock: if file_transfer_target_connection == connection: m2proto.send(file_transfer_source_connection, 16) elif msg_type == 17: with clients_lock: if file_transfer_target_connection == connection: m2proto.send(file_transfer_source_connection, 17) file_transfer_source_connection = None file_transfer_target_connection = None elif msg_type == 18: with clients_lock: if file_transfer_source_connection == connection: m2proto.send(file_transfer_target_connection, 18) file_transfer_source_connection = None file_transfer_target_connection = None elif msg_type == 4: with clients_lock: if file_transfer_source_connection == connection: m2proto.send(file_transfer_target_connection, 4, payload) else: break finally: with clients_lock: try: del clients[threadNumber] connection.shutdown(socket.SHUT_RDWR) connection.close() except: pass