def __handle_register_packet(self, packet: Packet): """ For registration a new node to the network at first we should make a Node with stream.add_node for'sender' and save it. Code design suggestion: 1.For checking whether an address is registered since now or not you can use SemiNode object except Node. Warnings: 1. Don't forget to ignore Register Request packets when you are a non-root peer. :param packet: Arrived register packet :type packet Packet :return: """ register_type = self.__identify_register_type(packet) if self.is_root and register_type == RegisterType.REQ: new_node = SemiNode(packet.get_source_server_ip(), packet.get_source_server_port()) if new_node in self.registered: return self.registered.append(new_node) sender_address = packet.get_source_server_address() self.stream.add_node(sender_address, set_register_connection=True) register_response_packet = PacketFactory.new_register_packet( RegisterType.RES, self.address) self.stream.add_message_to_out_buff(sender_address, register_response_packet, want_register=True) elif register_type == RegisterType.RES: log('Register request ACKed by root. You are now registered.')
def __handle_message_packet(self, packet: Packet): """ Only broadcast message to the other nodes. Warnings: 1. Do not forget to ignore messages from unknown sources. 2. Make sure that you are not sending a message to a register_connection. :param packet: Arrived message packet :type packet Packet :return: """ log(f'New message arrived: {packet.get_body()}') sender_address = packet.get_source_server_address() updated_packet = PacketFactory.new_message_packet( packet.get_body(), self.address) if self.__check_neighbour(sender_address): # From known source for neighbor_address in [ *self.children_addresses, self.parent_address ]: if neighbor_address is not None and neighbor_address != sender_address: self.stream.add_message_to_out_buff( neighbor_address, updated_packet)
def run(self): """ The main loop of the program. Code design suggestions: 1. Parse server in_buf of the stream. ---- done 2. Handle all packets were received from our Stream server. ---- done 3. Parse user_interface_buffer to make message packets. ---- done 4. Send packets stored in nodes buffer of our Stream object. ---- done 5. ** sleep the current thread for 2 seconds ** -------- done Warnings: 1. At first check reunion daemon condition; Maybe we have a problem in this time and so we should hold any actions until Reunion acceptance. ------- done 2. In every situation checkout Advertise Response packets; even if Reunion in failure mode or not ------- done :return: """ while True: if not self.is_root: if self.is_client_connected: input_buffer = self.stream.read_in_buf() for buf in input_buffer: packet = Packet(buf) print('gonna print a received packet! ') print(packet.__dict__) self.handle_packet(packet) self.stream.clear_in_buff( ) # TODO buffer messages that use unvailable addreses unavailable_addreses = self.stream.send_out_buf_messages() if self.root_address in unavailable_addreses: self.is_client_connected = False for add in unavailable_addreses: if add in self.successors_address: self.successors_address.remove(add) else: input_buffer = self.stream.read_in_buf() for buf in input_buffer: packet = Packet(buf) if packet.type == PacketType.ADVERTISE: self.__handle_advertise_packet(packet) self.stream.clear_in_buff() self.handle_user_interface_buffer() else: input_buffer = self.stream.read_in_buf() for buf in input_buffer: packet = Packet(buf) print('gonna print a received packet! ') print(packet.__dict__) self.handle_packet(packet) self.stream.clear_in_buff() self.handle_user_interface_buffer() unavailable_addreses = self.stream.send_out_buf_messages() for add in unavailable_addreses: if add in self.successors_address: self.successors_address.remove(add) time.sleep(2)
def send_helloback(self, packet): if not self.is_root: return print('Sending Hello back') packet.body = 'RES' + packet.body[3:] packet.source_ip = self.address[0] packet.source_port = self.address[1] packet = Packet(packet.get_buf()) self.send_broadcast_packet(packet)
def forward_helloback(self, packet): packet = self.change_header(packet) packet.body = packet.body[:-20] number_of_entries = str(int(packet.body[3:5]) - 1).zfill(2) packet.body = 'RES' + number_of_entries + packet.body[5:] packet = Packet(packet.get_buf()) fw_address = packet.body[-20:] fw_address = (fw_address[:15], fw_address[15:]) if fw_address in self.successors_address: self.stream.add_message_to_out_buff(fw_address, packet) else: return
def parse_in_buf(self): buffer = self.stream.read_in_buf() header_size = 20 if len(buffer) < header_size: return None packet = Packet(buf=buffer[0:20]) packet_length = packet.get_length() if len(buffer) < packet_length: return None packet = Packet(buf=buffer[0:packet_length]) self.stream.delete_buffer(packet_length) return packet
def forward_hello(self, packet, is_mine=False): if is_mine: self.stream.add_message_to_out_buff( self.client_predecessor_address, packet) else: print('Forwarding a Hello that is not mine') packet = self.change_header(packet) packet.body += str(self.address[0]) + str(self.address[1]) new_number_of_elements = int(packet.body[3:5]) + 1 packet.body = 'REQ' + str(new_number_of_elements).zfill( 2) + packet.body[5:] packet = Packet(packet.get_buf()) self.stream.add_message_to_out_buff( self.client_predecessor_address, packet)
def __pass_reunion_hello_back(self, packet: Packet): new_addresses = packet.get_addresses()[1:] next_node_address = new_addresses[0] log(f'HelloBack packet passed down to Node({next_node_address}).') passed_packet = PacketFactory.new_reunion_packet( ReunionType.RES, self.address, new_addresses) self.stream.add_message_to_out_buff(next_node_address, passed_packet)
def __handle_reunion_hello_back(self, packet: Packet): if packet.get_addresses()[-1] == self.address: # It's our hello back! self.last_hello_back_time = time.time() log('We received our HelloBack.') else: self.__pass_reunion_hello_back(packet)
def __handle_advertise_response(self, packet: Packet) -> None: self.last_hello_time = time.time() self.last_hello_back_time = time.time() parent_address = packet.get_advertised_address() log(f'Trying to join Node({parent_address})...') self.parent_address = parent_address join_packet = PacketFactory.new_join_packet(self.address) self.stream.add_node( parent_address) # Add a non_register Node to stream to the parent log(f'Join Request added to out buf on Node({parent_address}).') self.stream.add_message_to_out_buff(parent_address, join_packet) self.reunion_mode = ReunionMode.ACCEPTANCE if not self.reunion_daemon.is_alive(): self.reunion_daemon.start()
def __handle_join_packet(self, packet: Packet): """ When a Join packet received we should add a new node to our nodes array. In reality, there is a security level that forbids joining every node to our network. :param packet: Arrived register packet. :type packet Packet :return: """ new_member_address = packet.get_source_server_address() log(f'New JOIN packet from Node({new_member_address}).') self.stream.add_node(new_member_address) self.children_addresses.append(new_member_address)
def __handle_advertise_request(self, packet: Packet) -> None: sender_address = packet.get_source_server_address() sender_semi_node = SemiNode(sender_address[0], sender_address[1]) if sender_semi_node not in self.registered: log(f'Advertise Request from unregistered source({sender_address}).' ) return advertised_address = self.__get_neighbour(sender_address) log(f'Advertising Node({advertised_address}) to Node({sender_address}).' ) advertise_response_packet = PacketFactory.new_advertise_packet( AdvertiseType.RES, self.address, advertised_address) self.stream.add_message_to_out_buff(sender_address, advertise_response_packet, want_register=True) # Add to network_graph self.network_graph.add_node(sender_semi_node.get_ip(), sender_semi_node.get_port(), advertised_address)
def __identify_reunion_type(self, packet: Packet) -> ReunionType: reunion_type = packet.get_body()[:3] return ReunionType(reunion_type)
def change_header(self, packet): packet.source_ip, packet.source_port = self.address[0], self.address[1] packet = Packet(packet.get_buf()) return packet
def __identify_advertise_type(self, packet: Packet) -> AdvertiseType: advertise_type = packet.get_body()[:3] return AdvertiseType(advertise_type)
def __identify_register_type(self, packet: Packet) -> RegisterType: register_type = packet.get_body()[:3] return RegisterType(register_type)
def __respond_to_reunion(self, packet: Packet): reversed_addresses = packet.get_addresses_in_reverse() response_packet = PacketFactory.new_reunion_packet( ReunionType.RES, self.address, reversed_addresses) next_node_address = reversed_addresses[0] self.stream.add_message_to_out_buff(next_node_address, response_packet)
def __update_last_reunion(self, packet: Packet): sender_address = packet.get_addresses()[0] next_node = packet.get_addresses()[-1] self.network_graph.keep_alive(sender_address) log(f'New Hello from Node({sender_address}).') log(f'HelloBack added to out buf of Node({next_node})')
def __format_reunion_hello_addresses_on_pass( self, packet: Packet) -> List[Address]: addresses = packet.get_addresses() addresses.append(self.address) return addresses
def __validate_received_packet(packet: Packet) -> bool: if packet.get_length() != len(packet.get_body()): return False # TODO: More conditions return True