def forward_to_main_router(self, parsed_message): new_source_mac = self.router_data["server_side"]["mac_address"] destination_ip = parsed_message["destination_ip"] # find the router to which this one is connected for ip_address in self.network_connections: self.main_router_ip_address = ip_address break new_destination_mac = self.arp_table_mac[self.main_router_ip_address] destination_socket = self.socket_server_side parsed_message.update( source_mac=new_source_mac, destination_mac=new_destination_mac ) utils.show_status( self.router_id, "notifying main router of incoming message" ) self.notify_incoming_message() self.send_message(parsed_message, destination_socket, destination_ip)
def run(self): utils.show_status(self.getName(), "starting") connected = self.go_online() if(self.connected_to_server is False): if(connected is True): utils.show_status(self.router_id, "listening for packets") while not self.stop_event.isSet(): self.listen_server_side_aux_router() utils.show_status(self.router_id, "closing connections") # self.socket_server_side.shutdown(0) self.socket_server_side.close() # self.socket_client_side.shutdown(0) self.socket_client_side.close() # exit procedure self.stop_event.clear() utils.show_status(self.router_id, "going offline") del self.routers_threads[self.router_id] elif(connected is True): utils.show_status(self.router_id, "listening for packets") else: self.join()
def notify_incoming_connection(self): msg = " ".join(["notifying",self.router_id, \ "of an incoming connection"]) utils.show_status(self.client_id, msg) listen_task = threading.Thread( target=self.router_thread.listen_connections_client_side, daemon=True) listen_task.start()
def notify_incoming_message(self): msg = " ".join(["notifying", self.router_id, "of an incoming message"]) utils.show_status(self.client_id, msg) my_ip_address = self.client_data["ip_address"] listen_task = threading.Thread( target=self.router_thread.listen_client_side, args=[my_ip_address], daemon=True) listen_task.start()
def accept_connections(self): connections = len(self.routers_gateway_ip) + 1 while connections > 0: connected = self.listen_connections_server_side() if(connected is True): connections -= 1 utils.show_status(self.router_id, "all connections established")
def go_online(self): if(self.server_ip in self.network_connections): self.connected_to_server = True self.accept_connections() connected = True else: # connect with routers in network_connections connected = self.connect_with_routers() utils.show_status(self.router_id, "connected to the network") return connected
def listen_client_side(self, ip_address): utils.show_status( self.router_id, "releasing lock, client can send the message" ) # releasing lock, client can send the message self.sync_event_message.set() sender_socket = self.arp_table_socket[ip_address] self.listen_on_demand(sender_socket, self.handle_message_client_side)
def join(self, timeout=None): if(self.connected_to_server is True): utils.show_status(self.router_id, "going offline") self.socket_server_side.close() self.socket_client_side.close() self.stop_event.clear() del self.routers_threads[self.router_id] else: self.stop_event.set() threading.Thread.join(self, timeout)
def send_message(self, parsed_message): destination_ip = self.server_data["gateway_ip"] packet = utils.rewrite_packet(parsed_message) msg = " ".join(["Sending message to:", destination_ip]) utils.show_status(self.server_id, msg) self.notify_incoming_connection() # alert main router check.socket_send(self.server_connection, packet, "Could not send the message")
def handle_message_server_side(self, parsed_message): utils.show_status( self.router_id, "deciding where the message should go..." ) if(self.connected_to_server is True): self.handle_message_main_router(parsed_message) else: self.handle_message_aux_router(parsed_message)
def notify_incoming_connection(self): msg = " ".join(["notifying",self.router_id, \ "of an incoming connection"]) utils.show_status(self.server_id, msg) my_ip_address = self.server_data["ip_address"] listen_task = threading.Thread( target=self.router_thread.listen_server_side_main_router, args=[my_ip_address], daemon=True) listen_task.start()
def forward_message(self, parsed_message): msg = " ".join(["client", parsed_message["destination_ip"], \ "is online: forwading message"]) utils.show_status(self.server_id, msg) parsed_message.update( source_mac=self.server_data.get("mac_address"), destination_mac=self.arp_table_mac[self.server_data["gateway_ip"]]) utils.report(self.server_id, parsed_message, "reading packet received from a router") self.send_message(parsed_message)
def handle_message(self, parsed_message): time.sleep(2) utils.show_status(self.server_id, "deciding how to handle the message...") if (parsed_message["message"] == "{going offline}"): self.mark_client_offline(parsed_message) elif (parsed_message["message"] == "{going online}"): self.mark_client_online(parsed_message) elif (self.is_client_unreachable(parsed_message)): self.resend_back_message(parsed_message) else: self.forward_message(parsed_message)
def resend_back_message(self, parsed_message): msg = " ".join(["client", parsed_message["destination_ip"], \ "is not online: resending message back"]) utils.show_status(self.server_id, msg) sender_ip_address = parsed_message["source_ip"] parsed_message.update( source_ip=self.server_data.get("ip_address"), source_mac=self.server_data.get("mac_address"), destination_ip=sender_ip_address, destination_mac=self.arp_table_mac[self.server_data["gateway_ip"]], message="Client not currently available") self.send_message(parsed_message)
def go_online(self): utils.show_status(self.server_id, "connecting to the network") router_port = self.server_data["gateway_port"] router_address = ("localhost", router_port) gateway_ip = self.server_data["gateway_ip"] connected = check.socket_connect(self.server_connection, router_address, self.server_id) if (connected is True): msg = " ".join(["connected to", gateway_ip]) utils.show_status(self.server_id, msg) return connected
def handle_message_client_side(self, parsed_message): client_ip = parsed_message.get("source_ip") client_mac = parsed_message["source_mac"] if(self.waiting_arp_request is True): self.arp_table_mac[client_ip] = client_mac self.waiting_arp_request = False message_to_send = self.packets_queue.pop() self.handle_message_server_side(message_to_send) elif(self.connected_to_server is True): self.forward_to_server(parsed_message) else: utils.show_status(self.router_id, "forwading to main router") self.forward_to_main_router(parsed_message) time.sleep(2)
def connect_with_routers(self): connected_to_all = True for ip_address, port in self.network_connections.items(): connected = check.socket_connect( self.socket_server_side, ("localhost", port), self.router_id ) if(connected is True): msg = " ".join(["connected with router:", ip_address]) utils.show_status(self.router_id, msg) else: connected_to_all = False utils.show_status(self.router_id, "all connections established") return connected_to_all
def go_offline(self): utils.show_status(self.client_id, "going offline") gateway_ip = self.client_data["gateway_ip"] server_ip = self.client_data["server_ip"] leave_packet = utils.write_packet(self.client_data.get("ip_address"), server_ip, self.client_data.get("mac_address"), self.arp_table_mac[gateway_ip], "{going offline}") self.notify_incoming_message() self.sync_event_message.wait() # wait for router approval self.sync_event_message.clear() check.socket_send(self.client_connection, leave_packet, self.client_id, "Leave packet could not be sent") self.join()
def forward_to_client(self, parsed_message): destination_ip = parsed_message["destination_ip"] new_source_mac = self.router_data["client_side"]["mac_address"] if(destination_ip not in self.arp_table_mac and self.waiting_arp_request is False): utils.show_status(self.router_id, "sending ARP request") self.send_arp_request(parsed_message, new_source_mac, destination_ip) else: utils.show_status( self.router_id, "forwading packet to recipient client" ) new_destination_mac = self.arp_table_mac[destination_ip] self.forward_message( parsed_message, new_source_mac, destination_ip, new_destination_mac )
def load_network(path): network_data = {} try: with open(path, "r") as file: cfg = yaml.safe_load(file) servers_data = cfg["servers"] routers_data = cfg["routers"] clients_data = cfg["clients"] except yaml.YAMLError as err_msg: msg = " ".join(["error loading network configuration file", \ str(err_msg)]) utils.show_status("main", msg) sys.exit() # pack dictionaries network_data["servers_data"] = servers_data network_data["routers_data"] = routers_data network_data["clients_data"] = clients_data return network_data
def send_message(self, parsed_message, destination_socket, destination_ip): packet = utils.rewrite_packet( parsed_message ) utils.report( self.router_id, parsed_message, "preparing to forward the following packet:" ) check.socket_send( destination_socket, packet, self.router_id, "packet to the client could not be sent" ) msg = " ".join(["message sent to", destination_ip]) utils.show_status(self.router_id, msg)
def listen_server_side_aux_router(self): received_message = check.socket_recv( self.socket_server_side, self.router_id ) if(received_message is not None and len(received_message) > 0): parsed_message = utils.read_packet(received_message) msg = " ".join(["message received from:", self.server_ip]) utils.show_status(self.router_id, msg) utils.report( self.router_id, parsed_message, "reading packet received" ) self.handle_message_server_side(parsed_message)
def listen_packets(self): received_message = check.socket_recv(self.client_connection, self.client_id) if (received_message is not None and len(received_message) > 0): parsed_message = utils.read_packet(received_message) time.sleep(2) # give time to router to show its status msg = " ".join( ["message received from:", parsed_message["source_ip"]]) utils.show_status(self.client_id, msg) utils.report(self.client_id, parsed_message, "reading received packet") if (parsed_message["destination_mac"] == BROADCAST_MAC): msg = " ".join([ "received an ARP request from", parsed_message["source_ip"] ]) utils.show_status(self.client_id, msg) self.send_message(parsed_message.get("source_ip"), "{ARP reply}")
def listen_connections_server_side(self): network_connection, address = check.socket_accept( self.socket_server_side, "Connection could not be established" ) if(network_connection != None and network_connection not in self.arp_table_socket): if(address[1] in self.routers_gateway_ip): ip_address = self.routers_gateway_ip[address[1]] msg = " ".join(["connected with router:", ip_address]) utils.show_status(self.router_id, msg) else: msg = " ".join(["connected with server:", self.server_ip]) utils.show_status(self.router_id, msg) ip_address = self.server_ip self.arp_table_socket[ip_address] = network_connection return True return False
def run(self): utils.show_status(self.getName(), "starting") connected = self.go_online() if (connected is True): utils.show_status(self.server_id, "listening for incoming packets") while not self.stop_event.isSet(): self.listen_packets() # exit procedure utils.show_status(self.server_id, "closing connection") self.server_connection.close() utils.show_status(self.server_id, "going offline") del self.servers_threads[self.server_id]
def listen_connections_client_side(self): utils.show_status( self.router_id, "releasing lock, client can connect to this router" ) self.sync_event_connection.set() while True: client_connection, address = check.socket_accept( self.socket_client_side, self.router_id ) if(client_connection != None and client_connection not in self.arp_table_socket): ip_address = self.clients_gateway_ip[address[1]] self.arp_table_socket[ip_address] = client_connection msg = " ".join(["connected with client", ip_address]) utils.show_status(self.router_id, msg) self.sync_event_connection.set() # waiting for router approval break # only the first valid connection is accepted
def send_message(self, recipient_ip, message): gateway_ip = self.client_data["gateway_ip"] packet = utils.write_packet(self.client_data["ip_address"], recipient_ip, self.client_data.get("mac_address"), self.arp_table_mac[gateway_ip], message) utils.show_status(self.client_id, "waiting for router listening messages") self.notify_incoming_message() # waiting for router approving message sending self.sync_event_message.wait() sent = check.socket_send(self.client_connection, packet, self.router_id) if (sent is True): msg = " ".join(["message sent to", gateway_ip]) utils.show_status(self.client_id, msg) self.sync_event_message.clear()
def close_all_connections(entities_threads): utils.show_status("main", "beginning shutdown") # unpack dictionary and creating defensive copies to avoid changing # size of the dictionaries during iteration if ("servers_threads" in entities_threads): servers_threads = entities_threads["servers_threads"] servers_threads_list = list(servers_threads.values()) for server_thread in servers_threads_list: server_thread.join() if ("routers_threads" in entities_threads): routers_threads = entities_threads["routers_threads"] routers_threads_list = list(routers_threads.values()) for router_thread in routers_threads_list: router_thread.join() if ("clients_threads" in entities_threads): clients_threads = entities_threads["clients_threads"] clients_threads_list = list(clients_threads.values()) for client_thread in clients_threads_list: client_thread.join() utils.show_status("main", "shutdown completed")
def notify_incoming_message(self): utils.show_status( self.router_id, "notifying an incoming message from this router" ) my_ip_address = self.router_data["server_side"]["ip_address"] for router, router_data in self.routers_data.items(): if(router_data["server_side"]["ip_address"] == \ self.main_router_ip_address): router_id = router break router_thread = self.routers_threads[router_id] # tell the main router to start listening for a message # from this router listen_task = threading.Thread( target=router_thread.listen_server_side_main_router, args=[my_ip_address], daemon=True ) listen_task.start()
def go_online(self): utils.show_status(self.client_id, "connecting to the network") server_ip = self.client_data["server_ip"] router_port = self.client_data["gateway_port"] router_address = ("localhost", router_port) gateway_ip = self.client_data["gateway_ip"] self.notify_incoming_connection() # waiting for router approving connection self.sync_event_connection.wait() self.sync_event_connection.clear() # ready for reuse connected = check.socket_connect(self.client_connection, router_address, self.client_id) if (connected is True): utils.show_status(self.client_id, "going online") # waiting for router completing connection procedure self.sync_event_connection.wait() self.sync_event_connection.clear() # ready for reuse greeting_packet = utils.write_packet( self.client_data.get("ip_address"), server_ip, self.client_data.get("mac_address"), self.arp_table_mac[gateway_ip], "{going online}") utils.show_status(self.client_id, "waiting for router accepting message") self.notify_incoming_message() # waiting for router approving message sending self.sync_event_message.wait() self.sync_event_message.clear() check.socket_send(self.client_connection, greeting_packet, self.client_id, "Greeting packet could not be sent") return connected