def test(self): # Sender doesn't use private flag ping_public = m.OutgoingPingQuery(tc.CLIENT_ID) bencoded_public = ping_public.encode(tc.TID) # Sender uses private flag PRIVATE1 m.private_dht_name = 'PRIVATE1' ping_private1 = m.OutgoingPingQuery(tc.CLIENT_ID) bencoded_private1 = ping_private1.encode(tc.TID) # Sender uses private flag PRIVATE1 m.private_dht_name = 'PRIVATE2' ping_private2 = m.OutgoingPingQuery(tc.CLIENT_ID) bencoded_private2 = ping_private2.encode(tc.TID) # Receiver in the public DHT accepts messages (ignores private flag) m.private_dht_name = None m.IncomingMsg(bencoded_public, tc.CLIENT_ADDR) m.IncomingMsg(bencoded_private1, tc.CLIENT_ADDR) m.IncomingMsg(bencoded_private2, tc.CLIENT_ADDR) # Receiver in the private DHT accepts ONLY messages from the # private DHT it belongs to m.private_dht_name = 'PRIVATE1' assert_raises(m.MsgError, m.IncomingMsg, bencoded_public, tc.CLIENT_ADDR) m.IncomingMsg(bencoded_private1, tc.CLIENT_ADDR) assert_raises(m.MsgError, m.IncomingMsg, bencoded_private2, tc.CLIENT_ADDR)
def test_no_callback_for_type(self): msg = message.OutgoingPingQuery(tc.CLIENT_ID) msg_data = msg.encode(tc.TID) self.s._on_datagram_received(msg_data, tc.CLIENT_ADDR) ok_(not self.got_query) ok_(not self.got_response) ok_(not self.got_routing_response)
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 __init__(self, my_node, querier, bootstrap_lookup_f, bootstrap_nodes): self.my_node = my_node self.querier = querier self.bootstrap_lookup = bootstrap_lookup_f #Copy the bootstrap list self.bootstrap_nodes = [n for n in 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) #This must be called by an external party: self.do_bootstrap() #After initializing callbacks # maintenance variables # self.last_maintenance_index = -1 self.maintenance_mode = BOOTSTRAP_MODE self.lookup_mode = False 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 ]
def send_query_and_get_timeout(self, querier): ping_msg = message.OutgoingPingQuery(tc.CLIENT_ID) query = querier.send_query(ping_msg, tc.DEAD_NODE, self.on_response, self.on_timeout, self.on_error, timeout_delay=tc.TIMEOUT_DELAY) if querier is self.querier_mock: query.timeout_task.fire_callbacks() time.sleep(tc.TIMEOUT_DELAY + .1) assert not self.got_response and self.got_timeout
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_ping_with_timeout(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(3) # The server never responds and the timeout is triggered stored_q = self.querier.on_timeout(tc.SERVER_ADDR) assert stored_q is q
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 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_errors(self): # client side query_msg = message.OutgoingPingQuery(tc.CLIENT_ID) # querier.send_query() encodes query_data = query_msg.encode(tc.TID) # server side # rpc_manager.datagram_received() decodes and calls responder (callback) query_msg = message.IncomingMsg(query_data) ## 'xxxxxx' is not a valid QUERY query_msg.query = 'zzzzzzzz' assert not self.notification_callback_done ok_( self.responder.on_query_received(query_msg, tc.CLIENT_ADDR) is None )
def do_maintenance(self): self.maintenance_counter += 1 maintenance_delay = .0000001 if self.maintenance_counter == 1: # bootstrap ping msg = message.OutgoingPingQuery(self.my_node.id) queries_to_send = [Query(msg, tc.SERVER_NODE)] maintenance_lookup_target = None elif self.maintenance_counter == 2: queries_to_send = [] maintenance_lookup_target = tc.CLIENT_ID else: queries_to_send = [] maintenance_lookup_target = None return (maintenance_delay, queries_to_send, maintenance_lookup_target)
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_error(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.OutgoingErrorMsg(message.GENERIC_E) 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) stored_q = self.querier.on_error_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 send_query_and_get_error(self, querier): ping_msg = message.OutgoingPingQuery() query = querier.send_query(ping_msg, tc.EXTERNAL_NODE, self.on_response, self.on_timeout, self.on_error, timeout_delay=tc.TIMEOUT_DELAY) if querier is self.querier_mock: # the server creates the response error_msg = message.OutgoingErrorMsg(ping_msg.tid, message.GENERIC_E) error_data = error_msg.encode() # rpc_m decodes the response received _, _, error_msg_dict = message.decode(error_data) # rpc_m notifies of the message (callback) querier.on_error_received(error_msg_dict, tc.EXTERNAL_NODE) time.sleep(tc.TIMEOUT_DELAY + .1)
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 __init__(self, my_node, querier, bootstrap_nodes): self.my_node = my_node self.querier = querier #Copy the bootstrap list self.bootstrap_nodes = [n for n in bootstrap_nodes] self.main = RoutingTable(my_node, NODES_PER_BUCKET) self.replacement = RoutingTable(my_node, NODES_PER_BUCKET) self.ping_msg = message.OutgoingPingQuery(my_node.id) self.find_node_msg = message.OutgoingFindNodeQuery( my_node.id, my_node.id) self.mode = BOOTSTRAP_MODE self.num_concurrent_refresh_msgs = 0 #This must be called by an external party: self.do_bootstrap() #After initializing callbacks # Add myself to the routing table rnode = self.main.add(my_node) self._reset_refresh_task(rnode)
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_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 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))
def test_printing(self): out_msg = m.OutgoingPingQuery(tc.CLIENT_ID) in_msg = m.IncomingMsg(out_msg.encode(tc.TID), tc.CLIENT_ADDR) str(out_msg) repr(out_msg) repr(in_msg)
def setup(self): b_ping = m.OutgoingPingQuery(tc.CLIENT_ID).encode(tc.TID) self.msg_d = m.IncomingMsg(b_ping, tc.CLIENT_ADDR)._msg_dict
error_code = (999, "some weird error string") b_err = m.OutgoingErrorMsg(error_code).encode(tc.TID) logger.info( "TEST LOGGING ** IGNORE EXPECTED INFO ** Unknown error: %r", error_code) _ = m.IncomingMsg(b_err, tc.CLIENT_ADDR) def test_nodes2(self): response = m.OutgoingGetPeersResponse(tc.CLIENT_ID, peers=tc.PEERS) response._dict[m.RESPONSE][m.NODES2] = mt.compact_nodes2(tc.NODES) bencoded = response.encode(tc.TID) m.IncomingMsg(bencoded, tc.CLIENT_ADDR) b_ping_q = m.OutgoingPingQuery(tc.CLIENT_ID).encode(tc.TID) b_fn_q = m.OutgoingFindNodeQuery(tc.CLIENT_ID, tc.NODE_ID).encode(tc.TID) b_gp_q = m.OutgoingGetPeersQuery(tc.CLIENT_ID, tc.INFO_HASH).encode(tc.TID) b_ap_q = m.OutgoingAnnouncePeerQuery(tc.CLIENT_ID, tc.INFO_HASH, tc.BT_PORT, tc.TOKEN).encode(tc.TID) class TestSanitizeQueryError: def setup(self): self.ping_d = m.IncomingMsg(b_ping_q, tc.CLIENT_ADDR)._msg_dict self.fn_d = m.IncomingMsg(b_fn_q, tc.CLIENT_ADDR)._msg_dict self.gp_d = m.IncomingMsg(b_gp_q, tc.CLIENT_ADDR)._msg_dict self.ap_d = m.IncomingMsg(b_ap_q, tc.CLIENT_ADDR)._msg_dict def test_weird_msg(self): self.ping_d[m.ARGS] = []