def __delete_packet(self, pktid: str) -> None: """ Delete a packet from the net :param pktid: id of the packet :return: None """ if LocalData.exist_in_received_packets(pktid): LocalData.delete_received_packet(pktid)
def show(self) -> None: """ Shows the menu that interacts with the user :return: None """ choice = '' while choice != 'q': print('\n- Main Menù -----------------------') print('| <1> Search a file to download |') print('| <2> Share a file |') print('| <3> Files in sharing |') print('| <4> Your tracker |') print('-----------------------------------') choice = input('Select an option (q to logout): ') if choice in {'1', '2', '3', '4'}: if choice == '1': command = 'LOOK' elif choice == '2': command = 'ADDR' elif choice == '3': command = 'SHAR' elif choice == '4': command = 'TRAC' self.handler.serve(command) elif choice == 'q': self.handler.serve('LOGO') if LocalData.tracker_is_empty(): break else: choice = '' continue elif choice != 'q': shell_colors.print_red('Input code is wrong. Choose one action!\n') # waiting 60s for any upload running spinner = SpinnerThread('Waiting for any upload in progress', '') spinner.start() timer = Timer(60, lambda: (self.server.stop(), spinner.stop())) timer.start() timer.join() spinner.join() LocalData.clear_shared_files() shell_colors.print_blue('\nYou leaved the Network\nBye!\n')
def __forward_packet(self, ttl: str, packet: str) -> None: """ Forward a supe packet in the net to superpeer :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: packet = packet[:80] + str(new_ttl).zfill(2) + packet[82:] superpeer_ip4 = LocalData.get_superpeer_ip4() superpeer_ip6 = LocalData.get_superpeer_ip6() superpeer_port = LocalData.get_superpeer_port() net_utils.send_packet_and_close(superpeer_ip4, superpeer_ip6, superpeer_port, 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(choice: str) -> None: """ Handle the peer packet :param choice: the choice to handle :return: None """ tracker_ip4 = LocalData.get_tracker_ip4() tracker_ip6 = LocalData.get_tracker_ip6() tracker_port = LocalData.get_tracker_port() ssid = LocalData.get_session_id() log = Logger.Logger('peer/peer.log') if choice == "LOOK": # Search a file 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 + ssid + search.ljust(20) sd = None try: sd = net_utils.send_packet(tracker_ip4, tracker_ip6, tracker_port, packet) except net_utils.socket.error as e: shell.print_red( f'\nError while sending the request to the tracker: {tracker_ip4}|{tracker_ip6} [{tracker_port}].' ) shell.print_red(f'Error: {e}') if sd is not None: sd.close() return # Receiving the response list try: command = sd.recv(4).decode() except net_utils.socket.error as e: shell.print_red( f'Unable to read the command from the socket: {e}\n') sd.close() return if command != 'ALOO': shell.print_red( f'\nReceived a packet with a wrong command ({command}).') return try: num_files = int(sd.recv(3).decode()) except net_utils.socket.error as e: shell.print_red( f'Unable to read the command from the socket: {e}\n') sd.close() return if num_files == 0: shell.print_yellow(f'{search} not found.\n') sd.close() return downloadables = list() for i in range(num_files): try: file_md5 = sd.recv(32).decode() file_name = sd.recv(100).decode().lstrip().rstrip() len_file = int(sd.recv(10)) len_part = int(sd.recv(6)) except net_utils.socket.error as e: shell.print_red( f'\nError while receiving the response from the tracker: {e}\n' ) continue except ValueError: shell.print_red(f'\nInvalid packet from tracker: {e}\n') continue downloadables.append((file_md5, file_name, len_file, len_part)) sd.close() if not downloadables: shell.print_red( f'\nSomething went wrong while retrieving {search}\n') return shell.print_green(f'\nFiles found:') for count, downloadable in enumerate(downloadables, 1): print( f'{count}] {LocalData.get_downloadable_file_name(downloadable)} | ', end='') shell.print_yellow( f'{LocalData.get_downloadable_file_md5(downloadable)}') # Download choice while True: file_index = input( '\nChoose a file to download (q to cancel): ') if file_index == "q": return try: file_index = int(file_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue if not 0 <= file_index <= len(downloadables) - 1: shell.print_red( f'\nWrong index: number in range 1 - {len(downloadables)} expected\n' ) continue else: choosed_file_md5 = LocalData.get_downloadable_file_md5( downloadables[file_index]) choosed_file_name = LocalData.get_downloadable_file_name( downloadables[file_index]) if LocalData.is_shared_file(choosed_file_md5, choosed_file_name): shell.print_green( f'\nYou already have downloaded {choosed_file_name}.' ) continue choosed_file_lenght = LocalData.get_downloadable_file_length( downloadables[file_index]) choosed_file_part_lenght = LocalData.get_downloadable_file_part_length( downloadables[file_index]) break choosed_file_parts = int( math.ceil(choosed_file_lenght / choosed_file_part_lenght)) choosed_file_part_list_length = int( math.ceil(choosed_file_parts / 8)) # Download phase LocalData.create_downloading_part_list( choosed_file_part_list_length) # 1) Initiating the thread responsible for update of the part_list_table in background update_event = Event() updater_thread = UpdaterThread.UpdaterThread( choosed_file_md5, choosed_file_part_list_length, update_event, log) updater_thread.start() # 2) Create the new file f_obj = open(f'shared/{choosed_file_name}', 'wb') f_obj.close() LocalData.set_num_parts_owned(0) progress_bar.print_progress_bar(0, choosed_file_parts, prefix='Downloading:', suffix='Complete', length=50) # Adding the file to the shared file list LocalData.add_shared_file(choosed_file_md5, choosed_file_name) # Until all the parts hasn't been downloaded while choosed_file_parts != LocalData.get_num_parts_owned(): update_event.wait(70) update_event.clear() # We can use a with statement to ensure threads are cleaned up promptly with ThreadPoolExecutor(max_workers=10) as executor: # Get the file parts we don't have yet downloadable_parts = LocalData.get_downloadable_parts() for part_num in downloadable_parts: try: # Start the load operations executor.submit(download_task.run, choosed_file_md5, choosed_file_name, part_num, choosed_file_part_lenght, choosed_file_parts, log) except OSError as e: log.write_red( f'\nError while downloading {choosed_file_name}: {e}' ) executor.shutdown() updater_thread.stop() shell.print_green('\nDownload completed.') elif choice == "ADDR": # check if shared directory exist if not os.path.exists('shared'): shell.print_red('\nCannot find the shared folder.') return # check for file available in shared directory if not os.listdir('shared'): shell.print_yellow( 'No file available for sharing.\nAdd 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): # print scandir results 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: file_index = input('\nChoose a file to share (q to cancel): ') if file_index == "q": return try: file_index = int(file_index) - 1 except ValueError: shell.print_red( f'\nWrong index: number in range 1 - {len(temp_files)} expected\n' ) continue if 0 <= file_index <= len(temp_files) - 1: file_name = LocalData.get_shared_file_name( temp_files[file_index]) file_md5 = LocalData.get_shared_file_md5( temp_files[file_index]) # check if file is already in sharing if not LocalData.is_shared_file(file_md5, file_name): try: f_obj = open('shared/' + file_name, 'rb') except OSError as e: shell.print_red( f'Cannot open the file to upload: {e}') return try: filesize = str(os.fstat(f_obj.fileno()).st_size) except OSError as e: shell.print_red(f'Something went wrong: {e}') return except ValueError as e: shell.print_red( f'\nUnable to convert filesize in string: {e}\n' ) return part_size = str(net_utils.get_part_size()) # build packet and sent to tracker packet = choice + ssid + filesize.zfill( 10) + part_size.zfill(6) + file_name.ljust( 100) + file_md5 sd = None try: sd = net_utils.send_packet(tracker_ip4, tracker_ip6, tracker_port, packet) except net_utils.socket.error as e: shell.print_red( f'\nError while sending the request to the tracker: {tracker_ip4}|{tracker_ip6} [{tracker_port}].' ) shell.print_red(f'Error: {e}') if sd is not None: sd.close() return try: response = sd.recv(200).decode() except net_utils.socket.error as e: shell.print_red( f'Unable to read the response from the socket: {e}\n' ) sd.close() return sd.close() if len(response) != 12: shell.print_red( f"Invalid response: : {response}. Expected: AADR<num_part>" ) return command = response[0:4] if command != 'AADR': shell.print_red( f'\nReceived a packet with a wrong command ({command}).' ) return num_part = response[4:12] # add file to shared_files LocalData.add_shared_file(file_md5, file_name) shell.print_blue( f'\nNew shared file added {file_name} | {file_md5}', end='') shell.print_green(f' #parts: {num_part}') break else: # if not in sharing 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 == "LOGO": packet = choice + ssid sd = None try: sd = net_utils.send_packet(tracker_ip4, tracker_ip6, tracker_port, packet) except net_utils.socket.error as e: shell.print_red( f'\nError while sending the request to the tracker: {tracker_ip4}|{tracker_ip6} [{tracker_port}].' ) shell.print_red(f'{e}') if sd is not None: sd.close() return try: response = sd.recv(50).decode() except net_utils.socket.error as e: shell.print_red( f'Unable to read the response from the socket: {e}\n') sd.close() return sd.close() if len(response) != 14: shell.print_red( f"Invalid response form the socket: {response}.") return command = response[0:4] if command == "ALOG": part_own = int(response[4:14]) shell.print_green('\nSuccessfully logged out') shell.print_blue( f'{part_own} parts has been removed from sharing.\n') LocalData.clear_tracker() elif command == "NLOG": part_down = int(response[4:14]) shell.print_yellow( f'\nUnable to logout:\nYou have shared only {part_down} parts with other peer.\n' ) else: shell.print_red( f'\nReceived a packet with a wrong command from the socket: {command} -> {response}' ) elif choice == 'SHAR': files = LocalData.get_shared_files() if not files: shell.print_red('\nYou currently have no files in sharing.') print('\nFiles actually in sharing:') for count, file in enumerate(files, 1): print(f'{count}] {LocalData.get_downloadable_file_name(file)}') elif choice == 'TRAC': shell.print_green( f'\nYour tracker is: {LocalData.get_tracker_ip4()}|{LocalData.get_tracker_ip6()} [{LocalData.get_tracker_port()}]' ) else: shell.print_yellow( f'\nInvalid input code: "{choice}".\nPlease retry.\n') 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 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 == "RETP": if len(packet) != 44: self.log.write_red(f'Invalid packet received: {packet}') return file_md5 = packet[4:36] try: num_part = int(packet[36:44]) except ValueError: shell.print_red(f'Invalid packet received: Part-Num must be an integer -> {num_part}\n') return file_name = LocalData.get_shared_file_name_from_md5(file_md5) if file_name is None: error_packet = 'Sorry, the requested file is not available anymore.' self.send_packet(sd, socket_ip_sender, socket_port_sender, error_packet) 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}') error_packet = 'Sorry, the peer encountered a problem while uploading the file.' self.send_packet(sd, socket_ip_sender, socket_port_sender, error_packet) sd.close() return try: Uploader(sd, f_obj, num_part, self.log).start() self.log.write_blue(f'Sent {socket_ip_sender} [{socket_port_sender}] -> ', 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 run(self) -> None: """ Start file download :return: None """ try: packet = 'RETP' + self.file_md5 + str(self.part_num).zfill(8) sock = self.__connect(self.owner_ip4, self.owner_ip6, self.owner_port, packet) except socket.error as e: shell_colors.print_red(f'\nImpossible to send data to {self.owner_ip4}|{self.owner_ip6} [{self.owner_port}]: {e}\n') return ack = sock.recv(4).decode() if ack != "AREP": shell_colors.print_red(f'Invalid command received: {ack}. Expected: AREP') sock.close() return try: total_chunks = int(sock.recv(6).decode()) except ValueError: shell_colors.print_red('Impossible to retrieve the part. Trying later.') return for i in range(total_chunks): chunk_size = sock.recv(5) # if not all the 5 expected bytes has been received while len(chunk_size) < 5: chunk_size += sock.recv(1) chunk_size = int(chunk_size) data = sock.recv(chunk_size) # if not all the expected bytes has been received while len(data) < chunk_size: data += sock.recv(1) self.f_obj.write(data) self.f_obj.close() try: packet = 'RPAD' + LocalData.session_id + self.file_md5 + str(self.part_num).zfill(8) sock = self.__connect(LocalData.get_tracker_ip4(), LocalData.get_tracker_ip6(), LocalData.get_tracker_port(), packet) except socket.error as e: shell_colors.print_red(f'\nImpossible to send data to {self.owner_ip4}|{self.owner_ip6} [{self.owner_port}]: {e}\n') return ack = sock.recv(4).decode() if ack != "APAD": shell_colors.print_red(f'\nInvalid command received: {ack}. Expected: APAD\n') sock.close() return try: num_parts_owned = int(sock.recv(8).decode()) except ValueError: shell_colors.print_red('Error while retrieving the parts owned from the tracker.') return binary_utils.update_owned_parts(self.part_num) LocalData.set_num_parts_owned(num_parts_owned) progress_bar.print_progress_bar(num_parts_owned, self.total_file_parts, prefix='Downloading:', suffix='Complete', length=50)
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] 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('Invalid packet. Unable to reply.') return pktid = packet[4:20] ip_peer = packet[20:75] port_peer = int(packet[75:80]) ttl = packet[80:82] # packet management if pktid == LocalData.get_sent_packet(): return if not LocalData.exist_in_received_packets(pktid): LocalData.add_received_packet(pktid) t = Timer(20, function=self.__delete_packet, args=(pktid, )) t.start() else: return # forwarding the supe packet to superpeer self.__forward_packet(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_file_name_from_md5(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: self.log.write_red('Invalid packet. Unable to reply.') sd.close() return