source: trunk/src/halSession.hpp @ 754

Revision 754, 27.0 KB checked in by Eoin, 10 years ago (diff)
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#include "halCatchDefines.hpp"
46
47namespace boost {
48namespace serialization {
49
50template<class Archive, class address_type>
51void save(Archive& ar, const address_type& ip, const unsigned int version)
52{       
53        unsigned long addr = ip.to_ulong();     
54        ar & BOOST_SERIALIZATION_NVP(addr);
55}
56
57template<class Archive, class address_type>
58void load(Archive& ar, address_type& ip, const unsigned int version)
59{       
60        unsigned long addr;
61        ar & BOOST_SERIALIZATION_NVP(addr);     
62        ip = address_type(addr);
63}
64
65template<class Archive, class String, class Traits>
66void save(Archive& ar, const boost::filesystem::basic_path<String, Traits>& p, const unsigned int version)
67{       
68        String str = p.string();
69        ar & BOOST_SERIALIZATION_NVP(str);
70}
71
72template<class Archive, class String, class Traits>
73void load(Archive& ar, boost::filesystem::basic_path<String, Traits>& p, const unsigned int version)
74{       
75        String str;
76        ar & BOOST_SERIALIZATION_NVP(str);
77
78        p = str;
79}
80
81template<class Archive, class String, class Traits>
82inline void serialize(
83        Archive & ar,
84        boost::filesystem::basic_path<String, Traits>& p,
85        const unsigned int file_version)
86{
87        split_free(ar, p, file_version);           
88}
89
90template<class Archive, class address_type>
91void serialize(Archive& ar, libtorrent::ip_range<address_type>& addr, const unsigned int version)
92{       
93        ar & BOOST_SERIALIZATION_NVP(addr.first);
94        ar & BOOST_SERIALIZATION_NVP(addr.last);
95        addr.flags = libtorrent::ip_filter::blocked;
96}
97
98template<class Archive>
99void serialize(Archive& ar, hal::tracker_detail& tracker, const unsigned int version)
100{       
101        ar & BOOST_SERIALIZATION_NVP(tracker.url);
102        ar & BOOST_SERIALIZATION_NVP(tracker.tier);
103}
104
105} // namespace serialization
106} // namespace boost
107
108BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v4)
109BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v6)
110
111namespace libtorrent
112{
113
114template<class Addr>
115bool operator==(const libtorrent::ip_range<Addr>& lhs, const int flags)
116{
117        return (lhs.flags == flags);
118}
119
120inline std::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 bool operator!=(const libt::dht_settings& lhs, const libt::dht_settings& rhs)
136{
137        return lhs.max_peers_reply != rhs.max_peers_reply ||
138                   lhs.search_branching != rhs.search_branching ||
139                   lhs.service_port != rhs.service_port ||
140           lhs.max_fail_count != rhs.max_fail_count;
141}
142
143template<typename Addr>
144void write_range(fs::ofstream& ofs, const libt::ip_range<Addr>& range)
145{ 
146        const typename Addr::bytes_type first = range.first.to_bytes();
147        const typename Addr::bytes_type last = range.last.to_bytes();
148        ofs.write((char*)first.elems, first.size());
149        ofs.write((char*)last.elems, last.size());
150}
151
152template<typename Addr>
153void write_vec_range(fs::ofstream& ofs, const std::vector<libt::ip_range<Addr> >& vec)
154{ 
155        ofs << vec.size();
156       
157        for (typename std::vector<libt::ip_range<Addr> >::const_iterator i=vec.begin(); 
158                i != vec.end(); ++i)
159        {
160                write_range(ofs, *i);
161        }
162}
163
164template<typename Addr>
165void read_range_to_filter(fs::ifstream& ifs, libt::ip_filter& ip_filter)
166{ 
167        typename Addr::bytes_type first;
168        typename Addr::bytes_type last;
169        ifs.read((char*)first.elems, first.size());
170        ifs.read((char*)last.elems, last.size());       
171       
172        ip_filter.add_rule(Addr(first), Addr(last),
173                libt::ip_filter::blocked);
174}
175
176static event_logger::eventLevel lbtAlertToHalEvent(libt::alert::severity_t severity)
177{
178        switch (severity)
179        {
180        case libt::alert::debug:
181                return event_logger::debug;
182       
183        case libt::alert::info:
184                return event_logger::info;
185       
186        case libt::alert::warning:
187                return event_logger::warning;
188       
189        case libt::alert::critical:
190        case libt::alert::fatal:
191                return event_logger::critical;
192       
193        default:
194                return event_logger::none;
195        }
196}
197
198static event_logger::eventLevel lbt_category_to_event(int category)
199{
200        switch (category)
201        {
202        case libt::alert::debug_notification:
203                return event_logger::debug;
204       
205        case libt::alert::peer_notification:
206        case libt::alert::port_mapping_notification:
207        case libt::alert::storage_notification:
208        case libt::alert::tracker_notification:
209        case libt::alert::status_notification:
210        case libt::alert::progress_notification:
211        case libt::alert::ip_block_notification:
212                return event_logger::info;
213       
214        case libt::alert::performance_warning:
215                return event_logger::warning;
216       
217        case libt::alert::error_notification:
218                return event_logger::critical;
219       
220        default:
221                return event_logger::none;
222        }
223}
224
225struct uninitialized;
226
227class bit_impl :
228        public sc::state_machine<bit_impl, uninitialized>
229{
230        friend class bit;
231
232private:
233        bit_impl();
234
235public: 
236        ~bit_impl();
237
238        bool listen_on(std::pair<int, int> const& range)
239        {
240                try
241                {
242               
243                if (!session_->is_listening())
244                {
245                        return session_->listen_on(range);
246                }
247                else
248                {
249                        int port = session_->listen_port();
250                       
251                        if (port < range.first || port > range.second)
252                                return session_->listen_on(range);     
253                        else
254                        {
255                                signals.successful_listen();
256                               
257                                return true;
258                        }
259                }
260               
261                }
262                catch (const std::exception& e)
263                {
264                        event_log().post(shared_ptr<EventDetail>(
265                                new EventStdException(event_logger::fatal, e, L"From bit::listen_on.")));
266
267                        return false;
268                }
269                catch (...)
270                {
271                        return false;
272                }
273        }
274
275        int is_listening_on() 
276        {
277                if (!session_->is_listening())
278                        return -1;     
279                else
280                        return session_->listen_port();
281        }
282
283        void stop_listening()
284        {
285                ensure_dht_off();
286                session_->listen_on(std::make_pair(0, 0));
287        }
288
289        bool ensure_dht_on(const dht_settings& dht)
290        {               
291                libt::dht_settings settings;
292                settings.max_peers_reply = dht.max_peers_reply;
293                settings.search_branching = dht.search_branching;
294                settings.service_port = dht.service_port;
295                settings.max_fail_count = dht.max_fail_count;
296               
297                HAL_DEV_MSG(hal::wform(L"Seleted DHT port = %1%") % settings.service_port);
298               
299                if (dht_settings_ != settings)
300                {
301                        dht_settings_ = settings;
302                        session_->set_dht_settings(dht_settings_);
303                }
304
305                if (!dht_on_)
306                {               
307                        try
308                        {
309                        session_->start_dht(dht_state_);
310                        dht_on_ = true;
311                        }
312                        catch(...)
313                        {}
314                }
315                        return dht_on_;
316        }
317
318        void ensure_dht_off()
319        {
320                if (dht_on_)
321                {
322                        session_->stop_dht();           
323                        dht_on_ = false;
324                }
325        }
326
327        void set_mapping(bool upnp, bool nat_pmp)
328        {
329                if (upnp)
330                {
331                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Starting UPnP mapping.")));
332
333                        upnp_ = session_->start_upnp();
334                }
335                else
336                {
337                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Stopping UPnP mapping.")));
338
339                        session_->stop_upnp();
340                        upnp_ = NULL;
341                }
342
343                if (nat_pmp)
344                {
345                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Starting NAT-PMP mapping.")));
346
347                        natpmp_ = session_->start_natpmp();
348                }
349                else
350                {
351                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Stopping NAT-PMP mapping.")));
352
353                        session_->stop_natpmp();
354                        natpmp_ = NULL;
355                }
356        }
357
358        std::wstring upnp_router_model()
359        {
360                if (upnp_)
361                        return to_wstr_shim(upnp_->router_model());
362                else
363                        return L"UPnP not started";
364        }
365
366        void set_timeouts(int peers, int tracker)
367        {
368                libt::session_settings settings = session_->settings();
369                settings.peer_connect_timeout = peers;
370                settings.tracker_completion_timeout = tracker;
371
372                session_->set_settings(settings);
373
374                event_log().post(shared_ptr<EventDetail>(new EventMsg(
375                        hal::wform(L"Set Timeouts, peer %1%, tracker %2%.") % peers % tracker)));
376        }
377
378        cache_settings get_cache_settings()
379        {
380                libt::session_settings settings = session_->settings();
381                cache_settings cache;
382
383                cache.cache_size = settings.cache_size;
384                cache.cache_expiry = settings.cache_expiry;
385
386                return cache;
387        }
388
389        void set_cache_settings(const cache_settings& cache)
390        {
391                libt::session_settings settings = session_->settings();
392
393                settings.cache_size = cache.cache_size;
394                settings.cache_expiry = cache.cache_expiry;
395
396                session_->set_settings(settings);
397
398                event_log().post(shared_ptr<EventDetail>(new EventMsg(
399                        hal::wform(L"Set cache parameters, %1% size and %2% expiry.") 
400                                % settings.cache_size % settings.cache_expiry)));
401        }
402
403        queue_settings get_queue_settings()
404        {               
405                libt::session_settings settings = session_->settings();
406                queue_settings queue;
407
408                queue.auto_manage_interval = settings.auto_manage_interval;
409                queue.active_downloads = settings.active_downloads;
410                queue.active_seeds = settings.active_seeds;
411                queue.seeds_hard_limit = settings.active_limit;
412                queue.seed_ratio_limit = settings.share_ratio_limit;
413                queue.seed_ratio_time_limit = settings.seed_time_ratio_limit;
414                queue.seed_time_limit = settings.seed_time_limit;
415                queue.dont_count_slow_torrents = settings.dont_count_slow_torrents;
416                queue.auto_scrape_min_interval = settings.auto_scrape_min_interval;
417                queue.auto_scrape_interval = settings.auto_scrape_interval;
418                queue.close_redundant_connections = settings.close_redundant_connections;
419
420                return queue;
421        }
422
423        void set_queue_settings(const queue_settings& queue)
424        {
425                libt::session_settings settings = session_->settings();
426
427                settings.auto_manage_interval = queue.auto_manage_interval;
428                settings.active_downloads = queue.active_downloads;
429                settings.active_seeds = queue.active_seeds;
430                settings.active_limit = queue.seeds_hard_limit;
431                settings.share_ratio_limit = queue.seed_ratio_limit;
432                settings.seed_time_ratio_limit = queue.seed_ratio_time_limit;
433                settings.seed_time_limit = queue.seed_time_limit;
434                settings.dont_count_slow_torrents = queue.dont_count_slow_torrents;
435                settings.auto_scrape_min_interval = queue.auto_scrape_min_interval;
436                settings.auto_scrape_interval = queue.auto_scrape_interval;
437                settings.close_redundant_connections = queue.close_redundant_connections;
438
439                session_->set_settings(settings);
440
441                event_log().post(shared_ptr<EventDetail>(new EventMsg(
442                        hal::wform(L"Set queue parameters, %1% downloads and %2% active seeds.") 
443                                % settings.active_downloads % settings.active_seeds)));
444        }
445
446        timeouts get_timeouts()
447        {               
448                libt::session_settings settings = session_->settings();
449                timeouts times;
450
451                times.tracker_completion_timeout = settings.tracker_completion_timeout;
452                times.tracker_receive_timeout = settings.tracker_receive_timeout;
453                times.stop_tracker_timeout = settings.stop_tracker_timeout;
454
455                times.request_queue_time = settings.request_queue_time;
456                times.piece_timeout = settings.piece_timeout;
457                times.min_reconnect_time = settings.min_reconnect_time;         
458
459                times.peer_timeout = settings.peer_timeout;
460                times.urlseed_timeout = settings.urlseed_timeout;
461                times.peer_connect_timeout = settings.peer_connect_timeout;
462                times.inactivity_timeout = settings.inactivity_timeout;
463                times.handshake_timeout = settings.handshake_timeout;
464
465                return times;
466        }
467
468        void set_timeouts(const timeouts& times)
469        {
470                libt::session_settings settings = session_->settings();
471
472                settings.tracker_completion_timeout = times.tracker_completion_timeout;
473                settings.tracker_receive_timeout = times.tracker_receive_timeout;
474                settings.stop_tracker_timeout = times.stop_tracker_timeout;
475
476                settings.request_queue_time = times.request_queue_time;
477                settings.piece_timeout = times.piece_timeout;
478                settings.min_reconnect_time = times.min_reconnect_time;         
479
480                settings.peer_timeout = times.peer_timeout;
481                settings.urlseed_timeout = times.urlseed_timeout;
482                settings.peer_connect_timeout = times.peer_connect_timeout;
483                settings.inactivity_timeout = times.inactivity_timeout;
484                settings.handshake_timeout = times.handshake_timeout;
485
486                session_->set_settings(settings);
487
488                event_log().post(shared_ptr<EventDetail>(new EventMsg(
489                        hal::wform(L"Set timeouts, peers- %1% secs, tracker- %2% secs.") 
490                                % settings.peer_timeout % settings.tracker_receive_timeout)));
491        }
492
493        void set_session_limits(int maxConn, int maxUpload)
494        {               
495                session_->set_max_uploads(maxUpload);
496                session_->set_max_connections(maxConn);
497               
498                event_log().post(shared_ptr<EventDetail>(new EventMsg(
499                        hal::wform(L"Set connections totals %1% and uploads %2%.") 
500                                % maxConn % maxUpload)));
501        }
502
503        void set_session_speed(float download, float upload)
504        {
505                int down = (download > 0) ? static_cast<int>(download*1024) : -1;
506                session_->set_download_rate_limit(down);
507                int up = (upload > 0) ? static_cast<int>(upload*1024) : -1;
508                session_->set_upload_rate_limit(up);
509               
510                event_log().post(shared_ptr<EventDetail>(new EventMsg(
511                        hal::wform(L"Set session rates at download %1% and upload %2%.") 
512                                % session_->download_rate_limit() % session_->upload_rate_limit())));
513        }
514
515        cache_details get_cache_details() const
516        {
517                libt::cache_status cs = session_->get_cache_status();
518
519                return cache_details(cs.blocks_written, cs.writes, 
520                        cs.blocks_read, cs.blocks_read_hit, cs.reads,
521                        cs.cache_size, cs.read_cache_size);
522        }
523
524        bool ensure_ip_filter_on(progress_callback fn)
525        {
526                try
527                {
528               
529                if (!ip_filter_loaded_)
530                {
531                        ip_filter_load(fn);
532                        ip_filter_loaded_ = true;
533                }
534               
535                if (!ip_filter_on_)
536                {
537                        session_->set_ip_filter(ip_filter_);
538                        ip_filter_on_ = true;
539                        ip_filter_count();
540                }
541               
542                }
543                catch(const std::exception& e)
544                {               
545                        hal::event_log().post(boost::shared_ptr<hal::EventDetail>(
546                                new hal::EventStdException(event_logger::critical, e, L"ensure_ip_filter_on"))); 
547
548                        ensure_ip_filter_off();
549                }
550
551                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters on.")));     
552
553                return false;
554        }
555
556        void ensure_ip_filter_off()
557        {
558                session_->set_ip_filter(libt::ip_filter());
559                ip_filter_on_ = false;
560               
561                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters off.")));   
562        }
563
564#       ifndef TORRENT_DISABLE_ENCRYPTION       
565        void ensure_pe_on(const pe_settings& pe_s)
566        {
567                libt::pe_settings pe;
568               
569                switch (pe_s.encrypt_level)
570                {
571                        case 0:
572                                pe.allowed_enc_level = libt::pe_settings::plaintext;
573                                break;
574                        case 1:
575                                pe.allowed_enc_level = libt::pe_settings::rc4;
576                                break;
577                        case 2:
578                                pe.allowed_enc_level = libt::pe_settings::both;
579                                break;
580                        default:
581                                pe.allowed_enc_level = libt::pe_settings::both;
582                               
583                                hal::event_log().post(shared_ptr<hal::EventDetail>(
584                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
585                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_ENCODING_LEVEL)) % pe_s.encrypt_level).str())));
586                }
587
588                switch (pe_s.conn_in_policy)
589                {
590                        case 0:
591                                pe.in_enc_policy = libt::pe_settings::forced;
592                                break;
593                        case 1:
594                                pe.in_enc_policy = libt::pe_settings::enabled;
595                                break;
596                        case 2:
597                                pe.in_enc_policy = libt::pe_settings::disabled;
598                                break;
599                        default:
600                                pe.in_enc_policy = libt::pe_settings::enabled;
601                               
602                                hal::event_log().post(shared_ptr<hal::EventDetail>(
603                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
604                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % pe_s.conn_in_policy).str())));
605                }
606
607                switch (pe_s.conn_out_policy)
608                {
609                        case 0:
610                                pe.out_enc_policy = libt::pe_settings::forced;
611                                break;
612                        case 1:
613                                pe.out_enc_policy = libt::pe_settings::enabled;
614                                break;
615                        case 2:
616                                pe.out_enc_policy = libt::pe_settings::disabled;
617                                break;
618                        default:
619                                pe.out_enc_policy = libt::pe_settings::enabled;
620                               
621                                hal::event_log().post(shared_ptr<hal::EventDetail>(
622                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
623                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % pe_s.conn_out_policy).str())));
624                }
625               
626                pe.prefer_rc4 = pe_s.prefer_rc4;
627               
628                try
629                {
630               
631                session_->set_pe_settings(pe);
632               
633                }
634                catch(const std::exception& e)
635                {
636                        hal::event_log().post(boost::shared_ptr<hal::EventDetail>(
637                                        new hal::EventStdException(event_logger::critical, e, L"ensure_pe_on"))); 
638                                       
639                        ensure_pe_off();               
640                }
641               
642                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption on.")));
643        }
644
645        void ensure_pe_off()
646        {
647                libt::pe_settings pe;
648                pe.out_enc_policy = libt::pe_settings::disabled;
649                pe.in_enc_policy = libt::pe_settings::disabled;
650               
651                pe.allowed_enc_level = libt::pe_settings::both;
652                pe.prefer_rc4 = true;
653               
654                session_->set_pe_settings(pe);
655
656                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption off.")));
657        }
658#       endif
659       
660        void set_resolve_countries(bool b)
661        {               
662                resolve_countries_ = b;
663
664                for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); 
665                        i != e; ++i)
666                {
667                        (*i).torrent->set_resolve_countries(resolve_countries_);
668                }
669
670                if (b)                 
671                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Set to resolve countries.")));
672                else                   
673                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Not resolving countries.")));
674        }
675
676        void start_smart_ban_plugin()
677        {
678                session_->add_extension(&libt::create_smart_ban_plugin);
679                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started smart ban plugin.")));
680        }
681
682        void start_ut_pex_plugin()
683        {
684                session_->add_extension(&libt::create_ut_pex_plugin);
685                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started uTorrent peer exchange plugin.")));
686        }
687
688        void start_ut_metadata_plugin()
689        {
690                session_->add_extension(&libt::create_ut_metadata_plugin);
691                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started uTorrent metadata plugin.")));
692        }
693
694        void start_metadata_plugin()
695        {
696                session_->add_extension(&libt::create_metadata_plugin);
697                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started metadata plugin.")));
698        }
699
700        void ip_v4_filter_block(boost::asio::ip::address_v4 first, boost::asio::ip::address_v4 last)
701        {
702                ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
703                ip_filter_count();
704                ip_filter_changed_ = true;
705        }
706
707        void ip_v6_filter_block(boost::asio::ip::address_v6 first, boost::asio::ip::address_v6 last)
708        {
709                ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
710                ip_filter_count();
711                ip_filter_changed_ = true;
712        }
713
714        size_t ip_filter_size()
715        {
716                return ip_filter_count_;
717        }
718
719        void clear_ip_filter()
720        {
721                ip_filter_ = libt::ip_filter();
722                session_->set_ip_filter(libt::ip_filter());     
723                ip_filter_changed_ = true;
724                ip_filter_count();
725        }
726
727        bool ip_filter_import_dat(boost::filesystem::path file, progress_callback fn, bool octalFix);
728
729        struct 
730        {
731                signaler<> successful_listen;
732                signaler<> torrent_finished;
733
734                boost::signal<bool()> torrent_paused;
735        } 
736        signals;
737
738        void start_alert_handler();
739        void stop_alert_handler();
740        void alert_handler();
741
742        void add_torrent(wpath file, wpath saveDirectory, bool startStopped, bool managed, bit::allocations alloc, 
743                        boost::filesystem::wpath moveToDirectory) 
744        {
745                try 
746                {       
747//              torrent_internal_ptr TIp;
748
749                std::pair<std::string, std::string> names = extract_names(file);
750                wstring xml_name = from_utf8(names.first) + L".xml";
751
752/*              if (false && fs::exists(file.parent_path()/xml_name))
753                {
754                        torrent_standalone tsa;
755                       
756                        if (tsa.load_standalone(file.parent_path()/xml_name))
757                        {
758                                TIp = tsa.torrent;
759                               
760                                TIp->set_save_directory(saveDirectory, true);                   
761                                if (useMoveTo)
762                                        TIp->set_move_to_directory(moveToDirectory);
763
764                                TIp->prepare(file);
765                        }
766                }
767*/
768                torrent_internal_ptr TIp =
769                        the_torrents_.create_torrent(file, saveDirectory, alloc, moveToDirectory);
770
771                if(TIp)
772                {
773                        TIp->set_managed(managed);
774                        TIp->set_transfer_speed(bittorrent::Instance().default_torrent_download(), 
775                                bittorrent::Instance().default_torrent_upload());
776                        TIp->set_connection_limit(bittorrent::Instance().default_torrent_max_connections(), 
777                                bittorrent::Instance().default_torrent_max_uploads());
778                        TIp->set_resolve_countries(resolve_countries_);
779
780                        TIp->start();
781                }
782               
783                }
784                catch (const std::exception& e)
785                {
786                        event_log().post(shared_ptr<EventDetail>(
787                                new EventTorrentException(event_logger::critical, event_logger::torrentException, 
788                                        std::string(e.what()), to_utf8(file.string()), std::string("addTorrent"))));
789                }
790        }
791
792        void remove_torrent(const wstring& name)
793        {
794                try {
795                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removing Torrent.")));
796
797                boost::shared_ptr<file_details_vec> files = boost::shared_ptr<file_details_vec>(new file_details_vec());               
798                torrent_internal_ptr pTI = the_torrents_.get(name);
799
800                the_torrents_.remove_torrent(name);
801               
802                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removed")));
803               
804                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(name, "remove_torrent")
805        }
806
807        void remove_torrent_wipe_files(const std::wstring& name, remove_files fn)
808        {
809                try {
810                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removing Torrent and files.")));
811
812                boost::shared_ptr<file_details_vec> files = boost::shared_ptr<file_details_vec>(new file_details_vec());               
813                torrent_internal_ptr pTI = the_torrents_.get(name);
814
815                pTI->get_file_details(*files);
816                thread_t t(bind(fn, pTI->get_save_directory(), files));
817
818                pTI->clear_resume_data();
819                pTI->delete_torrent_file();
820
821                the_torrents_.remove_torrent(name);
822               
823                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removed, started thread.")));
824               
825                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(name, "remove_torrent_wipe_files")
826        }
827
828        void resume_all()
829        {
830                try {
831                       
832                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Resuming all torrents.")));
833               
834                for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); i != e;)
835                {
836                        wpath file = wpath(hal::app().get_working_directory())/L"torrents"/(*i).torrent->filename();
837                       
838                        if (exists(file))
839                        {               
840                                try 
841                                {
842                                       
843                                (*i).torrent->prepare(file);   
844                                (*i).torrent->start(); 
845                               
846                                ++i;
847                               
848                                }
849                                catch(const libt::duplicate_torrent&)
850                                {
851                                        hal::event_log().post(shared_ptr<hal::EventDetail>(
852                                                new hal::EventDebug(hal::event_logger::debug, L"Encountered duplicate torrent")));
853                                       
854                                        ++i; // Harmless, don't worry about it.
855                                }
856                                catch(const std::exception& e) 
857                                {
858                                        hal::event_log().post(shared_ptr<hal::EventDetail>(
859                                                new hal::EventStdException(hal::event_logger::warning, e, L"resume_all")));
860                                       
861                                        the_torrents_.erase(i++);
862                                }                       
863                        }
864                        else
865                        {
866                                the_torrents_.erase(i++);
867                        }
868                }
869               
870                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "resume_all")
871        }
872
873        bool close_counter(int* count)
874        {
875                --(*count);
876                return true;
877        }
878       
879        void close_all(boost::optional<report_num_active> fn)
880        {
881                try 
882                {       
883
884                event_log().post(shared_ptr<EventDetail>(new EventInfo(L"Saving torrent data ...")));
885
886                save_torrent_data();
887
888                event_log().post(shared_ptr<EventDetail>(new EventInfo(L"       ... stopping all torrents")));
889
890                session_->pause();             
891
892                // Ok this polling loop here is a bit curde, but a blocking wait is actually appropiate.               
893                { 
894                int num_active = 1;
895
896                while (num_active > 0)
897                {
898                        num_active = 0;
899
900                        for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); 
901                                        i != e; ++i)
902                        {
903                                if (    (*i).torrent
904                                        && 
905                                        (*i).torrent->state() != torrent_details::torrent_in_error
906                                        && 
907                                        (       (       (*i).torrent->state() != torrent_details::torrent_stopped
908                                                        && 
909                                                        (*i).torrent->state() != torrent_details::torrent_paused
910                                                )
911                                                || 
912                                                (*i).torrent->awaiting_resume_data()
913                                        )
914                                )
915                                {
916#                                       ifdef HAL_TORRENT_DEV_MSGES
917                                                (*i).torrent->output_torrent_debug_details();
918#                                       endif
919                                        num_active += 1;
920                                }
921                        }
922
923                        event_log().post(shared_ptr<EventDetail>(new EventInfo(hal::wform(L"    ... %1% still active") % (num_active))));
924
925                        if (fn) (*fn)(num_active);
926                        boost::this_thread::sleep(pt::milliseconds(500));
927                } 
928               
929                }
930               
931                event_log().post(shared_ptr<EventDetail>(new EventInfo(L"       ... all torrents stopped.")));         
932               
933                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "close_all()")
934        }
935       
936        void save_torrent_data()
937        {       
938                mutex_t::scoped_lock l(mutex_);
939                try
940                {
941               
942                the_torrents_.save_to_ini();
943                bittorrent_ini_.save_data();
944                       
945                if (dht_on_) 
946                {       
947                        halencode(hal::app().get_working_directory()/L"DHTState.bin", session_->dht_state());
948                }
949               
950                }               
951                catch(std::exception& e)
952                {
953                        event_log().post(shared_ptr<EventDetail>(\
954                                new EventStdException(event_logger::critical, e, L"save_torrent_data()")));
955                }
956        }
957       
958        int default_torrent_max_connections() { return default_torrent_max_connections_; }
959        int default_torrent_max_uploads() { return default_torrent_max_uploads_; }
960        float default_torrent_download() { return default_torrent_download_; }
961        float default_torrent_upload() { return default_torrent_upload_; }
962       
963private:
964        bool create_torrent(const create_torrent_params& params, fs::wpath out_file, progress_callback fn);
965       
966        boost::optional<libt::session> session_;       
967        mutable mutex_t mutex_;
968
969        boost::optional<thread_t> alert_checker_;
970        bool keepChecking_;
971       
972        ini_file bittorrent_ini_;
973        torrent_manager the_torrents_; 
974       
975        int default_torrent_max_connections_;
976        int default_torrent_max_uploads_;
977        float default_torrent_download_;
978        float default_torrent_upload_;
979       
980        bool resolve_countries_;
981        bool ip_filter_on_;
982        bool ip_filter_loaded_;
983        bool ip_filter_changed_;
984        libt::ip_filter ip_filter_;
985        size_t ip_filter_count_;
986       
987        void ip_filter_count();
988        void ip_filter_load(progress_callback fn);
989        void ip_filter_import(std::vector<libt::ip_range<boost::asio::ip::address_v4> >& v4,
990                std::vector<libt::ip_range<boost::asio::ip::address_v6> >& v6);
991       
992        bool dht_on_;
993        libt::dht_settings dht_settings_;
994        libt::entry dht_state_; 
995
996        libt::upnp* upnp_;
997        libt::natpmp* natpmp_;
998};
999
1000}
1001
1002#include "halSessionStates.hpp"
Note: See TracBrowser for help on using the repository browser.