예제 #1
0
    def test_successful_get_peers(self):
        ts, datagrams = self.controller.main_loop()
        ping_timeout_ts = ts
        #FIXME: assert_almost_equal(ts, time.time()+2)
        ping = datagrams[0].data
        addr = datagrams[0].addr
        #fabricate response
        ping = self.servers_msg_f.incoming_msg(Datagram(ping, addr))
        pong = self.servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE)
        data = pong.stamp(ping.tid)
        # get a node in the routing table
        self.controller.on_datagram_received(message.Datagram(data, addr))
        #The lookup starts with a single node
        lookup_result = []
        datagrams = self.controller.get_peers(lookup_result, tc.INFO_HASH,
                                              lambda x, y: x.append(y), 0)
        #FIXME: assert_almost_equal(ts, ping_timeout_ts)#time.time()+2)
        #FIXME: eq_(len(datagrams), 1)

        # Now a get_peers with local results
        info_hash = identifier.Id('info_hash info_hash ')
        self.controller._tracker.put(info_hash, tc.CLIENT_ADDR)
        lookup_result = []
        self.controller.get_peers(lookup_result, info_hash,
                                  lambda x, y: x.append(y), 0)
예제 #2
0
 def _old(self):
     # controller.start() starts reactor (we don't want to use reactor in
     # tests), sets _running, and calls main_loop
     self.controller._running = True
     # controller.start calls main_loop, which does maintenance (bootstrap)
     self.controller.main_loop()
     # minitwisted informs of a response
     data = message.OutgoingPingResponse(tc.CLIENT_NODE,
                                         tc.SERVER_ID).stamp('\0\0')
     self.controller.on_datagram_received(
         message.Datagram(data, tc.SERVER_ADDR))
     self.controller.main_loop()  # maintenance (maintenance lookup)
예제 #3
0
    def test_adding_and_removing_node(self):
        # The routing table is initially empty
        eq_(self.controller._routing_m.get_main_rnodes(), [])

        q = self.controller.msg_f.outgoing_ping_query(tc.SERVER_NODE)
        expected_ts, expected_datagrams = self.querier2.register_queries([q])
        # main_loop is called by reactor.start()
        # It returns a maintenance ping
        ts, datagrams = self.controller.main_loop()
        #FIXME: assert_almost_equal(ts, expected_ts)
        eq_(len(datagrams), 1)
        eq_(datagrams[0], expected_datagrams[0])
        time.sleep((ts - time.time()) / 2)
        # SERVER_NODE gets msg and replies before the timeout
        tid = self.servers_msg_f.incoming_msg(
            Datagram(datagrams[0].data, tc.CLIENT_ADDR)).tid
        data = self.servers_msg_f.outgoing_ping_response(
            tc.CLIENT_NODE).stamp(tid)
        eq_(self.controller._routing_m.get_main_rnodes(), [])
        datagram = message.Datagram(data, tc.SERVER_ADDR)
        self.controller.on_datagram_received(datagram)
        # SERVER_NODE is added to the routing table
        eq_(self.controller._routing_m.get_main_rnodes(), [tc.SERVER_NODE])

        time.sleep((ts - time.time()))
        # main_loop is called to trigger timeout
        # It returns a maintenance lookup
        ts, datagrams = self.controller.main_loop()
        q = self.controller.msg_f.outgoing_find_node_query(
            tc.SERVER_NODE, self.my_id, None)
        expected_ts, expected_datagrams = self.querier2.register_queries([q])
        #FIXME: assert_almost_equal(ts, expected_ts)
        #FIXME: eq_(len(datagrams), 1)
        #FIXME: eq_(datagrams[0], expected_datagrams[0])

        time.sleep(ts - time.time())
        # main_loop is called to trigger timeout
        # It triggers a timeout (removing SERVER_NODE from the routing table
        # returns a maintenance ping
        ts, datagrams = self.controller.main_loop()
        #FIXME: eq_(self.controller._routing_m.get_main_rnodes(), [])
        # No reply for this query
        #this call should trigger timeout
        self.controller.main_loop()
예제 #4
0
    def register_queries(self, queries):
        """
        A Querier object keeps a registry of sent queries while waiting for
        responses.

        """
        assert len(queries)
        datagrams = []
        current_ts = time.time()
        timeout_ts = current_ts + TIMEOUT_DELAY
        for i, query in enumerate(queries):
            msg = query
            tid = self._next_tid()
            logger.debug('registering query %d to node: %r\n%r' %
                         (i, query.dst_node, msg))
            self._timeouts.append((timeout_ts, msg))
            # if node is not in the dictionary, it will create an empty list
            self._pending.setdefault(query.dst_node.addr, []).append(msg)
            datagrams.append(
                message.Datagram(msg.stamp(tid), query.dst_node.addr))
        return timeout_ts, datagrams
예제 #5
0
 def test_retry_get_peers(self):
     ts, datagrams = self.controller.main_loop()
     ping_timeout_ts = ts
     #FIXME: assert_almost_equal(ts, time.time()+2)
     eq_(len(datagrams), 1)
     ping = datagrams[0].data
     addr = datagrams[0].addr
     #this get_peers fails because there are no nodes in the routing table
     datagrams = self.controller.get_peers(None, tc.INFO_HASH, None, 0)
     eq_(len(datagrams), 0)
     #fabricate response
     ping = self.servers_msg_f.incoming_msg(Datagram(ping, addr))
     pong = self.servers_msg_f.outgoing_ping_response(tc.CLIENT_NODE)
     data = pong.stamp(ping.tid)
     # get a node in the routing table
     self.controller.on_datagram_received(message.Datagram(data, addr))
     # This call does nothing because it's too early
     ts, datagrams = self.controller.main_loop()
     #eq_(ts, ping_timeout_ts)
     eq_(datagrams, [])
     # Controller retries lookup  get_peers
     time.sleep(ts - time.time())
     ts, datagrams = self.controller.main_loop()
예제 #6
0
 def test_bad_datagram_received(self):
     ts, datagrams = self.controller.on_datagram_received(
         message.Datagram('aa', tc.CLIENT_ADDR))
     assert not datagrams
예제 #7
0
    def on_datagram_received(self, datagram):
        """
        Perform the actions associated to the arrival of the given
        datagram. The datagram will be ignored in cases such as invalid
        format. Otherwise, the datagram will be decoded and different modules
        will be informed to take action on it. For instance, if the datagram
        contains a response to a lookup query, both routing and lookup manager
        will be informed. Additionally, if that response contains peers, the
        lookup's handler will be called (see get\_peers above).
        This method is designed to be used as minitwisted's networking handler.

        """
        exp_queries_to_send = []

        data = datagram.data
        addr = datagram.addr
        datagrams_to_send = []
        try:
            msg = self.msg_f.incoming_msg(datagram)

        except (message.MsgError):
            # ignore message
            return self._next_main_loop_call_ts, datagrams_to_send

        if msg.type == message.QUERY:

            if msg.src_node.id == self._my_id:
                logger.debug('Got a msg from myself:\n%r', msg)
                return self._next_main_loop_call_ts, datagrams_to_send
            #zinat: inform experimental_module
            exp_queries_to_send = self._experimental_m.on_query_received(msg)

            response_msg = self._responder.get_response(msg)
            if response_msg:
                bencoded_response = response_msg.stamp(msg.tid)
                datagrams_to_send.append(
                    message.Datagram(bencoded_response, addr))
            maintenance_queries_to_send = self._routing_m.on_query_received(
                msg.src_node)

        elif msg.type == message.RESPONSE:
            related_query = self._querier.get_related_query(msg)
            if not related_query:
                # Query timed out or unrequested response
                return self._next_main_loop_call_ts, datagrams_to_send
            ## zinat: if related_query.experimental_obj:
            exp_queries_to_send = self._experimental_m.on_response_received(
                msg, related_query)
            #TODO: you need to get datagrams to be able to send messages (raul)
            # lookup related tasks
            if related_query.lookup_obj:
                (lookup_queries_to_send, peers, num_parallel_queries,
                 lookup_done) = related_query.lookup_obj.on_response_received(
                     msg, msg.src_node)
                datagrams = self._register_queries(lookup_queries_to_send)
                datagrams_to_send.extend(datagrams)

                lookup_obj = related_query.lookup_obj
                lookup_id = lookup_obj.lookup_id
                callback_f = lookup_obj.callback_f
                if peers:
                    self._add_cache_peers(lookup_obj.info_hash, peers)
                    if callback_f and callable(callback_f):
                        callback_f(lookup_id, peers, msg.src_node)
                if lookup_done:
                    if callback_f and callable(callback_f):
                        callback_f(lookup_id, None, msg.src_node)
                    queries_to_send = self._announce(related_query.lookup_obj)
                    datagrams = self._register_queries(queries_to_send)
                    datagrams_to_send.extend(datagrams)

            # maintenance related tasks
            maintenance_queries_to_send = \
                self._routing_m.on_response_received(
                msg.src_node, related_query.rtt, msg.all_nodes)

        elif msg.type == message.ERROR:
            related_query = self._querier.get_related_query(msg)
            if not related_query:
                # Query timed out or unrequested response
                return self._next_main_loop_call_ts, datagrams_to_send
            #TODO: zinat: same as response
            exp_queries_to_send = self._experimental_m.on_error_received(
                msg, related_query)
            # lookup related tasks
            if related_query.lookup_obj:
                peers = None  # an error msg doesn't have peers
                (lookup_queries_to_send, num_parallel_queries,
                 lookup_done) = related_query.lookup_obj.on_error_received(
                     msg, addr)
                datagrams = self._register_queries(lookup_queries_to_send)
                datagrams_to_send.extend(datagrams)

                callback_f = related_query.lookup_obj.callback_f
                if callback_f and callable(callback_f):
                    lookup_id = related_query.lookup_obj.lookup_id
                    if lookup_done:
                        callback_f(lookup_id, None, msg.src_node)
                if lookup_done:
                    datagrams = self._announce(related_query.lookup_obj)
                    datagrams_to_send.extend(datagrams)
            # maintenance related tasks
            maintenance_queries_to_send = \
                self._routing_m.on_error_received(addr)

        else:  # unknown type
            return self._next_main_loop_call_ts, datagrams_to_send
        # we are done with the plugins
        # now we have maintenance_queries_to_send, let's send them!
        datagrams = self._register_queries(maintenance_queries_to_send)
        datagrams_to_send.extend(datagrams)
        if exp_queries_to_send:
            datagrams = self._register_queries(exp_queries_to_send)
            datagrams_to_send.extend(datagrams)
        return self._next_main_loop_call_ts, datagrams_to_send