def get_neighbours(self, new_peer_id, new_peer_ip_address, new_peer_port): if not self.peer.successor["id"]: # I AM YOUR PREDECESSOR -- only one node in network data = self._generate_data_second_node() self._add_second_node(new_peer_id, new_peer_ip_address, new_peer_port) return data if self.peer.predecessor["id"] < new_peer_id < self.peer.peer_id: data = self._generate_data_new_predecessor() self._add_node_to_predecessor(new_peer_id, new_peer_ip_address, new_peer_port) return data if self.peer.peer_id < new_peer_id < self.peer.successor["id"]: data = self._generate_data_new_successor() self._add_node_to_successor(new_peer_id, new_peer_ip_address, new_peer_port) return data if new_peer_id > self.peer.peer_id and new_peer_id > self.peer.successor[ "id"]: if self.peer.successor["id"] < self.peer.peer_id: # WRAP AROUND data = self._generate_data_new_successor() self._add_node_to_successor(new_peer_id, new_peer_ip_address, new_peer_port) return data else: # print("Recursively ask my successor") req_packet = P2PRequestPacket( libp2pproto.GET_NEIGHBOURS_OP_WORD, [new_peer_id, new_peer_ip_address, new_peer_port]) res_pkt = send_p2p_tcp_packet(self.peer.successor["ip_addr"], self.peer.successor["port"], req_packet) return res_pkt.data[0] if new_peer_id < self.peer.peer_id and new_peer_id < self.peer.successor[ "id"]: if self.peer.successor["id"] < self.peer.peer_id: # WRAP AROUND data = self._generate_data_new_successor() self._add_node_to_successor(new_peer_id, new_peer_ip_address, new_peer_port) return data else: # print("Recursively ask my successor") req_packet = P2PRequestPacket( libp2pproto.GET_NEIGHBOURS_OP_WORD, [new_peer_id, new_peer_ip_address, new_peer_port]) res_pkt = send_p2p_tcp_packet(self.peer.successor["ip_addr"], self.peer.successor["port"], req_packet) return res_pkt.data[0]
def _handle_download_file_request(self, filename): overall_bytes = b"" for chunk_name in generate_chunks_filename(filename): ip_addr_port = self.dhash.get(chunk_name) if ip_addr_port == None: return libp2puds.construct_unknown_res() else: ip_addr, port = ip_addr_port.split(":")[0], int( ip_addr_port.split(":")[1]) print("Download source of %s is: %s" % (chunk_name, ip_addr_port)) if ip_addr == self.ip_addr: real_filename = remove_chunk_suffix(chunk_name) chunk_number = get_chunk_number_from_filename(chunk_name) byte_data = get_file_chunk_byte(real_filename, chunk_number) overall_bytes = overall_bytes + byte_data else: req_packet = P2PRequestPacket( libp2pproto.DOWNLOAD_FILE_OP_WORD, [chunk_name]) res_pkt = send_p2p_tcp_packet( self.peer.successor['ip_addr'], self.peer.successor['port'], req_packet) if len(res_pkt.data) > 0: overall_bytes = overall_bytes + res_pkt.data[0].encode( ) return UdsResponsePacket(libp2puds.OK_RES_CODE, libp2puds.OK_RES_MSG, [overall_bytes.decode()])
def get(self, filename): dbconn = sqlite3.connect(DB_NAME) cursor = dbconn.cursor() cursor.execute(SELECT_QUERY, (filename, )) datum = cursor.fetchone() dbconn.close() if datum == None: if self._check_filename_responsibility(filename): # If I am responsible and file is not found == ggwp return None else: # Ask successor req_packet = P2PRequestPacket(libp2pproto.GET_FILE_OP_WORD, [filename]) res_packet = send_p2p_tcp_packet( self.peer.successor["ip_addr"], self.peer.successor['port'], req_packet) if len(res_packet.data) > 0: return res_packet.data[0] else: return None return None else: ip_addr_port_str = datum[2].replace(' ', '') return json.loads(ip_addr_port_str)[0]
def put(self, filename, ip_addr_port): if self._check_filename_responsibility(filename): dbconn = sqlite3.connect(DB_NAME) cursor = dbconn.cursor() cursor.execute(SELECT_QUERY, (filename, )) db_result = cursor.fetchone() if db_result == None: insert_query = """ INSERT INTO p2pdht (filename, ip_addr_list) VALUES (?, ?) """ cursor.execute(insert_query, (filename, json.dumps([ip_addr_port]))) else: update_query = """ UPDATE p2pdht SET ip_addr_list=? WHERE id=? """ ip_addr_list = json.loads(db_result[2]) ip_addr_list.append(ip_addr_port) cursor.execute(update_query, (json.dumps(ip_addr_list), int(db_result[0]))) dbconn.commit() dbconn.close() return True else: # Ask successor req_packet = P2PRequestPacket(libp2pproto.PUT_FILE_OP_WORD, [filename, ip_addr_port]) res_packet = send_p2p_tcp_packet(self.peer.successor["ip_addr"], self.peer.successor['port'], req_packet) return res_packet.code == libp2pproto.OK_RES_CODE
def _handle_p2p_list_request(self, ip_addr): successor_data = [] if self.peer.successor["ip_addr"] != ip_addr: req_packet = P2PRequestPacket(libp2pproto.LIST_FILES_OP_WORD, [ip_addr]) res_pkt = send_p2p_tcp_packet(self.peer.successor['ip_addr'], self.peer.successor['port'], req_packet) successor_data = res_pkt.data successor_data = successor_data + self.dhash.get_local_keys() return P2PResponsePacket(libp2pproto.OK_RES_CODE, libp2pproto.OK_RES_MSG, successor_data)
def _handle_list_files_request(self): data = self.dhash.get_local_keys() if self.peer.successor['id']: req_packet = P2PRequestPacket(libp2pproto.LIST_FILES_OP_WORD, [self.ip_addr]) res_pkt = send_p2p_tcp_packet(self.peer.successor['ip_addr'], self.peer.successor['port'], req_packet) data = res_pkt.data + self.dhash.get_local_keys() data = [remove_chunk_suffix(f) for f in data] return UdsResponsePacket(libp2puds.OK_RES_CODE, libp2puds.OK_RES_MSG, data)
def _handle_p2p_connection(self, socket): data_string = "" while True: try: data_bytes = socket.recv(MAX_PACKET_SIZE) data_string = data_string + data_bytes.decode("utf-8") # print("-------", data.req_str) req_pkt = P2PRequestPacket.parse(data_string) res_pkt = self._process_p2p_request(req_pkt) socket.sendall(res_pkt.encode_bytes()) socket.close() break except ValueError as err: if int(str(err)) == libp2pproto.MALFORMED_PACKET_ERROR: malform_res = libp2pproto.construct_malformed_res() socket.sendall(malform_res.encode_bytes())
def _process_p2p_request(self, req_pkt): op_word, args = req_pkt.op_word, req_pkt.args # print(op_word, args) if op_word == libp2pproto.GET_NEIGHBOURS_OP_WORD: peer_id = int(args[libp2pproto.GET_NEIGHBOURS_PEER_ID_INDEX]) ip_addr = args[libp2pproto.GET_NEIGHBOURS_PEER_IP_ADDR_INDEX] port = int(args[libp2pproto.GET_NEIGHBOURS_PEER_PORT_INDEX]) return self._handle_p2p_get_neighbors(peer_id, ip_addr, port) if op_word == libp2pproto.INFORM_PREDECESSOR_PREDECESSOR_OP_WORD: peer_id = int(args[libp2pproto.INFORM_PREDECESSOR_PEER_ID_INDEX]) ip_addr = args[libp2pproto.INFORM_PREDECESSOR_PEER_IP_ADDR_INDEX] port = int(args[libp2pproto.INFORM_PREDECESSOR_PEER_PORT_INDEX]) inform_packet = P2PRequestPacket( libp2pproto.INFORM_PREDECESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port, peer_id, ip_addr, port ]) return send_p2p_tcp_packet(self.peer.predecessor["ip_addr"], self.peer.predecessor["port"], inform_packet) if op_word == libp2pproto.INFORM_PREDECESSOR_OP_WORD: peer_id = int(args[libp2pproto.INFORM_PREDECESSOR_PEER_ID_INDEX]) ip_addr = args[libp2pproto.INFORM_PREDECESSOR_PEER_IP_ADDR_INDEX] port = int(args[libp2pproto.INFORM_PREDECESSOR_PEER_PORT_INDEX]) next_successor_peer_id = int( args[libp2pproto.INFORM_PREDECESSOR_SUCCESSOR_PEER_ID_INDEX]) next_successor_ip_addr = args[ libp2pproto.INFORM_PREDECESSOR_SUCCESSOR_PEER_IP_ADDR_INDEX] next_successor_port = int( args[libp2pproto.INFORM_PREDECESSOR_SUCCESSOR_PEER_PORT_INDEX]) return self._handle_p2p_inform_predecessor(peer_id, ip_addr, port, next_successor_peer_id, next_successor_ip_addr, next_successor_port) if op_word == libp2pproto.INFORM_SUCCESSOR_OP_WORD: peer_id = int(args[libp2pproto.INFORM_SUCCESSOR_PEER_ID_INDEX]) ip_addr = args[libp2pproto.INFORM_SUCCESSOR_PEER_IP_ADDR_INDEX] port = int(args[libp2pproto.INFORM_SUCCESSOR_PEER_PORT_INDEX]) return self._handle_p2p_inform_successor(peer_id, ip_addr, port) if op_word == libp2pproto.QUERY_SUCCESSOR_FOR_NEIGHBOURS_OP_WORD: return self._handle_p2p_query_successor_for_neighbours() if op_word == libp2pproto.PUT_FILE_OP_WORD: filename = args[libp2pproto.PUT_FILE_FILENAME_INDEX] ip_addr_port = args[libp2pproto.PUT_FILE_IP_ADDR_PORT_INDEX] return self._handle_p2p_put_request(filename, ip_addr_port) if op_word == libp2pproto.GET_FILE_OP_WORD: filename = args[libp2pproto.GET_FILE_FILENAME_INDEX] return self._handle_p2p_get_request(filename) if op_word == libp2pproto.LIST_FILES_OP_WORD: ip_addr = args[libp2pproto.LIST_FILES_IP_ADDR_INDEX] return self._handle_p2p_list_request(ip_addr) if op_word == libp2pproto.DOWNLOAD_FILE_OP_WORD: filename = args[libp2pproto.DOWNLOAD_FILE_FILENAME_INDEX] return self._handle_p2p_download_request(filename) return libp2pproto.construct_unknown_res()
def _stabilisation(self): if not self.peer.successor["id"]: #Genesis node. No Stabilisation needed return # print("---------------STABLISATION---------------") # self.peer.print_info() # print() stab_packet = P2PRequestPacket( libp2pproto.QUERY_SUCCESSOR_FOR_NEIGHBOURS_OP_WORD, []) try: res_packet = send_p2p_tcp_packet(self.peer.successor["ip_addr"], self.peer.successor["port"], stab_packet) if res_packet is not None: data = res_packet.data[0].split(" ") successor_predecessor_peer_id = int(data[0]) successor_successor_peer_id = int(data[3]) if successor_predecessor_peer_id != self.peer.peer_id: # Oh, you have a new predecessor, let me add that as my successor self.peer.next_successor["id"] = self.peer.successor["id"] self.peer.next_successor["ip_addr"] = self.peer.successor[ "ip_addr"] self.peer.next_successor["port"] = self.peer.successor[ "port"] self.peer.successor["id"] = int(data[0]) self.peer.successor["ip_addr"] = data[1] self.peer.successor["port"] = int(data[2]) # Inform successor of new predecessor inform_packet = P2PRequestPacket( libp2pproto.INFORM_SUCCESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port ]) send_p2p_tcp_packet(self.peer.successor["ip_addr"], self.peer.successor["port"], inform_packet) # Inform predecessor of new next successor inform_packet = P2PRequestPacket( libp2pproto.INFORM_PREDECESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port, self.peer.successor["id"], self.peer.successor["ip_addr"], self.peer.successor["port"] ]) send_p2p_tcp_packet(self.peer.predecessor["ip_addr"], self.peer.predecessor["port"], inform_packet) # Ensure that there's 3 nodes in the network. # If there's 2 node, then the successor's successor will be the current node elif successor_successor_peer_id != self.peer.peer_id: if successor_successor_peer_id != self.peer.next_successor[ "id"]: # You have a new successor, let me add that as my next successor self.peer.next_successor["id"] = int(data[3]) self.peer.next_successor["ip_addr"] = data[4] self.peer.next_successor["port"] = int(data[5]) else: self.peer.next_successor["id"] = None self.peer.next_successor["ip_addr"] = None self.peer.next_successor["port"] = None # Handle when node leaves the network except socket.error as e: if e.errno == 111: # print("Destination node has left the network...") if self.peer.next_successor["id"]: self.peer.successor["id"] = self.peer.next_successor["id"] self.peer.successor["ip_addr"] = self.peer.next_successor[ "ip_addr"] self.peer.successor["port"] = self.peer.next_successor[ "port"] self.peer.next_successor["id"] = None self.peer.next_successor["ip_addr"] = None self.peer.next_successor["port"] = None # print("Informing my predecessor to add me as its successor and my successor as its next successor") inform_packet = P2PRequestPacket( libp2pproto.INFORM_PREDECESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port, self.peer.successor["id"], self.peer.successor["ip_addr"], self.peer.successor["port"] ]) send_p2p_tcp_packet(self.peer.predecessor["ip_addr"], self.peer.predecessor["port"], inform_packet) # print("Informing my successor to add me as its predecessor") inform_packet = P2PRequestPacket( libp2pproto.INFORM_SUCCESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port ]) send_p2p_tcp_packet(self.peer.successor["ip_addr"], self.peer.successor["port"], inform_packet) self._stabilisation() else: self.peer.predecessor["id"] = None self.peer.predecessor["ip_addr"] = None self.peer.predecessor["port"] = None self.peer.successor["id"] = None self.peer.successor["ip_addr"] = None self.peer.successor["port"] = None else: raise e.strerror
def enter_p2p_network(self, peers_ip_port_list, dns_ip_addr): if len(peers_ip_port_list) == 0: # First node has no peers pass else: rand_index = randrange(len(peers_ip_port_list)) peer_id, peer_ip_addr, peer_port = peers_ip_port_list[rand_index] print("Joining P2P Network...") print("Chosen peer_ip addr: ", peer_ip_addr, "\tport: ", peer_port) req_packet = P2PRequestPacket(libp2pproto.GET_NEIGHBOURS_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port ]) try: res_packet = send_p2p_tcp_packet(peer_ip_addr, peer_port, req_packet) data = res_packet.data[0].split(" ") self.peer.predecessor["id"] = int(data[0]) self.peer.predecessor["ip_addr"] = data[1] self.peer.predecessor["port"] = int(data[2]) self.peer.successor["id"] = int(data[3]) self.peer.successor["ip_addr"] = data[4] self.peer.successor["port"] = int(data[5]) # handle case where there are at least 3 nodes in the network if int(data[6]) != -1: self.peer.next_successor["id"] = int(data[6]) self.peer.next_successor["ip_addr"] = data[7] self.peer.next_successor["port"] = int(data[8]) # print("Informing my predecessor's predecessor to add me as its next successor") inform_packet = P2PRequestPacket( libp2pproto.INFORM_PREDECESSOR_PREDECESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port ]) send_p2p_tcp_packet(self.peer.predecessor["ip_addr"], self.peer.predecessor["port"], inform_packet) # print("Informing my predecessor to add me as its successor and my successor as its next successor") inform_packet = P2PRequestPacket( libp2pproto.INFORM_PREDECESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port, self.peer.successor["id"], self.peer.successor["ip_addr"], self.peer.successor["port"] ]) send_p2p_tcp_packet(self.peer.predecessor["ip_addr"], self.peer.predecessor["port"], inform_packet) # print("Informing my successor to add me as its predecessor") inform_packet = P2PRequestPacket( libp2pproto.INFORM_SUCCESSOR_OP_WORD, [ self.peer.peer_id, self.peer.ip_addr, self.peer.external_port ]) send_p2p_tcp_packet(self.peer.successor["ip_addr"], self.peer.successor["port"], inform_packet) # Handle when node has left the network except socket.error as e: if e.errno == 111: libp2pdns.send_dns_remove_entry(peer_id, dns_ip_addr) del peers_ip_port_list[rand_index] self.enter_p2p_network(peers_ip_port_list, dns_ip_addr) else: raise e.strerror self.scheduler.add_job(self._stabilisation, 'interval', seconds=STABILISATION_INTERVAL) self.scheduler.start() return