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}')
Example #2
0
    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)
Example #3
0
    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
Example #5
0
	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
Example #6
0
    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
Example #8
0
    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
Example #9
0
    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