1 // libTorrent - BitTorrent library
2 // Copyright (C) 2005-2011, Jari Sundell
3 //
4 // This program is free software; you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation; either version 2 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program; if not, write to the Free Software
16 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 //
18 // In addition, as a special exception, the copyright holders give
19 // permission to link the code of portions of this program with the
20 // OpenSSL library under certain conditions as described in each
21 // individual source file, and distribute linked combinations
22 // including the two.
23 //
24 // You must obey the GNU General Public License in all respects for
25 // all of the code used other than OpenSSL. If you modify file(s)
26 // with this exception, you may extend this exception to your version
27 // of the file(s), but you are not obligated to do so. If you do not
28 // wish to do so, delete this exception statement from your version.
29 // If you delete this exception statement from all source files in the
30 // program, then also delete it here.
31 //
32 // Contact: Jari Sundell <jaris@ifi.uio.no>
33 //
34 // Skomakerveien 33
35 // 3185 Skoppum, NORWAY
36
37 #include "config.h"
38
39 #include <rak/address_info.h>
40 #include <rak/string_manip.h>
41
42 #include "exceptions.h"
43 #include "torrent.h"
44 #include "object.h"
45 #include "object_stream.h"
46 #include "throttle.h"
47 #include "connection_manager.h"
48 #include "poll.h"
49
50 #include "manager.h"
51
52 #include "protocol/handshake_manager.h"
53 #include "protocol/peer_factory.h"
54 #include "data/file_manager.h"
55 #include "data/hash_queue.h"
56 #include "data/hash_torrent.h"
57 #include "download/download_constructor.h"
58 #include "download/download_manager.h"
59 #include "download/download_wrapper.h"
60 #include "utils/instrumentation.h"
61 #include "torrent/peer/connection_list.h"
62 #include "torrent/download/resource_manager.h"
63
64 namespace torrent {
65
66 uint32_t
calculate_max_open_files(uint32_t openMax)67 calculate_max_open_files(uint32_t openMax) {
68 if (openMax >= 8096)
69 return 256;
70 else if (openMax >= 1024)
71 return 128;
72 else if (openMax >= 512)
73 return 64;
74 else if (openMax >= 128)
75 return 16;
76 else // Assumes we don't try less than 64.
77 return 4;
78 }
79
80 uint32_t
calculate_reserved(uint32_t openMax)81 calculate_reserved(uint32_t openMax) {
82 if (openMax >= 8096)
83 return 256;
84 else if (openMax >= 1024)
85 return 128;
86 else if (openMax >= 512)
87 return 64;
88 else if (openMax >= 128)
89 return 32;
90 else // Assumes we don't try less than 64.
91 return 16;
92 }
93
94 void
initialize()95 initialize() {
96 if (manager != NULL)
97 throw internal_error("torrent::initialize(...) called but the library has already been initialized");
98
99 cachedTime = rak::timer::current();
100
101 instrumentation_initialize();
102
103 manager = new Manager;
104 manager->main_thread_main()->init_thread();
105
106 uint32_t maxFiles = calculate_max_open_files(manager->poll()->open_max());
107
108 manager->connection_manager()->set_max_size(manager->poll()->open_max() - maxFiles - calculate_reserved(manager->poll()->open_max()));
109 manager->file_manager()->set_max_open_files(maxFiles);
110
111 manager->main_thread_disk()->init_thread();
112 manager->main_thread_disk()->start_thread();
113 }
114
115 // Clean up and close stuff. Stopping all torrents and waiting for
116 // them to finish is not required, but recommended.
117 void
cleanup()118 cleanup() {
119 if (manager == NULL)
120 throw internal_error("torrent::cleanup() called but the library is not initialized.");
121
122 manager->main_thread_disk()->stop_thread_wait();
123
124 delete manager;
125 manager = NULL;
126 }
127
128 bool
is_inactive()129 is_inactive() {
130 return manager == NULL ||
131 std::find_if(manager->download_manager()->begin(), manager->download_manager()->end(), std::not1(std::mem_fun(&DownloadWrapper::is_stopped)))
132 == manager->download_manager()->end();
133 }
134
135 thread_base*
main_thread()136 main_thread() {
137 return manager->main_thread_main();
138 }
139
chunk_manager()140 ChunkManager* chunk_manager() { return manager->chunk_manager(); }
client_list()141 ClientList* client_list() { return manager->client_list(); }
file_manager()142 FileManager* file_manager() { return manager->file_manager(); }
connection_manager()143 ConnectionManager* connection_manager() { return manager->connection_manager(); }
dht_manager()144 DhtManager* dht_manager() { return manager->dht_manager(); }
resource_manager()145 ResourceManager* resource_manager() { return manager->resource_manager(); }
146
147 uint32_t
total_handshakes()148 total_handshakes() {
149 return manager->handshake_manager()->size();
150 }
151
down_throttle_global()152 Throttle* down_throttle_global() { return manager->download_throttle(); }
up_throttle_global()153 Throttle* up_throttle_global() { return manager->upload_throttle(); }
154
down_rate()155 const Rate* down_rate() { return manager->download_throttle()->rate(); }
up_rate()156 const Rate* up_rate() { return manager->upload_throttle()->rate(); }
version()157 const char* version() { return VERSION; }
158
hash_queue_size()159 uint32_t hash_queue_size() { return manager->hash_queue()->size(); }
160
161 EncodingList*
encoding_list()162 encoding_list() {
163 return manager->encoding_list();
164 }
165
166 Download
download_add(Object * object)167 download_add(Object* object) {
168 std::auto_ptr<DownloadWrapper> download(new DownloadWrapper);
169
170 DownloadConstructor ctor;
171 ctor.set_download(download.get());
172 ctor.set_encoding_list(manager->encoding_list());
173
174 ctor.initialize(*object);
175
176 std::string infoHash;
177 if (download->info()->is_meta_download())
178 infoHash = object->get_key("info").get_key("pieces").as_string();
179 else
180 infoHash = object_sha1(&object->get_key("info"));
181
182 if (manager->download_manager()->find(infoHash) != manager->download_manager()->end())
183 throw input_error("Info hash already used by another torrent.");
184
185 if (!download->info()->is_meta_download()) {
186 char buffer[1024];
187 uint64_t metadata_size = 0;
188 object_write_bencode_c(&object_write_to_size, &metadata_size, object_buffer_t(buffer, buffer + sizeof(buffer)), &object->get_key("info"));
189 download->main()->set_metadata_size(metadata_size);
190 }
191
192 download->set_hash_queue(manager->hash_queue());
193 download->initialize(infoHash, PEER_NAME + rak::generate_random<std::string>(20 - std::string(PEER_NAME).size()));
194
195 // Add trackers, etc, after setting the info hash so that log
196 // entries look sane.
197 ctor.parse_tracker(*object);
198
199 // Default PeerConnection factory functions.
200 download->main()->connection_list()->slot_new_connection(&createPeerConnectionDefault);
201
202 // Consider move as much as possible into this function
203 // call. Anything that won't cause possible torrent creation errors
204 // go in there.
205 manager->initialize_download(download.get());
206
207 download->set_bencode(object);
208 return Download(download.release());
209 }
210
211 void
download_remove(Download d)212 download_remove(Download d) {
213 manager->cleanup_download(d.ptr());
214 }
215
216 // Add all downloads to dlist. Make sure it's cleared.
217 void
download_list(DList & dlist)218 download_list(DList& dlist) {
219 for (DownloadManager::const_iterator itr = manager->download_manager()->begin();
220 itr != manager->download_manager()->end(); ++itr)
221 dlist.push_back(Download(*itr));
222 }
223
224 // Make sure you check that it's valid.
225 Download
download_find(const std::string & infohash)226 download_find(const std::string& infohash) {
227 return *manager->download_manager()->find(infohash);
228 }
229
230 uint32_t
download_priority(Download d)231 download_priority(Download d) {
232 ResourceManager::iterator itr = manager->resource_manager()->find(d.ptr()->main());
233
234 if (itr == manager->resource_manager()->end())
235 throw internal_error("torrent::download_priority(...) could not find the download in the resource manager.");
236
237 return itr->priority();
238 }
239
240 void
download_set_priority(Download d,uint32_t pri)241 download_set_priority(Download d, uint32_t pri) {
242 ResourceManager::iterator itr = manager->resource_manager()->find(d.ptr()->main());
243
244 if (itr == manager->resource_manager()->end())
245 throw internal_error("torrent::download_set_priority(...) could not find the download in the resource manager.");
246
247 if (pri > 1024)
248 throw internal_error("torrent::download_set_priority(...) received an invalid priority.");
249
250 manager->resource_manager()->set_priority(itr, pri);
251 }
252
253 }
254