def get_node_by_server(self, ip, port): """ Will find the node that has IP/Port address of input. Warnings: 1. Before comparing the address parse it to a standard format with Node.parse_### functions. :param ip: input address IP :param port: input address Port :return: The node that input address. :rtype: Node """ input = Node.parse_address((ip, port)) # print('.........') # print(input[0]) # print(input[1]) # print('.........') # print(len(self.nodes)) for node in self.nodes: add = Node.parse_address(node.get_server_address()) # print('xxxxxxxxxxxx') # print(add[0]) # print(add[1]) # print('xxxxxxxxxxxx') if (input[0] == add[0]) and (input[1] == add[1]): return node pass
def __handle_advertise_packet(self, packet): """ For advertising peers in the network, It is peer discovery message. Request: We should act as the root of the network and reply with a neighbour address in a new Advertise Response packet. Response: When an Advertise Response packet type arrived we should update our parent peer and send a Join packet to the new parent. Code design suggestion: 1. Start the Reunion daemon thread when the first Advertise Response packet received. 2. When an Advertise Response message arrived, make a new Join packet immediately for the advertised address. Warnings: 1. Don't forget to ignore Advertise Request packets when you are a non-root peer. 2. The addresses which still haven't registered to the network can not request any peer discovery message. 3. Maybe it's not the first time that the source of the packet sends Advertise Request message. This will happen in rare situations like Reunion Failure. Pay attention, don't advertise the address to the packet sender sub-tree. 4. When an Advertise Response packet arrived update our Peer parent for sending Reunion Packets. :param packet: Arrived register packet :type packet Packet :return: """ if (packet.body[0:3] == 'RES') and (not self.is_root): self.children.clear() self.stream.remove_not_reg_nodes() self.parent = Node.parse_address( (packet.body[3:18], packet.body[18:23])) succ = self.stream.add_node(self.parent) if not succ: return join = PacketFactory.new_join_packet(self.address) self.stream.add_message_to_out_buff(self.parent, join) self.is_connected = True self.r_h_b_received = True self.since_last = 0 # now we are connected elif (packet.body[0:3] == 'REQ') and (self.is_root): if not self.graph.is_registered( packet.get_source_server_address()): return address = self.graph.find_live_node( packet.get_source_server_address()).get_address() if address is None: return self.graph.add_node(packet.sender_ip, packet.sender_port, address) res_pkt = PacketFactory.new_advertise_packet( 'RES', self.address, address) self.stream.add_message_to_out_buff( packet.get_source_server_address(), res_pkt) pass
def find_node(self, ip, port): input = Node.parse_address((ip, port)) for g_node in self.nodes: if (g_node.get_address()[0] == input[0]) and (g_node.get_address()[1] == input[1]): return g_node for g_node in self.registered: if (g_node.get_address()[0] == input[0]) and (g_node.get_address()[1] == input[1]): return g_node pass
def get_address(self): return Node.parse_address(self.address)
def __handle_advertise_packet(self, packet): """ For advertising peers in the network, It is peer discovery message. Request: We should act as the root of the network and reply with a neighbour address in a new Advertise Response packet. Response: When an Advertise Response packet type arrived we should update our parent peer and send a Join packet to the new parent. Code design suggestion: 1. Start the Reunion daemon thread when the first Advertise Response packet received. 2. When an Advertise Response message arrived, make a new Join packet immediately for the advertised address. Warnings: 1. Don't forget to ignore Advertise Request packets when you are a non-root peer. 2. The addresses which still haven't registered to the network can not request any peer discovery message. 3. Maybe it's not the first time that the source of the packet sends Advertise Request message. This will happen in rare situations like Reunion Failure. Pay attention, don't advertise the address to the packet sender sub-tree. 4. When an Advertise Response packet arrived update our Peer parent for sending Reunion Packets. :param packet: Arrived advertise packet :type packet Packet :return: """ body_str = packet.get_body() if self.is_root: if len(body_str) != 3 or body_str != Packet.BODY_REQ: return if not self.__check_registered(packet.get_source_server_address()): print( 'Peer that has sent request advertise has not registered before.' ) return neighbour_address = self.__get_neighbour( packet.get_source_server_address()) print('neighbour for', packet.get_source_server_address(), 'is', neighbour_address) response_packet = self.packet_factory.new_advertise_packet( Packet.BODY_RES, packet.get_source_server_address(), Node.parse_address(neighbour_address)) message = response_packet.get_buf() self.stream.add_message_to_out_buff( packet.get_source_server_address(), message, is_register_node=True) self.network_graph.add_node(packet.get_source_server_ip(), packet.get_source_server_port(), neighbour_address) self.network_graph.turn_on_node(packet.get_source_server_address()) self.last_received_hello_times[ packet.get_source_server_address()] = time.time() else: if len(body_str) != 23 or body_str[:3] != Packet.BODY_RES: return parent_ip = body_str[3:18] parent_port = body_str[18:23] self.parent_address = (parent_ip, parent_port) self.stream.add_node(self.parent_address) join_packet = self.packet_factory.new_join_packet(self.address) message = join_packet.get_buf() self.stream.add_message_to_out_buff(self.parent_address, message) self.waiting_for_hello_back = False if not self.reunion_daemon.is_alive(): self.reunion_daemon.start()
def __init__(self, server_ip, server_port, is_root=False, root_address=None): """ The Peer object constructor. Code design suggestions: 1. Initialise a Stream object for our Peer. 2. Initialise a PacketFactory object. 3. Initialise our UserInterface for interaction with user commandline. 4. Initialise a Thread for handling reunion daemon. Warnings: 1. For root Peer, we need a NetworkGraph object. 2. In root Peer, start reunion daemon as soon as possible. 3. In client Peer, we need to connect to the root of the network, Don't forget to set this connection as a register_connection. :param server_ip: Server IP address for this Peer that should be pass to Stream. :param server_port: Server Port address for this Peer that should be pass to Stream. :param is_root: Specify that is this Peer root or not. :param root_address: Root IP/Port address if we are a client. :type server_ip: str :type server_port: int :type is_root: bool :type root_address: tuple """ self.address = (Node.parse_ip(server_ip), Node.parse_port(str(server_port))) self.root_address = None if root_address is None else Node.parse_address( root_address) self.stream = Stream(server_ip, server_port, root_address) self.packet_factory = PacketFactory() self.ui = UserInterface() self.ui.daemon = True self.is_root = is_root self.parent_address = None self.children = [] self.network_graph = None self.registered_peers = None self.waiting_for_hello_back = False self.last_sent_hello_time = None self.reunion_daemon = threading.Thread(target=self.run_reunion_daemon) self.reunion_daemon.daemon = True if is_root: root_graph_node = GraphNode(self.address) root_graph_node.depth = 0 self.network_graph = NetworkGraph(root_graph_node) self.registered_peers = dict() self.last_received_hello_times = dict() self.reunion_daemon.start() elif root_address is not None: self.stream.add_node(root_address, set_register_connection=True) self.start_user_interface() print('Peer initialized.')
def address_equal(self, address1, address2): address1 = Node.parse_address(address1) address2 = Node.parse_address(address2) return (address1[0] == address2[0]) and (address1[1] == address2[1])
def set_root_address(self, ip, port): self.root_address = Node.parse_address((ip, port)) print(self.root_address)