示例#1
0
    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
示例#2
0
 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]
示例#3
0
 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
     ]
示例#4
0
    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,
        ]
示例#5
0
    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)
示例#6
0
    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 []
示例#7
0
    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
示例#8
0
 def _get_maintenance_query(self, node_):
     return message.OutgoingPingQuery(node_, self.my_node.id)