source: trunk/src/halSession.hpp @ 741

Revision 741, 33.4 KB checked in by Eoin, 11 years ago (diff)

Torrent manager given it's own header with cleanup refactoring.

Line 
1
2//         Copyright Eóin O'Callaghan 2006 - 2009.
3// Distributed under the Boost Software License, Version 1.0.
4//    (See accompanying file LICENSE_1_0.txt or copy at
5//          http://www.boost.org/LICENSE_1_0.txt)
6
7#pragma once
8
9#include <boost/tuple/tuple.hpp>
10#include <boost/enable_shared_from_this.hpp>
11#include <boost/multi_index_container.hpp>
12#include <boost/multi_index/ordered_index.hpp>
13#include <boost/multi_index/indexed_by.hpp>
14#include <boost/multi_index/identity.hpp>
15#include <boost/multi_index/member.hpp>
16#include <boost/multi_index/tag.hpp>
17
18#pragma warning (push, 1)
19#       include <libtorrent/file.hpp>
20#       include <libtorrent/hasher.hpp>
21#       include <libtorrent/storage.hpp>
22#       include <libtorrent/file_pool.hpp>
23#       include <libtorrent/alert_types.hpp>
24#       include <libtorrent/entry.hpp>
25#       include <libtorrent/bencode.hpp>
26#       include <libtorrent/upnp.hpp>
27#       include <libtorrent/natpmp.hpp>
28#       include <libtorrent/session.hpp>
29#       include <libtorrent/ip_filter.hpp>
30#       include <libtorrent/torrent_handle.hpp>
31#       include <libtorrent/peer_connection.hpp>
32#       include <libtorrent/extensions/metadata_transfer.hpp>
33#       include <libtorrent/extensions/ut_pex.hpp>
34#       include <libtorrent/extensions/ut_metadata.hpp>
35#       include <libtorrent/extensions/smart_ban.hpp>
36#pragma warning (pop)
37
38#include "halIni.hpp"
39#include "halTypes.hpp"
40#include "halEvent.hpp"
41#include "halConfig.hpp"
42#include "halTorrentInternal.hpp"
43#include "halTorrentManager.hpp"
44#include "halSignaler.hpp"
45
46namespace boost {
47namespace serialization {
48
49template<class Archive, class address_type>
50void save(Archive& ar, const address_type& ip, const unsigned int version)
51{       
52        unsigned long addr = ip.to_ulong();     
53        ar & BOOST_SERIALIZATION_NVP(addr);
54}
55
56template<class Archive, class address_type>
57void load(Archive& ar, address_type& ip, const unsigned int version)
58{       
59        unsigned long addr;
60        ar & BOOST_SERIALIZATION_NVP(addr);     
61        ip = address_type(addr);
62}
63
64template<class Archive, class String, class Traits>
65void save(Archive& ar, const boost::filesystem::basic_path<String, Traits>& p, const unsigned int version)
66{       
67        String str = p.string();
68        ar & BOOST_SERIALIZATION_NVP(str);
69}
70
71template<class Archive, class String, class Traits>
72void load(Archive& ar, boost::filesystem::basic_path<String, Traits>& p, const unsigned int version)
73{       
74        String str;
75        ar & BOOST_SERIALIZATION_NVP(str);
76
77        p = str;
78}
79
80template<class Archive, class String, class Traits>
81inline void serialize(
82        Archive & ar,
83        boost::filesystem::basic_path<String, Traits>& p,
84        const unsigned int file_version)
85{
86        split_free(ar, p, file_version);           
87}
88
89template<class Archive, class address_type>
90void serialize(Archive& ar, libtorrent::ip_range<address_type>& addr, const unsigned int version)
91{       
92        ar & BOOST_SERIALIZATION_NVP(addr.first);
93        ar & BOOST_SERIALIZATION_NVP(addr.last);
94        addr.flags = libtorrent::ip_filter::blocked;
95}
96
97template<class Archive>
98void serialize(Archive& ar, hal::tracker_detail& tracker, const unsigned int version)
99{       
100        ar & BOOST_SERIALIZATION_NVP(tracker.url);
101        ar & BOOST_SERIALIZATION_NVP(tracker.tier);
102}
103
104} // namespace serialization
105} // namespace boost
106
107BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v4)
108BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v6)
109
110namespace libtorrent
111{
112
113template<class Addr>
114bool operator==(const libtorrent::ip_range<Addr>& lhs, const int flags)
115{
116        return (lhs.flags == flags);
117}
118
119inline
120std::ostream& operator<<(std::ostream& os, libtorrent::ip_range<asio::ip::address_v4>& ip)
121{
122        os << ip.first.to_ulong();
123        os << ip.last.to_ulong();
124       
125        return os;
126}
127
128} // namespace libtorrent
129
130namespace hal
131{
132
133namespace libt = libtorrent;
134
135inline
136bool operator!=(const libt::dht_settings& lhs, const libt::dht_settings& rhs)
137{
138        return lhs.max_peers_reply != rhs.max_peers_reply ||
139                   lhs.search_branching != rhs.search_branching ||
140                   lhs.service_port != rhs.service_port ||
141           lhs.max_fail_count != rhs.max_fail_count;
142}
143
144template<typename Addr>
145void write_range(fs::ofstream& ofs, const libt::ip_range<Addr>& range)
146{ 
147        const typename Addr::bytes_type first = range.first.to_bytes();
148        const typename Addr::bytes_type last = range.last.to_bytes();
149        ofs.write((char*)first.elems, first.size());
150        ofs.write((char*)last.elems, last.size());
151}
152
153template<typename Addr>
154void write_vec_range(fs::ofstream& ofs, const std::vector<libt::ip_range<Addr> >& vec)
155{ 
156        ofs << vec.size();
157       
158        for (typename std::vector<libt::ip_range<Addr> >::const_iterator i=vec.begin(); 
159                i != vec.end(); ++i)
160        {
161                write_range(ofs, *i);
162        }
163}
164
165template<typename Addr>
166void read_range_to_filter(fs::ifstream& ifs, libt::ip_filter& ip_filter)
167{ 
168        typename Addr::bytes_type first;
169        typename Addr::bytes_type last;
170        ifs.read((char*)first.elems, first.size());
171        ifs.read((char*)last.elems, last.size());       
172       
173        ip_filter.add_rule(Addr(first), Addr(last),
174                libt::ip_filter::blocked);
175}
176
177static event_logger::eventLevel lbtAlertToHalEvent(libt::alert::severity_t severity)
178{
179        switch (severity)
180        {
181        case libt::alert::debug:
182                return event_logger::debug;
183       
184        case libt::alert::info:
185                return event_logger::info;
186       
187        case libt::alert::warning:
188                return event_logger::warning;
189       
190        case libt::alert::critical:
191        case libt::alert::fatal:
192                return event_logger::critical;
193       
194        default:
195                return event_logger::none;
196        }
197}
198
199static event_logger::eventLevel lbt_category_to_event(int category)
200{
201        switch (category)
202        {
203        case libt::alert::debug_notification:
204                return event_logger::debug;
205       
206        case libt::alert::peer_notification:
207        case libt::alert::port_mapping_notification:
208        case libt::alert::storage_notification:
209        case libt::alert::tracker_notification:
210        case libt::alert::status_notification:
211        case libt::alert::progress_notification:
212        case libt::alert::ip_block_notification:
213                return event_logger::info;
214       
215        case libt::alert::performance_warning:
216                return event_logger::warning;
217       
218        case libt::alert::error_notification:
219                return event_logger::critical;
220       
221        default:
222                return event_logger::none;
223        }
224}
225
226#define HAL_GENERIC_TORRENT_PROP_EXCEPTION_CATCH(FUNCTION) \
227catch (const libt::invalid_handle&) \
228{\
229        event_log.post(shared_ptr<EventDetail>( \
230                new EventInvalidTorrent(event_logger::info, event_logger::invalid_torrent, name, std::string(FUNCTION)))); \
231}\
232catch (const invalid_torrent& t) \
233{ \
234        event_log.post(shared_ptr<EventDetail>( \
235                new EventInvalidTorrent(event_logger::info, event_logger::invalid_torrent, t.who(), std::string(FUNCTION)))); \
236} \
237catch (const access_violation& e) \
238{ \
239        hal::event_log.post(shared_ptr<hal::EventDetail>( \
240                new hal::EventMsg(hal::wform(L"Torrent property %1% access_violation (code %2$x) at %3$x. Bad address %4$x") % hal::from_utf8(FUNCTION) % e.code() % (unsigned)e.where() % (unsigned)e.badAddress(), \
241                        hal::event_logger::critical))); \
242} \
243catch (const win32_exception& e) \
244{ \
245        hal::event_log.post(shared_ptr<hal::EventDetail>( \
246                new hal::EventMsg(hal::wform(L"Torrent property %1% win32_exception (code %2$x) at %3$x") % hal::from_utf8(FUNCTION) % e.code() % (unsigned)e.where(), \
247                        hal::event_logger::critical))); \
248} \
249catch (const std::exception& e) \
250{ \
251        event_log.post(shared_ptr<EventDetail>( \
252                new EventTorrentException(event_logger::critical, event_logger::torrentException, std::string(e.what()), name, std::string(FUNCTION)))); \
253} \
254catch(...) \
255{ \
256        hal::event_log.post(shared_ptr<hal::EventDetail>( \
257                new hal::EventMsg(hal::wform(L"%1% catch all") % hal::from_utf8(FUNCTION), \
258                        hal::event_logger::critical))); \
259}
260
261#define HAL_GENERIC_TORRENT_EXCEPTION_CATCH(TORRENT, FUNCTION) \
262catch (const libt::invalid_handle&) \
263{\
264        event_log.post(shared_ptr<EventDetail>( \
265                new EventInvalidTorrent(event_logger::info, event_logger::invalid_torrent, TORRENT, std::string(FUNCTION)))); \
266}\
267catch (const invalid_torrent& t) \
268{\
269        event_log.post(shared_ptr<EventDetail>( \
270                new EventInvalidTorrent(event_logger::info, event_logger::invalid_torrent, t.who(), std::string(FUNCTION)))); \
271}\
272catch (const access_violation& e) \
273{ \
274        hal::event_log.post(shared_ptr<hal::EventDetail>( \
275                new hal::EventMsg(hal::wform(L"Generic Torrent %1% access_violation (code %2$x) at %3$x. Bad address %4$x (%5%)") % hal::from_utf8(FUNCTION) % e.code() % (unsigned)e.where() % (unsigned)e.badAddress() % TORRENT, \
276                        hal::event_logger::critical))); \
277} \
278catch (const win32_exception& e) \
279{ \
280        hal::event_log.post(shared_ptr<hal::EventDetail>( \
281                new hal::EventMsg(hal::wform(L"Generic Torrent %1% win32_exception (code %2$x) at %3$x (%4%)") % hal::from_utf8(FUNCTION) % e.code() % (unsigned)e.where() % TORRENT, \
282                        hal::event_logger::critical))); \
283} \
284catch (const std::exception& e) \
285{ \
286        event_log.post(shared_ptr<EventDetail>( \
287                new EventTorrentException(event_logger::critical, event_logger::torrentException, std::string(e.what()), TORRENT, std::string(FUNCTION)))); \
288} \
289catch (...) \
290{ \
291        hal::event_log.post(shared_ptr<hal::EventDetail>( \
292                new hal::EventMsg(hal::wform(L"Generic Torrent %1% catch all") % hal::from_utf8(FUNCTION), \
293                        hal::event_logger::critical))); \
294}
295
296#define HAL_GENERIC_PIMPL_EXCEPTION_CATCH(FUNCTION) \
297catch (const access_violation& e) \
298{ \
299        hal::event_log.post(shared_ptr<hal::EventDetail>( \
300                new hal::EventMsg(hal::wform(L"Generic Session Pimpl %1% access_violation (code %2$x) at %3$x. Bad address %4$x") % hal::from_utf8(FUNCTION) % e.code() % (unsigned)e.where() % (unsigned)e.badAddress(), \
301                        hal::event_logger::critical))); \
302} \
303catch (const win32_exception& e) \
304{ \
305        hal::event_log.post(shared_ptr<hal::EventDetail>( \
306                new hal::EventMsg(hal::wform(L"Generic Session Pimpl %1% win32_exception (code %2$x) at %3$x") % hal::from_utf8(FUNCTION) % e.code() % (unsigned)e.where(), \
307                        hal::event_logger::critical))); \
308} \
309catch (const std::exception& e) \
310{ \
311        hal::event_log.post(shared_ptr<hal::EventDetail>( \
312        new hal::EventMsg(hal::wform(L"Generic Session Pimpl %1% std_exception: %2%") % hal::from_utf8(FUNCTION) % hal::from_utf8(e.what()), \
313                        hal::event_logger::critical))); \
314} \
315catch (...) \
316{ \
317        hal::event_log.post(shared_ptr<hal::EventDetail>( \
318                new hal::EventMsg(hal::wform(L"Generic Session Pimpl %1% catch all") % hal::from_utf8(FUNCTION), \
319                        hal::event_logger::critical))); \
320}
321
322class bit_impl
323{
324        friend class bit;
325
326private:
327        bit_impl();     
328public: 
329        ~bit_impl();
330
331        bool listen_on(std::pair<int, int> const& range)
332        {
333                try
334                {
335               
336                if (!session_.is_listening())
337                {
338                        return session_.listen_on(range);
339                }
340                else
341                {
342                        int port = session_.listen_port();
343                       
344                        if (port < range.first || port > range.second)
345                                return session_.listen_on(range);       
346                        else
347                        {
348                                signals.successful_listen();
349                               
350                                return true;
351                        }
352                }
353               
354                }
355                catch (const std::exception& e)
356                {
357                        event_log.post(shared_ptr<EventDetail>(
358                                new EventStdException(event_logger::fatal, e, L"From bit::listenOn.")));
359
360                        return false;
361                }
362                catch (...)
363                {
364                        return false;
365                }
366        }
367
368        int is_listening_on() 
369        {
370                if (!session_.is_listening())
371                        return -1;     
372                else
373                        return session_.listen_port();
374        }
375
376        void stop_listening()
377        {
378                ensure_dht_off();
379                session_.listen_on(std::make_pair(0, 0));
380        }
381
382        bool ensure_dht_on(const dht_settings& dht)
383        {               
384                libt::dht_settings settings;
385                settings.max_peers_reply = dht.max_peers_reply;
386                settings.search_branching = dht.search_branching;
387                settings.service_port = dht.service_port;
388                settings.max_fail_count = dht.max_fail_count;
389               
390                HAL_DEV_MSG(hal::wform(L"Seleted DHT port = %1%") % settings.service_port);
391               
392                if (dht_settings_ != settings)
393                {
394                        dht_settings_ = settings;
395                        session_.set_dht_settings(dht_settings_);
396                }
397
398                if (!dht_on_)
399                {               
400                        try
401                        {
402                        session_.start_dht(dht_state_);
403                        dht_on_ = true;
404                        }
405                        catch(...)
406                        {}
407                }
408                        return dht_on_;
409        }
410
411        void ensure_dht_off()
412        {
413                if (dht_on_)
414                {
415                        session_.stop_dht();           
416                        dht_on_ = false;
417                }
418        }
419
420        void set_mapping(bool upnp, bool nat_pmp)
421        {
422                if (upnp)
423                {
424                        event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Starting UPnP mapping.")));
425
426                        upnp_ = session_.start_upnp();
427                }
428                else
429                {
430                        event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Stopping UPnP mapping.")));
431
432                        session_.stop_upnp();
433                        upnp_ = NULL;
434                }
435
436                if (nat_pmp)
437                {
438                        event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Starting NAT-PMP mapping.")));
439
440                        natpmp_ = session_.start_natpmp();
441                }
442                else
443                {
444                        event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Stopping NAT-PMP mapping.")));
445
446                        session_.stop_natpmp();
447                        natpmp_ = NULL;
448                }
449        }
450
451        std::wstring upnp_router_model()
452        {
453                if (upnp_)
454                        return to_wstr_shim(upnp_->router_model());
455                else
456                        return L"UPnP not started";
457        }
458
459        void set_timeouts(int peers, int tracker)
460        {
461                libt::session_settings settings = session_.settings();
462                settings.peer_connect_timeout = peers;
463                settings.tracker_completion_timeout = tracker;
464
465                session_.set_settings(settings);
466
467                event_log.post(shared_ptr<EventDetail>(new EventMsg(
468                        hal::wform(L"Set Timeouts, peer %1%, tracker %2%.") % peers % tracker)));
469        }
470
471        cache_settings get_cache_settings()
472        {
473                libt::session_settings settings = session_.settings();
474                cache_settings cache;
475
476                cache.cache_size = settings.cache_size;
477                cache.cache_expiry = settings.cache_expiry;
478
479                return cache;
480        }
481
482        void set_cache_settings(const cache_settings& cache)
483        {
484                libt::session_settings settings = session_.settings();
485
486                settings.cache_size = cache.cache_size;
487                settings.cache_expiry = cache.cache_expiry;
488
489                session_.set_settings(settings);
490
491                event_log.post(shared_ptr<EventDetail>(new EventMsg(
492                        hal::wform(L"Set cache parameters, %1% size and %2% expiry.") 
493                                % settings.cache_size % settings.cache_expiry)));
494        }
495
496        queue_settings get_queue_settings()
497        {               
498                libt::session_settings settings = session_.settings();
499                queue_settings queue;
500
501                queue.auto_manage_interval = settings.auto_manage_interval;
502                queue.active_downloads = settings.active_downloads;
503                queue.active_seeds = settings.active_seeds;
504                queue.seeds_hard_limit = settings.active_limit;
505                queue.seed_ratio_limit = settings.share_ratio_limit;
506                queue.seed_ratio_time_limit = settings.seed_time_ratio_limit;
507                queue.seed_time_limit = settings.seed_time_limit;
508                queue.dont_count_slow_torrents = settings.dont_count_slow_torrents;
509                queue.auto_scrape_min_interval = settings.auto_scrape_min_interval;
510                queue.auto_scrape_interval = settings.auto_scrape_interval;
511                queue.close_redundant_connections = settings.close_redundant_connections;
512
513                return queue;
514        }
515
516        void set_queue_settings(const queue_settings& queue)
517        {
518                libt::session_settings settings = session_.settings();
519
520                settings.auto_manage_interval = queue.auto_manage_interval;
521                settings.active_downloads = queue.active_downloads;
522                settings.active_seeds = queue.active_seeds;
523                settings.active_limit = queue.seeds_hard_limit;
524                settings.share_ratio_limit = queue.seed_ratio_limit;
525                settings.seed_time_ratio_limit = queue.seed_ratio_time_limit;
526                settings.seed_time_limit = queue.seed_time_limit;
527                settings.dont_count_slow_torrents = queue.dont_count_slow_torrents;
528                settings.auto_scrape_min_interval = queue.auto_scrape_min_interval;
529                settings.auto_scrape_interval = queue.auto_scrape_interval;
530                settings.close_redundant_connections = queue.close_redundant_connections;
531
532                session_.set_settings(settings);
533
534                event_log.post(shared_ptr<EventDetail>(new EventMsg(
535                        hal::wform(L"Set queue parameters, %1% downloads and %2% active seeds.") 
536                                % settings.active_downloads % settings.active_seeds)));
537        }
538
539        timeouts get_timeouts()
540        {               
541                libt::session_settings settings = session_.settings();
542                timeouts times;
543
544                times.tracker_completion_timeout = settings.tracker_completion_timeout;
545                times.tracker_receive_timeout = settings.tracker_receive_timeout;
546                times.stop_tracker_timeout = settings.stop_tracker_timeout;
547
548                times.request_queue_time = settings.request_queue_time;
549                times.piece_timeout = settings.piece_timeout;
550                times.min_reconnect_time = settings.min_reconnect_time;         
551
552                times.peer_timeout = settings.peer_timeout;
553                times.urlseed_timeout = settings.urlseed_timeout;
554                times.peer_connect_timeout = settings.peer_connect_timeout;
555                times.inactivity_timeout = settings.inactivity_timeout;
556                times.handshake_timeout = settings.handshake_timeout;
557
558                return times;
559        }
560
561        void set_timeouts(const timeouts& times)
562        {
563                libt::session_settings settings = session_.settings();
564
565                settings.tracker_completion_timeout = times.tracker_completion_timeout;
566                settings.tracker_receive_timeout = times.tracker_receive_timeout;
567                settings.stop_tracker_timeout = times.stop_tracker_timeout;
568
569                settings.request_queue_time = times.request_queue_time;
570                settings.piece_timeout = times.piece_timeout;
571                settings.min_reconnect_time = times.min_reconnect_time;         
572
573                settings.peer_timeout = times.peer_timeout;
574                settings.urlseed_timeout = times.urlseed_timeout;
575                settings.peer_connect_timeout = times.peer_connect_timeout;
576                settings.inactivity_timeout = times.inactivity_timeout;
577                settings.handshake_timeout = times.handshake_timeout;
578
579                session_.set_settings(settings);
580
581                event_log.post(shared_ptr<EventDetail>(new EventMsg(
582                        hal::wform(L"Set timeouts, peers- %1% secs, tracker- %2% secs.") 
583                                % settings.peer_timeout % settings.tracker_receive_timeout)));
584        }
585
586        void set_session_limits(int maxConn, int maxUpload)
587        {               
588                session_.set_max_uploads(maxUpload);
589                session_.set_max_connections(maxConn);
590               
591                event_log.post(shared_ptr<EventDetail>(new EventMsg(
592                        hal::wform(L"Set connections totals %1% and uploads %2%.") 
593                                % maxConn % maxUpload)));
594        }
595
596        void set_session_speed(float download, float upload)
597        {
598                int down = (download > 0) ? static_cast<int>(download*1024) : -1;
599                session_.set_download_rate_limit(down);
600                int up = (upload > 0) ? static_cast<int>(upload*1024) : -1;
601                session_.set_upload_rate_limit(up);
602               
603                event_log.post(shared_ptr<EventDetail>(new EventMsg(
604                        hal::wform(L"Set session rates at download %1% and upload %2%.") 
605                                % session_.download_rate_limit() % session_.upload_rate_limit())));
606        }
607
608        cache_details get_cache_details() const
609        {
610                libt::cache_status cs = session_.get_cache_status();
611
612                return cache_details(cs.blocks_written, cs.writes, 
613                        cs.blocks_read, cs.blocks_read_hit, cs.reads,
614                        cs.cache_size, cs.read_cache_size);
615        }
616
617        bool ensure_ip_filter_on(progress_callback fn)
618        {
619                try
620                {
621               
622                if (!ip_filter_loaded_)
623                {
624                        ip_filter_load(fn);
625                        ip_filter_loaded_ = true;
626                }
627               
628                if (!ip_filter_on_)
629                {
630                        session_.set_ip_filter(ip_filter_);
631                        ip_filter_on_ = true;
632                        ip_filter_count();
633                }
634               
635                }
636                catch(const std::exception& e)
637                {               
638                        hal::event_log.post(boost::shared_ptr<hal::EventDetail>(
639                                new hal::EventStdException(event_logger::critical, e, L"ensureIpFilterOn"))); 
640
641                        ensure_ip_filter_off();
642                }
643
644                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"IP filters on.")));       
645
646                return false;
647        }
648
649        void ensure_ip_filter_off()
650        {
651                session_.set_ip_filter(libt::ip_filter());
652                ip_filter_on_ = false;
653               
654                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"IP filters off.")));     
655        }
656
657#       ifndef TORRENT_DISABLE_ENCRYPTION       
658        void ensure_pe_on(const pe_settings& pe_s)
659        {
660                libt::pe_settings pe;
661               
662                switch (pe_s.encrypt_level)
663                {
664                        case 0:
665                                pe.allowed_enc_level = libt::pe_settings::plaintext;
666                                break;
667                        case 1:
668                                pe.allowed_enc_level = libt::pe_settings::rc4;
669                                break;
670                        case 2:
671                                pe.allowed_enc_level = libt::pe_settings::both;
672                                break;
673                        default:
674                                pe.allowed_enc_level = libt::pe_settings::both;
675                               
676                                hal::event_log.post(shared_ptr<hal::EventDetail>(
677                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
678                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_ENCODING_LEVEL)) % pe_s.encrypt_level).str())));
679                }
680
681                switch (pe_s.conn_in_policy)
682                {
683                        case 0:
684                                pe.in_enc_policy = libt::pe_settings::forced;
685                                break;
686                        case 1:
687                                pe.in_enc_policy = libt::pe_settings::enabled;
688                                break;
689                        case 2:
690                                pe.in_enc_policy = libt::pe_settings::disabled;
691                                break;
692                        default:
693                                pe.in_enc_policy = libt::pe_settings::enabled;
694                               
695                                hal::event_log.post(shared_ptr<hal::EventDetail>(
696                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
697                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % pe_s.conn_in_policy).str())));
698                }
699
700                switch (pe_s.conn_out_policy)
701                {
702                        case 0:
703                                pe.out_enc_policy = libt::pe_settings::forced;
704                                break;
705                        case 1:
706                                pe.out_enc_policy = libt::pe_settings::enabled;
707                                break;
708                        case 2:
709                                pe.out_enc_policy = libt::pe_settings::disabled;
710                                break;
711                        default:
712                                pe.out_enc_policy = libt::pe_settings::enabled;
713                               
714                                hal::event_log.post(shared_ptr<hal::EventDetail>(
715                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
716                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % pe_s.conn_out_policy).str())));
717                }
718               
719                pe.prefer_rc4 = pe_s.prefer_rc4;
720               
721                try
722                {
723               
724                session_.set_pe_settings(pe);
725               
726                }
727                catch(const std::exception& e)
728                {
729                        hal::event_log.post(boost::shared_ptr<hal::EventDetail>(
730                                        new hal::EventStdException(event_logger::critical, e, L"ensurePeOn"))); 
731                                       
732                        ensure_pe_off();               
733                }
734               
735                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption on.")));
736        }
737
738        void ensure_pe_off()
739        {
740                libt::pe_settings pe;
741                pe.out_enc_policy = libt::pe_settings::disabled;
742                pe.in_enc_policy = libt::pe_settings::disabled;
743               
744                pe.allowed_enc_level = libt::pe_settings::both;
745                pe.prefer_rc4 = true;
746               
747                session_.set_pe_settings(pe);
748
749                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption off.")));
750        }
751#       endif
752       
753        void set_resolve_countries(bool b)
754        {               
755                resolve_countries_ = b;
756
757                for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); 
758                        i != e; ++i)
759                {
760                        (*i).torrent->set_resolve_countries(resolve_countries_);
761                }
762
763                if (b)                 
764                        event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Set to resolve countries.")));
765                else                   
766                        event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Not resolving countries.")));
767        }
768
769        void start_smart_ban_plugin()
770        {
771                session_.add_extension(&libt::create_smart_ban_plugin);
772                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Started smart ban plugin.")));
773        }
774
775        void start_ut_pex_plugin()
776        {
777                session_.add_extension(&libt::create_ut_pex_plugin);
778                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Started uTorrent peer exchange plugin.")));
779        }
780
781        void start_ut_metadata_plugin()
782        {
783                session_.add_extension(&libt::create_ut_metadata_plugin);
784                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Started uTorrent metadata plugin.")));
785        }
786
787        void start_metadata_plugin()
788        {
789                session_.add_extension(&libt::create_metadata_plugin);
790                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Started metadata plugin.")));
791        }
792
793        void ip_v4_filter_block(boost::asio::ip::address_v4 first, boost::asio::ip::address_v4 last)
794        {
795                ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
796                ip_filter_count();
797                ip_filter_changed_ = true;
798        }
799
800        void ip_v6_filter_block(boost::asio::ip::address_v6 first, boost::asio::ip::address_v6 last)
801        {
802                ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
803                ip_filter_count();
804                ip_filter_changed_ = true;
805        }
806
807        size_t ip_filter_size()
808        {
809                return ip_filter_count_;
810        }
811
812        void clear_ip_filter()
813        {
814                ip_filter_ = libt::ip_filter();
815                session_.set_ip_filter(libt::ip_filter());     
816                ip_filter_changed_ = true;
817                ip_filter_count();
818        }
819
820        bool ip_filter_import_dat(boost::filesystem::path file, progress_callback fn, bool octalFix);
821
822        struct 
823        {
824                signaler<> successful_listen;
825                signaler<> torrent_finished;
826
827                boost::signal<bool()> torrent_paused;
828        } 
829        signals;
830
831        void start_alert_handler();
832        void stop_alert_handler();
833        void alert_handler();
834
835        void add_torrent(wpath file, wpath saveDirectory, bool startStopped, bool managed, bit::allocations alloc, 
836                        boost::filesystem::wpath moveToDirectory) 
837        {
838                try 
839                {       
840//              torrent_internal_ptr TIp;
841
842                std::pair<std::string, std::string> names = extract_names(file);
843                wstring xml_name = from_utf8(names.first) + L".xml";
844
845/*              if (false && fs::exists(file.parent_path()/xml_name))
846                {
847                        torrent_standalone tsa;
848                       
849                        if (tsa.load_standalone(file.parent_path()/xml_name))
850                        {
851                                TIp = tsa.torrent;
852                               
853                                TIp->set_save_directory(saveDirectory, true);                   
854                                if (useMoveTo)
855                                        TIp->set_move_to_directory(moveToDirectory);
856
857                                TIp->prepare(file);
858                        }
859                }
860*/
861                torrent_internal_ptr TIp =
862                        the_torrents_.create_torrent(file, saveDirectory, alloc, moveToDirectory);
863
864                if(TIp)
865                {
866                        TIp->set_managed(managed);
867                        TIp->set_transfer_speed(bittorrent().default_torrent_download(), bittorrent().default_torrent_upload());
868                        TIp->set_connection_limit(bittorrent().default_torrent_max_connections(), bittorrent().default_torrent_max_uploads());
869                        TIp->set_resolve_countries(resolve_countries_);
870
871
872                        if (!startStopped) 
873                                TIp->add_to_session();
874                        else
875                                TIp->set_state_stopped();
876                }
877               
878                }
879                catch (const std::exception& e)
880                {
881                        event_log.post(shared_ptr<EventDetail>(
882                                new EventTorrentException(event_logger::critical, event_logger::torrentException, 
883                                        std::string(e.what()), to_utf8(file.string()), std::string("addTorrent"))));
884                }
885        }
886
887        void remove_to_bin(boost::shared_ptr<file_details_vec> files, wpath path)
888        {
889                foreach(file_details file, *files)
890                {
891                        std::wstring file_location = (wform(L"File %1%\\%2%\\%3%") 
892                                % path.file_string() % file.branch % file.filename).str();
893
894                        HAL_DEV_MSG(wform(L"File %1%\\%2%\\%3%") % path.file_string() % file.branch % file.filename);
895                }
896        }
897
898        void removal_thread(torrent_internal_ptr pIT, bool wipeFiles)
899        {
900                try {
901
902                if (!wipeFiles)
903                {
904                        if (pIT->in_session())
905                                session_.remove_torrent(pIT->handle());
906                }
907                else
908                {
909                        if (pIT->in_session())
910                        {
911                                session_.remove_torrent(pIT->handle(), libt::session::delete_files);
912                        }
913                        else
914                        {
915                                //libt::torrent_info m_info = pIT->infoMemory();
916                               
917/*                              // delete the files from disk
918                                std::string error;
919                                std::set<std::string> directories;
920                               
921                                for (libt::torrent_info::file_iterator i = m_info.begin_files(true)
922                                        , end(m_info.end_files(true)); i != end; ++i)
923                                {
924                                        std::string p = (hal::path_to_utf8(pIT->save_directory()) / i->path).string();
925                                        fs::path bp = i->path.parent_path();
926                                       
927                                        std::pair<std::set<std::string>::iterator, bool> ret;
928                                        ret.second = true;
929                                        while (ret.second && !bp.empty())
930                                        {
931                                                std::pair<std::set<std::string>::iterator, bool> ret =
932                                                        directories.insert((hal::path_to_utf8(pIT->save_directory()) / bp).string());
933                                                bp = bp.parent_path();
934                                        }
935                                        if (!fs::remove(hal::from_utf8(p).c_str()) && errno != ENOENT)
936                                                error = std::strerror(errno);
937                                }
938
939                                // remove the directories. Reverse order to delete subdirectories first
940
941                                for (std::set<std::string>::reverse_iterator i = directories.rbegin()
942                                        , end(directories.rend()); i != end; ++i)
943                                {
944                                        if (!fs::remove(hal::from_utf8(*i).c_str()) && errno != ENOENT)
945                                                error = std::strerror(errno);
946                                }
947                                */
948                        }
949                }
950
951                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "removalThread")
952        }
953
954        void remove_torrent(const wstring& name)
955        {
956                try {
957                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Removing Torrent.")));
958
959                boost::shared_ptr<file_details_vec> files = boost::shared_ptr<file_details_vec>(new file_details_vec());               
960                torrent_internal_ptr pTI = the_torrents_.get(name);
961
962        //      pTI->get_file_details(*files);         
963        //      thread_t t(bind(&bit_impl::remove_to_bin, this, files, pTI->get_save_directory()));
964
965                libt::torrent_handle handle = pTI->handle();
966                the_torrents_.remove_torrent(name);
967               
968                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Removed, started thread.")));
969               
970                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(name, "remove_torrent")
971        }
972
973        void remove_torrent_wipe_files(const std::wstring& name, remove_files fn)
974        {
975                try {
976                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Removing Torrent and files.")));
977
978                boost::shared_ptr<file_details_vec> files = boost::shared_ptr<file_details_vec>(new file_details_vec());               
979                torrent_internal_ptr pTI = the_torrents_.get(name);
980
981                pTI->get_file_details(*files);
982                thread_t t(bind(fn, pTI->get_save_directory(), files));
983
984                pTI->clear_resume_data();
985                pTI->delete_torrent_file();
986
987                the_torrents_.remove_torrent(name);
988               
989                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Removed, started thread.")));
990               
991                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(name, "remove_torrent_wipe_files")
992        }
993
994        void resume_all()
995        {
996                try {
997                       
998                event_log.post(shared_ptr<EventDetail>(new EventMsg(L"Resuming torrent.")));
999               
1000                for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); i != e;)
1001                {
1002                        wpath file = wpath(hal::app().get_working_directory())/L"torrents"/(*i).torrent->filename();
1003                       
1004                        if (exists(file))
1005                        {               
1006                                try 
1007                                {
1008                                       
1009                                (*i).torrent->prepare(file);   
1010
1011                                switch ((*i).torrent->get_state())
1012                                {
1013                                        case torrent_details::torrent_stopped:
1014                                        case torrent_details::torrent_in_error:
1015                                                break;
1016                                        case torrent_details::torrent_paused:
1017                                                (*i).torrent->add_to_session(true);
1018                                                break;
1019                                        case torrent_details::torrent_active:
1020                                                (*i).torrent->add_to_session(false);
1021                                                (*i).torrent->resume();
1022                                                break;
1023                                        default:
1024                                                assert(false);
1025                                };
1026                               
1027                                ++i;
1028                               
1029                                }
1030                                catch(const libt::duplicate_torrent&)
1031                                {
1032                                        hal::event_log.post(shared_ptr<hal::EventDetail>(
1033                                                new hal::EventDebug(hal::event_logger::debug, L"Encountered duplicate torrent")));
1034                                       
1035                                        ++i; // Harmless, don't worry about it.
1036                                }
1037                                catch(const std::exception& e) 
1038                                {
1039                                        hal::event_log.post(shared_ptr<hal::EventDetail>(
1040                                                new hal::EventStdException(hal::event_logger::warning, e, L"resume_all")));
1041                                       
1042                                        the_torrents_.erase(i++);
1043                                }                       
1044                        }
1045                        else
1046                        {
1047                                the_torrents_.erase(i++);
1048                        }
1049                }
1050               
1051                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "resume_all")
1052        }
1053
1054        bool close_counter(int* count)
1055        {
1056                --(*count);
1057                return true;
1058        }
1059       
1060        void close_all(boost::optional<report_num_active> fn)
1061        {
1062                try 
1063                {       
1064
1065                event_log.post(shared_ptr<EventDetail>(new EventInfo(L"Saving torrent data...")));
1066
1067                save_torrent_data();
1068
1069                event_log.post(shared_ptr<EventDetail>(new EventInfo(L"Stopping all torrents...")));
1070
1071                session_.pause();               
1072
1073                // Ok this polling loop here is a bit curde, but a blocking wait is actually appropiate.               
1074                { 
1075                int num_active = 1;
1076
1077                while (num_active > 0)
1078                {
1079                        num_active = 0;
1080
1081                        for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); 
1082                                        i != e; ++i)
1083                        {
1084                                if ((*i).torrent && 
1085                                                (((*i).torrent->state() != torrent_details::torrent_stopped
1086                                                        && (*i).torrent->state() != torrent_details::torrent_paused
1087                                                        && (*i).torrent->state() != torrent_details::torrent_in_error)
1088                                                || (*i).torrent->awaiting_resume_data()))
1089                                {
1090#                                       ifdef HAL_TORRENT_DEV_MSGES
1091                                                (*i).torrent->output_torrent_debug_details();
1092#                                       endif
1093                                        num_active += 1;
1094                                }
1095                        }
1096
1097                        event_log.post(shared_ptr<EventDetail>(new EventInfo(hal::wform(L"%1% still active") % (num_active))));
1098
1099                        if (fn) (*fn)(num_active);
1100                        boost::this_thread::sleep(pt::milliseconds(500));
1101                } 
1102               
1103                }
1104               
1105                event_log.post(shared_ptr<EventDetail>(new EventInfo(L"All torrents stopped.")));               
1106               
1107                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "close_all()")
1108        }
1109       
1110        void save_torrent_data()
1111        {       
1112                mutex_t::scoped_lock l(mutex_);
1113                try
1114                {
1115               
1116                the_torrents_.save_to_ini();
1117                bittorrent_ini_.save_data();
1118                       
1119                if (dht_on_) 
1120                {       
1121                        halencode(hal::app().get_working_directory()/L"DHTState.bin", session_.dht_state());
1122                }
1123               
1124                }               
1125                catch(std::exception& e)
1126                {
1127                        event_log.post(shared_ptr<EventDetail>(\
1128                                new EventStdException(event_logger::critical, e, L"save_torrent_data()")));
1129                }
1130        }
1131       
1132        int default_torrent_max_connections() { return default_torrent_max_connections_; }
1133        int default_torrent_max_uploads() { return default_torrent_max_uploads_; }
1134        float default_torrent_download() { return default_torrent_download_; }
1135        float default_torrent_upload() { return default_torrent_upload_; }
1136       
1137private:
1138        bool create_torrent(const create_torrent_params& params, fs::wpath out_file, progress_callback fn);
1139       
1140        libt::session session_; 
1141        mutable mutex_t mutex_;
1142
1143        boost::optional<thread_t> alert_checker_;
1144        bool keepChecking_;
1145       
1146        ini_file bittorrent_ini_;
1147        torrent_manager the_torrents_; 
1148       
1149        int default_torrent_max_connections_;
1150        int default_torrent_max_uploads_;
1151        float default_torrent_download_;
1152        float default_torrent_upload_;
1153       
1154        bool resolve_countries_;
1155        bool ip_filter_on_;
1156        bool ip_filter_loaded_;
1157        bool ip_filter_changed_;
1158        libt::ip_filter ip_filter_;
1159        size_t ip_filter_count_;
1160       
1161        void ip_filter_count();
1162        void ip_filter_load(progress_callback fn);
1163        void ip_filter_import(std::vector<libt::ip_range<boost::asio::ip::address_v4> >& v4,
1164                std::vector<libt::ip_range<boost::asio::ip::address_v6> >& v6);
1165       
1166        bool dht_on_;
1167        libt::dht_settings dht_settings_;
1168        libt::entry dht_state_; 
1169
1170        libt::upnp* upnp_;
1171        libt::natpmp* natpmp_;
1172};
1173
1174}
Note: See TracBrowser for help on using the repository browser.