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.
36 #include "libtorrent/session.hpp"
37 #include "libtorrent/hasher.hpp"
39 #include <boost/thread.hpp>
40 #include <boost/tuple/tuple.hpp>
41 #include <boost/filesystem/operations.hpp>
42 #include <boost/filesystem/convenience.hpp>
45 #include "libtorrent/assert.hpp"
46 #include "libtorrent/alert_types.hpp"
47 #include "libtorrent/create_torrent.hpp"
49 using boost::filesystem::remove_all
;
50 using boost::filesystem::create_directory
;
51 using namespace libtorrent
;
53 void print_alerts(libtorrent::session
& ses
, char const* name
, bool allow_disconnects
, bool allow_no_torrents
)
55 std::vector
<torrent_handle
> handles
= ses
.get_torrents();
56 TEST_CHECK(!handles
.empty() || allow_no_torrents
);
58 if (!handles
.empty()) h
= handles
[0];
59 std::auto_ptr
<alert
> a
;
63 if (peer_disconnected_alert
* p
= dynamic_cast<peer_disconnected_alert
*>(a
.get()))
65 std::cerr
<< name
<< "(" << p
->ip
<< "): " << p
->message() << "\n";
67 else if (a
->message() != "block downloading"
68 && a
->message() != "block finished"
69 && a
->message() != "piece finished")
71 std::cerr
<< name
<< ": " << a
->message() << "\n";
73 TEST_CHECK(dynamic_cast<peer_error_alert
*>(a
.get()) == 0
74 || (!handles
.empty() && h
.is_seed())
75 || a
->message() == "connecting to peer"
76 || a
->message() == "closing connection to ourself"
77 || a
->message() == "duplicate connection"
78 || a
->message() == "duplicate peer-id, connection closed"
79 || (allow_disconnects
&& a
->message() == "Broken pipe")
80 || (allow_disconnects
&& a
->message() == "Connection reset by peer")
81 || (allow_disconnects
&& a
->message() == "End of file."));
86 void test_sleep(int millisec
)
89 boost::xtime_get(&xt
, boost::TIME_UTC
);
90 boost::uint64_t nanosec
= (millisec
% 1000) * 1000000 + xt
.nsec
;
91 int sec
= millisec
/ 1000;
92 if (nanosec
> 1000000000)
94 nanosec
-= 1000000000;
99 boost::thread::sleep(xt
);
102 void stop_web_server(int port
)
104 std::stringstream cmd
;
105 cmd
<< "kill `cat ./lighty" << port
<< ".pid` >/dev/null";
106 system(cmd
.str().c_str());
109 void start_web_server(int port
, bool ssl
)
111 stop_web_server(port
);
115 system("echo . > tmp");
116 system("echo test province >>tmp");
117 system("echo test city >> tmp");
118 system("echo test company >> tmp");
119 system("echo test department >> tmp");
120 system("echo tester >> tmp");
121 system("echo test@test.com >> tmp");
122 system("openssl req -new -x509 -keyout server.pem -out server.pem "
123 "-days 365 -nodes <tmp");
126 std::ofstream
f("lighty_config");
127 f
<< "server.modules = (\"mod_access\", \"mod_redirect\", \"mod_setenv\")\n"
128 "server.document-root = \"" << boost::filesystem::initial_path().string() << "\"\n"
129 "server.range-requests = \"enable\"\n"
130 "server.port = " << port
<< "\n"
131 "server.pid-file = \"./lighty" << port
<< ".pid\"\n"
133 "\"^/redirect$\" => \"" << (ssl
?"https":"http") << "://127.0.0.1:" << port
<< "/test_file\""
134 ", \"^/infinite_redirect$\" => \"" << (ssl
?"https":"http") << "://127.0.0.1:" << port
<< "/infinite_redirect\""
135 ", \"^/relative/redirect$\" => \"../test_file\""
137 "$HTTP[\"url\"] == \"/test_file.gz\" {\n"
138 " setenv.add-response-header = ( \"Content-Encoding\" => \"gzip\" )\n"
139 "# mimetype.assign = ()\n"
141 // this requires lighttpd to be built with ssl support.
142 // The port distribution for mac is not built with ssl
143 // support by default.
145 f
<< "ssl.engine = \"enable\"\n"
146 "ssl.pemfile = \"server.pem\"\n";
149 system("lighttpd -f lighty_config &");
153 void stop_proxy(int port
)
155 std::stringstream cmd
;
156 cmd
<< "delegated -P" << port
<< " -Fkill";
157 system(cmd
.str().c_str());
160 void start_proxy(int port
, int proxy_type
)
162 using namespace libtorrent
;
165 std::stringstream cmd
;
166 // we need to echo n since dg will ask us to configure it
167 cmd
<< "echo n | delegated -P" << port
<< " ADMIN=test@test.com "
168 "PERMIT=\"*:*:localhost\" REMITTABLE=+,https RELAY=proxy,delegate";
171 case proxy_settings::socks4
:
172 cmd
<< " SERVER=socks4";
174 case proxy_settings::socks5
:
175 cmd
<< " SERVER=socks5";
177 case proxy_settings::socks5_pw
:
178 cmd
<< " SERVER=socks5 AUTHORIZER=-list{testuser:testpass}";
180 case proxy_settings::http
:
181 cmd
<< " SERVER=http";
183 case proxy_settings::http_pw
:
184 cmd
<< " SERVER=http AUTHORIZER=-list{testuser:testpass}";
187 system(cmd
.str().c_str());
191 using namespace libtorrent
;
194 boost::intrusive_ptr
<T
> clone_ptr(boost::intrusive_ptr
<T
> const& ptr
)
196 return boost::intrusive_ptr
<T
>(new T(*ptr
));
199 boost::intrusive_ptr
<torrent_info
> create_torrent(std::ostream
* file
, int piece_size
, int num_pieces
)
201 char const* tracker_url
= "http://non-existent-name.com/announce";
203 using namespace boost::filesystem
;
206 int total_size
= piece_size
* num_pieces
;
207 fs
.add_file(path("temporary"), total_size
);
208 libtorrent::create_torrent
t(fs
, piece_size
);
209 t
.add_tracker(tracker_url
);
211 std::vector
<char> piece(piece_size
);
212 for (int i
= 0; i
< int(piece
.size()); ++i
)
213 piece
[i
] = (i
% 26) + 'A';
215 // calculate the hash for all pieces
216 int num
= t
.num_pieces();
217 sha1_hash ph
= hasher(&piece
[0], piece
.size()).final();
218 for (int i
= 0; i
< num
; ++i
)
223 while (total_size
> 0)
225 file
->write(&piece
[0], (std::min
)(int(piece
.size()), total_size
));
226 total_size
-= piece
.size();
230 std::vector
<char> tmp
;
231 std::back_insert_iterator
<std::vector
<char> > out(tmp
);
232 bencode(out
, t
.generate());
233 return boost::intrusive_ptr
<torrent_info
>(new torrent_info(&tmp
[0], tmp
.size()));
236 boost::tuple
<torrent_handle
, torrent_handle
, torrent_handle
>
237 setup_transfer(session
* ses1
, session
* ses2
, session
* ses3
238 , bool clear_files
, bool use_metadata_transfer
, bool connect_peers
239 , std::string suffix
, int piece_size
240 , boost::intrusive_ptr
<torrent_info
>* torrent
)
242 using namespace boost::filesystem
;
247 assert(ses1
->id() != ses2
->id());
249 assert(ses3
->id() != ses2
->id());
251 boost::intrusive_ptr
<torrent_info
> t
;
254 create_directory("./tmp1" + suffix
);
255 std::ofstream
file(("./tmp1" + suffix
+ "/temporary").c_str());
256 t
= ::create_torrent(&file
, piece_size
, 1024 / 8);
260 remove_all("./tmp2" + suffix
+ "/temporary");
261 remove_all("./tmp3" + suffix
+ "/temporary");
263 std::cerr
<< "generated torrent: " << t
->info_hash() << std::endl
;
270 // they should not use the same save dir, because the
271 // file pool will complain if two torrents are trying to
272 // use the same files
273 sha1_hash info_hash
= t
->info_hash();
274 torrent_handle tor1
= ses1
->add_torrent(clone_ptr(t
), "./tmp1" + suffix
);
275 TEST_CHECK(!ses1
->get_torrents().empty());
280 tor3
= ses3
->add_torrent(clone_ptr(t
), "./tmp3" + suffix
);
281 TEST_CHECK(!ses3
->get_torrents().empty());
284 if (use_metadata_transfer
)
285 tor2
= ses2
->add_torrent("http://non-existent-name.com/announce"
286 , t
->info_hash(), 0, "./tmp2" + suffix
);
288 tor2
= ses2
->add_torrent(clone_ptr(t
), "./tmp2" + suffix
);
289 TEST_CHECK(!ses2
->get_torrents().empty());
291 assert(ses1
->get_torrents().size() == 1);
292 assert(ses2
->get_torrents().size() == 1);
298 std::cerr
<< "connecting peer\n";
299 tor1
.connect_peer(tcp::endpoint(address::from_string("127.0.0.1")
300 , ses2
->listen_port()));
304 // give the other peers some time to get an initial
305 // set of pieces before they start sharing with each-other
306 tor3
.connect_peer(tcp::endpoint(
307 address::from_string("127.0.0.1")
308 , ses2
->listen_port()));
309 tor3
.connect_peer(tcp::endpoint(
310 address::from_string("127.0.0.1")
311 , ses1
->listen_port()));
315 return boost::make_tuple(tor1
, tor2
, tor3
);