def on_query_received(self, node_): ''' Return None when nothing to do Return a list of queries when queries need to be sent (the queries will be sent out by the caller) ''' if self._maintenance_mode != NORMAL_MODE: return log_distance = self.my_node.log_distance(node_) try: sbucket = self.table.get_sbucket(log_distance) except (IndexError): return # Got a query from myself. Just ignore it. m_bucket = sbucket.main rnode = m_bucket.get_rnode(node_) if rnode: # node in routing table: inform rnode self._update_rnode_on_query_received(rnode) return # node is not in the routing table if m_bucket.there_is_room(): # There is room in the bucket. Just add the new node. rnode = node_.get_rnode(log_distance) m_bucket.add(rnode) self.table.num_rnodes += 1 self._update_rnode_on_query_received(rnode) return # No room in the main routing table # Check whether there is a bad node to be replaced. bad_rnode = self._pop_bad_rnode(m_bucket) if bad_rnode: # We have a bad node in the bucket. Replace it with the new node. rnode = node_.get_rnode(log_distance) m_bucket.add(rnode) self._update_rnode_on_query_received(rnode) self.table.num_rnodes += 0 return # No bad nodes. Check for questionable nodes q_rnodes = self._get_questionable_rnodes(m_bucket) queries_to_send = [] for q_rnode in q_rnodes: # Ping questinable nodes to check whether they are still alive. # (0 timeouts so far, candidate node) c_rnode = node_.get_rnode(log_distance) self._update_rnode_on_query_received(c_rnode) self._pinged_q_rnodes[q_rnode] = [0, c_rnode] queries_to_send.append( message.OutgoingPingQuery(node_, self.my_node.id)) return queries_to_send
def on_query_received(self, msg): if not self._stop and msg.query == 'ping': self._stop = True self.pinged_ips[msg.src_node.ip] = msg.src_node.ip print '\nExperimentalModule got query (%s) from node %r =' % ( msg.query, msg.src_node) if msg.src_node.ip not in self.pinged_ips: # prepare to ping to the node from which it got ping probe_query = message.OutgoingPingQuery( msg.src_node, self.my_id, ExpObj(msg.query)) # self.pinged_ips[msg.src_node.ip] = True self.pinged_ips[msg.src_node.ip] = STATUS_PINGED # print 'ping send to ip address : ' , self.pinged_ips['ip_address'] return [probe_query]
def __init__(self, my_node, bootstrap_nodes): self.my_node = my_node self.bootstrap_nodes = iter(bootstrap_nodes) self.table = RoutingTable(my_node, NODES_PER_BUCKET) self.ping_msg = message.OutgoingPingQuery(my_node.id) self.find_closest_msg = message.OutgoingFindNodeQuery( my_node.id, my_node.id) self._next_stale_maintenance_index = 0 self._maintenance_mode = BOOTSTRAP_MODE self._replacement_queue = _ReplacementQueue(self.table) self._query_received_queue = _QueryReceivedQueue(self.table) self._found_nodes_queue = _FoundNodesQueue(self.table) self._maintenance_tasks = [ self._ping_a_staled_rnode, self._ping_a_query_received_node, self._ping_a_found_node, self._ping_a_replacement_node ]
def __init__(self, my_node, bootstrap_nodes): self.my_node = my_node #Copy the bootstrap list self.bootstrap_nodes = iter(bootstrap_nodes) self.table = RoutingTable(my_node, NODES_PER_BUCKET) self.ping_msg = message.OutgoingPingQuery(my_node.id) self.find_closest_msg = message.OutgoingFindNodeQuery( my_node.id, my_node.id) # maintenance variables self._maintenance_mode = BOOTSTRAP_MODE self._pinged_q_rnodes = {} # questionable nodes which have been # recently pinged self._maintenance_tasks = [ self._refresh_stale_bucket, #self._ping_a_staled_rnode, # self._ping_a_query_received_node, # self._ping_a_found_node, ]
def _get_maintenance_query(self, node_): if not node_.id: # Bootstrap nodes don't have id return message.OutgoingFindNodeQuery(node_, self.my_node.id, self.my_node.id, None) if random.choice((False, True)): # 50% chance to send find_node with my id as target return message.OutgoingFindNodeQuery(node_, self.my_node.id, self.my_node.id, None) # 50% chance to send a find_node to fill up a non-full bucket target_log_distance = self.table.find_next_bucket_with_room_index( node_=node_) if target_log_distance: target = self.my_node.id.generate_close_id(target_log_distance) return message.OutgoingFindNodeQuery(node_, self.my_node.id, target, None) else: # Every bucket is full. We send a ping instead. return message.OutgoingPingQuery(node_, self.my_node.id)
def on_timeout(self, node_): if not node_.id: return [] # This is a bootstrap node (just addr, no id) log_distance = self.my_node.log_distance(node_) try: sbucket = self.table.get_sbucket(log_distance) except (IndexError): return [] # Got a timeout from myself, WTF? Just ignore. m_bucket = sbucket.main rnode = m_bucket.get_rnode(node_) if not rnode: # This node is not in the table. Nothing to do here return [] # The node is in the table. Update it self._update_rnode_on_timeout(rnode) t_strikes, c_rnode = self._pinged_q_rnodes.get(node_, (None, None)) if t_strikes is None: # The node is not being checked by a "questinable ping". return [] elif t_strikes == 0: # This is the first timeout self._pinged_q_rnodes[node_] = (1, c_rnode) # Let's give it another chance return [message.OutgoingPingQuery(node_, self.my_node.id)] elif t_strikes == 1: # Second timeout. You're a bad node, replace if possible # check if the candidate node is in the routing table log_distance = self.my_node.log_distance(c_rnode) m_bucket = self.table.get_sbucket(log_distance).main c_rnode_in_table = m_bucket.get_rnode(c_rnode) if c_rnode_in_table: print 'questionable node replaced' # replace m_bucket.remove(rnode) m_bucket.add(c_rnode) self.table.num_rnodes += 0 return []
def on_response_received(self, node_, rtt, nodes): log_distance = self.my_node.log_distance(node_) try: sbucket = self.table.get_sbucket(log_distance) except (IndexError): return # Got a response from myself. Just ignore it. m_bucket = sbucket.main rnode = m_bucket.get_rnode(node_) if rnode: logger.debug('node in main') # node in routing table: update self._update_rnode_on_response_received(rnode, rtt) if self._maintenance_mode == NORMAL_MODE: m_bucket.last_changed_ts = time.time() if node_ in self._pinged_q_rnodes: logger.debug('remove from questionable') rnode.questionable = False # This node is questionable. This response proves that it is # alive. Remove it from the questionable dict. del self._pinged_q_rnodes[node_] return # The node is not in main if m_bucket.there_is_room(): logger.debug('node not in main, there is room') rnode = node_.get_rnode(log_distance) m_bucket.add(rnode) self.table.num_rnodes += 1 self._update_rnode_on_response_received(rnode, rtt) if self._maintenance_mode == NORMAL_MODE: m_bucket.last_changed_ts = time.time() return # The main bucket is full # if there is a bad node inside the bucket, # replace it with the sending node_ logger.debug('node not in main, no room') bad_rnode = self._pop_bad_rnode(m_bucket) if bad_rnode: logger.debug('there is a bad rnode') rnode = node_.get_rnode(log_distance) m_bucket.add(rnode) # No need to update table self.table.num_rnodes += 0 self._update_rnode_on_response_received(rnode, rtt) if self._maintenance_mode == NORMAL_MODE: m_bucket.last_changed_ts = time.time() return # There are no bad nodes. Ping questionable nodes (if any) logger.debug('no bad nodes, ping questionable nodes') q_rnodes = self._get_questionable_rnodes(m_bucket) queries_to_send = [] for q_rnode in q_rnodes: # (0 timeouts so far, candidate node) c_rnode = node_.get_rnode(log_distance) self._update_rnode_on_response_received(c_rnode, rtt) self._pinged_q_rnodes[q_rnode] = [0, c_rnode] queries_to_send.append( message.OutgoingPingQuery(node_, self.my_node.id)) return queries_to_send
def _get_maintenance_query(self, node_): return message.OutgoingPingQuery(node_, self.my_node.id)