source: trunk/src/halSession.hpp @ 648

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