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