source: src/halTorrent.cpp @ 338

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