3 Copyright (c) 2008, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
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.
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.
34 #include "setup_transfer.hpp"
35 #include "libtorrent/socket.hpp"
36 #include "libtorrent/io.hpp"
38 #include <boost/bind.hpp>
40 using namespace libtorrent
;
42 int read_message(stream_socket
& s
, char* buffer
)
44 using namespace libtorrent::detail
;
46 libtorrent::asio::read(s
, libtorrent::asio::buffer(buffer
, 4), libtorrent::asio::transfer_all(), ec
);
49 std::cout
<< ec
.message() << std::endl
;
53 int length
= read_int32(ptr
);
55 libtorrent::asio::read(s
, libtorrent::asio::buffer(buffer
, length
), libtorrent::asio::transfer_all(), ec
);
58 std::cout
<< ec
.message() << std::endl
;
64 char const* message_name
[] = {"choke", "unchoke", "interested", "not_interested"
65 , "have", "bitfield", "request", "piece", "cancel", "dht_port", "", "", ""
66 , "suggest_piece", "have_all", "have_none", "reject_request", "allowed_fast"};
68 void send_allow_fast(stream_socket
& s
, int piece
)
70 std::cout
<< "send allow fast: " << piece
<< std::endl
;
71 using namespace libtorrent::detail
;
72 char msg
[] = "\0\0\0\x05\x11\0\0\0\0";
74 write_int32(piece
, ptr
);
76 libtorrent::asio::write(s
, libtorrent::asio::buffer(msg
, 9), libtorrent::asio::transfer_all(), ec
);
79 std::cout
<< ec
.message() << std::endl
;
84 void send_suggest_piece(stream_socket
& s
, int piece
)
86 std::cout
<< "send suggest piece: " << piece
<< std::endl
;
87 using namespace libtorrent::detail
;
88 char msg
[] = "\0\0\0\x05\x0d\0\0\0\0";
90 write_int32(piece
, ptr
);
92 libtorrent::asio::write(s
, libtorrent::asio::buffer(msg
, 9), libtorrent::asio::transfer_all(), ec
);
95 std::cout
<< ec
.message() << std::endl
;
100 void send_unchoke(stream_socket
& s
)
102 std::cout
<< "send unchoke" << std::endl
;
103 char msg
[] = "\0\0\0\x01\x01";
105 libtorrent::asio::write(s
, libtorrent::asio::buffer(msg
, 5), libtorrent::asio::transfer_all(), ec
);
108 std::cout
<< ec
.message() << std::endl
;
113 void do_handshake(stream_socket
& s
, sha1_hash
const& ih
, char* buffer
)
115 char handshake
[] = "\x13" "BitTorrent protocol\0\0\0\0\0\0\0\x04"
116 " " // space for info-hash
117 "aaaaaaaaaaaaaaaaaaaa" // peer-id
118 "\0\0\0\x01\x0e"; // have_all
119 std::cout
<< "send handshake" << std::endl
;
121 std::memcpy(handshake
+ 28, ih
.begin(), 20);
122 libtorrent::asio::write(s
, libtorrent::asio::buffer(handshake
, sizeof(handshake
) - 1), libtorrent::asio::transfer_all(), ec
);
125 std::cout
<< ec
.message() << std::endl
;
130 libtorrent::asio::read(s
, libtorrent::asio::buffer(buffer
, 68), libtorrent::asio::transfer_all(), ec
);
133 std::cout
<< ec
.message() << std::endl
;
136 std::cout
<< "received handshake" << std::endl
;
138 TEST_CHECK(buffer
[0] == 19);
139 TEST_CHECK(std::memcmp(buffer
+ 1, "BitTorrent protocol", 19) == 0);
141 char* extensions
= buffer
+ 20;
142 // check for fast extension support
143 TEST_CHECK(extensions
[7] & 0x4);
145 #ifndef TORRENT_DISABLE_EXTENSIONS
146 // check for extension protocol support
147 TEST_CHECK(extensions
[5] & 0x10);
150 #ifndef TORRENT_DISABLE_DHT
151 // check for DHT support
152 TEST_CHECK(extensions
[7] & 0x1);
155 TEST_CHECK(std::memcmp(buffer
+ 28, ih
.begin(), 20) == 0);
158 // makes sure that pieces that are allowed and then
159 // rejected aren't requested again
160 void test_reject_fast()
162 boost::intrusive_ptr
<torrent_info
> t
= ::create_torrent();
163 sha1_hash ih
= t
->info_hash();
164 session
ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
165 ses1
.add_torrent(t
, "./tmp1");
170 stream_socket
s(ios
);
171 s
.connect(tcp::endpoint(address::from_string("127.0.0.1"), ses1
.listen_port()));
173 char recv_buffer
[1000];
174 do_handshake(s
, ih
, recv_buffer
);
176 std::vector
<int> allowed_fast
;
177 allowed_fast
.push_back(0);
178 allowed_fast
.push_back(1);
179 allowed_fast
.push_back(2);
180 allowed_fast
.push_back(3);
182 std::for_each(allowed_fast
.begin(), allowed_fast
.end()
183 , bind(&send_allow_fast
, boost::ref(s
), _1
));
185 while (!allowed_fast
.empty())
187 read_message(s
, recv_buffer
);
188 int msg
= recv_buffer
[0];
189 if (msg
>= 0 && msg
< int(sizeof(message_name
)/sizeof(message_name
[0])))
190 std::cerr
<< message_name
[msg
] << std::endl
;
192 std::cerr
<< msg
<< std::endl
;
193 if (recv_buffer
[0] != 0x6) continue;
195 using namespace libtorrent::detail
;
196 char* ptr
= recv_buffer
+ 1;
197 int piece
= read_int32(ptr
);
199 std::vector
<int>::iterator i
= std::find(allowed_fast
.begin()
200 , allowed_fast
.end(), piece
);
201 TEST_CHECK(i
!= allowed_fast
.end());
202 if (i
!= allowed_fast
.end())
203 allowed_fast
.erase(i
);
204 // send reject request
205 recv_buffer
[0] = 0x10;
207 libtorrent::asio::write(s
, libtorrent::asio::buffer("\0\0\0\x0d", 4), libtorrent::asio::transfer_all(), ec
);
210 std::cout
<< ec
.message() << std::endl
;
213 libtorrent::asio::write(s
, libtorrent::asio::buffer(recv_buffer
, 13), libtorrent::asio::transfer_all(), ec
);
214 std::cout
<< ec
.message() << std::endl
;
217 std::cout
<< ec
.message() << std::endl
;
223 void test_respect_suggest()
225 boost::intrusive_ptr
<torrent_info
> t
= ::create_torrent();
226 sha1_hash ih
= t
->info_hash();
227 session
ses1(fingerprint("LT", 0, 1, 0, 0), std::make_pair(48900, 49000));
228 ses1
.add_torrent(t
, "./tmp1");
233 stream_socket
s(ios
);
234 s
.connect(tcp::endpoint(address::from_string("127.0.0.1"), ses1
.listen_port()));
236 char recv_buffer
[1000];
237 do_handshake(s
, ih
, recv_buffer
);
239 std::vector
<int> suggested
;
240 suggested
.push_back(0);
241 suggested
.push_back(1);
242 suggested
.push_back(2);
243 suggested
.push_back(3);
245 std::for_each(suggested
.begin(), suggested
.end()
246 , bind(&send_suggest_piece
, boost::ref(s
), _1
));
250 int fail_counter
= 100;
251 while (!suggested
.empty() && fail_counter
> 0)
253 read_message(s
, recv_buffer
);
254 std::cerr
<< "msg: ";
255 int msg
= recv_buffer
[0];
256 if (msg
>= 0 && msg
< int(sizeof(message_name
)/sizeof(message_name
[0])))
257 std::cerr
<< message_name
[msg
] << std::endl
;
259 std::cerr
<< msg
<< std::endl
;
261 if (recv_buffer
[0] != 0x6) continue;
263 using namespace libtorrent::detail
;
264 char* ptr
= recv_buffer
+ 1;
265 int piece
= read_int32(ptr
);
267 std::vector
<int>::iterator i
= std::find(suggested
.begin()
268 , suggested
.end(), piece
);
269 TEST_CHECK(i
!= suggested
.end());
270 if (i
!= suggested
.end())
272 // send reject request
273 recv_buffer
[0] = 0x10;
275 libtorrent::asio::write(s
, libtorrent::asio::buffer("\0\0\0\x0d", 4), libtorrent::asio::transfer_all(), ec
);
278 std::cout
<< ec
.message() << std::endl
;
281 libtorrent::asio::write(s
, libtorrent::asio::buffer(recv_buffer
, 13), libtorrent::asio::transfer_all(), ec
);
284 std::cout
<< ec
.message() << std::endl
;
288 TEST_CHECK(fail_counter
> 0);
294 test_respect_suggest();