source: trunk/src/halSession.hpp @ 541

Revision 541, 26.7 KB checked in by Eoin, 12 years ago (diff)

Updating halConfig serialization.

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