def _get_response(self, msg): if msg.query == message.PING: return message.OutgoingPingResponse(self._my_id) elif msg.query == message.FIND_NODE: log_distance = msg.target.log_distance(self._my_id) rnodes = self._routing_m.get_closest_rnodes(log_distance, NUM_NODES, False) return message.OutgoingFindNodeResponse(self._my_id, rnodes) elif msg.query == message.GET_PEERS: token = self._token_m.get() log_distance = msg.info_hash.log_distance(self._my_id) rnodes = self._routing_m.get_closest_rnodes(log_distance, NUM_NODES, False) peers = self._tracker.get(msg.info_hash) if peers: logger.debug('RESPONDING with PEERS:\n%r' % peers) return message.OutgoingGetPeersResponse(self._my_id, token, nodes=rnodes, peers=peers) elif msg.query == message.ANNOUNCE_PEER: peer_addr = (msg.sender_addr[0], msg.bt_port) self._tracker.put(msg.info_hash, peer_addr) return message.OutgoingAnnouncePeerResponse(self._my_id) else: logger.debug('Invalid QUERY: %r' % (msg.query))
def _setup(self): global time time = querier.time = MockTime() self.ping_msg = message.OutgoingPingQuery(tc.CLIENT_ID) ping_r_out = message.OutgoingPingResponse(tc.SERVER_ID) self.ping_r_in = message.IncomingMsg(ping_r_out.encode(tc.TID), tc.SERVER_ADDR) fn_r_out = message.OutgoingFindNodeResponse(tc.SERVER_ID, nodes2=tc.NODES) self.fn_r_in = message.IncomingMsg(fn_r_out.encode(tc.TID), tc.SERVER_ADDR) self.got_response = False self.got_error = False self.got_timeout = False self.got_routing_response = False self.got_routing_error = False self.got_routing_timeout = False self.got_routing_nodes_found = False timeout_task = minitwisted.Task(1, self.on_timeout, tc.SERVER_NODE) self.query = querier.Query(tc.TID, self.ping_msg.query, tc.SERVER_NODE, timeout_task)
def test_complete(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.SERVER_ID).encode('\0\0') self.controller._on_datagram_received(data, tc.SERVER_ADDR) self.controller._main_loop() # maintenance (maintenance lookup)
def test_querier_responder(self): # client # setup self.c.add_msg_callback(message.RESPONSE, self.on_response_received) self.c.add_msg_callback(message.RESPONSE, self.on_routing_response_received) self.c.add_msg_callback(message.ERROR, self.on_error_received) self.c.add_timeout_callback(self.on_routing_timeout) # server # setup self.s.add_msg_callback(message.QUERY, self.on_query_received) # client creates and sends query t_task = self.c.get_timeout_task(tc.SERVER_ADDR, tc.TIMEOUT_DELAY, self.on_timeout) msg = message.OutgoingPingQuery(tc.CLIENT_ID) msg_data = msg.encode(tc.TID) self.c.send_msg_to(msg_data, tc.SERVER_ADDR) # client sets up timeout # server receives query, creates response and sends it back self.s._on_datagram_received(msg_data, tc.CLIENT_ADDR) # rpc_manager would send the message back automatically ok_(self.got_query) self.got_query = False msg = message.OutgoingPingResponse(tc.SERVER_ID) msg_data = msg.encode(tc.TID) self.s.send_msg_to(msg_data, tc.CLIENT_ADDR) # client gets response self.c._on_datagram_received(msg_data, tc.SERVER_ADDR) ok_(self.got_response) self.got_response = False ok_(self.got_routing_response) self.got_routing_response = False # client gets error msg_data = message.OutgoingErrorMsg(message.GENERIC_E).encode(tc.TID) self.c._on_datagram_received(msg_data, tc.SERVER_ADDR) ok_(self.got_error) self.got_error = False # client gets timeout t_task.fire_callbacks() ok_(self.got_timeout) self.got_timeout = False ok_(self.got_routing_timeout) self.got_routing_timeout = False # server gets invalid message self.s._on_datagram_received('zzz', tc.CLIENT_ADDR) ok_(not self.got_query) ok_(not self.got_response) ok_(not self.got_routing_response)
def _test_fire_callback_on_response(self): # the server creates the response pong_msg = message.OutgoingPingResponse(tc.SERVER_ID) pong_data = pong_msg.encode(tc.TID) # IncomingMsg decodes the response received pong_msg = message.IncomingMsg(pong_data, tc.SERVER_ADDR) # querier notifies of the message (callback) self.query.on_response_received(pong_msg) ok_(self.got_response) ok_(not self.got_error) ok_(not self.got_timeout)
def test_unsolicited_response(self): # Server creates unsolicited response # It might well be that the server responds using another port, # and therefore, the addr is not matched # TODO: consider accepting responses from a different port ping_r_msg_out = message.OutgoingPingResponse(tc.SERVER_ID) bencoded_r = ping_r_msg_out.encode('zz') # The client receives the bencoded message ping_r_in = message.IncomingMsg(bencoded_r, tc.SERVER_ADDR) stored_q = self.querier.on_response_received(ping_r_in, tc.SERVER_ADDR) assert stored_q is None
def send_query_and_get_response(self, querier_, later_delay=0): ping_msg = message.OutgoingPingQuery(tc.CLIENT_ID) msg = message.OutgoingFindNodeQuery(tc.CLIENT_ID, tc.CLIENT_ID) if later_delay: task = querier_.send_query_later(later_delay, msg, tc.EXTERNAL_NODE, self.on_response, self.on_timeout, self.on_error, tc.TIMEOUT_DELAY) # This second query is just to have two elements # in the querier_.pending[tc.EXTERNAL_ADDR] list task = querier_.send_query_later(later_delay, msg, tc.EXTERNAL_NODE, self.on_response, self.on_timeout, self.on_error, tc.TIMEOUT_DELAY) else: node_ = (querier_ == self.querier_mock) and tc.SERVER_NODE query = querier_.send_query(ping_msg, node_ or tc.EXTERNAL_NODE, self.on_response, self.on_timeout, self.on_error, timeout_delay=tc.TIMEOUT_DELAY) # querier creates TID msg_tid = '\0\0' if querier_ is self.querier_mock: # server gets query # the server creates the response pong_msg = message.OutgoingPingResponse(tc.SERVER_ID) pong_msg_data = pong_msg.encode(msg_tid) # the client gets the response # rpc_m decodes msg and calls callback pong_msg = message.IncomingMsg(pong_msg_data) querier_.on_response_received(pong_msg, tc.SERVER_ADDR) if later_delay: ok_(not self.got_response) ok_(not self.got_timeout) time.sleep(later_delay*2) time.sleep(tc.TIMEOUT_DELAY+.1) ### It crashed (timeout_task.cancelled??????) #TODO2: move the 'real' tests to integration ############################################### ### A DHT node must be running on peer_addr ### ############################################### ok_(self.got_response) ok_(not self.got_timeout)
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)
def test_fire_callback_on_late_response(self): self.query.timeout_task.fire_callbacks() self.query.timeout_task.cancel() # the server creates the response pong_msg = message.OutgoingPingResponse(tc.SERVER_ID) pong_data = pong_msg.encode(tc.TID) # IncomingMsg decodes the response received pong_msg = message.IncomingMsg(pong_data, tc.SERVER_ADDR) # querier notifies of the message (but it's too late) self.query.on_response_received(pong_msg) logger.warning("**IGNORE WARNING LOG**") assert not self.got_response and not self.got_error \ and self.got_timeout
def test_ping(self): #client outgoing_query = m.OutgoingPingQuery(tc.CLIENT_ID) data = outgoing_query.encode(tc.TID) # query_manager would do it #server incoming_query = m.IncomingMsg(data) assert incoming_query.type is m.QUERY outgoing_response = m.OutgoingPingResponse(tc.SERVER_ID) data = outgoing_response.encode(incoming_query.tid) #client incoming_response = m.IncomingMsg(data) assert incoming_response.type is m.RESPONSE incoming_response.sanitize_response(outgoing_query.query)
def _test_ping_error(self): outgoing_query = m.OutgoingPingQuery(tc.CLIENT_ID) outgoing_query.tid = tc.TID # TID and ARGS ID are None assert_raises(m.MsgError, outgoing_query.encode) logger.error( "**IGNORE 2 ERROR LOGS** This exception was raised by a test") outgoing_query = m.OutgoingPingQuery() outgoing_query.my_id = tc.CLIENT_ID #outgoing_query.tid = tc.TID assert_raises(m.MsgError, outgoing_query.encode) logger.error( "**IGNORE 2 ERROR LOGS** This exception was raised by a test") outgoing_query = m.OutgoingPingQuery() #outgoing_query.my_id = tc.CLIENT_ID outgoing_query.tid = tc.TID assert_raises(m.MsgError, outgoing_query.encode) logger.error( "**IGNORE 2 ERROR LOGS** This exception was raised by a test") outgoing_query = m.OutgoingPingQuery() assert_raises(m.MsgError, outgoing_query.__setattr__, 'my_id', '') logger.error( "**IGNORE 2 ERROR LOGS** This exception was raised by a test") outgoing_query = m.OutgoingPingQuery() outgoing_query.my_id = tc.CLIENT_ID outgoing_query.tid = 567 data = outgoing_query.encode() assert_raises(m.MsgError, m.decode, data) logger.error( "**IGNORE 2 ERROR LOGS** This exception was raised by a test") outgoing_query = m.OutgoingPingQuery() outgoing_query.my_id = tc.CLIENT_ID outgoing_query.tid = tc.TID data = outgoing_query.encode() data += 'this string ruins the bencoded msg' assert_raises(m.MsgError, m.decode, data) logger.error( "**IGNORE 2 ERROR LOGS** This exception was raised by a test") outgoing_response = m.OutgoingPingResponse(tc.TID, tc.SERVER_ID) outgoing_response.tid = None assert_raises(m.MsgError, outgoing_response.encode) logger.error( "**IGNORE ERROR LOGS** This exception was raised by a test")
def setup(self): self.queries = [ m.OutgoingPingQuery(tc.CLIENT_ID), m.OutgoingFindNodeQuery(tc.CLIENT_ID, tc.TARGET_ID), m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH), m.OutgoingAnnouncePeerQuery(tc.CLIENT_ID, tc.INFO_HASH, tc.BT_PORT, tc.TOKEN), ] self.responses = [ m.OutgoingPingResponse(tc.SERVER_ID), m.OutgoingFindNodeResponse(tc.SERVER_ID, tc.NODES), m.OutgoingGetPeersResponse(tc.SERVER_ID, tc.TOKEN, tc.NODES, tc.PEERS), m.OutgoingAnnouncePeerResponse(tc.SERVER_ID), ]
def test_response_with_different_tid(self): # Client creates a query ping_msg = message.OutgoingPingQuery(tc.CLIENT_ID) q = Query(ping_msg, tc.SERVER_NODE) timeout_task = minitwisted.Task(TIMEOUT_DELAY, None) # Client registers query bencoded_msg = self.querier.register_query(q, timeout_task) # Client sends bencoded_msg time.sleep(1) # Server gets bencoded_msg and creates response ping_r_msg_out = message.OutgoingPingResponse(tc.SERVER_ID) bencoded_r = ping_r_msg_out.encode('zz') # The client receives the bencoded message ping_r_in = message.IncomingMsg(bencoded_r, tc.SERVER_ADDR) stored_q = self.querier.on_response_received(ping_r_in, tc.SERVER_ADDR) assert stored_q is None
def test_return_response_for_ping(self): # client side query_msg = message.OutgoingPingQuery(tc.CLIENT_ID) # rpc_manager.sendto() encodes query_data = query_msg.encode(tc.TID) # server side # rpc_manager.datagram_received() decodes query_msg = message.IncomingMsg(query_data) assert not self.notification_callback_done response_msg = self.responder.on_query_received( query_msg, tc.CLIENT_ADDR) response_data = response_msg.encode(query_msg.tid) assert self.notification_callback_done expected_msg = message.OutgoingPingResponse(tc.SERVER_ID) expected_data = expected_msg.encode(tc.TID) eq_(response_data, expected_data)
def test_ping_with_response(self): # Client creates a query ping_msg = message.OutgoingPingQuery(tc.CLIENT_ID) q = Query(ping_msg, tc.SERVER_NODE) # Querier.register_query sets a TID and timeout_task q.tid = tc.TID q.timeout_task = minitwisted.Task(TIMEOUT_DELAY, None) q.query_ts = time.time() # The query is sent time.sleep(1) # The server creates a response ping_r_msg_out = message.OutgoingPingResponse(tc.SERVER_ID) bencoded_r = ping_r_msg_out.encode(tc.TID) # The client receives the bencoded message ping_r_in = message.IncomingMsg(bencoded_r, tc.SERVER_ADDR) q.on_response_received(ping_r_in) assert 1 < q.rtt < 1.1 assert q.lookup_obj is None
def test_unsolicited_response(self): # We have a pending response from NO_ADDR (TID \0\0) # but we get a response with different TID # client ping = message.OutgoingPingQuery(tc.CLIENT_ID) self.querier.send_query(ping, tc.SERVER_NODE, self.on_response, self.on_error, self.on_timeout, tc.TIMEOUT_DELAY) ok_(not self.got_response) ok_(not self.got_routing_response) ok_(not self.got_routing_nodes_found) # server pong = message.OutgoingPingResponse(tc.SERVER_ID) pong_in = message.IncomingMsg(pong.encode(tc.TID)) # client self.querier.on_response_received(pong_in, tc.SERVER_ADDR) ok_(not self.got_response) ok_(not self.got_routing_response) ok_(not self.got_routing_nodes_found)
def test_msg_exhanges(self): self._exchange_msgs(m.OutgoingPingQuery(tc.CLIENT_ID), m.OutgoingPingResponse(tc.SERVER_ID)) self._exchange_msgs( m.OutgoingFindNodeQuery(tc.CLIENT_ID, tc.TARGET_ID), m.OutgoingFindNodeResponse(tc.SERVER_ID, tc.NODES)) # Test different combinations of token, nodes and peers self._exchange_msgs( m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH), m.OutgoingGetPeersResponse(tc.SERVER_ID, tc.TOKEN, tc.NODES, tc.PEERS)) self._exchange_msgs( m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH), m.OutgoingGetPeersResponse(tc.SERVER_ID, tc.TOKEN, tc.NODES)) self._exchange_msgs( m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH), m.OutgoingGetPeersResponse(tc.SERVER_ID, tc.TOKEN, peers=tc.PEERS)) assert_raises(AssertionError, m.OutgoingGetPeersResponse, tc.SERVER_ID, tc.TOKEN) self._exchange_msgs( m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH), m.OutgoingGetPeersResponse(tc.SERVER_ID, peers=tc.PEERS)) self._exchange_msgs( m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH), m.OutgoingGetPeersResponse(tc.SERVER_ID, nodes=tc.NODES)) self._exchange_msgs( m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH), m.OutgoingGetPeersResponse(tc.SERVER_ID, nodes=tc.NODES, peers=tc.PEERS)) assert_raises(AssertionError, m.OutgoingGetPeersResponse, tc.SERVER_ID) self._exchange_msgs( m.OutgoingAnnouncePeerQuery(tc.CLIENT_ID, tc.INFO_HASH, tc.BT_PORT, tc.TOKEN), m.OutgoingAnnouncePeerResponse(tc.SERVER_ID))
self.ping_d[m.QUERY] = {} assert_raises(m.MsgError, m.IncomingMsg, bencode.encode(self.ping_d), tc.CLIENT_ADDR) # unknown m.QUERY is not an error at this point # responder will process it and send an errror msg if necesary self.ping_d[m.QUERY] = 'a' m.IncomingMsg(bencode.encode(self.ping_d), tc.CLIENT_ADDR) def test_announce(self): # Port must be integer self.ap_d[m.ARGS][m.PORT] = 'a' assert_raises(m.MsgError, m.IncomingMsg, bencode.encode(self.ap_d), tc.CLIENT_ADDR) b_ping_r = m.OutgoingPingResponse(tc.CLIENT_ID).encode(tc.TID) b_fn2_r = m.OutgoingFindNodeResponse(tc.CLIENT_ID, tc.NODES).encode(tc.TID) b_gp_r = m.OutgoingGetPeersResponse(tc.CLIENT_ID, tc.TOKEN, tc.NODES, peers=tc.PEERS).encode(tc.TID) b_ap_r = m.OutgoingAnnouncePeerResponse(tc.CLIENT_ID).encode(tc.TID) class TestSanitizeResponseError: def setup(self): self.ping_r = m.IncomingMsg(b_ping_r, tc.SERVER_ADDR) self.fn2_r = m.IncomingMsg(b_fn2_r, tc.SERVER_ADDR) self.gp_r = m.IncomingMsg(b_gp_r, tc.SERVER_ADDR) self.ap_r = m.IncomingMsg(b_ap_r, tc.SERVER_ADDR)
def on_query_received(self, msg, addr): self.got_query = True return message.OutgoingPingResponse(tc.SERVER_ID)
def _on_ping(self, query_msg): return message.OutgoingPingResponse(self.my_id)