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