source: trunk/src/halSession.hpp @ 618

Revision 618, 30.1 KB checked in by Eoin, 12 years ago (diff)

Port randomization and router model reporting added.

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