def stop_communication(self): """ Stop listening to and for peers. Stop threaded peer sync. """ if self.rcv.is_listening: self.rcv.stop_listening() if getattr(self, '_ping_peer_thread', None): self.peer_sync_active = False self._ping_peer_thread.join(0) else: debug_print("Listener: Wasn't running! Nothing stopped!")
def start_communication(self): """ Start listening to and for peers. Start threaded peer sync. """ if not self.rcv.is_listening: self.rcv.start_listening() self.peer_sync_active = True self._ping_peer_thread = threading.Thread(target=self.schedule_peer_ping_sync) self._ping_peer_thread.setDaemon(True) self._ping_peer_thread.start() else: debug_print("Listener: Already running! Nothing started!")
def schedule_peer_ping_sync(self, interval=None): """ Run a search for active peers every x seconds. Notes: THIS IS A BLOCKING CALL. Use threading. Args: interval (int): time between syncs in sec. (Default: 'self.peer_sync_interval'.) """ if not interval: interval = self.peer_sync_interval while self.peer_sync_active: self.do_peer_ping_sync() debug_print('Network Node Sync: Next sync in {} seconds'.format(interval)) time.sleep(interval)
def do_peer_ping_sync(self): """ Sends a sync request to peers, sleeps 'PEER_SYNC_TIMEOUT' seconds and then updates the node list. Notes: THIS IS A BLOCKING CALL. Use threading. """ debug_print('Network Node Sync: Started') self.snd.send(SYNC_REQUEST_MSG) timestamp = dt.utcnow() time.sleep(PEER_SYNC_TIMEOUT) # give peers x secs to resp # create a list of peers that responded after the timestamp peers_alive = [node for node in self.know_network_nodes.values() if node.last_seen > timestamp] # create a list of peers that are currently displayed but not online anymore peers_offline = [node for node in self.know_network_nodes.values() if node not in peers_alive] for node in peers_offline: self.update_known_peers_and_inform_gui('remove', (node.ip, node.port)) debug_print('Network Node Sync: Finished')
def hold_master_election(network_nodes): """ This is the default master election algorithm. The network_node with the 'lowest ip' will be considered master. Args: network_nodes (list of NetworkNode): network nodes Returns (NetworkNode): master node """ if not network_nodes: return NetworkNode('', 0) lowest_addr = NetworkNode('999.999.999.999', 999999) debug_print("Electing master amongst the following peers:") debug_print('[' + ', '.join([n.ip for n in network_nodes]) + ']') for node in network_nodes: if ip_to_int(node.ip) < ip_to_int(lowest_addr.ip): lowest_addr = node return lowest_addr
def update_known_peers(self, action, addr): """ Updates a peer list by adding/removing the given addr. Basic error treatment makes sure that addresses are unique per list. Args: action: 'add' or 'remove' addr (tuple): (ip, port) """ peer_ip = addr[0] peer_port = addr[1] if peer_ip == self.own_ip: return if action.lower() == 'add': if not self.know_network_nodes.get(peer_ip, None): debug_print("Node '{}' joined!".format(peer_ip)) self.know_network_nodes[peer_ip] = NetworkNode( peer_ip, peer_port) else: debug_print("Node '{}' was seen!".format(peer_ip)) self.know_network_nodes[peer_ip].last_seen = dt.utcnow() if action.lower() == 'remove': if self.know_network_nodes.get(peer_ip, None): debug_print("Node '{}' left!".format(peer_ip)) del self.know_network_nodes[peer_ip]
def process_incoming_message(self, msg, addr): """ This function processes all incoming messages and starts the appropriate actions. Args: msg (str): message addr (tuple): (ip, port) """ full_str = msg + ' from: ' + addr[0] debug_print('Message rcvd:' + full_str) if addr[0] != self.own_ip: if msg == GOODBYE_MSG: self.update_known_peers_and_inform_gui('remove', addr) elif msg == SYNC_AKN_MSG: self.update_known_peers_and_inform_gui('add', addr) elif msg == SYNC_REQUEST_MSG: self.update_known_peers_and_inform_gui('add', addr) self.resp_to_ping_sync() else: self.update_known_peers_and_inform_gui('add', addr) self.window.make_state_active(full_str) else: self.update_known_peers('add', addr)
def stop_listening(self): """ Stoppes the threaded listener function. """ if self.is_listening: debug_print("Listener: Stopping service ...") self._stop.set() self._server_thread.join(timeout=0) self.is_listening = False self._server_socket.close() debug_print("Listener: Stopped") else: debug_print("Listener: Service wasn't running. Nothing to stop.")
def start_listening(self): """ Starts a (threaded) listener function. """ if not self.is_listening: debug_print('Listener: Starting service ...') self._stop = threading.Event() self._server_socket = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self._server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) self._server_socket.bind(('', self.port)) self.is_listening = True self._server_thread = threading.Thread(target=self._listen_for_broadcasts) self._server_thread.setDaemon(True) self._server_thread.start() debug_print('Listener: Started ...') else: debug_print('Listener: Service already running. Nothing was started.')
Args: msg (str): message addr (tuple): (ip, port) """ full_str = msg + ' from: ' + addr[0] debug_print('Message rcvd:' + full_str) if addr[0] != self.own_ip: if msg == GOODBYE_MSG: self.update_known_peers_and_inform_gui('remove', addr) elif msg == SYNC_AKN_MSG: self.update_known_peers_and_inform_gui('add', addr) elif msg == SYNC_REQUEST_MSG: self.update_known_peers_and_inform_gui('add', addr) self.resp_to_ping_sync() else: self.update_known_peers_and_inform_gui('add', addr) self.window.make_state_active(full_str) else: self.update_known_peers('add', addr) if __name__ == '__main__': """ This is executed if this file is called from cli. """ debug_print('Let\'s do this.') app = App() app.start()