source: trunk/src/halSession.hpp @ 491

Revision 491, 29.9 KB checked in by Eoin, 11 years ago (diff)

Merging changes from branch into trunk.

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