source: trunk/src/halTorrent.cpp @ 403

Revision 403, 53.8 KB checked in by Eoin, 12 years ago (diff)

Added command to recheck torrents.

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#include "stdAfx.hpp"
8
9#define TORRENT_MAX_ALERT_TYPES 20
10
11#include <libtorrent/file.hpp>
12#include <libtorrent/hasher.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 "global/wtl_app.hpp"
24#include "global/string_conv.hpp"
25#include "global/ini_adapter.hpp"
26
27#include "halTorrent.hpp"
28#include "halEvent.hpp"
29#include "halSignaler.hpp"
30
31#define foreach BOOST_FOREACH
32
33namespace boost {
34namespace serialization {
35
36#define IP_SAVE  3
37
38template<class Archive, class address_type>
39void save(Archive& ar, const address_type& ip, const unsigned int version)
40{       
41#if IP_SAVE == 1
42        typename address_type::bytes_type bytes = ip.to_bytes();       
43        for (typename address_type::bytes_type::iterator i=bytes.begin(); i != bytes.end(); ++i)
44                ar & BOOST_SERIALIZATION_NVP(*i);
45#elif IP_SAVE == 2
46        string dotted = ip.to_string(); 
47        ar & BOOST_SERIALIZATION_NVP(dotted);
48#elif IP_SAVE == 3
49        unsigned long addr = ip.to_ulong();     
50        ar & BOOST_SERIALIZATION_NVP(addr);
51#endif
52}
53
54template<class Archive, class address_type>
55void load(Archive& ar, address_type& ip, const unsigned int version)
56{       
57#if IP_SAVE == 1
58        typename address_type::bytes_type bytes;       
59        for (typename address_type::bytes_type::iterator i=bytes.begin(); i != bytes.end(); ++i)
60                ar & BOOST_SERIALIZATION_NVP(*i);       
61        ip = address_type(bytes);
62#elif IP_SAVE == 2     
63        string dotted;
64        ar & BOOST_SERIALIZATION_NVP(dotted);   
65        ip = address_type::from_string(dotted);
66#elif IP_SAVE == 3
67        unsigned long addr;
68        ar & BOOST_SERIALIZATION_NVP(addr);     
69        ip = address_type(addr);
70#endif
71}
72
73template<class Archive, class address_type>
74void serialize(Archive& ar, libtorrent::ip_range<address_type>& addr, const unsigned int version)
75{       
76        ar & BOOST_SERIALIZATION_NVP(addr.first);
77        ar & BOOST_SERIALIZATION_NVP(addr.last);
78        addr.flags = libtorrent::ip_filter::blocked;
79}
80
81template<class Archive>
82void serialize(Archive& ar, hal::TrackerDetail& tracker, const unsigned int version)
83{       
84        ar & BOOST_SERIALIZATION_NVP(tracker.url);
85        ar & BOOST_SERIALIZATION_NVP(tracker.tier);
86}
87
88} // namespace serialization
89} // namespace boost
90
91BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v4)
92BOOST_SERIALIZATION_SPLIT_FREE(asio::ip::address_v6)
93
94namespace libtorrent
95{
96template<class Addr>
97bool operator==(const libtorrent::ip_range<Addr>& lhs, const int flags)
98{
99        return (lhs.flags == flags);
100}
101
102std::ostream& operator<<(std::ostream& os, libtorrent::ip_range<asio::ip::address_v4>& ip)
103{
104        os << ip.first.to_ulong();
105        os << ip.last.to_ulong();
106       
107        return os;
108}
109
110} // namespace libtorrent
111
112#include "halTorrentInternal.hpp"
113
114namespace hal
115{
116        libtorrent::session* TorrentInternal::the_session_ = 0;
117        wpath_t TorrentInternal::workingDir_;
118}
119
120namespace hal
121{
122
123namespace lbt = libtorrent;
124namespace fs = boost::filesystem;
125namespace pt = boost::posix_time;
126
127typedef std::wstring wstring_t;
128typedef std::string string_t;
129
130typedef boost::wformat wformat_t;
131typedef boost::format format_t;
132
133typedef boost::filesystem::wpath wpath_t;
134typedef boost::filesystem::path path_t;
135
136using boost::serialization::make_nvp;
137using boost::shared_ptr;
138using boost::bind;
139
140BitTorrent& bittorrent()
141{
142        static BitTorrent t;
143        return t;
144}
145
146bool operator!=(const lbt::dht_settings& lhs, const lbt::dht_settings& rhs)
147{
148        return lhs.max_peers_reply != rhs.max_peers_reply ||
149                   lhs.search_branching != rhs.search_branching ||
150                   lhs.service_port != rhs.service_port ||
151           lhs.max_fail_count != rhs.max_fail_count;
152}
153
154template<typename Addr>
155void write_range(fs::ofstream& ofs, const lbt::ip_range<Addr>& range)
156{ 
157        const typename Addr::bytes_type first = range.first.to_bytes();
158        const typename Addr::bytes_type last = range.last.to_bytes();
159        ofs.write((char*)first.elems, first.size());
160        ofs.write((char*)last.elems, last.size());
161}
162
163template<typename Addr>
164void write_vec_range(fs::ofstream& ofs, const std::vector<lbt::ip_range<Addr> >& vec)
165{ 
166        ofs << vec.size();
167       
168        for (typename std::vector<lbt::ip_range<Addr> >::const_iterator i=vec.begin(); 
169                i != vec.end(); ++i)
170        {
171                write_range(ofs, *i);
172        }
173}
174
175template<typename Addr>
176void read_range_to_filter(fs::ifstream& ifs, lbt::ip_filter& ip_filter)
177{ 
178        typename Addr::bytes_type first;
179        typename Addr::bytes_type last;
180        ifs.read((char*)first.elems, first.size());
181        ifs.read((char*)last.elems, last.size());       
182       
183        ip_filter.add_rule(Addr(first), Addr(last),
184                lbt::ip_filter::blocked);
185}
186
187static Event::eventLevel lbtAlertToHalEvent(lbt::alert::severity_t severity)
188{
189        switch (severity)
190        {
191        case lbt::alert::debug:
192                return Event::debug;
193       
194        case lbt::alert::info:
195                return Event::info;
196       
197        case lbt::alert::warning:
198                return Event::warning;
199       
200        case lbt::alert::critical:
201        case lbt::alert::fatal:
202                return Event::critical;
203       
204        default:
205                return Event::none;
206        }
207}
208
209const PeerDetails& TorrentDetail::peerDetails() const
210{
211        if (!peerDetailsFilled_)
212        {
213                bittorrent().getAllPeerDetails(hal::to_utf8(name_), peerDetails_);
214                peerDetailsFilled_ = true;
215        }
216       
217        return peerDetails_;
218}
219
220const FileDetails& TorrentDetail::fileDetails() const
221{
222        if (!fileDetailsFilled_)
223        {
224                bittorrent().getAllFileDetails(hal::to_utf8(name_), fileDetails_);
225                fileDetailsFilled_ = true;
226        }
227       
228        return fileDetails_;
229}
230
231bool nameLess(const TorrentDetail_ptr& left, const TorrentDetail_ptr& right)
232{
233        return left->state() < right->state();
234}
235
236void TorrentDetails::sort(
237        boost::function<bool (const TorrentDetail_ptr&, const TorrentDetail_ptr&)> fn) const
238{
239        std::stable_sort(torrents_.begin(), torrents_.end(), fn);
240}
241
242class BitTorrent_impl
243{
244        friend class BitTorrent;
245       
246public:
247       
248        ~BitTorrent_impl()
249        {
250                keepChecking_ = false;
251               
252                saveTorrentData();
253               
254                try
255                {
256               
257                if (ip_filter_changed_)
258                {       
259                        fs::ofstream ofs(workingDirectory/L"IPFilter.bin", std::ios::binary);
260//                      boost::archive::binary_oarchive oba(ofs);
261                       
262                        lbt::ip_filter::filter_tuple_t vectors = ip_filter_.export_filter();   
263                       
264                        std::vector<lbt::ip_range<asio::ip::address_v4> > v4(vectors.get<0>());
265                        std::vector<lbt::ip_range<asio::ip::address_v6> > v6(vectors.get<1>());
266                       
267                        v4.erase(std::remove(v4.begin(), v4.end(), 0), v4.end());
268                        v6.erase(std::remove(v6.begin(), v6.end(), 0), v6.end());
269
270                        write_vec_range(ofs, v4);
271//                      write_vec_range(ofs, v6);
272                }       
273                }
274                catch(std::exception& e)
275                {
276                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
277                                new hal::EventStdException(Event::critical, e, L"~BitTorrent_impl"))); 
278                }
279        }
280
281        struct 
282        {
283                signaler<> successful_listen;
284                signaler<> torrent_finished;
285        } 
286        signals;
287               
288        void alertHandler()
289        {
290                if (keepChecking_)
291                {
292               
293                std::auto_ptr<lbt::alert> p_alert = theSession.pop_alert();
294               
295                class AlertHandler
296                {
297                public:
298                AlertHandler(BitTorrent_impl& bit_impl) :
299                        bit_impl_(bit_impl)
300                {}
301               
302                void operator()(lbt::torrent_finished_alert const& a) const
303                {
304                        event().post(shared_ptr<EventDetail>(
305                                new EventMsg((wformat_t(hal::app().res_wstr(LBT_EVENT_TORRENT_FINISHED)) 
306                                                % get(a.handle)->name()), 
307                                        Event::info, a.timestamp())));
308                       
309                        get(a.handle)->finished();     
310                }
311               
312                void operator()(lbt::torrent_paused_alert const& a) const
313                {
314                        event().post(shared_ptr<EventDetail>(
315                                new EventMsg((wformat_t(hal::app().res_wstr(LBT_EVENT_TORRENT_PAUSED)) 
316                                                % get(a.handle)->name()), 
317                                        Event::info, a.timestamp())));
318
319                        get(a.handle)->signals.torrent_paused();
320                }
321               
322                void operator()(lbt::peer_error_alert const& a) const
323                {
324                        event().post(shared_ptr<EventDetail>(
325                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
326                                        wformat_t(hal::app().res_wstr(HAL_PEER_ALERT))
327                                                % hal::from_utf8_safe(a.msg())
328                                                % hal::from_utf8_safe(a.ip.address().to_string()))
329                        )       );                             
330                }
331                       
332                void operator()(lbt::peer_ban_alert const& a) const
333                {
334                        event().post(shared_ptr<EventDetail>(
335                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
336                                        wformat_t(hal::app().res_wstr(HAL_PEER_BAN_ALERT))
337                                                % get(a.handle)->name()
338                                                % hal::from_utf8_safe(a.ip.address().to_string()))
339                        )       );                             
340                }
341                       
342                void operator()(lbt::hash_failed_alert const& a) const
343                {
344                        event().post(shared_ptr<EventDetail>(
345                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
346                                        wformat_t(hal::app().res_wstr(HAL_HASH_FAIL_ALERT))
347                                                % get(a.handle)->name()
348                                                % a.piece_index)
349                        )       );                             
350                }
351                       
352                void operator()(lbt::url_seed_alert const& a) const
353                {
354                        event().post(shared_ptr<EventDetail>(
355                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
356                                        wformat_t(hal::app().res_wstr(HAL_URL_SEED_ALERT))
357                                                % get(a.handle)->name()
358                                                % hal::from_utf8_safe(a.url)
359                                                % hal::from_utf8_safe(a.msg()))
360                        )       );                             
361                }
362               
363                void operator()(lbt::tracker_warning_alert const& a) const
364                {
365                        event().post(shared_ptr<EventDetail>(
366                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
367                                        wformat_t(hal::app().res_wstr(HAL_TRACKER_WARNING_ALERT))
368                                                % get(a.handle)->name()
369                                                % hal::from_utf8_safe(a.msg()))
370                        )       );                             
371                }
372               
373                void operator()(lbt::tracker_announce_alert const& a) const
374                {
375                        event().post(shared_ptr<EventDetail>(
376                                new EventMsg((wformat_t(hal::app().res_wstr(HAL_TRACKER_ANNOUNCE_ALERT)) 
377                                                % get(a.handle)->name()), 
378                                        Event::info, a.timestamp())));
379                }
380               
381                void operator()(lbt::tracker_alert const& a) const
382                {
383                        event().post(shared_ptr<EventDetail>(
384                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
385                                        wformat_t(hal::app().res_wstr(HAL_TRACKER_ALERT))
386                                                % get(a.handle)->name()
387                                                % hal::from_utf8_safe(a.msg())
388                                                % a.times_in_row
389                                                % a.status_code)
390                        )       );                             
391                }
392               
393                void operator()(lbt::tracker_reply_alert const& a) const
394                {
395                        event().post(shared_ptr<EventDetail>(
396                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
397                                        wformat_t(hal::app().res_wstr(HAL_TRACKER_REPLY_ALERT))
398                                                % get(a.handle)->name()
399                                                % hal::from_utf8_safe(a.msg())
400                                                % a.num_peers)
401                        )       );                             
402                }
403               
404                void operator()(lbt::fastresume_rejected_alert const& a) const
405                {
406                        event().post(shared_ptr<EventDetail>(
407                                new EventGeneral(lbtAlertToHalEvent(a.severity()), a.timestamp(),
408                                        wformat_t(hal::app().res_wstr(HAL_FAST_RESUME_ALERT))
409                                                % get(a.handle)->name()
410                                                % hal::from_utf8_safe(a.msg()))
411                        )       );                             
412                }
413               
414                void operator()(lbt::piece_finished_alert const& a) const
415                {
416                        event().post(shared_ptr<EventDetail>(
417                                new EventGeneral(Event::debug, a.timestamp(),
418                                        wformat_t(hal::app().res_wstr(HAL_PIECE_FINISHED_ALERT))
419                                                % get(a.handle)->name()
420                                                % a.piece_index)
421                        )       );                             
422                }
423               
424                void operator()(lbt::block_finished_alert const& a) const
425                {
426                        event().post(shared_ptr<EventDetail>(
427                                new EventGeneral(Event::debug, a.timestamp(),
428                                        wformat_t(hal::app().res_wstr(HAL_BLOCK_FINISHED_ALERT))
429                                                % get(a.handle)->name()
430                                                % a.block_index
431                                                % a.piece_index)
432                        )       );                             
433                }
434               
435                void operator()(lbt::block_downloading_alert const& a) const
436                {
437                        event().post(shared_ptr<EventDetail>(
438                                new EventGeneral(Event::debug, a.timestamp(),
439                                        wformat_t(hal::app().res_wstr(HAL_BLOCK_DOWNLOADING_ALERT))
440                                                % get(a.handle)->name()
441                                                % a.block_index
442                                                % a.piece_index)
443                        )       );                             
444                }
445               
446                void operator()(lbt::listen_failed_alert const& a) const
447                {
448                        if (a.endpoint.address().is_v6())
449                        {       
450                                event().post(shared_ptr<EventDetail>(
451                                        new EventGeneral(Event::info, a.timestamp(),
452                                                hal::app().res_wstr(HAL_LISTEN_V6_FAILED_ALERT))
453                                )       );             
454                        }
455                        else
456                        {
457                                event().post(shared_ptr<EventDetail>(
458                                        new EventGeneral(Event::info, a.timestamp(),
459                                                wformat_t(hal::app().res_wstr(HAL_LISTEN_FAILED_ALERT))
460                                                        % hal::from_utf8_safe(a.msg()))
461                                )       );
462                        }
463                }
464               
465                void operator()(lbt::listen_succeeded_alert const& a) const
466                {
467                        event().post(shared_ptr<EventDetail>(
468                                new EventGeneral(Event::info, a.timestamp(),
469                                        wformat_t(hal::app().res_wstr(HAL_LISTEN_SUCCEEDED_ALERT))
470                                                % hal::from_utf8_safe(a.msg()))
471                        )       );     
472
473                        bit_impl_.signals.successful_listen();
474                }
475               
476                void operator()(lbt::peer_blocked_alert const& a) const
477                {
478                        event().post(shared_ptr<EventDetail>(
479                                new EventGeneral(Event::debug, a.timestamp(),
480                                        wformat_t(hal::app().res_wstr(HAL_IPFILTER_ALERT))
481                                                % hal::from_utf8_safe(a.ip.to_string())
482                                                % hal::from_utf8_safe(a.msg()))
483                        )       );                             
484                }
485               
486                void operator()(lbt::alert const& a) const
487                {
488                        event().post(shared_ptr<EventDetail>(
489                                        new EventLibtorrent(lbtAlertToHalEvent(a.severity()), 
490                                                a.timestamp(), Event::unclassified, hal::from_utf8_safe(a.msg()))));           
491                }
492               
493                private:
494                        BitTorrent_impl& bit_impl_;
495                       
496                        TorrentInternal_ptr get(lbt::torrent_handle h) const 
497                        { 
498                                return bit_impl_.theTorrents.get(from_utf8_safe(h.get_torrent_info().name())); 
499                        }
500               
501                } handler(*this);
502               
503                while (p_alert.get())
504                {       
505                        try
506                        {
507                       
508                        lbt::handle_alert<
509                                lbt::torrent_finished_alert,
510                                lbt::torrent_paused_alert,
511                                lbt::peer_error_alert,
512                                lbt::peer_ban_alert,
513                                lbt::hash_failed_alert,
514                                lbt::url_seed_alert,
515                                lbt::tracker_alert,
516                                lbt::tracker_warning_alert,
517                                lbt::tracker_announce_alert,
518                                lbt::tracker_reply_alert,
519                                lbt::fastresume_rejected_alert,
520                                lbt::piece_finished_alert,
521                                lbt::block_finished_alert,
522                                lbt::block_downloading_alert,
523                                lbt::listen_failed_alert,
524                                lbt::listen_succeeded_alert,
525                                lbt::peer_blocked_alert,
526                                lbt::alert
527                        >::handle_alert(p_alert, handler);                     
528                       
529                        }
530                        catch(lbt::unhandled_alert&)
531                        {
532                                handler(*p_alert);
533                        }
534                        catch(std::exception& e)
535                        {
536                                // These are logged as debug because they are rarely important to act on!
537                                event().post(shared_ptr<EventDetail>(\
538                                        new EventStdException(Event::debug, e, L"alertHandler")));
539                        }
540                       
541                        p_alert = theSession.pop_alert();
542                }
543               
544                timer_.expires_from_now(boost::posix_time::seconds(5));
545                timer_.async_wait(bind(&BitTorrent_impl::alertHandler, this));
546                }
547        }
548       
549        void saveTorrentData()
550        {       try
551                {
552               
553                theTorrents.save();
554                bittorrentIni.save_data();
555                       
556                if (dht_on_) 
557                {       
558                        halencode(workingDirectory/L"DHTState.bin", theSession.dht_state());
559                }
560               
561                }               
562                catch(std::exception& e)
563                {
564                        event().post(shared_ptr<EventDetail>(\
565                                new EventStdException(Event::critical, e, L"saveTorrentData")));
566                }
567        }
568       
569        int defTorrentMaxConn() { return defTorrentMaxConn_; }
570        int defTorrentMaxUpload() { return defTorrentMaxUpload_; }
571        float defTorrentDownload() { return defTorrentDownload_; }
572        float defTorrentUpload() { return defTorrentUpload_; }
573       
574        const wpath_t workingDir() { return workingDirectory; };
575
576private:
577        BitTorrent_impl() :
578                theSession(lbt::fingerprint(HALITE_FINGERPRINT)),
579                timer_(io_),
580                keepChecking_(false),
581                bittorrentIni(L"BitTorrent.xml"),
582                theTorrents(bittorrentIni),
583                defTorrentMaxConn_(-1),
584                defTorrentMaxUpload_(-1),
585                defTorrentDownload_(-1),
586                defTorrentUpload_(-1),
587                ip_filter_on_(false),
588                ip_filter_loaded_(false),
589                ip_filter_changed_(false),
590                ip_filter_count_(0),
591                dht_on_(false)
592        {
593                TorrentInternal::the_session_ = &theSession;
594                TorrentInternal::workingDir_ = workingDir();
595               
596                theSession.set_severity_level(lbt::alert::debug);               
597                theSession.add_extension(&lbt::create_metadata_plugin);
598                theSession.add_extension(&lbt::create_ut_pex_plugin);
599                theSession.set_max_half_open_connections(10);
600               
601                hal::event().post(shared_ptr<hal::EventDetail>(
602                        new hal::EventMsg(L"Loading BitTorrent.xml.", hal::Event::info)));             
603                bittorrentIni.load_data();
604                hal::event().post(shared_ptr<hal::EventDetail>(
605                        new hal::EventMsg(L"Loading torrent parameters.", hal::Event::info))); 
606                theTorrents.load();
607                hal::event().post(shared_ptr<hal::EventDetail>(
608                        new hal::EventMsg(L"Loading done!", hal::Event::info)));
609               
610                try
611                {                                               
612                if (fs::exists(workingDirectory/L"Torrents.xml"))
613                {
614                        {
615                        fs::wifstream ifs(workingDirectory/L"Torrents.xml");
616               
617                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Loading old Torrents.xml")));
618               
619                        TorrentMap torrents;
620                        boost::archive::xml_wiarchive ia(ifs); 
621                        ia >> make_nvp("torrents", torrents);
622                       
623                        theTorrents = torrents;
624                        }
625                       
626                        event().post(shared_ptr<EventDetail>(new EventMsg(
627                                wformat_t(L"Total %1%.") % theTorrents.size())));                               
628                       
629                        fs::rename(workingDirectory/L"Torrents.xml", workingDirectory/L"Torrents.xml.safe.to.delete");
630                }                       
631                }
632                catch(const std::exception& e)
633                {
634                        event().post(shared_ptr<EventDetail>(
635                                new EventStdException(Event::fatal, e, L"Loading Old Torrents.xml")));
636                }               
637                               
638                if (exists(workingDirectory/L"DHTState.bin"))
639                {
640                        try
641                        {
642                                dht_state_ = haldecode(workingDirectory/L"DHTState.bin");
643                        }               
644                        catch(const std::exception& e)
645                        {
646                                event().post(shared_ptr<EventDetail>(
647                                        new EventStdException(Event::critical, e, L"Loading DHTState.bin")));
648                        }
649                }
650               
651                {       lbt::session_settings settings = theSession.settings();
652                        settings.user_agent = string_t("Halite ") + HALITE_VERSION_STRING;
653                        theSession.set_settings(settings);
654                }
655               
656                timer_.expires_from_now(boost::posix_time::seconds(5));
657                timer_.async_wait(bind(&BitTorrent_impl::alertHandler, this));
658        }
659       
660        std::pair<lbt::entry, lbt::entry> prepTorrent(wpath_t filename, wpath_t saveDirectory);
661        void removalThread(TorrentInternal_ptr pIT, bool wipeFiles);
662       
663        lbt::session theSession;
664        asio::io_service io_;
665        asio::deadline_timer timer_;
666        bool keepChecking_;
667       
668        static wpath_t workingDirectory;
669        ini_file bittorrentIni;
670        TorrentManager theTorrents;     
671       
672        int defTorrentMaxConn_;
673        int defTorrentMaxUpload_;
674        float defTorrentDownload_;
675        float defTorrentUpload_;
676       
677        bool ip_filter_on_;
678        bool ip_filter_loaded_;
679        bool ip_filter_changed_;
680        lbt::ip_filter ip_filter_;
681        size_t ip_filter_count_;
682       
683        void ip_filter_count();
684        void ip_filter_load(progressCallback fn);
685        void ip_filter_import(std::vector<lbt::ip_range<asio::ip::address_v4> >& v4,
686                std::vector<lbt::ip_range<asio::ip::address_v6> >& v6);
687       
688        bool dht_on_;
689        lbt::dht_settings dht_settings_;
690        lbt::entry dht_state_;
691       
692};
693
694wpath_t BitTorrent_impl::workingDirectory = hal::app().working_directory();
695
696BitTorrent::BitTorrent() :
697        pimpl(new BitTorrent_impl())
698{}
699
700#define HAL_GENERIC_TORRENT_EXCEPTION_CATCH(TORRENT, FUNCTION) \
701catch (const lbt::invalid_handle&) \
702{\
703        event().post(shared_ptr<EventDetail>( \
704                new EventInvalidTorrent(Event::critical, Event::invalidTorrent, TORRENT, std::string(FUNCTION)))); \
705}\
706catch (const invalidTorrent& t) \
707{\
708        event().post(shared_ptr<EventDetail>( \
709                new EventInvalidTorrent(Event::info, Event::invalidTorrent, t.who(), std::string(FUNCTION)))); \
710}\
711catch (const std::exception& e) \
712{\
713        event().post(shared_ptr<EventDetail>( \
714                new EventTorrentException(Event::critical, Event::torrentException, std::string(e.what()), TORRENT, std::string(FUNCTION)))); \
715}
716
717void BitTorrent::shutDownSession()
718{
719        pimpl.reset();
720}
721
722void BitTorrent::saveTorrentData()
723{
724        pimpl->saveTorrentData();
725}
726
727bool BitTorrent::listenOn(std::pair<int, int> const& range)
728{
729        try
730        {
731       
732        if (!pimpl->theSession.is_listening())
733        {
734                return pimpl->theSession.listen_on(range);
735        }
736        else
737        {
738                int port = pimpl->theSession.listen_port();
739               
740                if (port < range.first || port > range.second)
741                        return pimpl->theSession.listen_on(range);     
742                else
743                {
744                        pimpl->signals.successful_listen();
745                       
746                        return true;
747                }
748        }
749       
750        }
751        catch (const std::exception& e)
752        {
753                event().post(shared_ptr<EventDetail>(
754                        new EventStdException(Event::fatal, e, L"From BitTorrent::listenOn.")));
755
756                return false;
757        }
758        catch(...)
759        {
760                return false;
761        }
762}
763
764int BitTorrent::isListeningOn() 
765{
766        if (!pimpl->theSession.is_listening())
767                return -1;     
768        else
769                return pimpl->theSession.listen_port();
770}
771
772void BitTorrent::stopListening()
773{
774        ensureDhtOff();
775        pimpl->theSession.listen_on(std::make_pair(0, 0));
776}
777
778bool BitTorrent::ensureDhtOn()
779{
780        if (!pimpl->dht_on_)
781        {               
782                try
783                {
784                pimpl->theSession.start_dht(pimpl->dht_state_);
785                pimpl->dht_on_ = true;
786                }
787                catch(...)
788                {}
789        }
790                return pimpl->dht_on_;
791}
792
793void BitTorrent::ensureDhtOff()
794{
795        if (pimpl->dht_on_)
796        {
797                pimpl->theSession.stop_dht();           
798                pimpl->dht_on_ = false;
799        }
800}
801
802void BitTorrent::setDhtSettings(int max_peers_reply, int search_branching, 
803        int service_port, int max_fail_count)
804{
805        lbt::dht_settings settings;
806        settings.max_peers_reply = max_peers_reply;
807        settings.search_branching = search_branching;
808        settings.service_port = service_port;
809        settings.max_fail_count = max_fail_count;
810       
811        if (pimpl->dht_settings_ != settings)
812        {
813                pimpl->dht_settings_ = settings;
814                pimpl->theSession.set_dht_settings(pimpl->dht_settings_);
815        }
816}
817
818void BitTorrent::setMapping(int mapping)
819{
820        if (mapping != mappingNone)
821        {
822                if (mapping == mappingUPnP)
823                {
824                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Starting UPnP mapping.")));
825                        pimpl->theSession.stop_upnp();
826                        pimpl->theSession.stop_natpmp();
827
828                        pimpl->signals.successful_listen.connect_once(bind(&lbt::session::start_upnp, &pimpl->theSession));
829                }
830                else
831                {
832                        event().post(shared_ptr<EventDetail>(new EventMsg(L"Starting NAT-PMP mapping.")));
833                        pimpl->theSession.stop_upnp();
834                        pimpl->theSession.stop_natpmp();
835
836                        pimpl->signals.successful_listen.connect_once(bind(&lbt::session::start_natpmp, &pimpl->theSession));
837                }
838        }
839        else
840        {
841                event().post(shared_ptr<EventDetail>(new EventMsg(L"No mapping.")));
842                pimpl->theSession.stop_upnp();
843                pimpl->theSession.stop_natpmp();
844        }
845}
846
847void BitTorrent::setTimeouts(int peers, int tracker)
848{
849        lbt::session_settings settings = pimpl->theSession.settings();
850        settings.peer_connect_timeout = peers;
851        settings.tracker_completion_timeout = tracker;
852
853        pimpl->theSession.set_settings(settings);
854
855        event().post(shared_ptr<EventDetail>(new EventMsg(
856                wformat_t(L"Set Timeouts, peer %1%, tracker %2%") % peers % tracker)));
857}
858
859void BitTorrent::setSessionLimits(int maxConn, int maxUpload)
860{               
861        pimpl->theSession.set_max_uploads(maxUpload);
862        pimpl->theSession.set_max_connections(maxConn);
863       
864        event().post(shared_ptr<EventDetail>(new EventMsg(
865                wformat_t(L"Set connections totals %1% and uploads %2%.") 
866                        % maxConn % maxUpload)));
867}
868
869void BitTorrent::setSessionSpeed(float download, float upload)
870{
871        int down = (download > 0) ? static_cast<int>(download*1024) : -1;
872        pimpl->theSession.set_download_rate_limit(down);
873        int up = (upload > 0) ? static_cast<int>(upload*1024) : -1;
874        pimpl->theSession.set_upload_rate_limit(up);
875       
876        event().post(shared_ptr<EventDetail>(new EventMsg(
877                wformat_t(L"Set session rates at download %1% and upload %2%.") 
878                        % pimpl->theSession.download_rate_limit() % pimpl->theSession.upload_rate_limit())));
879}
880
881void BitTorrent_impl::ip_filter_count()
882{
883        lbt::ip_filter::filter_tuple_t vectors = ip_filter_.export_filter();
884       
885        vectors.get<0>().erase(std::remove(vectors.get<0>().begin(), vectors.get<0>().end(), 0),
886                vectors.get<0>().end());
887        vectors.get<1>().erase(std::remove(vectors.get<1>().begin(), vectors.get<1>().end(), 0),
888                vectors.get<1>().end());
889        ip_filter_count_ = vectors.get<0>().size() + vectors.get<1>().size();
890}
891
892void BitTorrent_impl::ip_filter_load(progressCallback fn)
893{
894        fs::ifstream ifs(workingDirectory/L"IPFilter.bin", std::ios::binary);
895        if (ifs)
896        {
897                size_t v4_size;
898                ifs >> v4_size;
899               
900                size_t total = v4_size/100;
901                size_t previous = 0;
902               
903                for(unsigned i=0; i<v4_size; ++i)
904                {
905                        if (i-previous > total)
906                        {
907                                previous = i;
908                                if (fn) if (fn(size_t(i/total))) break;
909                        }
910                       
911                        read_range_to_filter<asio::ip::address_v4>(ifs, ip_filter_);
912                }
913        }       
914}
915
916void  BitTorrent_impl::ip_filter_import(std::vector<lbt::ip_range<asio::ip::address_v4> >& v4,
917        std::vector<lbt::ip_range<asio::ip::address_v6> >& v6)
918{
919        for(std::vector<lbt::ip_range<asio::ip::address_v4> >::iterator i=v4.begin();
920                i != v4.end(); ++i)
921        {
922                ip_filter_.add_rule(i->first, i->last, lbt::ip_filter::blocked);
923        }
924/*      for(std::vector<lbt::ip_range<asio::ip::address_v6> >::iterator i=v6.begin();
925                i != v6.end(); ++i)
926        {
927                ip_filter_.add_rule(i->first, i->last, lbt::ip_filter::blocked);
928        }
929*/     
930        /* Note here we do not set ip_filter_changed_ */
931}
932
933void BitTorrent::ensureIpFilterOn(progressCallback fn)
934{
935        try
936        {
937       
938        if (!pimpl->ip_filter_loaded_)
939        {
940                pimpl->ip_filter_load(fn);
941                pimpl->ip_filter_loaded_ = true;
942        }
943       
944        if (!pimpl->ip_filter_on_)
945        {
946                pimpl->theSession.set_ip_filter(pimpl->ip_filter_);
947                pimpl->ip_filter_on_ = true;
948                pimpl->ip_filter_count();
949        }
950       
951        }
952        catch(const std::exception& e)
953        {               
954                hal::event().post(boost::shared_ptr<hal::EventDetail>(
955                        new hal::EventStdException(Event::critical, e, L"ensureIpFilterOn"))); 
956
957                ensureIpFilterOff();
958        }
959
960        event().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters on."))); 
961}
962
963void BitTorrent::ensureIpFilterOff()
964{
965        pimpl->theSession.set_ip_filter(lbt::ip_filter());
966        pimpl->ip_filter_on_ = false;
967       
968        event().post(shared_ptr<EventDetail>(new EventMsg(L"IP filters off.")));       
969}
970
971#ifndef TORRENT_DISABLE_ENCRYPTION     
972void BitTorrent::ensurePeOn(int enc_level, int in_enc_policy, int out_enc_policy, bool prefer_rc4)
973{
974        lbt::pe_settings pe;
975       
976        switch (enc_level)
977        {
978                case 0:
979                        pe.allowed_enc_level = lbt::pe_settings::plaintext;
980                        break;
981                case 1:
982                        pe.allowed_enc_level = lbt::pe_settings::rc4;
983                        break;
984                case 2:
985                        pe.allowed_enc_level = lbt::pe_settings::both;
986                        break;
987                default:
988                        pe.allowed_enc_level = lbt::pe_settings::both;
989                       
990                        hal::event().post(shared_ptr<hal::EventDetail>(
991                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
992                                        (wformat_t(hal::app().res_wstr(HAL_INCORRECT_ENCODING_LEVEL)) % enc_level).str())));
993        }
994
995        switch (in_enc_policy)
996        {
997                case 0:
998                        pe.in_enc_policy = lbt::pe_settings::forced;
999                        break;
1000                case 1:
1001                        pe.in_enc_policy = lbt::pe_settings::enabled;
1002                        break;
1003                case 2:
1004                        pe.in_enc_policy = lbt::pe_settings::disabled;
1005                        break;
1006                default:
1007                        pe.in_enc_policy = lbt::pe_settings::enabled;
1008                       
1009                        hal::event().post(shared_ptr<hal::EventDetail>(
1010                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1011                                        (wformat_t(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % in_enc_policy).str())));
1012        }
1013
1014        switch (out_enc_policy)
1015        {
1016                case 0:
1017                        pe.out_enc_policy = lbt::pe_settings::forced;
1018                        break;
1019                case 1:
1020                        pe.out_enc_policy = lbt::pe_settings::enabled;
1021                        break;
1022                case 2:
1023                        pe.out_enc_policy = lbt::pe_settings::disabled;
1024                        break;
1025                default:
1026                        pe.out_enc_policy = lbt::pe_settings::enabled;
1027                       
1028                        hal::event().post(shared_ptr<hal::EventDetail>(
1029                                new hal::EventGeneral(hal::Event::warning, hal::Event::unclassified, 
1030                                        (wformat_t(hal::app().res_wstr(HAL_INCORRECT_CONNECT_POLICY)) % in_enc_policy).str())));
1031        }
1032       
1033        pe.prefer_rc4 = prefer_rc4;
1034       
1035        try
1036        {
1037       
1038        pimpl->theSession.set_pe_settings(pe);
1039       
1040        }
1041        catch(const std::exception& e)
1042        {
1043                hal::event().post(boost::shared_ptr<hal::EventDetail>(
1044                                new hal::EventStdException(Event::critical, e, L"ensurePeOn"))); 
1045                               
1046                ensurePeOff();         
1047        }
1048       
1049        event().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption on.")));
1050}
1051
1052void BitTorrent::ensurePeOff()
1053{
1054        lbt::pe_settings pe;
1055        pe.out_enc_policy = lbt::pe_settings::disabled;
1056        pe.in_enc_policy = lbt::pe_settings::disabled;
1057       
1058        pe.allowed_enc_level = lbt::pe_settings::both;
1059        pe.prefer_rc4 = true;
1060       
1061        pimpl->theSession.set_pe_settings(pe);
1062
1063        event().post(shared_ptr<EventDetail>(new EventMsg(L"Protocol encryption off.")));
1064}
1065#endif
1066
1067void BitTorrent::ip_v4_filter_block(asio::ip::address_v4 first, asio::ip::address_v4 last)
1068{
1069        pimpl->ip_filter_.add_rule(first, last, lbt::ip_filter::blocked);
1070        pimpl->ip_filter_count();
1071        pimpl->ip_filter_changed_ = true;
1072}
1073
1074void BitTorrent::ip_v6_filter_block(asio::ip::address_v6 first, asio::ip::address_v6 last)
1075{
1076        pimpl->ip_filter_.add_rule(first, last, lbt::ip_filter::blocked);
1077        pimpl->ip_filter_count();
1078        pimpl->ip_filter_changed_ = true;
1079}
1080
1081size_t BitTorrent::ip_filter_size()
1082{
1083        return pimpl->ip_filter_count_;
1084}
1085
1086void BitTorrent::clearIpFilter()
1087{
1088        pimpl->ip_filter_ = lbt::ip_filter();
1089        pimpl->theSession.set_ip_filter(lbt::ip_filter());     
1090        pimpl->ip_filter_changed_ = true;
1091        pimpl->ip_filter_count();
1092}
1093
1094void BitTorrent::ip_filter_import_dat(boost::filesystem::path file, progressCallback fn, bool octalFix)
1095{
1096        try
1097        {
1098
1099        fs::ifstream ifs(file); 
1100        if (ifs)
1101        {
1102                boost::uintmax_t total = fs::file_size(file)/100;
1103                boost::uintmax_t progress = 0;
1104                boost::uintmax_t previous = 0;
1105               
1106                boost::regex reg("\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s*-\\s*(\\d+\\.\\d+\\.\\d+\\.\\d+)\\s*.*");
1107                boost::regex ip_reg("0*(\\d*)\\.0*(\\d*)\\.0*(\\d*)\\.0*(\\d*)");
1108                boost::smatch m;
1109               
1110                string_t ip_address_line;               
1111                while (!std::getline(ifs, ip_address_line).eof())
1112                {               
1113                        progress += (ip_address_line.length() + 2);
1114                        if (progress-previous > total)
1115                        {
1116                                previous = progress;
1117                                if (fn)
1118                                {
1119                                        if (fn(size_t(progress/total))) 
1120                                                break;
1121                                }
1122                        }
1123                       
1124                        if (boost::regex_match(ip_address_line, m, reg))
1125                        {
1126                                string_t first = m[1];
1127                                string_t last = m[2];
1128                               
1129                                if (octalFix)
1130                                {
1131                                        if (boost::regex_match(first, m, ip_reg))
1132                                        {
1133                                                first = ((m.length(1) != 0) ? m[1] : string_t("0")) + "." +
1134                                                                ((m.length(2) != 0) ? m[2] : string_t("0")) + "." +
1135                                                                ((m.length(3) != 0) ? m[3] : string_t("0")) + "." +
1136                                                                ((m.length(4) != 0) ? m[4] : string_t("0"));
1137                                        }                                       
1138                                        if (boost::regex_match(last, m, ip_reg))
1139                                        {
1140                                                last = ((m.length(1) != 0) ? m[1] : string_t("0")) + "." +
1141                                                           ((m.length(2) != 0) ? m[2] : string_t("0")) + "." +
1142                                                           ((m.length(3) != 0) ? m[3] : string_t("0")) + "." +
1143                                                           ((m.length(4) != 0) ? m[4] : string_t("0"));
1144                                        }
1145                                }
1146                               
1147                                try
1148                                {                       
1149                                pimpl->ip_filter_.add_rule(asio::ip::address_v4::from_string(first),
1150                                        asio::ip::address_v4::from_string(last), lbt::ip_filter::blocked);     
1151                                }
1152                                catch(...)
1153                                {
1154                                        hal::event().post(shared_ptr<hal::EventDetail>(
1155                                                new hal::EventDebug(hal::Event::info, 
1156                                                        from_utf8((format_t("Invalid IP range: %1%-%2%.") % first % last).str()))));
1157                                }
1158                        }
1159                }
1160        }
1161       
1162        pimpl->ip_filter_changed_ = true;
1163        pimpl->ip_filter_count();
1164       
1165        }
1166        catch(const std::exception& e)
1167        {
1168                event().post(shared_ptr<EventDetail>(
1169                        new EventStdException(Event::critical, e, L"ip_filter_import_dat")));
1170        }
1171}
1172
1173const SessionDetail BitTorrent::getSessionDetails()
1174{
1175        SessionDetail details;
1176       
1177        details.port = pimpl->theSession.is_listening() ? pimpl->theSession.listen_port() : -1;
1178       
1179        lbt::session_status status = pimpl->theSession.status();
1180       
1181        details.speed = std::pair<double, double>(status.download_rate, status.upload_rate);
1182       
1183        details.dht_on = pimpl->dht_on_;
1184        details.dht_nodes = status.dht_nodes;
1185        details.dht_torrents = status.dht_torrents;
1186       
1187        details.ip_filter_on = pimpl->ip_filter_on_;
1188        details.ip_ranges_filtered = pimpl->ip_filter_count_;
1189       
1190        return details;
1191}
1192
1193void BitTorrent::setSessionHalfOpenLimit(int halfConn)
1194{
1195        pimpl->theSession.set_max_half_open_connections(halfConn);
1196
1197        event().post(shared_ptr<EventDetail>(new EventMsg(
1198                wformat_t(L"Set half-open connections limit to %1%.") % pimpl->theSession.max_half_open_connections())));
1199}
1200
1201void BitTorrent::setTorrentDefaults(int maxConn, int maxUpload, float download, float upload)
1202{
1203        pimpl->defTorrentMaxConn_ = maxConn;
1204        pimpl->defTorrentMaxUpload_ = maxUpload;
1205
1206        event().post(shared_ptr<EventDetail>(new EventMsg(
1207                wformat_t(L"Set torrent connections total %1% and uploads %2%.") % maxConn % maxUpload)));
1208
1209        pimpl->defTorrentDownload_ = download;
1210        pimpl->defTorrentUpload_ = upload;
1211
1212        event().post(shared_ptr<EventDetail>(new EventMsg(
1213                wformat_t(L"Set torrent default rates at %1$.2fkb/s down and %2$.2fkb/s upload.") % download % upload)));
1214}
1215
1216std::pair<lbt::entry, lbt::entry> BitTorrent_impl::prepTorrent(wpath_t filename, wpath_t saveDirectory)
1217{
1218        lbt::entry metadata = haldecode(filename);
1219        lbt::torrent_info info(metadata);
1220       
1221        wstring_t torrentName = hal::from_utf8_safe(info.name());
1222        if (!boost::find_last(torrentName, L".torrent")) 
1223                torrentName += L".torrent";
1224       
1225        wpath_t torrentFilename = torrentName;
1226        const wpath_t resumeFile = workingDirectory/L"resume"/torrentFilename.leaf();
1227       
1228        //  vvv Handle old naming style!
1229        const wpath_t oldResumeFile = workingDirectory/L"resume"/filename.leaf();
1230       
1231        if (filename.leaf() != torrentFilename.leaf() && exists(oldResumeFile))
1232                fs::rename(oldResumeFile, resumeFile);
1233        //  ^^^ Handle old naming style!       
1234       
1235        lbt::entry resumeData; 
1236       
1237        if (fs::exists(resumeFile)) 
1238        {
1239                try 
1240                {
1241                        resumeData = haldecode(resumeFile);
1242                }
1243                catch(std::exception &e) 
1244                {               
1245                        hal::event().post(boost::shared_ptr<hal::EventDetail>(
1246                                new hal::EventStdException(Event::critical, e, L"prepTorrent, Resume"))); 
1247       
1248                        fs::remove(resumeFile);
1249                }
1250        }
1251
1252        if (!fs::exists(workingDirectory/L"torrents"))
1253                fs::create_directory(workingDirectory/L"torrents");
1254
1255        if (!fs::exists(workingDirectory/L"torrents"/torrentFilename.leaf()))
1256                fs::copy_file(filename.string(), workingDirectory/L"torrents"/torrentFilename.leaf());
1257
1258        if (!fs::exists(saveDirectory))
1259                fs::create_directory(saveDirectory);
1260       
1261        return std::make_pair(metadata, resumeData);
1262}
1263
1264void BitTorrent::addTorrent(wpath_t file, wpath_t saveDirectory, bool startStopped, bool compactStorage, 
1265                boost::filesystem::wpath moveToDirectory, bool useMoveTo) 
1266{
1267        try 
1268        {       
1269       
1270        TorrentInternal_ptr TIp;
1271       
1272        if (useMoveTo)
1273                TIp.reset(new TorrentInternal(file, saveDirectory, compactStorage, moveToDirectory));           
1274        else
1275                TIp.reset(new TorrentInternal(file, saveDirectory, compactStorage));
1276       
1277        std::pair<TorrentManager::torrentByName::iterator, bool> p =
1278                pimpl->theTorrents.insert(TIp);
1279       
1280        if (p.second)
1281        {
1282                TorrentInternal_ptr me = pimpl->theTorrents.get(TIp->name());
1283               
1284                me->setTransferSpeed(bittorrent().defTorrentDownload(), bittorrent().defTorrentUpload());
1285                me->setConnectionLimit(bittorrent().defTorrentMaxConn(), bittorrent().defTorrentMaxUpload());
1286               
1287                if (!startStopped) me->addToSession();
1288        }
1289       
1290        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(to_utf8(file.string()), "addTorrent")
1291}
1292
1293void add_files(lbt::torrent_info& t, fs::path const& p, fs::path const& l)
1294{
1295/*      fs::path f(p / l);
1296        if (fs::is_directory(f))
1297        {
1298                for (fs::directory_iterator i(f), end; i != end; ++i)
1299                        add_files(t, p, l / i->leaf());
1300        }
1301        else
1302        {
1303        //      std::cerr << "adding \"" << l.string() << "\"\n";
1304                lbt::file fi(f, lbt::file::in);
1305                fi.seek(0, lbt::file::end);
1306                libtorrent::size_type size = fi.tell();
1307                t.add_file(l, size);
1308        }
1309*/
1310}
1311
1312void BitTorrent::newTorrent(wpath_t filename, wpath_t files)
1313{
1314/*      try
1315        {
1316       
1317        libtorrent::torrent_info t;
1318        path full_path = pimpl->workingDirectory/"incoming"/files.leaf();
1319       
1320        ofstream out(filename, std::ios_base::binary);
1321       
1322        int piece_size = 256 * 1024;
1323        char const* creator_str = "Halite v0.3 (libtorrent v0.11)";
1324
1325        add_files(t, full_path.branch_path(), full_path.leaf());
1326        t.set_piece_size(piece_size);
1327
1328        lbt::storage st(t, full_path.branch_path());
1329        t.add_tracker("http://www.nitcom.com.au/announce.php");
1330        t.set_priv(false);
1331        t.add_node(make_pair("192.168.11.12", 6881));
1332
1333        // calculate the hash for all pieces
1334        int num = t.num_pieces();
1335        std::vector<char> buf(piece_size);
1336        for (int i = 0; i < num; ++i)
1337        {
1338                        st.read(&buf[0], i, 0, t.piece_size(i));
1339                        libtorrent::hasher h(&buf[0], t.piece_size(i));
1340                        t.set_hash(i, h.final());
1341                //      std::cerr << (i+1) << "/" << num << "\r";
1342        }
1343
1344        t.set_creator(creator_str);
1345
1346        // create the torrent and print it to out
1347        lbt::entry e = t.create_torrent();
1348        lbt::bencode(std::ostream_iterator<char>(out), e);
1349        }
1350        catch (std::exception& e)
1351        {
1352                ::MessageBoxA(0, e.what(), "Create Torrent exception.", 0);
1353        }
1354*/
1355}
1356
1357const TorrentDetails& BitTorrent::torrentDetails()
1358{
1359        return torrentDetails_;
1360}
1361
1362const TorrentDetails& BitTorrent::updateTorrentDetails(const wstring_t& focused, const std::set<wstring_t>& selected)
1363{
1364        try {
1365       
1366        mutex_t::scoped_lock l(torrentDetails_.mutex_); 
1367       
1368        torrentDetails_.clearAll(l);   
1369        torrentDetails_.torrents_.reserve(pimpl->theTorrents.size());
1370       
1371        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); i != e; ++i)
1372        {
1373                wstring_t utf8Name = (*i).torrent->name();
1374                TorrentDetail_ptr pT = (*i).torrent->getTorrentDetail_ptr();
1375               
1376                if (selected.find(utf8Name) != selected.end())
1377                {
1378                        torrentDetails_.selectedTorrents_.push_back(pT);
1379                }
1380               
1381                if (focused == utf8Name)
1382                        torrentDetails_.selectedTorrent_ = pT;
1383               
1384                torrentDetails_.torrentMap_[(*i).torrent->name()] = pT;
1385                torrentDetails_.torrents_.push_back(pT);
1386        }
1387       
1388        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "updateTorrentDetails")
1389       
1390        return torrentDetails_;
1391}
1392
1393void BitTorrent::resumeAll()
1394{
1395        try {
1396               
1397        event().post(shared_ptr<EventDetail>(new EventMsg(L"Resuming torrent.")));
1398       
1399        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); i != e;)
1400        {
1401                wpath_t file = wpath_t(pimpl->workingDirectory)/L"torrents"/(*i).torrent->filename();
1402               
1403                if (exists(file))
1404                {               
1405                        try 
1406                        {
1407                               
1408                        (*i).torrent->prepare(file, (*i).torrent->saveDirectory());     
1409
1410                        switch ((*i).torrent->state())
1411                        {
1412                                case TorrentDetail::torrent_stopped:
1413                                        break;
1414                                case TorrentDetail::torrent_paused:
1415                                        (*i).torrent->addToSession(true);
1416                                        break;
1417                                case TorrentDetail::torrent_active:
1418                                        (*i).torrent->addToSession(false);
1419                                        break;
1420                                default:
1421                                        assert(false);
1422                        };
1423                       
1424                        ++i;
1425                       
1426                        }
1427                        catch(const lbt::duplicate_torrent&)
1428                        {
1429                                hal::event().post(shared_ptr<hal::EventDetail>(
1430                                        new hal::EventDebug(hal::Event::debug, L"Encountered duplicate torrent")));
1431                               
1432                                ++i; // Harmless, don't worry about it.
1433                        }
1434                        catch(const std::exception& e) 
1435                        {
1436                                hal::event().post(shared_ptr<hal::EventDetail>(
1437                                        new hal::EventStdException(hal::Event::warning, e, L"resumeAll")));
1438                               
1439                                pimpl->theTorrents.erase(i++);
1440                        }                       
1441                }
1442                else
1443                {
1444                        pimpl->theTorrents.erase(i++);
1445                }
1446        }
1447       
1448        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "resumeAll")
1449}
1450
1451void BitTorrent::closeAll()
1452{
1453        try {
1454       
1455        event().post(shared_ptr<EventDetail>(new EventInfo(L"Stopping all torrents...")));
1456       
1457        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1458                i != e; ++i)
1459        {
1460                if ((*i).torrent->inSession())
1461                {
1462                        (*i).torrent->handle().pause(); // Internal pause, not registered in Torrents.xml
1463                }
1464        }
1465       
1466        // Ok this polling loop here is a bit curde, but a blocking wait is actually appropiate.
1467        for (bool nonePaused = true; !nonePaused; )
1468        {
1469                for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1470                                i != e; ++i)
1471                {
1472                        // NB. this checks for an internal paused state.
1473                        nonePaused &= ((*i).torrent->inSession() ? (*i).torrent->handle().is_paused() : true);
1474                }
1475               
1476                Sleep(200);
1477        }
1478       
1479        event().post(shared_ptr<EventDetail>(new EventInfo(L"All torrents stopped.")));
1480               
1481        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end(); 
1482                i != e; ++i)
1483        {
1484                if ((*i).torrent->inSession())
1485                {
1486                        (*i).torrent->removeFromSession();
1487                        (*i).torrent->writeResumeData();
1488                }
1489        }
1490       
1491        event().post(shared_ptr<EventDetail>(new EventInfo(L"Fast-resume data written.")));
1492       
1493        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "closeAll")
1494}
1495
1496PeerDetail::PeerDetail(lbt::peer_info& peerInfo) :
1497        ipAddress(hal::from_utf8_safe(peerInfo.ip.address().to_string())),
1498        country(L""),
1499        speed(std::make_pair(peerInfo.payload_down_speed, peerInfo.payload_up_speed)),
1500        client(hal::from_utf8_safe(peerInfo.client))
1501{
1502        std::vector<wstring_t> status_vec;
1503       
1504#ifndef TORRENT_DISABLE_RESOLVE_COUNTRIES
1505        if (peerInfo.country[0] != 0 && peerInfo.country[1] != 0)
1506                country = (wformat_t(L"(%1%)") % hal::from_utf8_safe(string_t(peerInfo.country, 2))).str().c_str();
1507#endif 
1508
1509        if (peerInfo.flags & lbt::peer_info::handshake)
1510        {
1511                status_vec.push_back(app().res_wstr(HAL_PEER_HANDSHAKE));
1512        }               
1513        else if (peerInfo.flags & lbt::peer_info::connecting)
1514        {
1515                status_vec.push_back(app().res_wstr(HAL_PEER_CONNECTING));
1516        }
1517        else
1518        {
1519        #ifndef TORRENT_DISABLE_ENCRYPTION             
1520                if (peerInfo.flags & lbt::peer_info::rc4_encrypted)
1521                        status_vec.push_back(app().res_wstr(HAL_PEER_RC4_ENCRYPTED));           
1522                if (peerInfo.flags & lbt::peer_info::plaintext_encrypted)
1523                        status_vec.push_back(app().res_wstr(HAL_PEER_PLAINTEXT_ENCRYPTED));
1524        #endif
1525               
1526                if (peerInfo.flags & lbt::peer_info::interesting)
1527                        status_vec.push_back(app().res_wstr(HAL_PEER_INTERESTING));     
1528                if (peerInfo.flags & lbt::peer_info::choked)
1529                        status_vec.push_back(app().res_wstr(HAL_PEER_CHOKED)); 
1530                if (peerInfo.flags & lbt::peer_info::remote_interested)
1531                        status_vec.push_back(app().res_wstr(HAL_PEER_REMOTE_INTERESTING));     
1532                if (peerInfo.flags & lbt::peer_info::remote_choked)
1533                        status_vec.push_back(app().res_wstr(HAL_PEER_REMOTE_CHOKED));   
1534                if (peerInfo.flags & lbt::peer_info::supports_extensions)
1535                        status_vec.push_back(app().res_wstr(HAL_PEER_SUPPORT_EXTENSIONS));     
1536        //      if (peerInfo.flags & lbt::peer_info::local_connection)                                          // Not sure whats up here?
1537        //              status_vec.push_back(app().res_wstr(HAL_PEER_LOCAL_CONNECTION));                       
1538                if (peerInfo.flags & lbt::peer_info::queued)
1539                        status_vec.push_back(app().res_wstr(HAL_PEER_QUEUED));
1540        }
1541       
1542        seed = (peerInfo.flags & lbt::peer_info::seed) ? true : false;
1543       
1544        if (!status_vec.empty()) status = status_vec[0];
1545       
1546        if (status_vec.size() > 1)
1547        {
1548                for (size_t i=1; i<status_vec.size(); ++i)
1549                {
1550                        status += L"; ";
1551                        status += status_vec[i];
1552                }
1553        }       
1554}
1555
1556void BitTorrent::getAllPeerDetails(const std::string& filename, PeerDetails& peerContainer)
1557{
1558        getAllPeerDetails(from_utf8_safe(filename), peerContainer);
1559}
1560
1561void BitTorrent::getAllPeerDetails(const std::wstring& filename, PeerDetails& peerContainer)
1562{
1563        try {
1564       
1565        pimpl->theTorrents.get(filename)->getPeerDetails(peerContainer);
1566       
1567        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getAllPeerDetails")
1568}
1569
1570void BitTorrent::getAllFileDetails(const std::string& filename, FileDetails& fileDetails)
1571{
1572        getAllFileDetails(from_utf8_safe(filename), fileDetails);
1573}
1574
1575void BitTorrent::getAllFileDetails(const std::wstring& filename, FileDetails& fileDetails)
1576{
1577        try {
1578       
1579        pimpl->theTorrents.get(filename)->getFileDetails(fileDetails);
1580       
1581        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getAllFileDetails")
1582}
1583
1584bool BitTorrent::isTorrent(const std::string& filename)
1585{       
1586        return isTorrent(hal::to_wstr_shim(filename));
1587}
1588
1589bool BitTorrent::isTorrent(const std::wstring& filename)
1590{       
1591        try {
1592       
1593        return pimpl->theTorrents.exists(filename);
1594       
1595        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "isTorrent")
1596       
1597        return false;
1598}
1599
1600void BitTorrent::pauseTorrent(const std::string& filename)
1601{
1602        pauseTorrent(hal::to_wstr_shim(filename));
1603}
1604
1605void BitTorrent::pauseTorrent(const std::wstring& filename)
1606{
1607        try {
1608       
1609        pimpl->theTorrents.get(filename)->pause();
1610       
1611        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "pauseTorrent")
1612}
1613
1614void BitTorrent::resumeTorrent(const std::string& filename)
1615{
1616        resumeTorrent(hal::to_wstr_shim(filename));
1617}
1618
1619void BitTorrent::resumeTorrent(const std::wstring& filename)
1620{
1621        try {
1622       
1623        pimpl->theTorrents.get(filename)->resume();
1624       
1625        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "resumeTorrent")
1626}
1627
1628void BitTorrent::stopTorrent(const std::string& filename)
1629{
1630        stopTorrent(hal::to_wstr_shim(filename));
1631}
1632
1633void BitTorrent::stopTorrent(const std::wstring& filename)
1634{
1635        try {
1636       
1637        pimpl->theTorrents.get(filename)->stop();
1638       
1639        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "stopTorrent")
1640}
1641
1642bool BitTorrent::isTorrentActive(const std::string& filename)
1643{
1644        return isTorrentActive(hal::to_wstr_shim(filename));
1645}
1646
1647bool BitTorrent::isTorrentActive(const std::wstring& filename)
1648{
1649        try {
1650       
1651        return pimpl->theTorrents.get(filename)->isActive();
1652       
1653        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "isTorrentActive")
1654       
1655        return false; // ??? is this correct
1656}
1657
1658void BitTorrent::reannounceTorrent(const std::string& filename)
1659{
1660        reannounceTorrent(hal::to_wstr_shim(filename));
1661}
1662
1663void BitTorrent::reannounceTorrent(const std::wstring& filename)
1664{
1665        try {
1666       
1667        pimpl->theTorrents.get(filename)->handle().force_reannounce();
1668       
1669        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "reannounceTorrent")
1670}
1671
1672void BitTorrent::setTorrentLogin(const std::string& filename, std::wstring username, std::wstring password)
1673{
1674        setTorrentLogin(hal::to_wstr_shim(filename), username, password);
1675}
1676
1677void BitTorrent::setTorrentLogin(const std::wstring& filename, std::wstring username, std::wstring password)
1678{
1679        try {
1680       
1681        pimpl->theTorrents.get(filename)->setTrackerLogin(username, password);
1682       
1683        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentLogin")
1684}
1685
1686std::pair<std::wstring, std::wstring> BitTorrent::getTorrentLogin(const std::string& filename)
1687{
1688        return getTorrentLogin(hal::to_wstr_shim(filename));
1689}
1690
1691std::pair<std::wstring, std::wstring> BitTorrent::getTorrentLogin(const std::wstring& filename)
1692{
1693        try {
1694       
1695        return pimpl->theTorrents.get(filename)->getTrackerLogin();
1696       
1697        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentLogin")
1698       
1699        return std::make_pair(L"", L"");
1700}
1701
1702void BitTorrent_impl::removalThread(TorrentInternal_ptr pIT, bool wipeFiles)
1703{
1704        try {
1705
1706        if (!wipeFiles)
1707        {
1708                theSession.remove_torrent(pIT->handle());
1709        }
1710        else
1711        {
1712                if (pIT->inSession())
1713                {
1714                        theSession.remove_torrent(pIT->handle(), lbt::session::delete_files);
1715                }
1716                else
1717                {
1718                        lbt::torrent_info m_info = pIT->infoMemory();
1719                       
1720                        // delete the files from disk
1721                        std::string error;
1722                        std::set<std::string> directories;
1723                       
1724                        for (lbt::torrent_info::file_iterator i = m_info.begin_files(true)
1725                                , end(m_info.end_files(true)); i != end; ++i)
1726                        {
1727                                std::string p = (hal::to_utf8(pIT->saveDirectory()) / i->path).string();
1728                                fs::path bp = i->path.branch_path();
1729                               
1730                                std::pair<std::set<std::string>::iterator, bool> ret;
1731                                ret.second = true;
1732                                while (ret.second && !bp.empty())
1733                                {
1734                                        std::pair<std::set<std::string>::iterator, bool> ret = 
1735                                                directories.insert((hal::to_utf8(pIT->saveDirectory()) / bp).string());
1736                                        bp = bp.branch_path();
1737                                }
1738                                if (!fs::remove(hal::from_utf8(p).c_str()) && errno != ENOENT)
1739                                        error = std::strerror(errno);
1740                        }
1741
1742                        // remove the directories. Reverse order to delete subdirectories first
1743
1744                        for (std::set<std::string>::reverse_iterator i = directories.rbegin()
1745                                , end(directories.rend()); i != end; ++i)
1746                        {
1747                                if (!fs::remove(hal::from_utf8(*i).c_str()) && errno != ENOENT)
1748                                        error = std::strerror(errno);
1749                        }
1750                }
1751        }
1752
1753        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "removalThread")
1754}
1755
1756void BitTorrent::removeTorrent(const std::string& filename)
1757{
1758        removeTorrent(hal::to_wstr_shim(filename));
1759}
1760
1761void BitTorrent::removeTorrent(const std::wstring& filename)
1762{
1763        try {
1764       
1765        TorrentInternal_ptr pTI = pimpl->theTorrents.get(filename);
1766        lbt::torrent_handle handle = pTI->handle();
1767        pimpl->theTorrents.erase(filename);
1768       
1769        thread_t t(bind(&BitTorrent_impl::removalThread, &*pimpl, pTI, false)); 
1770       
1771        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "removeTorrent")
1772}
1773
1774void BitTorrent::recheckTorrent(const std::string& filename)
1775{
1776        recheckTorrent(hal::to_wstr_shim(filename));
1777}
1778
1779void BitTorrent::recheckTorrent(const std::wstring& filename)
1780{
1781        try {
1782       
1783        pimpl->theTorrents.get(filename)->forceRecheck();
1784       
1785        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "recheckTorrent")
1786}
1787
1788void BitTorrent::removeTorrentWipeFiles(const std::string& filename)
1789{
1790        removeTorrentWipeFiles(hal::to_wstr_shim(filename));
1791}
1792
1793void BitTorrent::removeTorrentWipeFiles(const std::wstring& filename)
1794{
1795        try {
1796       
1797        TorrentInternal_ptr pTI = pimpl->theTorrents.get(filename);
1798        lbt::torrent_handle handle = pTI->handle();
1799        pimpl->theTorrents.erase(filename);
1800       
1801        thread_t t(bind(&BitTorrent_impl::removalThread, &*pimpl, pTI, true)); 
1802       
1803        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "removeTorrentWipeFiles")
1804}
1805
1806void BitTorrent::pauseAllTorrents()
1807{       
1808        try {
1809       
1810        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end();
1811                i != e; ++i)
1812        {               
1813                if ((*i).torrent->inSession())
1814                        (*i).torrent->pause();
1815        }
1816       
1817        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "pauseAllTorrents")
1818}
1819
1820void BitTorrent::unpauseAllTorrents()
1821{       
1822        try {
1823       
1824        for (TorrentManager::torrentByName::iterator i=pimpl->theTorrents.begin(), e=pimpl->theTorrents.end();
1825                i != e; ++i)
1826        {
1827                if ((*i).torrent->inSession() && (*i).torrent->state() == TorrentDetail::torrent_paused)
1828                        (*i).torrent->resume();
1829        }
1830       
1831        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH("Torrent Unknown!", "unpauseAllTorrents")
1832}
1833
1834void BitTorrent::setTorrentLimit(const std::string& filename, int maxConn, int maxUpload)
1835{
1836        setTorrentLimit(hal::from_utf8_safe(filename), maxConn, maxUpload);
1837}
1838
1839void BitTorrent::setTorrentLimit(const std::wstring& filename, int maxConn, int maxUpload)
1840{
1841        try {
1842       
1843        pimpl->theTorrents.get(filename)->setConnectionLimit(maxConn, maxUpload);
1844       
1845        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentLimit")
1846}
1847
1848void BitTorrent::setTorrentRatio(const std::string& filename, float ratio)
1849{
1850        setTorrentRatio(hal::from_utf8_safe(filename), ratio);
1851}
1852
1853void BitTorrent::setTorrentRatio(const std::wstring& filename, float ratio)
1854{
1855        try {
1856       
1857        pimpl->theTorrents.get(filename)->setRatio(ratio);
1858       
1859        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentRatio")
1860}
1861
1862float BitTorrent::getTorrentRatio(const std::string& filename)
1863{
1864        return getTorrentRatio(hal::from_utf8_safe(filename));
1865}
1866
1867float BitTorrent::getTorrentRatio(const std::wstring& filename)
1868{
1869        try {
1870       
1871        return pimpl->theTorrents.get(filename)->getRatio();
1872       
1873        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentRatio")
1874       
1875        return 0;
1876}
1877
1878void BitTorrent::setTorrentSpeed(const std::string& filename, float download, float upload)
1879{
1880        setTorrentSpeed(hal::from_utf8_safe(filename), download, upload);
1881}
1882
1883void BitTorrent::setTorrentSpeed(const std::wstring& filename, float download, float upload)
1884{
1885        try {
1886       
1887        pimpl->theTorrents.get(filename)->setTransferSpeed(download, upload);
1888       
1889        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentSpeed")
1890}
1891
1892std::pair<int, int> BitTorrent::getTorrentLimit(const std::string& filename)
1893{
1894        return getTorrentLimit(from_utf8_safe(filename));
1895}
1896
1897std::pair<int, int> BitTorrent::getTorrentLimit(const std::wstring& filename)
1898{
1899        try {
1900       
1901        return pimpl->theTorrents.get(filename)->getConnectionLimit();
1902       
1903        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentLimit")
1904       
1905        return std::pair<int, int>(0, 0);
1906}
1907
1908std::pair<float, float> BitTorrent::getTorrentSpeed(const std::string& filename)
1909{
1910        return getTorrentSpeed(from_utf8_safe(filename));
1911}
1912
1913std::pair<float, float> BitTorrent::getTorrentSpeed(const std::wstring& filename)
1914{
1915        try {
1916       
1917        return pimpl->theTorrents.get(filename)->getTransferSpeed();
1918       
1919        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentSpeed")
1920       
1921        return std::pair<float, float>(0, 0);
1922}
1923
1924void BitTorrent::setTorrentFilePriorities(const std::string& filename, 
1925        std::vector<int> fileIndices, int priority)
1926{
1927        setTorrentFilePriorities(from_utf8_safe(filename), fileIndices, priority);
1928}
1929
1930void BitTorrent::setTorrentFilePriorities(const std::wstring& filename, 
1931        std::vector<int> fileIndices, int priority)
1932{
1933        try {
1934       
1935        pimpl->theTorrents.get(filename)->setFilePriorities(fileIndices, priority);
1936       
1937        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentFilePriorities")
1938}
1939
1940void BitTorrent::setTorrentTrackers(const std::string& filename, 
1941        const std::vector<TrackerDetail>& trackers)
1942{
1943        setTorrentTrackers(from_utf8_safe(filename), trackers);
1944}
1945
1946void BitTorrent::setTorrentTrackers(const std::wstring& filename, 
1947        const std::vector<TrackerDetail>& trackers)
1948{
1949        try {
1950       
1951        pimpl->theTorrents.get(filename)->setTrackers(trackers);
1952       
1953        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "setTorrentTrackers")
1954}
1955
1956void BitTorrent::resetTorrentTrackers(const std::string& filename)
1957{
1958        resetTorrentTrackers(from_utf8_safe(filename));
1959}
1960
1961void BitTorrent::resetTorrentTrackers(const std::wstring& filename)
1962{
1963        try {
1964       
1965        pimpl->theTorrents.get(filename)->resetTrackers();
1966       
1967        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "resetTorrentTrackers")
1968}
1969
1970std::vector<TrackerDetail> BitTorrent::getTorrentTrackers(const std::string& filename)
1971{
1972        return getTorrentTrackers(from_utf8_safe(filename));
1973}
1974
1975std::vector<TrackerDetail> BitTorrent::getTorrentTrackers(const std::wstring& filename)
1976{
1977        try {
1978       
1979        return pimpl->theTorrents.get(filename)->getTrackers();
1980       
1981        } HAL_GENERIC_TORRENT_EXCEPTION_CATCH(filename, "getTorrentTrackers")
1982       
1983        return std::vector<TrackerDetail>();   
1984}
1985
1986void BitTorrent::startEventReceiver()
1987{
1988        pimpl->keepChecking_ = true;
1989        thread_t(bind(&asio::io_service::run, &pimpl->io_));
1990}
1991
1992void BitTorrent::stopEventReceiver()
1993{
1994        pimpl->keepChecking_ = false;
1995}
1996
1997int BitTorrent::defTorrentMaxConn() { return pimpl->defTorrentMaxConn_; }
1998int BitTorrent::defTorrentMaxUpload() { return pimpl->defTorrentMaxUpload_; }
1999float BitTorrent::defTorrentDownload() { return pimpl->defTorrentDownload_; }
2000float BitTorrent::defTorrentUpload() { return pimpl->defTorrentUpload_; }
2001       
2002};
2003
Note: See TracBrowser for help on using the repository browser.