source: trunk/src/halSession.hpp @ 680

Revision 680, 34.0 KB checked in by Eoin, 12 years ago (diff)

Using session pause all instead of per torrent. Need to hook in paused alert to shutdown cleanly.

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