1 /*
2 
3 Copyright (c) 2015, Steven Siloti
4 All rights reserved.
5 
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 
10     * Redistributions of source code must retain the above copyright
11       notice, this list of conditions and the following disclaimer.
12     * Redistributions in binary form must reproduce the above copyright
13       notice, this list of conditions and the following disclaimer in
14       the documentation and/or other materials provided with the distribution.
15     * Neither the name of the author nor the names of its
16       contributors may be used to endorse or promote products derived
17       from this software without specific prior written permission.
18 
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
30 
31 */
32 
33 #include "test.hpp"
34 
35 #if !defined TORRENT_DISABLE_EXTENSIONS && !defined TORRENT_DISABLE_DHT
36 
37 #include "libtorrent/config.hpp"
38 #include "libtorrent/session.hpp"
39 #include "libtorrent/extensions.hpp"
40 #include "libtorrent/alert_types.hpp"
41 #include "libtorrent/bdecode.hpp"
42 
43 using namespace lt;
44 
45 namespace
46 {
47 
48 struct test_plugin : plugin
49 {
implemented_features__anonfae6bf170111::test_plugin50 	feature_flags_t implemented_features() override
51 	{
52 		return plugin::dht_request_feature;
53 	}
54 
on_dht_request__anonfae6bf170111::test_plugin55 	bool on_dht_request(string_view /* query */
56 		, udp::endpoint const& /* source */, bdecode_node const& message
57 		, entry& response) override
58 	{
59 		if (message.dict_find_string_value("q") == "test_good")
60 		{
61 			response["r"]["good"] = 1;
62 			return true;
63 		}
64 		return false;
65 	}
66 };
67 
get_direct_response(lt::session & ses)68 dht_direct_response_alert* get_direct_response(lt::session& ses)
69 {
70 	for (;;)
71 	{
72 		alert* a = ses.wait_for_alert(seconds(30));
73 		// it shouldn't take more than 30 seconds to get a response
74 		// so fail the test and bail out if we don't get an alert in that time
75 		TEST_CHECK(a);
76 		if (!a) return nullptr;
77 		std::vector<alert*> alerts;
78 		ses.pop_alerts(&alerts);
79 		for (std::vector<alert*>::iterator i = alerts.begin(); i != alerts.end(); ++i)
80 		{
81 			if ((*i)->type() == dht_direct_response_alert::alert_type)
82 				return static_cast<dht_direct_response_alert*>(&**i);
83 		}
84 	}
85 }
86 
87 }
88 
89 #endif // #if !defined TORRENT_DISABLE_EXTENSIONS && !defined TORRENT_DISABLE_DHT
90 
TORRENT_TEST(direct_dht_request)91 TORRENT_TEST(direct_dht_request)
92 {
93 #if !defined TORRENT_DISABLE_EXTENSIONS && !defined TORRENT_DISABLE_DHT
94 
95 	std::vector<lt::session_proxy> abort;
96 	settings_pack sp;
97 	sp.set_bool(settings_pack::enable_lsd, false);
98 	sp.set_bool(settings_pack::enable_natpmp, false);
99 	sp.set_bool(settings_pack::enable_upnp, false);
100 	sp.set_str(settings_pack::dht_bootstrap_nodes, "");
101 	sp.set_int(settings_pack::max_retry_port_bind, 800);
102 	sp.set_str(settings_pack::listen_interfaces, "127.0.0.1:42434");
103 	lt::session responder(sp, {});
104 	sp.set_str(settings_pack::listen_interfaces, "127.0.0.1:45434");
105 	lt::session requester(sp, {});
106 
107 	responder.add_extension(std::make_shared<test_plugin>());
108 
109 	// successful request
110 
111 	entry r;
112 	r["q"] = "test_good";
113 	requester.dht_direct_request(udp::endpoint(address::from_string("127.0.0.1")
114 		, responder.listen_port()), r, reinterpret_cast<void*>(12345));
115 
116 	dht_direct_response_alert* ra = get_direct_response(requester);
117 	TEST_CHECK(ra);
118 	if (ra)
119 	{
120 		bdecode_node response = ra->response();
121 		TEST_EQUAL(ra->endpoint.address(), address::from_string("127.0.0.1"));
122 		TEST_EQUAL(ra->endpoint.port(), responder.listen_port());
123 		TEST_EQUAL(response.type(), bdecode_node::dict_t);
124 		TEST_EQUAL(response.dict_find_dict("r").dict_find_int_value("good"), 1);
125 		TEST_EQUAL(ra->userdata, reinterpret_cast<void*>(12345));
126 	}
127 
128 	// failed request
129 
130 	requester.dht_direct_request(udp::endpoint(address::from_string("127.0.0.1"), 53545)
131 		, r, reinterpret_cast<void*>(123456));
132 
133 	ra = get_direct_response(requester);
134 	TEST_CHECK(ra);
135 	if (ra)
136 	{
137 		TEST_EQUAL(ra->endpoint.address(), address::from_string("127.0.0.1"));
138 		TEST_EQUAL(ra->endpoint.port(), 53545);
139 		TEST_EQUAL(ra->response().type(), bdecode_node::none_t);
140 		TEST_EQUAL(ra->userdata, reinterpret_cast<void*>(123456));
141 	}
142 
143 	abort.emplace_back(responder.abort());
144 	abort.emplace_back(requester.abort());
145 #endif // #if !defined TORRENT_DISABLE_EXTENSIONS && !defined TORRENT_DISABLE_DHT
146 }
147