Esempio n. 1
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 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}')
Esempio n. 2
0
	def __delete_packet(self, pktid: str) -> None:
		""" Delete a packet received from the net

		:param pktid: id of the packet
		:return: None
		"""
		if LocalData.exist_in_received_packets(pktid):
			LocalData.delete_received_packet(pktid)
    def serve(self, sd: socket.socket) -> None:
        """ Handle the peer request

		:param sd: the socket descriptor used for read the request
		:return None
		"""

        try:
            packet = sd.recv(300).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[0:4]

        if command == "AQUE":

            if len(packet) != 212:
                self.log.write_red(
                    f'Invalid packet received: {packet}\nUnable to reply.')
                return

            pktid = packet[4:20]
            ip_peer = packet[20:75]
            port_peer = int(packet[75:80])
            file_md5 = packet[80:112]
            filename = packet[112:212]

            if pktid != LocalData.get_sent_net_quer_packet():
                return

            if not LocalData.exist_net_peer_file(ip_peer, port_peer, file_md5,
                                                 filename):
                LocalData.add_net_peer_file(ip_peer, port_peer, file_md5,
                                            filename)

        else:
            self.log.write_red(
                f'Invalid packet received: {packet}\nUnable to reply.')

        return
Esempio n. 4
0
	def __broadcast_packet(self, packet: str) -> None:
		""" Send the packet to a pool of hosts
		:param packet: packet to be broadcasted
		:return: None
		"""

		for superfriend in LocalData.get_super_friends():
			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'Broadcasting to {ip4}|{ip6} [{port}] -> ', end='')
				self.log.write(f'{packet}')
			except socket.error as e:
				self.log.write_red(f'Unable to broadcast a packet to {ip4}|{ip6} [{port}]: {e}')
Esempio n. 5
0
	def __broadcast(self, packet: str) -> None:
		""" Send the packet to a pool of hosts

		:param packet: packet to be sent
		:return: None
		"""
		superfriends = LocalData.get_super_friends()

		for superfriend in superfriends:

			try:
				net_utils.send_packet_and_close(
					LocalData.get_super_friend_ip4(superfriend),
					LocalData.get_super_friend_ip6(superfriend),
					LocalData.get_super_friend_port(superfriend),
					packet)
			except socket.error as e:
				shell.print_red(f'\nUnable to send the packet on the socket: {e}')
				return
	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
Esempio n. 7
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
Esempio n. 8
0
	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