source: trunk/src/halSession.hpp @ 780

Revision 780, 28.2 KB checked in by Eoin, 10 years ago (diff)

Archive supports Boost .40. Some 64bit casts added.

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                upnp = true;
330
331                if (upnp)
332                {
333                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Starting UPnP mapping.")));
334
335                        upnp_ = session_->start_upnp();
336                }
337                else
338                {
339                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Stopping UPnP mapping.")));
340
341                        session_->stop_upnp();
342                        upnp_ = NULL;
343                }
344
345                if (nat_pmp)
346                {
347                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Starting NAT-PMP mapping.")));
348
349                        natpmp_ = session_->start_natpmp();
350                }
351                else
352                {
353                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Stopping NAT-PMP mapping.")));
354
355                        session_->stop_natpmp();
356                        natpmp_ = NULL;
357                }
358        }
359
360        std::wstring upnp_router_model()
361        {
362                if (upnp_)
363                        return to_wstr_shim(upnp_->router_model());
364                else
365                        return L"UPnP not started";
366        }
367
368        void set_timeouts(int peers, int tracker)
369        {
370                libt::session_settings settings = session_->settings();
371                settings.peer_connect_timeout = peers;
372                settings.tracker_completion_timeout = tracker;
373
374                session_->set_settings(settings);
375
376                event_log().post(shared_ptr<EventDetail>(new EventMsg(
377                        hal::wform(L"Set Timeouts, peer %1%, tracker %2%.") % peers % tracker)));
378        }
379
380        cache_settings get_cache_settings()
381        {
382                libt::session_settings settings = session_->settings();
383                cache_settings cache;
384
385                cache.cache_size = settings.cache_size;
386                cache.cache_expiry = settings.cache_expiry;
387
388                return cache;
389        }
390
391        void set_cache_settings(const cache_settings& cache)
392        {
393                libt::session_settings settings = session_->settings();
394
395                settings.cache_size = cache.cache_size;
396                settings.cache_expiry = cache.cache_expiry;
397
398                session_->set_settings(settings);
399
400                event_log().post(shared_ptr<EventDetail>(new EventMsg(
401                        hal::wform(L"Set cache parameters, %1% size and %2% expiry.") 
402                                % settings.cache_size % settings.cache_expiry)));
403        }
404
405        queue_settings get_queue_settings()
406        {               
407                libt::session_settings settings = session_->settings();
408                queue_settings queue;
409
410                queue.auto_manage_interval = settings.auto_manage_interval;
411                queue.active_downloads = settings.active_downloads;
412                queue.active_seeds = settings.active_seeds;
413                queue.seeds_hard_limit = settings.active_limit;
414                queue.seed_ratio_limit = settings.share_ratio_limit;
415                queue.seed_ratio_time_limit = settings.seed_time_ratio_limit;
416                queue.seed_time_limit = settings.seed_time_limit;
417                queue.dont_count_slow_torrents = settings.dont_count_slow_torrents;
418                queue.auto_scrape_min_interval = settings.auto_scrape_min_interval;
419                queue.auto_scrape_interval = settings.auto_scrape_interval;
420                queue.close_redundant_connections = settings.close_redundant_connections;
421
422                return queue;
423        }
424
425        void set_queue_settings(const queue_settings& queue)
426        {
427                libt::session_settings settings = session_->settings();
428
429                settings.auto_manage_interval = queue.auto_manage_interval;
430                settings.active_downloads = queue.active_downloads;
431                settings.active_seeds = queue.active_seeds;
432                settings.active_limit = queue.seeds_hard_limit;
433                settings.share_ratio_limit = queue.seed_ratio_limit;
434                settings.seed_time_ratio_limit = queue.seed_ratio_time_limit;
435                settings.seed_time_limit = queue.seed_time_limit;
436                settings.dont_count_slow_torrents = queue.dont_count_slow_torrents;
437                settings.auto_scrape_min_interval = queue.auto_scrape_min_interval;
438                settings.auto_scrape_interval = queue.auto_scrape_interval;
439                settings.close_redundant_connections = queue.close_redundant_connections;
440
441                session_->set_settings(settings);
442
443                event_log().post(shared_ptr<EventDetail>(new EventMsg(
444                        hal::wform(L"Set queue parameters, %1% downloads and %2% active seeds.") 
445                                % settings.active_downloads % settings.active_seeds)));
446        }
447
448        timeouts get_timeouts()
449        {               
450                libt::session_settings settings = session_->settings();
451                timeouts times;
452
453                times.tracker_completion_timeout = settings.tracker_completion_timeout;
454                times.tracker_receive_timeout = settings.tracker_receive_timeout;
455                times.stop_tracker_timeout = settings.stop_tracker_timeout;
456
457                times.request_queue_time = settings.request_queue_time;
458                times.piece_timeout = settings.piece_timeout;
459                times.min_reconnect_time = settings.min_reconnect_time;         
460
461                times.peer_timeout = settings.peer_timeout;
462                times.urlseed_timeout = settings.urlseed_timeout;
463                times.peer_connect_timeout = settings.peer_connect_timeout;
464                times.inactivity_timeout = settings.inactivity_timeout;
465                times.handshake_timeout = settings.handshake_timeout;
466
467                return times;
468        }
469
470        void set_timeouts(const timeouts& times)
471        {
472                libt::session_settings settings = session_->settings();
473
474                settings.tracker_completion_timeout = times.tracker_completion_timeout;
475                settings.tracker_receive_timeout = times.tracker_receive_timeout;
476                settings.stop_tracker_timeout = times.stop_tracker_timeout;
477
478                settings.request_queue_time = times.request_queue_time;
479                settings.piece_timeout = times.piece_timeout;
480                settings.min_reconnect_time = times.min_reconnect_time;         
481
482                settings.peer_timeout = times.peer_timeout;
483                settings.urlseed_timeout = times.urlseed_timeout;
484                settings.peer_connect_timeout = times.peer_connect_timeout;
485                settings.inactivity_timeout = times.inactivity_timeout;
486                settings.handshake_timeout = times.handshake_timeout;
487
488                session_->set_settings(settings);
489
490                event_log().post(shared_ptr<EventDetail>(new EventMsg(
491                        hal::wform(L"Set timeouts, peers- %1% secs, tracker- %2% secs.") 
492                                % settings.peer_timeout % settings.tracker_receive_timeout)));
493        }
494
495        void set_session_limits(int maxConn, int maxUpload)
496        {               
497                session_->set_max_uploads(maxUpload);
498                session_->set_max_connections(maxConn);
499               
500                event_log().post(shared_ptr<EventDetail>(new EventMsg(
501                        hal::wform(L"Set connections totals %1% and uploads %2%.") 
502                                % maxConn % maxUpload)));
503        }
504
505        void set_session_speed(float download, float upload)
506        {
507                int down = (download > 0) ? static_cast<int>(download*1024) : -1;
508                session_->set_download_rate_limit(down);
509                int up = (upload > 0) ? static_cast<int>(upload*1024) : -1;
510                session_->set_upload_rate_limit(up);
511               
512                event_log().post(shared_ptr<EventDetail>(new EventMsg(
513                        hal::wform(L"Set session rates at download %1% and upload %2%.") 
514                                % session_->download_rate_limit() % session_->upload_rate_limit())));
515        }
516
517        cache_details get_cache_details() const
518        {
519                libt::cache_status cs = session_->get_cache_status();
520
521                return cache_details(cs.blocks_written, cs.writes, 
522                        cs.blocks_read, cs.blocks_read_hit, cs.reads,
523                        cs.cache_size, cs.read_cache_size);
524        }
525
526        bool ensure_ip_filter_on(progress_callback fn)
527        {
528                try
529                {
530               
531                if (!ip_filter_loaded_)
532                {
533                        ip_filter_load(fn);
534                        ip_filter_loaded_ = true;
535                }
536               
537                if (!ip_filter_on_)
538                {
539                        session_->set_ip_filter(ip_filter_);
540                        ip_filter_on_ = true;
541                        ip_filter_count();
542                }
543               
544                }
545                catch(const std::exception& e)
546                {               
547                        hal::event_log().post(boost::shared_ptr<hal::EventDetail>(
548                                new hal::EventStdException(event_logger::critical, e, L"ensure_ip_filter_on"))); 
549
550                        ensure_ip_filter_off();
551                }
552
553                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters on.")));     
554
555                return false;
556        }
557
558        void ensure_ip_filter_off()
559        {
560                session_->set_ip_filter(libt::ip_filter());
561                ip_filter_on_ = false;
562               
563                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters off.")));   
564        }
565
566#       ifndef TORRENT_DISABLE_ENCRYPTION       
567        void ensure_pe_on(const pe_settings& pe_s)
568        {
569                libt::pe_settings pe;
570               
571                switch (pe_s.encrypt_level)
572                {
573                        case 0:
574                                pe.allowed_enc_level = libt::pe_settings::plaintext;
575                                break;
576                        case 1:
577                                pe.allowed_enc_level = libt::pe_settings::rc4;
578                                break;
579                        case 2:
580                                pe.allowed_enc_level = libt::pe_settings::both;
581                                break;
582                        default:
583                                pe.allowed_enc_level = libt::pe_settings::both;
584                               
585                                hal::event_log().post(shared_ptr<hal::EventDetail>(
586                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
587                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_ENCODING_LEVEL)) % pe_s.encrypt_level).str())));
588                }
589
590                switch (pe_s.conn_in_policy)
591                {
592                        case 0:
593                                pe.in_enc_policy = libt::pe_settings::forced;
594                                break;
595                        case 1:
596                                pe.in_enc_policy = libt::pe_settings::enabled;
597                                break;
598                        case 2:
599                                pe.in_enc_policy = libt::pe_settings::disabled;
600                                break;
601                        default:
602                                pe.in_enc_policy = libt::pe_settings::enabled;
603                               
604                                hal::event_log().post(shared_ptr<hal::EventDetail>(
605                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
606                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % pe_s.conn_in_policy).str())));
607                }
608
609                switch (pe_s.conn_out_policy)
610                {
611                        case 0:
612                                pe.out_enc_policy = libt::pe_settings::forced;
613                                break;
614                        case 1:
615                                pe.out_enc_policy = libt::pe_settings::enabled;
616                                break;
617                        case 2:
618                                pe.out_enc_policy = libt::pe_settings::disabled;
619                                break;
620                        default:
621                                pe.out_enc_policy = libt::pe_settings::enabled;
622                               
623                                hal::event_log().post(shared_ptr<hal::EventDetail>(
624                                        new hal::EventGeneral(hal::event_logger::warning, hal::event_logger::unclassified, 
625                                                (hal::wform(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % pe_s.conn_out_policy).str())));
626                }
627               
628                pe.prefer_rc4 = pe_s.prefer_rc4;
629               
630                try
631                {
632               
633                session_->set_pe_settings(pe);
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"ensure_pe_on"))); 
640                                       
641                        ensure_pe_off();               
642                }
643               
644                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption on.")));
645        }
646
647        void ensure_pe_off()
648        {
649                libt::pe_settings pe;
650                pe.out_enc_policy = libt::pe_settings::disabled;
651                pe.in_enc_policy = libt::pe_settings::disabled;
652               
653                pe.allowed_enc_level = libt::pe_settings::both;
654                pe.prefer_rc4 = true;
655               
656                session_->set_pe_settings(pe);
657
658                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption off.")));
659        }
660#       endif
661       
662        void set_resolve_countries(bool b)
663        {               
664                resolve_countries_ = b;
665
666                for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); 
667                        i != e; ++i)
668                {
669                        (*i).torrent->set_resolve_countries(resolve_countries_);
670                }
671
672                if (b)                 
673                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Set to resolve countries.")));
674                else                   
675                        event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Not resolving countries.")));
676        }
677
678        void start_smart_ban_plugin()
679        {
680                session_->add_extension(&libt::create_smart_ban_plugin);
681                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started smart ban plugin.")));
682        }
683
684        void start_ut_pex_plugin()
685        {
686                session_->add_extension(&libt::create_ut_pex_plugin);
687                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started uTorrent peer exchange plugin.")));
688        }
689
690        void start_ut_metadata_plugin()
691        {
692                session_->add_extension(&libt::create_ut_metadata_plugin);
693                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started uTorrent metadata plugin.")));
694        }
695
696        void start_metadata_plugin()
697        {
698                session_->add_extension(&libt::create_metadata_plugin);
699                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Started metadata plugin.")));
700        }
701
702        void ip_v4_filter_block(boost::asio::ip::address_v4 first, boost::asio::ip::address_v4 last)
703        {
704                ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
705                ip_filter_count();
706                ip_filter_changed_ = true;
707        }
708
709        void ip_v6_filter_block(boost::asio::ip::address_v6 first, boost::asio::ip::address_v6 last)
710        {
711                ip_filter_.add_rule(first, last, libt::ip_filter::blocked);
712                ip_filter_count();
713                ip_filter_changed_ = true;
714        }
715
716        size_t ip_filter_size()
717        {
718                return ip_filter_count_;
719        }
720
721        void clear_ip_filter()
722        {
723                ip_filter_ = libt::ip_filter();
724                session_->set_ip_filter(libt::ip_filter());     
725                ip_filter_changed_ = true;
726                ip_filter_count();
727        }
728
729        bool ip_filter_import_dat(boost::filesystem::path file, progress_callback fn, bool octalFix);
730
731        struct 
732        {
733                signaler<> successful_listen;
734                signaler<> torrent_finished;
735
736                boost::signal<bool()> torrent_paused;
737        } 
738        signals;
739
740        void start_alert_handler();
741        void stop_alert_handler();
742        void alert_handler();
743
744        void add_torrent(wpath file, wpath saveDirectory, bool start_stopped, bool managed, bit::allocations alloc, 
745                        boost::filesystem::wpath moveToDirectory) 
746        {
747                try 
748                {       
749//              torrent_internal_ptr TIp;
750
751                std::pair<std::string, std::string> names = extract_names(file);
752                wstring xml_name = from_utf8(names.first) + L".xml";
753
754/*              if (false && fs::exists(file.parent_path()/xml_name))
755                {
756                        torrent_standalone tsa;
757                       
758                        if (tsa.load_standalone(file.parent_path()/xml_name))
759                        {
760                                TIp = tsa.torrent;
761                               
762                                TIp->set_save_directory(saveDirectory, true);                   
763                                if (useMoveTo)
764                                        TIp->set_move_to_directory(moveToDirectory);
765
766                                TIp->prepare(file);
767                        }
768                }
769*/
770                torrent_internal_ptr TIp =
771                        the_torrents_.create_torrent(file, saveDirectory, alloc, moveToDirectory);
772
773                if(TIp)
774                {
775                        TIp->set_managed(managed);
776                        TIp->set_transfer_speed(bittorrent::Instance().default_torrent_download(), 
777                                bittorrent::Instance().default_torrent_upload());
778                        TIp->set_connection_limit(bittorrent::Instance().default_torrent_max_connections(), 
779                                bittorrent::Instance().default_torrent_max_uploads());
780                        TIp->set_resolve_countries(resolve_countries_);
781
782                        TIp->start();
783
784                        if (!start_stopped) TIp->resume();
785                }
786               
787                }
788                catch (const std::exception& e)
789                {
790                        event_log().post(shared_ptr<EventDetail>(
791                                new EventTorrentException(event_logger::critical, event_logger::torrentException, 
792                                        std::string(e.what()), to_utf8(file.string()), std::string("addTorrent"))));
793                }
794        }
795
796        void remove_torrent(const wstring& name)
797        {
798                try {
799                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removing Torrent.")));
800
801                boost::shared_ptr<file_details_vec> files = boost::shared_ptr<file_details_vec>(new file_details_vec());               
802                torrent_internal_ptr pTI = the_torrents_.get(name);
803
804                the_torrents_.remove_torrent(name);
805               
806                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removed")));
807               
808                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(name, "remove_torrent")
809        }
810
811        void remove_torrent_wipe_files(const std::wstring& name, remove_files fn)
812        {
813                try {
814                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removing Torrent and files.")));
815
816                boost::shared_ptr<file_details_vec> files = boost::shared_ptr<file_details_vec>(new file_details_vec());               
817                torrent_internal_ptr pTI = the_torrents_.get(name);
818
819                pTI->get_file_details(*files);
820                thread_t t(bind(fn, pTI->get_save_directory(), files));
821
822                pTI->clear_resume_data();
823                pTI->delete_torrent_file();
824
825                the_torrents_.remove_torrent(name);
826               
827                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Removed, started thread.")));
828               
829                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(name, "remove_torrent_wipe_files")
830        }
831
832        void resume_all()
833        {
834                try {
835                       
836                event_log().post(shared_ptr<EventDetail>(new EventMsg(L"Resuming all torrents.")));
837               
838                for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); i != e;)
839                {
840                        wpath file = wpath(hal::app().get_working_directory())/L"torrents"/(*i).torrent->filename();
841                       
842                        if (exists(file))
843                        {               
844                                try 
845                                {
846                                       
847                                (*i).torrent->prepare(file);   
848                                (*i).torrent->start(); 
849                               
850                                ++i;
851                               
852                                }
853                                catch(const libt::duplicate_torrent&)
854                                {
855                                        hal::event_log().post(shared_ptr<hal::EventDetail>(
856                                                new hal::EventDebug(hal::event_logger::debug, L"Encountered duplicate torrent")));
857                                       
858                                        ++i; // Harmless, don't worry about it.
859                                }
860                                catch(const std::exception& e) 
861                                {
862                                        hal::event_log().post(shared_ptr<hal::EventDetail>(
863                                                new hal::EventStdException(hal::event_logger::warning, e, L"resume_all")));
864                                       
865                                        the_torrents_.erase(i++);
866                                }                       
867                        }
868                        else
869                        {
870                                the_torrents_.erase(i++);
871                        }
872                }
873               
874                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "resume_all")
875        }
876
877        bool close_counter(int* count)
878        {
879                --(*count);
880                return true;
881        }
882       
883        void close_all(boost::optional<report_num_active> fn)
884        {
885                try 
886                {       
887
888                event_log().post(shared_ptr<EventDetail>(new EventInfo(L"Saving torrent data ...")));
889
890                save_torrent_data();
891
892                event_log().post(shared_ptr<EventDetail>(new EventInfo(L"       ... stopping all torrents")));
893
894                session_->pause();             
895
896                // Ok this polling loop here is a bit curde, but a blocking wait is actually appropiate.               
897                { 
898                int num_active = 1;
899
900                while (num_active > 0)
901                {
902                        num_active = 0;
903
904                        for (torrent_manager::torrent_by_name::iterator i=the_torrents_.begin(), e=the_torrents_.end(); 
905                                        i != e; ++i)
906                        {
907                                if (    (*i).torrent
908                                        && 
909                                        (*i).torrent->state() != torrent_details::torrent_in_error
910                                        && 
911                                        (       (       (*i).torrent->state() != torrent_details::torrent_stopped
912                                                        && 
913                                                        (*i).torrent->state() != torrent_details::torrent_paused
914                                                )
915                                                || 
916                                                (*i).torrent->awaiting_resume_data()
917                                        )
918                                )
919                                {
920#                                       ifdef HAL_TORRENT_DEV_MSGES
921                                                (*i).torrent->output_torrent_debug_details();
922#                                       endif
923                                        num_active += 1;
924                                }
925                        }
926
927                        event_log().post(shared_ptr<EventDetail>(new EventInfo(hal::wform(L"    ... %1% still active") % (num_active))));
928
929                        if (fn) (*fn)(num_active);
930                        boost::this_thread::sleep(pt::milliseconds(500));
931                } 
932               
933                }
934               
935                event_log().post(shared_ptr<EventDetail>(new EventInfo(L"       ... all torrents stopped.")));         
936               
937                } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "close_all()")
938        }
939       
940        void save_torrent_data()
941        {       
942                mutex_t::scoped_lock l(mutex_);
943                try
944                {
945               
946                the_torrents_.save_to_ini();
947                bittorrent_ini_.save_data();
948                       
949                if (dht_on_) 
950                {       
951                        halencode(hal::app().get_working_directory()/L"DHTState.bin", session_->dht_state());
952                }
953               
954                }               
955                catch(std::exception& e)
956                {
957                        event_log().post(shared_ptr<EventDetail>(\
958                                new EventStdException(event_logger::critical, e, L"save_torrent_data()")));
959                }
960        }
961       
962        int default_torrent_max_connections() { return default_torrent_max_connections_; }
963        int default_torrent_max_uploads() { return default_torrent_max_uploads_; }
964        float default_torrent_download() { return default_torrent_download_; }
965        float default_torrent_upload() { return default_torrent_upload_; }
966       
967private:
968        bool create_torrent(const create_torrent_params& params, fs::wpath out_file, progress_callback fn);
969
970        void service_thread(size_t);
971        void alert_handler_wait(const boost::system::error_code&);
972
973        void execute_action(const boost::system::error_code&, bit::timeout_actions action);
974        void execute_callback(const boost::system::error_code&, action_callback_t action);
975
976        void acquire_work_object()
977        {
978                HAL_DEV_MSG(hal::wform(L"Acquiring service work object."));
979
980                work_.reset(new boost::asio::io_service::work(io_service_));
981        }
982
983        void discard_work_object()
984        {
985                work_.reset();
986
987                HAL_DEV_MSG(hal::wform(L"Discarded service work object"));
988        }
989
990        void schedual_action(boost::posix_time::ptime time, bit::timeout_actions action);
991        void schedual_action(boost::posix_time::time_duration duration, bit::timeout_actions action);
992        void schedual_callback(boost::posix_time::ptime time, action_callback_t action);
993        void schedual_callback(boost::posix_time::time_duration duration, action_callback_t action);   
994        void schedual_cancel();
995       
996        boost::optional<libt::session> session_;       
997        SessionDetail session_details_;
998
999        mutable mutex_t mutex_;
1000       
1001        ini_file bittorrent_ini_;
1002        torrent_manager the_torrents_; 
1003
1004        boost::asio::io_service io_service_;
1005        std::auto_ptr<boost::asio::io_service::work> work_;
1006
1007        boost::asio::deadline_timer action_timer_;
1008
1009        boost::asio::deadline_timer alert_timer_;
1010        bool keep_checking_;
1011
1012        typedef boost::shared_ptr<thread_t> shared_thread_ptr;
1013
1014        std::vector<shared_thread_ptr> service_threads_;
1015       
1016        int default_torrent_max_connections_;
1017        int default_torrent_max_uploads_;
1018        float default_torrent_download_;
1019        float default_torrent_upload_;
1020       
1021        bool resolve_countries_;
1022        bool ip_filter_on_;
1023        bool ip_filter_loaded_;
1024        bool ip_filter_changed_;
1025        libt::ip_filter ip_filter_;
1026        size_t ip_filter_count_;
1027       
1028        void ip_filter_count();
1029        void ip_filter_load(progress_callback fn);
1030        void ip_filter_import(std::vector<libt::ip_range<boost::asio::ip::address_v4> >& v4,
1031                std::vector<libt::ip_range<boost::asio::ip::address_v6> >& v6);
1032       
1033        bool dht_on_;
1034        libt::dht_settings dht_settings_;
1035        libt::entry dht_state_; 
1036
1037        libt::upnp* upnp_;
1038        libt::natpmp* natpmp_;
1039};
1040
1041}
1042
1043#include "halSessionStates.hpp"
Note: See TracBrowser for help on using the repository browser.