Beispiel #1
0
 def _get_maintenance_query(self, node_):
     if not node_.id:
         return Query(self.find_closest_msg, node_)
     elif random.choice((False, True)):
         return Query(self.find_closest_msg, node_)
     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 Query(
             message.OutgoingFindNodeQuery(self.my_node.id, target), node_)
     else:
         return Query(self.ping_msg, node_)
Beispiel #2
0
 def announce(self):
     if not self._bt_port:
         return [], False
     nodes_to_announce = self._lookup_queue.get_closest_responded_qnodes()
     announce_to_myself = False
     #TODO: is is worth it to announce to self? The problem is that I don't
     #know my own IP number. Maybe if 127.0.0.1 translates into "I (the
     #node returning 127.0.0.1) am in the swarm".
     '''
     if len(nodes_to_announce) < ANNOUNCE_REDUNDANCY:
         announce_to_myself = True
     elif (self._my_id.log_distance(self._info_hash) <
           nodes_to_announce[ANNOUNCE_REDUNDANCY-1].id.log_distance(
             self._info_hash)):
         nodes_to_announce = nodes_to_announce[:-1]
         announce_to_myself = True
     '''
     queries_to_send = []
     for qnode in nodes_to_announce:
         logger.debug('announcing to %r' % qnode.node)
         msg = message.OutgoingAnnouncePeerQuery(self._my_id,
                                                 self._info_hash,
                                                 self._bt_port, qnode.token)
         queries_to_send.append(Query(msg, qnode.node, self))
     return queries_to_send, announce_to_myself
Beispiel #3
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.update_lowest_index(log_distance)
            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.update_lowest_index(log_distance)
            self.table.num_rnodes += 0
            return

        # No bad nodes. Check for questionable nodes
        q_rnodes = self._get_questionable_rnodes(m_bucket)
        queries_to_send = []
        #        if q_rnodes:
        #            print time.time(), '-----pinging questionable nodes in',
        #            print log_distance
        #            print q_rnodes
        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(Query(self.ping_msg, q_rnode))
        return queries_to_send
Beispiel #4
0
    def _get_lookup_queries(self, nodes):
        queries = []
        for node_ in nodes:
            if node_.id == self._my_id:
                continue
            self._num_parallel_queries += 1
            self.num_queries += len(nodes)
            queries.append(Query(self._get_peers_msg, node_, self))

        return queries
Beispiel #5
0
    def _get_maintenance_query(self, node_):
        if not node_.id:
            # Bootstrap nodes don't have id
            return Query(self.find_closest_msg, node_)

        if random.choice((False, True)):
            # 50% chance to send find_node with my id as target
            return Query(self.find_closest_msg, node_)

        # 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 Query(
                message.OutgoingFindNodeQuery(self.my_node.id, target), node_)
        else:
            # Every bucket is full. We send a ping instead.
            return Query(self.ping_msg, node_)
Beispiel #6
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:
            # 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:
                # 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():
            rnode = node_.get_rnode(log_distance)
            m_bucket.add(rnode)
            self.table.update_lowest_index(log_distance)
            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_
        bad_rnode = self._pop_bad_rnode(m_bucket)
        if bad_rnode:
            rnode = node_.get_rnode(log_distance)
            m_bucket.add(rnode)
            self._update_rnode_on_response_received(rnode, rtt)
            if self._maintenance_mode == NORMAL_MODE:
                m_bucket.last_changed_ts = time.time()
            self.table.update_lowest_index(log_distance)
            self.table.num_rnodes += 0
            return

        # There are no bad nodes. Ping questionable nodes (if any)
        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(Query(self.ping_msg, q_rnode))
        return queries_to_send
Beispiel #7
0
    def announce(self):
        if not self._bt_port:
            return ([], False)
        nodes_to_announce = self._lookup_queue.get_closest_responded_qnodes()
        announce_to_myself = False
        queries_to_send = []
        for qnode in nodes_to_announce:
            logger.debug('announcing to %r' % qnode.node)
            msg = message.OutgoingAnnouncePeerQuery(self._my_id,
                                                    self._info_hash,
                                                    self._bt_port, qnode.token)
            queries_to_send.append(Query(msg, qnode.node, self))

        return (queries_to_send, announce_to_myself)
Beispiel #8
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 [Query(self.ping_msg, rnode)]
        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.update_lowest_index(log_distance)
                self.table.num_rnodes += 0
Beispiel #9
0
 def _get_maintenance_query(self, node_):
     return Query(self.ping_msg, node_)