source: trunk/src/halSession.hpp @ 614

Revision 614, 29.8 KB checked in by Eoin, 12 years ago (diff)

ListView? grouping works. But a lacking on the API side means it's incompatible with sorting!

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