def __forward_packet(self, ip_sender: str, ip_source: str, ttl: str, packet: str) -> None: """ Forward a packet in the net to neighbours :param ip_sender: ip address of sender host :param ttl: packet time to live :param packet: string representing the packet :return: None """ new_ttl = int(ttl) - 1 if new_ttl > 0: ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_source) # get the recipients list without the peer who sent the packet and the peer who forwarded it recipients = LocalData.get_super_friends_recipients(ip_sender, ip4_peer, ip6_peer) packet = packet[:80] + str(new_ttl).zfill(2) + packet[82:] for superfriend in recipients: ip4 = LocalData.get_super_friend_ip4(superfriend) ip6 = LocalData.get_super_friend_ip6(superfriend) port = LocalData.get_super_friend_port(superfriend) try: net_utils.send_packet_and_close(ip4, ip6, port, packet) self.log.write_blue(f'Forwarding to {ip4}|{ip6} [{port}] -> ', end='') self.log.write(f'{packet}') except socket.error as e: self.log.write_red(f'Unable to forward a packet to {ip4}|{ip6} [{port}]: {e}')
def __forward_packet(self, ip_sender: str, ip_source: str, ttl: str, packet: str) -> None: """ Forward a packet in the net to neighbours :param ip_sender: ip address of sender host :param ttl: packet time to live :param packet: string representing the packet :return: None """ new_ttl = int(ttl) - 1 if new_ttl > 0: ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_source) # get the recipients list without the peer who sent the packet recipients = AppData.get_neighbours_recipients( ip_sender, ip4_peer, ip6_peer) packet = packet[:80] + str(new_ttl).zfill(2) + packet[82:] for peer in recipients: self.__unicast(AppData.get_peer_ip4(peer), AppData.get_peer_ip6(peer), AppData.get_peer_port(peer), packet)
def run(self): tracker_ip4 = LocalData.get_tracker_ip4() tracker_ip6 = LocalData.get_tracker_ip6() tracker_port = LocalData.get_tracker_port() session_id = LocalData.get_session_id() while not self.__stop_event.is_set(): try: packet = 'FCHU' + session_id + self.file_md5 sock = self.__connect(tracker_ip4, tracker_ip6, tracker_port, packet) except socket.error as e: self.log.write_red( f'\nImpossible to send data to {tracker_ip4}|{tracker_ip6} [{tracker_port}]: {e}\n' ) break ack = sock.recv(4).decode() if ack != "AFCH": self.log.write_red( f'\nInvalid command received: {ack}. Expected: AFCH\n') sock.close() break num_hitpeer = int(sock.recv(3).decode()) part_list_table = list() for i in range(num_hitpeer): (hitpeer_ip4, hitpeer_ip6) = net_utils.get_ip_pair(sock.recv(55).decode()) hitpeer_port = sock.recv(5).decode() part_list = sock.recv(self.part_list_length) # Adding only other peers to the part list table regarding the file of interest if hitpeer_ip4 != net_utils.get_local_ipv4( ) and hitpeer_ip6 != net_utils.get_local_ipv6(): part_list_table.append( ((hitpeer_ip4, hitpeer_ip6, hitpeer_port), bytearray(part_list))) LocalData.set_part_list_table(part_list_table) self.log.write(f'\nPart list table for ', end='') self.log.write_yellow(f'{self.file_md5} ', end='') self.log.write(f'updated: ', end='') self.log.write_green(f'{len(part_list_table)} ', end='') self.log.write(f'sources added:') for source in part_list_table: self.log.write_blue( f'{source[0][0]}|{source[0][1]} [{source[0][2]}]') self.log.write('') LocalData.update_downloadable_parts() self.log.write_blue(f'Downloadable parts:') for part_num in LocalData.get_downloadable_parts(): self.log.write(f'{str(part_num)}, ', end='') self.log.write('') self.update_event.set() time.sleep(60)
def serve(self, sd: socket.socket) -> None: """ Handle the peer request :param sd: the socket descriptor used for read the request :return None """ try: response = sd.recv(300).decode() except socket.error as e: shell.print_red(f'Unable to read the response from the socket: {e}\n') sd.close() return sd.close() command = response[0:4] if command == "AQUE": if len(response) != 212: shell.print_red(f"Invalid response: : {command} -> {response}. Expected: AQUE<pkt_id><ip_peer><port_peer><file_md5><filename>") return pktid = response[4:20] ip_peer = response[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[75:80]) file_md5 = response[80:112] filename = response[112:212].lstrip().rstrip() if pktid != LocalData.get_sent_menu_quer_packet(): return if not LocalData.exist_menu_peer_file(ip4_peer, ip6_peer, port_peer, file_md5, filename): LocalData.add_menu_peer_file(ip4_peer, ip6_peer, port_peer, file_md5, filename) index = LocalData.menu_peer_file_index(ip4_peer, ip6_peer, port_peer, file_md5, filename) print(f'{index +1}] ', end='') print(f'{filename} ', end='') shell.print_yellow(f'md5={file_md5} ', end='') print(f'({ip4_peer}|{ip6_peer} [{port_peer}])') elif command == "ASUP": if len(response) != 80: shell.print_red(f"Invalid response: : {command} -> {response}. Expected: ASUP<pkt_id><ip_peer><port_peer>") return pktid = response[4:20] ip_peer = response[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[75:80]) if pktid != LocalData.get_sent_supe_packet(): return if not LocalData.is_super_friend(ip4_peer, ip6_peer, port_peer): LocalData.add_super_friend(ip4_peer, ip6_peer, port_peer) shell.print_green('New superfriend found: ', end='') print(f'{ip4_peer}|{ip6_peer} [{port_peer}]') else: shell.print_red(f"\nInvalid response: {command} -> {response}\n") return
def serve(self, choice: str) -> None: """ Handle the peer packet :param choice: the choice to handle :return: None """ if choice == "SUPE": # SUPE[4B].Packet_Id[16B].IP_Peer[55B].Port_Peer[5B].TTL[2B] pktid = str(uuid.uuid4().hex[:16].upper()) ip = net_utils.get_local_ip_for_response() port = net_utils.get_asup_port() ttl = '04' packet = choice + pktid + ip + str(port).zfill(5) + ttl LocalData.set_sent_supe_packet(pktid) old_superfriends_len = len(LocalData.get_super_friends()) server = ServerThread(port, MenuTimedResponseHandler()) server.daemon = True server.start() spinner = SpinnerThread('Searching superpeers (ENTER to continue)', 'Research done! (ENTER to continue)') spinner.start() timer = Timer(20, lambda: (spinner.stop(), server.stop())) timer.start() self.__broadcast(packet) input() print('\033[1A', end='\r') if timer.is_alive(): spinner.stop() spinner.join() timer.cancel() timer.join() server.stop() server.join() else: spinner.join() timer.join() server.join() if len(LocalData.get_super_friends()) == old_superfriends_len: shell.print_yellow('\nNo new superpeer found.\n') elif choice == "ADFF": if not os.path.exists('shared'): shell.print_red('\nCannot find the shared folder.') return dir_file = list() if not os.scandir('shared'): shell.print_yellow('\nNo file in the shared folder.') return for count, dir_entry in enumerate(os.scandir('shared'), 1): dir_file.append((dir_entry.name, hasher.get_md5(dir_entry.path), dir_entry.stat().st_size)) print(f'\n{count}) {dir_entry.name}', end='') shell.print_yellow(f' {hasher.get_md5(dir_entry.path)}', end='') print(f' size: {dir_entry.stat().st_size}') while True: index = input('\nPlease select a file to share(pres q to exit): ') if index == 'q': print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue if 0 <= index <= count - 1: chosen_file = dir_file.pop(index) filename = LocalData.get_shared_filename(chosen_file) filemd5 = LocalData.get_shared_filemd5(chosen_file) filedim = LocalData.get_shared_dim(chosen_file) if not LocalData.exist_shared_file(filename, filemd5, filedim): LocalData.add_shared_file(filename, filemd5, filedim) shell.print_green('\nThe file is now shared.') else: shell.print_yellow('\nThe file is already shared.') break else: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue elif choice == "DEFF": if not LocalData.get_shared_files(): shell.print_yellow('\nNo file in sharing.') return for count, file in enumerate(LocalData.get_shared_files(), 1): print(f'\n{count}) {LocalData.get_shared_filename(file)}', end='') shell.print_yellow(f' {LocalData.get_shared_filemd5(file)}', end='') print(f' size: {LocalData.get_shared_dim(file)}') while True: index = input('\nPlease select a file to delete from sharing(pres q to exit): ') if index == 'q': print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue if 0 <= index <= count - 1: deleted_file = LocalData.get_shared_file_by_index(index) shell.print_blue(f'\n{LocalData.get_shared_filename(deleted_file)}', end='') shell.print_yellow(f' {LocalData.get_shared_filemd5(deleted_file)}', end='') shell.print_blue(' removed from sharing.') break else: shell.print_red(f'\nWrong index: number in range 1 - {count} expected.') continue elif choice == "QUER": while True: search = input('\nEnter the file name: ') if search != '*': search = '%' + search + '%' if not 0 < len(search) <= 20: shell.print_red('\nFile name must be between 1 and 20 chars long.\n') continue break # Read matching files from DB try: conn = database.get_connection(db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: shell.print_red(f'\nError while getting connection from database: {e}') return try: total_db_file = file_repository.get_files_count_by_querystring(conn, search) if total_db_file == 0: shell.print_yellow('\nNo matching results from your peers.\n') else: shell.print_green('\nFiles from your logged peers:\n') file_rows = file_repository.get_files_by_querystring(conn, search) # print('\nFile from peers: ') for file_row in file_rows: file_md5 = file_row['file_md5'] file_name = file_row['file_name'] owner_rows = peer_repository.get_peers_by_file(conn, file_md5) for owner_row in owner_rows: owner_ip = owner_row['ip'] owner_port = int(owner_row['port']) ip4_peer, ip6_peer = net_utils.get_ip_pair(owner_ip) # stampa di debug # print(f'\n{LocalData.menu_peer_file_index(ip4_peer, ip6_peer, peer.port, file.file_md5, file.file_name)}', end='') # shell.print_yellow(f' {file.file_md5}', end='') # print(f' {file.file_name} from {ip4_peer|ip6_peer} on port {peer.port}') LocalData.add_menu_peer_file(ip4_peer, ip6_peer, owner_port, file_md5, file_name) index = LocalData.menu_peer_file_index(ip4_peer, ip6_peer, owner_port, file_md5, file_name) print(f'{index +1}] ', end='') print(f'{file_name} ', end='') shell.print_yellow(f'md5={file_md5} ', end='') print(f'({ip4_peer}|{ip6_peer} [{owner_port}])') conn.commit() conn.close() except database.Error as e: conn.rollback() conn.close() LocalData.clear_menu_peer_files() shell.print_red(f'\nError while retrieving data from database: {e}') # Send a search for a file on the superpeer network shell.print_green('\nFiles from the network:\n') pktid = str(uuid.uuid4().hex[:16].upper()) ip = net_utils.get_local_ip_for_response() port = net_utils.get_aque_port() ttl = '05' packet = choice + pktid + ip + str(port).zfill(5) + ttl + search.ljust(20) LocalData.set_sent_menu_quer_packet(pktid) server = ServerThread(port, MenuTimedResponseHandler()) server.daemon = True server.start() spinner = SpinnerThread('Searching files (ENTER to continue)', 'Research done! (ENTER to continue)') spinner.start() timer = Timer(20, lambda: (spinner.stop(), server.stop())) timer.start() self.__broadcast(packet) input() print('\033[1A', end='\r') if timer.is_alive(): spinner.stop() spinner.join() timer.cancel() timer.join() server.stop() server.join() else: spinner.join() timer.join() server.join() # Retrieving the list of database's files and superpeer network's files peer_files = LocalData.get_menu_peer_files() if len(peer_files) == total_db_file: shell.print_yellow('\nNo matching results from the superpeer network.\n') if len(peer_files) < 1: shell.print_yellow('\nNo file matching the keyword.\n') return while True: index = input('\nPlease select a file to download: ') if index == 'q': print('\n') LocalData.clear_menu_peer_files() return try: index = int(index) - 1 except ValueError: shell.print_red(f'\nWrong index: number in range 1 - {len(peer_files)} expected.') continue if 0 <= index <= len(peer_files): chosen_peer_file = LocalData.get_menu_peer_file_by_index(index) host_ip4 = LocalData.get_menu_file_owner_ip4(chosen_peer_file) host_ip6 = LocalData.get_menu_file_owner_ip6(chosen_peer_file) host_port = LocalData.get_menu_file_owner_port(chosen_peer_file) file_md5 = LocalData.get_menu_file_md5(chosen_peer_file) file_name = LocalData.get_menu_file_name(chosen_peer_file) # preparo packet per retr, faccio partire server in attesa download, invio packet e attendo packet = 'RETR' + file_md5 try: Downloader(host_ip4, host_ip6, host_port, packet, file_name).start() shell.print_green(f'\nDownload of {file_name} completed.\n') LocalData.clear_menu_peer_files() except OSError: shell.print_red(f'\nError while downloading {file_name}\n') break else: shell.print_red(f'\nWrong index: number in range 1 - {len(peer_files)} expected.') continue elif choice == "LISTSUPERPEERS": shell.print_green('\nList of known superpeers:') if not LocalData.get_super_friends(): shell.print_red('You do not know any superpeers.') else: for count, friend in enumerate(LocalData.get_super_friends(), 1): friend_ip4 = LocalData.get_super_friend_ip4(friend) friend_ip6 = LocalData.get_super_friend_ip6(friend) friend_port = LocalData.get_super_friend_port(friend) shell.print_blue(f'{count}] {friend_ip4} {friend_ip6} {str(friend_port)}') elif choice == "LISTPEERS": try: conn = database.get_connection(db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return try: peer_list = peer_repository.find_all(conn) if not peer_list: shell.print_red('You do not know any peers.') conn.close() return else: shell.print_green('\nList of known peers:') for count, peer_row in enumerate(peer_list, 1): shell.print_blue(f'{count}]' + peer_row['ip'] + peer_row['port'] + '\n') except database.Error as e: conn.rollback() conn.close() print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return elif choice == "LISTFILES": try: conn = database.get_connection(db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return try: files = file_repository.find_all(conn) shell.print_green('\nYour shared files:') if not LocalData.get_shared_files(): shell.print_red('You do not have shared files.') for count, shared_file in enumerate(LocalData.get_shared_files(), 1): print(f'{count}] {LocalData.get_shared_filename(shared_file)} ', end='') shell.print_yellow(f'{LocalData.get_shared_filemd5(shared_file)}\n') shell.print_green('\nLogged peers files:') if not files: shell.print_red('You do not have logged peers files.') conn.close() return for count, file_row in enumerate(files, 1): print(f'{count}] {file_row["file_name"]} ', end='') shell.print_yellow(f'{file_row["file_md5"]}') except database.Error as e: conn.rollback() conn.close() print(f'Error: {e}') print('The server has encountered an error while trying to serve the request.') return else: pass
def serve(self, sd: socket.socket) -> None: """ Handle the peer request :param sd: the socket descriptor used for read the request :return None """ try: command = sd.recv(4).decode() except OSError as e: shell_colors.print_red( f'\nUnable to read the command from the socket: {e}\n') sd.close() return if command == "AQUE": try: response = sd.recv(300).decode() except socket.error as e: shell_colors.print_red( f'\nUnable to read the {command} response from the socket: {e}\n' ) sd.close() return sd.close() if len(response) != 208: print( f"\nInvalid response: {command} -> {response}. Expected: AQUE<pkt_id><ip_peer><port_peer><fileMD5><filename>\n" ) return pktid = response[0:16] ip_peer = response[16:71] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[71:76]) filemd5 = response[76:108] filename = response[108:208].lower().lstrip().rstrip() if pktid != AppData.get_sent_packet(): sd.close() return if not AppData.exist_peer_files(ip4_peer, ip6_peer, port_peer, filemd5, filename): AppData.add_peer_files(ip4_peer, ip6_peer, port_peer, filemd5, filename) index = AppData.peer_file_index(ip4_peer, ip6_peer, port_peer, filemd5, filename) print(f'{index +1}] ', end='') shell_colors.print_blue(f'{filename} ', end='') shell_colors.print_yellow(f'md5={filemd5} ', end='') print(f'({ip4_peer}|{ip6_peer} [{port_peer}])') elif command == "ANEA": try: response = sd.recv(300).decode() except socket.error as e: shell_colors.print_red( f'\nUnable to read the {command} response from the socket: {e}\n' ) sd.close() return sd.close() if len(response) != 76: shell_colors.print_red( f"\nInvalid response: : {command} -> {response}. Expected: ANEA<pkt_id><ip_peer><port_peer>" ) return pktid = response[0:16] ip_peer = response[16:71] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(response[71:76]) if pktid != AppData.get_sent_packet(): return if len(AppData.get_neighbours()) >= 5: return if not AppData.is_neighbour(ip4_peer, ip6_peer, port_peer): AppData.add_neighbour(ip4_peer, ip6_peer, port_peer) shell_colors.print_green('New neighbour found: ', end='') print(f'{ip4_peer}|{ip6_peer} [{port_peer}]') else: wrong_response = sd.recv(300).decode() sd.close() shell_colors.print_red( f"\nInvalid response: {command} -> {wrong_response}\n") return
def serve(self, sd: socket.socket) -> None: """ Handle a network packet :param sd: the socket descriptor used for read the packet :return: None """ try: packet = sd.recv(200).decode() except socket.error as e: self.log.write_red(f'Unable to read the packet from the socket: {e}') sd.close() return # log the packet received socket_ip_sender = sd.getpeername()[0] if ipaddress.IPv6Address(socket_ip_sender).ipv4_mapped is None: socket_ip_sender = ipaddress.IPv6Address(socket_ip_sender).compressed else: socket_ip_sender = ipaddress.IPv6Address(socket_ip_sender).ipv4_mapped.compressed socket_port_sender = sd.getpeername()[1] self.log.write_green(f'{socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write(f'{packet}') command = packet[:4] if command == "SUPE": sd.close() if len(packet) != 82: self.log.write_red(f'Invalid packet received: {packet}\nUnable to reply.') return pktid = packet[4:20] ip_peer = packet[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(packet[75:80]) ttl = packet[80:82] # packet management if pktid == LocalData.get_sent_supe_packet(): # if the SUPE i sent has been forwarded to me erroneously return if not LocalData.exist_in_received_packets(pktid): LocalData.add_received_packet(pktid, ip_peer, port_peer) t = Timer(20, function=self.__delete_packet, args=(pktid,)) t.start() else: return # send the NEAR acknowledge response = "ASUP" + pktid + net_utils.get_local_ip_for_response() +\ str(net_utils.get_network_port()).zfill(5) try: net_utils.send_packet_and_close(ip4_peer, ip6_peer, port_peer, response) self.log.write_blue(f'Sending to {ip4_peer}|{ip6_peer} [{port_peer}] -> ', end='') self.log.write(f'{response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending an {response} to {ip4_peer}|{ip6_peer} [{port_peer}]: {e}') # forwarding the packet to other superpeers self.__forward_packet(socket_ip_sender, ip_peer, ttl, packet) elif command == "LOGI": error_response = "ALGI" + '0' * 16 if len(packet) != 64: self.log.write_red(f'Invalid packet received: {packet}') try: sd.send(error_response.encode()) sd.close() self.log.write_blue(f'Sending to {socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write(f'{error_response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending an ALGI response to {socket_ip_sender}: {e}') return return ip = packet[4:59] port = packet[59:64] try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: self.log.write_red(f'An error has occurred while trying to serve the request: {e}') try: sd.send(error_response.encode()) sd.close() self.log.write_blue(f'Sending to {socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write(f'{error_response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending {error_response} to {socket_ip_sender}: {e}') return return try: peer = peer_repository.find_by_ip(conn, ip) # if the peer didn't already logged in if peer is None: session_id = str(uuid.uuid4().hex[:16].upper()) peer = peer_repository.find(conn, session_id) # while the generated session_id exists while peer is not None: session_id = str(uuid.uuid4().hex[:16].upper()) peer = peer_repository.find(conn, session_id) peer = Peer(session_id, ip, port) peer.insert(conn) conn.commit() conn.close() except database.Error as e: conn.rollback() conn.close() self.log.write_red(f'An error has occurred while trying to serve the request: {e}') try: sd.send(error_response.encode()) sd.close() self.log.write_blue(f'Sending to {socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write(f'{error_response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending {error_response} to {socket_ip_sender}: {e}') return return response = "ALGI" + peer.session_id try: sd.send(response.encode()) sd.close() self.log.write_blue(f'Sending to {socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write(f'{response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending {response} to {socket_ip_sender}: {e}') return elif command == "ADFF": sd.close() if len(packet) != 152: self.log.write_red(f'Invalid packet received: {packet}\nUnable to add the file in the DB.') return session_id = packet[4:20] md5 = packet[20:52] name = packet[52:152].lower().lstrip().rstrip() try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: self.log.write_red(f'An error has occurred while trying to serve the request: {e}') return try: peer = peer_repository.find(conn, session_id) if peer is None: conn.close() self.log.write_red('Unauthorized request received: SessionID is invalid') return file = file_repository.find(conn, md5) if file is None: file = File(md5, name, 0) file.insert(conn) file_repository.add_owner(conn, md5, session_id) else: file.file_name = name file.update(conn) if not file_repository.peer_has_file(conn, session_id, md5): file_repository.add_owner(conn, md5, session_id) conn.commit() conn.close() except database.Error as e: conn.rollback() conn.close() self.log.write_red(f'An error has occurred while trying to serve the request: {e}') return self.log.write_blue(f'Successfully added file: {file.file_name} ({file.file_md5})') elif command == "DEFF": sd.close() if len(packet) != 52: self.log.write_red(f'Invalid packet received: {packet}\nUnable to delete the file from the DB.') return session_id = packet[4:20] md5 = packet[20:52] try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: self.log.write_red(f'An error has occurred while trying to serve the request: {e}') return try: peer = peer_repository.find(conn, session_id) if peer is None: conn.close() self.log.write_red('Unauthorized request received: SessionID is invalid') return if not file_repository.peer_has_file(conn, session_id, md5): conn.close() return peer_repository.file_unlink(conn, session_id, md5) copy = file_repository.get_copies(conn, md5) if copy == 0: file = file_repository.find(conn, md5) file.delete(conn) conn.commit() conn.close() except database.Error as e: conn.rollback() conn.close() self.log.write_red(f'An error has occurred while trying to serve the request: {e}') return self.log.write_blue(f'Successfully removed file: {file.file_name} ({file.file_md5})') elif command == "FIND": if len(packet) != 40: self.log.write_red(f'Invalid packet received: {packet}\nUnable to reply.') sd.close() return session_id = packet[4:20] query = packet[20:40].lower().lstrip().rstrip() if query != '*': query = '%' + query + '%' try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: self.log.write_red(f'An error has occurred while trying to serve the request: {e}') sd.close() return # check in my peers files (DB) try: peer = peer_repository.find(conn, session_id) if peer is None: self.log.write_red('Unauthorized request received: SessionID is invalid') sd.close() return else: file_rows = file_repository.get_files_by_querystring(conn, query) for file_row in file_rows: file_md5 = file_row['file_md5'] file_name = file_row['file_name'] owner_rows = peer_repository.get_peers_by_file(conn, file_md5) for owner_row in owner_rows: owner_ip = owner_row['ip'] owner_port = owner_row['port'] LocalData.add_net_peer_file(owner_ip, owner_port, file_md5, file_name) conn.commit() conn.close() except database.Error as e: conn.rollback() conn.close() self.log.write_red(f'An error has occurred while trying to serve the request: {e}') sd.close() return # check in my shared files for shared_file in LocalData.search_in_shared_files(query.strip('%')): LocalData.add_net_peer_file( net_utils.get_local_ip_for_response(), net_utils.get_network_port(), LocalData.get_shared_filemd5(shared_file), LocalData.get_shared_filename(shared_file) ) # flooding the QUER pktid = str(uuid.uuid4().hex[:16].upper()) ip = net_utils.get_local_ip_for_response() port = net_utils.get_aque_port() ttl = '05' query = packet[20:40] packet = "QUER" + pktid + ip + str(port).zfill(5) + ttl + query LocalData.set_sent_net_quer_packet(pktid) server = ServerThread(port, NetworkTimedResponseHandler(self.log)) server.daemon = True server.start() timer = Timer(20, lambda: server.stop()) timer.start() self.__broadcast_packet(packet) timer.join() try: self.log.write_blue(f'Sending {socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write('AFIN') # send the AFIN packet fragment = "AFIN" + str(LocalData.get_net_peer_files_md5_amount()).zfill(3) sd.send(fragment.encode()) self.log.write_blue(f'Sending fragment -> ', end='') self.log.write(f'{fragment}') for md5 in LocalData.get_net_peer_files().keys(): fragment = md5 + LocalData.get_net_peer_file_name_by_md5(md5).ljust(100) + str(LocalData.get_net_peer_file_copy_amount_by_md5(md5)).zfill(3) sd.send(fragment.encode()) self.log.write_blue(f'Sending fragment -> ', end='') self.log.write(f'{fragment}') for file_tuple in LocalData.get_net_peer_files_list_by_md5(md5): fragment = LocalData.get_net_peer_file_owner_ip(file_tuple) + str(LocalData.get_net_peer_file_owner_port(file_tuple)).zfill(5) sd.send(fragment.encode()) self.log.write_blue(f'Sending fragment -> ', end='') self.log.write(f'{fragment}') except socket.error as e: self.log.write_red(f'An error has occurred while sending an AFIN response to {socket_ip_sender}: {e}') sd.close() LocalData.clear_net_peer_files() elif command == "LOGO": if len(packet) != 20: self.log.write_red(f'Invalid packet received: {packet}\nUnable to reply.') sd.close() return session_id = packet[4:20] try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: self.log.write_red(f'An error has occurred while trying to serve the request: {e}') sd.close() return try: peer = peer_repository.find(conn, session_id) if peer is None: conn.close() self.log.write_red('Unauthorized request received: SessionID is invalid') sd.close() return deleted = file_repository.delete_peer_files(conn, session_id) peer.delete(conn) conn.commit() conn.close() except database.Error as e: conn.rollback() conn.close() self.log.write_red(f'An error has occurred while trying to serve the request: {e}') sd.close() return response = "ALGO" + str(deleted).zfill(3) try: sd.send(response.encode()) sd.close() self.log.write_blue(f'Sending {socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write(f'{response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending {response} to {socket_ip_sender}: {e}') return elif command == "QUER": sd.close() if len(packet) != 102: self.log.write_red(f'Invalid packet received: {packet}\nUnable to reply.') return self.log.write(f'{packet}') pktid = packet[4:20] ip_peer = packet[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(packet[75:80]) ttl = packet[80:82] query = packet[82:102].lower().lstrip().rstrip() if query != '*': query = '%' + query + '%' try: conn = database.get_connection(self.db_file) conn.row_factory = database.sqlite3.Row except database.Error as e: self.log.write_red(f'An error has occurred while trying to serve the request: {e}') return # check in my peers files (DB) try: total_file = file_repository.get_files_count_by_querystring(conn, query) if total_file != 0: file_rows = file_repository.get_files_by_querystring(conn, query) for file_row in file_rows: file_md5 = file_row['file_md5'] file_name = file_row['file_name'] owner_rows = peer_repository.get_peers_by_file(conn, file_md5) for owner_row in owner_rows: owner_ip = owner_row['ip'] owner_port = owner_row['port'] response = "AQUE" + pktid + owner_ip + owner_port + file_md5 + file_name.ljust(100) try: net_utils.send_packet_and_close(ip4_peer, ip6_peer, port_peer, response) self.log.write_blue(f'Sending {ip4_peer}|{ip6_peer} [{port_peer}] -> ', end='') self.log.write(f'{response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending {response}: {e}') conn.commit() conn.close() else: conn.close() except database.Error as e: conn.rollback() conn.close() self.log.write_red(f'An error has occurred while trying to serve the request: {e}') return # check in my shared files for local_shared_file in LocalData.search_in_shared_files(query.strip('%')): local_ip = net_utils.get_local_ip_for_response() local_port = str(net_utils.get_network_port()).zfill(5) file_md5 = LocalData.get_shared_filemd5(local_shared_file) file_name = LocalData.get_shared_filename(local_shared_file).ljust(100) response = "AQUE" + pktid + local_ip + local_port + file_md5 + file_name try: net_utils.send_packet_and_close(ip4_peer, ip6_peer, port_peer, response) self.log.write_blue(f'Sending {ip4_peer}|{ip6_peer} [{port_peer}] -> ', end='') self.log.write(f'{response}') except socket.error as e: self.log.write_red(f'An error has occurred while sending {response}: {e}') # forwarding the packet to other superpeers self.__forward_packet(socket_ip_sender, ip_peer, ttl, packet) elif command == "RETR": if len(packet) != 36: self.log.write_blue('Sending -> ', end='') self.log.write('Invalid packet. Unable to reply.') sd.send('Invalid packet. Unable to reply.'.encode()) sd.close() return file_md5 = packet[4:36] file_name = LocalData.get_shared_filename_by_filemd5(file_md5) if file_name is None: self.log.write_blue('Sending -> ', end='') self.log.write('Sorry, the requested file is not available anymore by the selected peer.') sd.send('Sorry, the requested file is not available anymore by the selected peer.'.encode()) sd.close() return try: f_obj = open('shared/' + file_name, 'rb') except OSError as e: self.log.write_red(f'Cannot open the file to upload: {e}') self.log.write_blue('Sending -> ', end='') self.log.write('Sorry, the peer encountered a problem while serving your packet.') sd.send('Sorry, the peer encountered a problem while serving your packet.'.encode()) sd.close() return try: Uploader(sd, f_obj, self.log).start() self.log.write_blue(f'Sent {sd.getpeername()[0]} [{sd.getpeername()[1]}] -> ', end='') self.log.write(f'{file_name}') sd.close() except OSError as e: self.log.write_red(f'Error while sending the file: {e}') sd.close() return else: sd.close() self.log.write_red(f'Invalid packet received from {socket_ip_sender} [{socket_port_sender}]: ', end='') self.log.write(f'{packet}') return
def serve(choice: str) -> None: """ Handle the peer packet :param choice: the choice to handle :return: None """ sp_ip4 = LocalData.get_superpeer_ip4() sp_ip6 = LocalData.get_superpeer_ip6() sp_port = LocalData.get_superpeer_port() p_ssid = LocalData.session_id if choice == "ADFF": # check se shared dir esiste if not os.path.exists('shared'): shell.print_red('\nCannot find the shared folder.') return # se non ci sono file nella shared dir avvisa ed esce if not os.scandir('shared'): shell.print_yellow( 'No file available for sharing. Add files to shared dir to get started.\n' ) return temp_files = [] shell.print_blue('\nFiles available for sharing:') for count, file in enumerate(os.scandir('shared'), 1): # stampa i risultati della scandir file_md5 = hasher.get_md5(f'shared/{file.name}') print(f'{count}] {file.name} | {file_md5}') temp_files.append((file_md5, file.name)) while True: index = input('Choose a file to share (q to cancel): ') if index == "q": print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(temp_files)} expected\n' ) continue if 0 <= index <= len(temp_files) - 1: file_name = LocalData.get_shared_file_name( temp_files[index]) file_md5 = LocalData.get_shared_file_md5(temp_files[index]) # controlla se il file è già in condivisione if not LocalData.is_shared_file(temp_files[index]): # crea il pacchetto e lo invia al super peer packet = choice + p_ssid + file_md5 + file_name.ljust( 100) try: net_utils.send_packet_and_close( sp_ip4, sp_ip6, sp_port, packet) shell.print_green( f'Packet sent to supernode: {sp_ip4}|{sp_ip6} [{sp_port}]' ) except net_utils.socket.error: shell.print_red( f'\nError while sending packet to supernode: {sp_ip4}|{sp_ip6} [{sp_port}]\n' ) # aggiunge il file alla struttura dati ed esce LocalData.add_shared_file(file_md5, file_name) shell.print_blue( f'\nNew shared file added {file_name} | {file_md5}' ) break else: # il file è già in condivisione shell.print_yellow( f'\n{file_name} | {file_md5} already in sharing.\n' ) break else: shell.print_red( f'\nWrong index: number in range 1 - {len(temp_files)} expected\n' ) continue elif choice == "DEFF": # recupera i files in sharing files = LocalData.get_shared_files() # check se ci sono file in sharing if not files: shell.print_yellow( 'No files currently in sharing. Add files choosing the command from the menu.\n' ) return # scelta del file da rimuovere shell.print_blue('\nFile currently in sharing:') for count, file in enumerate(files, 1): print( f'{count}] {LocalData.get_shared_file_name(file)} | {LocalData.get_shared_file_md5(file)}' ) while True: index = input( 'Choose a file to remove from sharing (q to cancel): ') if index == "q": print('\n') return try: index = int(index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(files)} expected\n' ) continue if 0 <= index <= len(files) - 1: # recupera il file dalla DS file = LocalData.get_shared_file(index) # crea ed invia il pacchetto al supernode packet = choice + p_ssid + LocalData.get_shared_file_md5( file) try: net_utils.send_packet_and_close( sp_ip4, sp_ip6, sp_port, packet) except net_utils.socket.error: shell.print_red( f'\nError while sending packet to supernode: {sp_ip4}|{sp_ip6} [{sp_port}]\n' ) # rimuove il file dalla DS LocalData.remove_shared_file(file) shell.print_green( f'\n{LocalData.get_shared_file_name(file)} | {LocalData.get_shared_file_md5(file)} removed successfully.' ) break else: shell.print_red( f'\nWrong index: number in range 1 - {len(files)} expected\n' ) continue elif choice == "FIND": while True: search = input('\nInsert file\'s name (q to cancel): ') if search == "q": print('\n') return if not 0 < len(search) <= 20: shell.print_red( '\nQuery string must be a valid value (1 - 20 chars).') continue break packet = choice + p_ssid + search.ljust(20) try: socket = net_utils.send_packet(sp_ip4, sp_ip6, sp_port, packet) except (net_utils.socket.error, AttributeError): shell.print_red( f'\nError while sending the request to the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) if socket is not None: socket.close() return spinner = SpinnerThread('Searching files', 'Research done!') spinner.start() try: socket.settimeout(25) command = socket.recv(4).decode() spinner.stop() spinner.join() print('\033[1A', end='\r') if command != "AFIN": shell.print_red( f'\nReceived a packet with a wrong command ({command}).\n' ) socket.close() return except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) return except ValueError: shell.print_red( f'\nInvalid packet from superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) return # ('file_name', 'file_md5', owners[]) downloadables = list() try: num_downloadables = int(socket.recv(3)) # check se ci sono file da scaricare if num_downloadables == 0: shell.print_yellow(f'{search} not found.\n') socket.close() return except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) return for i in range(num_downloadables): # ('owner_ip4', 'owner_ip6', 'owner_port') owners = list() try: file_md5 = socket.recv(32).decode() file_name = socket.recv(100).decode().lstrip().rstrip() num_copies = int(socket.recv(3)) except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue except ValueError: shell.print_red( f'\nInvalid packet from superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue for j in range(num_copies): try: (owner_ip4, owner_ip6) = net_utils.get_ip_pair( socket.recv(55).decode()) owner_port = int(socket.recv(5)) owners.append((owner_ip4, owner_ip6, owner_port)) except net_utils.socket.error: shell.print_red( f'\nError while receiving the response from the superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue except ValueError: shell.print_red( f'\nInvalid packet from superpeer: {sp_ip4}|{sp_ip6} [{sp_port}].\n' ) continue if owners: # prepara una lista con tutti i file che possono essere scaricati downloadables.append((file_name, file_md5, owners)) if not downloadables: shell.print_red( f'\nSomething went wrong while retrieving {search}\n') socket.close() return shell.print_green(f'\nFiles found:') for count, downloadable in enumerate(downloadables, 1): print(f'{count}] {downloadable[0]} | {downloadable[1]}') while True: choosed_file_index = input( 'Choose a file to download (q to cancel): ') if choosed_file_index == "q": print('\n') socket.close() return try: choosed_file_index = int(choosed_file_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue if not 0 <= choosed_file_index <= len(downloadables) - 1: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue else: choosed_file_name = downloadables[choosed_file_index][0] choosed_file_md5 = downloadables[choosed_file_index][1] choosed_file_owners = downloadables[choosed_file_index][2] shell.print_green( f'\nAvailable sources for {choosed_file_name}:') for count, choosed_file_owner in enumerate( choosed_file_owners, 1): print( f'{count}] {choosed_file_owner[0]}|{choosed_file_owner[1]} [{choosed_file_owner[2]}]' ) while True: choosed_owner_index = input( f'Choose a source for {choosed_file_name} (q to cancel): ' ) if choosed_owner_index == "q": print('\n') return try: choosed_owner_index = int(choosed_owner_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(choosed_file_owners)} expected\n' ) continue if 0 <= choosed_owner_index <= len( choosed_file_owners) - 1: packet = "RETR" + choosed_file_md5 try: Downloader( choosed_file_owners[choosed_owner_index] [0], choosed_file_owners[choosed_owner_index] [1], choosed_file_owners[choosed_owner_index] [2], packet, choosed_file_name).start() shell.print_green( f'\n{choosed_file_name} downloaded successfully.\n' ) except OSError: shell.print_red( f'\nError while downloading {choosed_file_name}.\n' ) break else: shell.print_red( f'\nWrong index: number in range 1 - {len(choosed_file_owners)} expected\n' ) continue break elif choice == "SHOWSUPER": print( f'\nYour current superpeer is: {sp_ip4}|{sp_ip6} [{sp_port}]\n' ) elif choice == "LOGO": packet = choice + p_ssid sock = net_utils.send_packet(sp_ip4, sp_ip6, sp_port, packet) try: command = sock.recv(4).decode() if command != "ALGO": shell.print_red( f'\nWrong response code "{command}": "{choice}" expected.\n' ) num_files = int(sock.recv(3)) shell.print_blue( f'\n{num_files} files has been removed from sharing.\n') except (net_utils.socket.error, AttributeError): shell.print_red( f'\nError while receiving the response for "{choice}".\n') LocalData.clear_backup_data() else: pass
def serve(self, sd: socket.socket) -> None: """ Handle the neighbours packet :param sd: the socket descriptor used for read the packet :return: None """ try: packet = sd.recv(200).decode() except socket.error as e: self.log.write_red( f'Unable to read the packet from the socket: {e}') sd.close() return # log the packet received socket_ip_sender = sd.getpeername()[0] if ipaddress.IPv6Address(socket_ip_sender).ipv4_mapped is None: socket_ip_sender = ipaddress.IPv6Address( socket_ip_sender).compressed else: socket_ip_sender = ipaddress.IPv6Address( socket_ip_sender).ipv4_mapped.compressed socket_port_sender = sd.getpeername()[1] self.log.write_green(f'{socket_ip_sender} [{socket_port_sender}] -> ', end='') self.log.write(f'{packet}') command = packet[:4] if command == "QUER": if len(packet) != 102: self.log.write_red('Invalid packet. Unable to reply.') sd.close() return pktid = packet[4:20] ip_peer = packet[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(packet[75:80]) ttl = packet[80:82] query = packet[82:102].lstrip().rstrip().lower() sd.close() # packet management if pktid == AppData.get_sent_packet(): return if not AppData.exist_in_received_packets(pktid): AppData.add_received_packet(pktid, ip_peer, port_peer) t = Timer(300, function=self.__delete_packet, args=(pktid, )) t.start() else: return # search for the requested file results = AppData.search_in_shared_files(query) for file in results: response = 'AQUE' +\ pktid + net_utils.get_local_ip_for_response() +\ str(net_utils.get_neighbours_port()).zfill(5) +\ AppData.get_shared_filemd5(file) +\ AppData.get_shared_filename(file).ljust(100) self.__unicast(ip4_peer, ip6_peer, port_peer, response) # forwarding the packet to other peers self.__forward_packet(socket_ip_sender, ip_peer, ttl, packet) elif command == "NEAR": if len(packet) != 82: self.log.write_red('Invalid packet. Unable to reply.') sd.close() return pktid = packet[4:20] ip_peer = packet[20:75] ip4_peer, ip6_peer = net_utils.get_ip_pair(ip_peer) port_peer = int(packet[75:80]) ttl = packet[80:82] sd.close() # packet management if pktid == AppData.get_sent_packet(): return if not AppData.exist_in_received_packets(pktid): AppData.add_received_packet(pktid, ip_peer, port_peer) t = Timer(300, function=self.__delete_packet, args=(pktid, )) t.start() else: return # send the NEAR acknowledge response = 'ANEA' + pktid + net_utils.get_local_ip_for_response( ) + str(net_utils.get_neighbours_port()).zfill(5) self.__unicast(ip4_peer, ip6_peer, port_peer, response) # forwarding the packet to other peers self.__forward_packet(socket_ip_sender, ip_peer, ttl, packet) elif command == "RETR": if len(packet) != 36: self.log.write_blue('Sending -> ', end='') self.log.write('Invalid packet. Unable to reply.') sd.send('Invalid packet. Unable to reply.'.encode()) sd.close() return file_md5 = packet[4:36] file_name = AppData.get_shared_filename_by_filemd5(file_md5) if file_name is None: self.log.write_blue('Sending -> ', end='') self.log.write( 'Sorry, the requested file is not available anymore by the selected peer.' ) sd.send( 'Sorry, the requested file is not available anymore by the selected peer.' .encode()) sd.close() return try: f_obj = open('shared/' + file_name, 'rb') except OSError as e: self.log.write_red(f'Cannot open the file to upload: {e}') self.log.write_blue('Sending -> ', end='') self.log.write( 'Sorry, the peer encountered a problem while serving your packet.' ) sd.send( 'Sorry, the peer encountered a problem while serving your packet.' .encode()) sd.close() return try: Uploader(sd, f_obj, self.log).start() self.log.write_blue( f'Sent {sd.getpeername()[0]} [{sd.getpeername()[1]}] -> ', end='') self.log.write(f'{file_name}') sd.close() except OSError: self.log.write_red('Error while sending the file.') sd.close() return else: self.log.write_red('Invalid packet. Unable to reply.') sd.close() return