Changeset 2913

Show
Ignore:
Timestamp:
04/23/06 12:17:48 (3 years ago)
Author:
madcat
Message:

Multi-tracker support.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • hydranode/hncore/bt/Jamfile

    r2430 r2913  
    22project cmod_bt ; 
    33 
    4 local BT_SOURCES = bencoder torrentinfo files torrent bittorrent client
     4local BT_SOURCES = bencoder bittorrent client files torrentinfo torrent tracker
    55hn.plugin : $(BT_SOURCES).cpp ; 
    66exe bget 
  • hydranode/hncore/bt/client.cpp

    r2889 r2913  
    106106 
    107107        m_socket->setHandler(this, &Client::onSocketEvent); 
    108         m_socket->connect(addr, 5000); 
     108        m_socket->connect(addr, 30000); 
    109109        Utils::timedCallback(boost::bind(&Client::sendPing, this), 2*60*1000); 
    110110} 
  • hydranode/hncore/bt/torrent.cpp

    r2834 r2913  
    2525#include <hncore/partdata.h> 
    2626#include <hncore/bt/torrent.h> 
    27 #include <hncore/bt/protocol.h> 
    2827#include <hncore/bt/client.h> 
    2928#include <hncore/bt/bittorrent.h> 
     29#include <hncore/bt/tracker.h> 
    3030#include <hnbase/timed_callback.h> 
    31 #include <boost/spirit.hpp> 
    32 #include <boost/spirit/dynamic/if.hpp> 
    33 #include <boost/spirit/dynamic/while.hpp> 
    34 #include <boost/spirit/actor/clear_actor.hpp> 
    35 #include <boost/tokenizer.hpp> 
    36 #include <boost/algorithm/string/case_conv.hpp> 
    37 #include <boost/lambda/construct.hpp> 
    38 #include <boost/lambda/bind.hpp> 
    3931#include <boost/multi_index_container.hpp> 
    4032#include <boost/multi_index/member.hpp> 
     
    4234#include <boost/multi_index/ordered_index.hpp> 
    4335#include <boost/multi_index/sequenced_index.hpp> 
     36#include <boost/lambda/construct.hpp> 
     37#include <boost/lambda/bind.hpp> 
     38#include <boost/spirit.hpp> 
    4439 
    4540namespace Bt { 
     
    4742const std::string TORRENT("bt.torrent"); 
    4843 
    49 //! Temporary structure for usage during tracker response parsing 
    50 struct Peer { 
    51         Peer() : m_cip(), m_port() {} 
    52         std::string m_id; 
    53         std::string m_ip; 
    54         uint32_t m_cip; 
    55         uint16_t m_port; 
    56         void clear() { 
    57                 m_id.clear(); 
    58                 m_ip.clear(); 
    59                 m_port = 0; 
    60                 m_cip = 0; 
    61         } 
    62 }; 
    63  
     44// Torrent class 
     45// ------------- 
    6446IMPLEMENT_EVENT_TABLE(Torrent, Torrent*, int); 
    6547 
    6648Torrent::Torrent(SharedFile *file, const TorrentInfo &info) 
    67 : m_file(file), m_partData(), m_info(info), m_socket(), m_trackerPort(80), 
    68 m_interval(), m_minInterval(), m_completeSrc(), m_partialSrc(), 
    69 m_uploaded(), m_downloaded() { 
     49: m_file(file), m_partData(), m_info(info), m_uploaded(),  
     50m_downloaded() { 
    7051        CHECK_THROW(file); 
    7152 
     
    7455        using namespace boost::spirit; 
    7556 
    76         std::string tmp = info.getAnnounceUrl(); 
    77         parse_info<> nfo = parse( 
    78                 tmp.data(), tmp.data() + tmp.size(), 
    79                 (str_p("http://") | str_p("udp://")) 
    80                 >> *( ( ':' >> uint_p[assign_a(m_trackerPort)] ) 
    81                     | ( '/' >> *graph_p[push_back_a(m_trackerUrl)] >> end_p) 
    82                     |   graph_p[push_back_a(m_trackerHost)] 
    83                     ) 
    84         ); 
    85         m_trackerIp.push_back(IPV4Address(m_trackerHost, m_trackerPort)); 
    86         m_curIp = m_trackerIp.begin(); 
    87         if ( 
    88                 m_trackerIp[0].getAddr() < std::numeric_limits<uint32_t>::max() 
    89                 && m_trackerIp[0].getPort() > 0 
    90         ) { 
    91                 connectToTracker(*m_curIp); 
    92         } else if (nfo.full) { 
    93                 m_trackerIp.clear(); 
    94                 m_curIp = m_trackerIp.end(); 
    95                 lookupTrackerHost(); 
    96         } else { 
    97                 logDebug(boost::format("Parse failed at %s") % nfo.stop); 
     57        TorrentInfo::AIter i = info.announceBegin(); 
     58        while (i != info.announceEnd()) { 
     59                std::string tmp = *i; 
     60                std::string host, url; 
     61                uint16_t port = 80; 
     62                parse_info<> nfo = parse( 
     63                        tmp.data(), tmp.data() + tmp.size(), 
     64                        (str_p("http://") | str_p("udp://")) 
     65                        >> *( ( ':' >> uint_p[assign_a(port)] ) 
     66                            | ( '/' >> *graph_p[push_back_a(url)] >> end_p) 
     67                            |   graph_p[push_back_a(host)] 
     68                            ) 
     69                ); 
     70                try { 
     71                        Tracker *tr = new Tracker(host, url, port, info); 
     72                        tr->foundPeer.connect( 
     73                                boost::bind(&Torrent::createClient, this, _1) 
     74                        ); 
     75                        tr->getUploaded.connect( 
     76                                boost::bind(&Torrent::getUploaded, this) 
     77                        ); 
     78                        tr->getDownloaded.connect( 
     79                                boost::bind(&Torrent::getDownloaded, this) 
     80                        ); 
     81                        tr->getPartData.connect( 
     82                                boost::bind(&Torrent::getPartData, this) 
     83                        ); 
     84                        m_trackers.insert(tr); 
     85                } catch (std::exception &e) { 
     86                        logDebug(boost::format("Tracker: %s") % e.what()); 
     87                } 
     88                ++i; 
    9889        } 
    9990 
     
    140131        using namespace boost::lambda; 
    141132        for_each(m_clients.begin(), m_clients.end(), bind(delete_ptr(), __1)); 
    142 
    143  
    144 void Torrent::lookupTrackerHost() { 
    145         DNS::lookup(m_trackerHost, this, &Torrent::onResolverEvent); 
    146         logMsg("Looking up host " + m_trackerHost + "... "); 
    147 
    148  
    149 void Torrent::onResolverEvent(HostInfo info) { 
    150         if (info.error()) { 
    151                 logError( 
    152                         boost::format("[%s] Host lookup failed: %s") 
    153                         % info.getName() % info.errorMsg() 
    154                 ); 
    155                 Utils::timedCallback(this, &Torrent::lookupTrackerHost, 60000); 
    156         } else { 
    157                 m_trackerIp = info.getAddresses(); 
    158                 for (uint32_t i = 0; i < m_trackerIp.size(); ++i) { 
    159                         m_trackerIp[i].setPort(m_trackerPort); 
    160                 } 
    161                 m_curIp = m_trackerIp.begin(); 
    162                 connectToTracker(*m_curIp); 
    163         } 
    164 
    165  
    166 void Torrent::connectToTracker(IPV4Address addr) try { 
    167         logMsg( 
    168                 boost::format("Connecting to tracker %s[%s]:%d...") 
    169                 % m_trackerHost % addr.getAddrStr() 
    170                 % m_trackerPort 
    171         ); 
    172         m_socket.reset(new TcpSocket(this, &Torrent::onSocketEvent)); 
    173         m_socket->connect(addr); 
    174 } catch (std::exception &e) { 
    175         logError( 
    176                 boost::format("[%s] Error connecting to tracker[%s]: %s") 
    177                 % getName() % m_trackerHost % e.what() 
    178         ); 
    179         onSocketEvent(m_socket.get(), SOCK_ERR); 
    180 
    181  
    182 void Torrent::onSocketEvent(TcpSocket *sock, SocketEvent evt) { 
    183         CHECK_RET(sock == m_socket.get()); 
    184  
    185         if (evt == SOCK_CONNECTED) { 
    186                 sendGetRequest(); 
    187         } else if (evt == SOCK_READ) { 
    188                 *m_socket >> m_inBuffer; 
    189                 parseBuffer(); 
    190         } else if ( 
    191                 evt == SOCK_CONNFAILED || evt == SOCK_TIMEOUT || 
    192                 evt == SOCK_ERR || evt == SOCK_LOST 
    193         ) { 
    194                 logError( 
    195                         boost::format( 
    196                                 "[%s] Connection to tracker failed/lost[%s]." 
    197                         ) % getName() % m_trackerHost 
    198                 ); 
    199                 if (m_inBuffer.size()) { 
    200                         parseBuffer(); 
    201                 } 
    202                 if (m_inBuffer.size()) { 
    203                         logDebug( 
    204                                 "Buffered data but did not parse: "  
    205                                 + Utils::hexDump(m_inBuffer) 
    206                         ); 
    207                 } 
    208                 m_socket.reset(); 
    209                 m_inBuffer.clear(); 
    210                 if (m_trackerIp.size() > 1) { 
    211                         if (m_curIp != m_trackerIp.end()) { 
    212                                 ++m_curIp; 
    213                         } 
    214                         if (m_curIp == m_trackerIp.end()) { 
    215                                 m_curIp = m_trackerIp.begin(); 
    216                         } 
    217                         connectToTracker(*m_curIp); 
    218                 } else if (m_interval) { 
    219                         Utils::timedCallback( 
    220                                 boost::bind( 
    221                                         &Torrent::connectToTracker, this, 
    222                                         *m_curIp 
    223                                 ), m_interval * 1000 
    224                         ); 
    225                         logMsg( 
    226                                 boost::format("[%s] Re-trying in %dm %ds.") 
    227                                 % m_trackerHost % (m_interval / 60) 
    228                                 % (m_interval % 60) 
    229                         ); 
    230                 } else if (!m_interval) { 
    231                         Utils::timedCallback( 
    232                                 boost::bind( 
    233                                         &Torrent::connectToTracker, this, 
    234                                         *m_curIp 
    235                                 ), 60000 
    236                         ); 
    237                 } 
    238         } else if (evt == SOCK_BLOCKED) { 
    239                 logError( 
    240                         boost::format( 
    241                                 "[%s] Connection attempt to the Tracker[%s] " 
    242                                 "was blocked by IpFilter!" 
    243                         ) % getName() % m_trackerHost 
    244                 ); 
    245         } 
    246 
    247  
    248 void Torrent::sendGetRequest() { 
    249         boost::format fmt( 
    250                 "GET /%s?%s HTTP/1.0\r\n" 
    251 //              "User-Agent: Hydranode 0.1.2;Linux\r\n" // optional 
    252                 "Connection: close\r\n" 
    253 //              "Accept-Encoding: gzip\r\n"  // we don't have gzip decompressor 
    254                 "Host: %s:%d\r\n" 
    255                 // these are just to be nice (Azureus sends them) 
    256 //              "Content-Type: application/x-www-form-urlencoded" 
    257 //              "Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2" 
    258         ); 
    259         fmt % m_trackerUrl; 
    260         std::ostringstream args; 
    261         args << "info_hash="  << Utils::urlEncode( 
    262                 m_info.getInfoHash().toString(), true 
    263         ) << "&"; 
    264         args << "peer_id="    << BitTorrent::instance().getId() << "&"; 
    265         args << "key="        << BitTorrent::instance().getKey() << "&"; 
    266         args << "port="       << BitTorrent::instance().getPort() << "&"; 
    267         args << "uploaded="   << m_uploaded << "&"; 
    268         args << "downloaded=" << m_downloaded << "&"; 
    269         if (m_partData) { 
    270                 args << "left="; 
    271                 args << m_partData->getSize() - m_partData->getCompleted(); 
    272                 args << "&"; 
    273         } else { 
    274                 args << "left=0&"; 
    275         } 
    276         if (!m_interval) { // if no interval, means we just started up 
    277                 args << "event="      << "started" << "&"; 
    278         } 
    279         args << "num_want="   << 80 << "&"; 
    280         args << "compact="    << 1; 
    281         fmt % args.str() % m_trackerHost % m_trackerPort; 
    282  
    283         std::string final = fmt.str(); 
    284         logTrace(TORRENT, "Sending HTTP GET request:\n" + final); 
    285         *m_socket << final << Socket::Endl << Socket::Endl; 
    286         float ratio = 0.0; 
    287         if (m_downloaded) { 
    288                 ratio = m_uploaded / m_downloaded; 
    289         } 
    290         logMsg( 
    291                 boost::format( 
    292                         "Torrent Statistics: Uploaded: %s " 
    293                         "Downloaded: %s Ratio: %5.3f" 
    294                 ) % Utils::bytesToString(m_uploaded) 
    295                 % Utils::bytesToString(m_downloaded) 
    296                 % ratio 
    297         ); 
    298 
    299  
    300 void Torrent::parseBuffer() { 
    301         using namespace boost::spirit; 
    302         uint32_t rc = 0; 
    303         std::string rcText; 
    304         uint32_t clen = 0; 
    305         std::string ctype; 
    306         std::string cenc, tenc; 
    307  
    308         std::string sepc("\r\n"); 
    309         uint32_t headerEnd = m_inBuffer.find(sepc + sepc); 
    310         if (headerEnd == std::string::npos) { 
    311                 headerEnd = m_inBuffer.find("\n\n"); 
    312                 if (headerEnd == std::string::npos) { 
    313                         return; 
    314                 } else { 
    315                         sepc = "\n"; 
    316                 } 
    317         } 
    318         std::string headerData = m_inBuffer.substr(0, headerEnd); 
    319         std::string contentData = m_inBuffer.substr(headerEnd + sepc.size()*2); 
    320         boost::char_separator<char> sep(sepc.c_str()); 
    321         boost::tokenizer<boost::char_separator<char> > tok(headerData, sep); 
    322         boost::tokenizer<boost::char_separator<char> >::iterator it( 
    323                 tok.begin() 
    324         ); 
    325         while (it != tok.end()) { 
    326                 std::string tmp(*it); 
    327                 parse_info<> info = parse( 
    328                         tmp.c_str(), 
    329                         ( 
    330                                 as_lower_d["content-length:"] 
    331                                 >> uint_p[assign_a(clen)] 
    332                         ) | ( 
    333                                 as_lower_d["content-type:"] 
    334                                 >> *anychar_p[push_back_a(ctype)] 
    335                         ) | ( 
    336                                 as_lower_d["content-encoding:"] 
    337                                 >> *anychar_p[push_back_a(cenc)] 
    338                         ) | ( 
    339                                 as_lower_d["transfer-encoding:"] 
    340                                 >> *anychar_p[push_back_a(tenc)] 
    341                         ) | ( 
    342                                 as_lower_d["http/"] >> uint_p >> '.' >> uint_p 
    343                                 >> uint_p[assign_a(rc)] 
    344                                 >> *anychar_p[push_back_a(rcText)] 
    345                         ) | *anychar_p 
    346                         , space_p 
    347                 ); 
    348                 ++it; 
    349         } 
    350         if (clen && contentData.size() != clen) { 
    351                 logTrace(TORRENT, "Dont have full content yet."); 
    352                 return; 
    353         } 
    354         if (tenc == "chunked") { 
    355                 // HTTP/1.1 protocol - doesn't work yet properly 
    356                 logTrace(TORRENT, "====" + contentData + "===="); 
    357                 int chunkLen; 
    358                 std::string content; 
    359                 parse_info<> info = parse( 
    360                         contentData.c_str(), 
    361                         hex_p[assign_a(chunkLen)] >> eol_p 
    362                         >> repeat_p(boost::ref(chunkLen)) 
    363                            [anychar_p[push_back_a(content)]] 
    364                         >> eol_p >> "0" >> eol_p >> eol_p 
    365                 ); 
    366                 if (info.full) { 
    367                         parseContent(content); 
    368                 } else { 
    369                         logDebug( 
    370                                 boost::format("Parse failed at: %s") % info.stop 
    371                         ); 
    372                         logDebug(boost::format("chunklen = %d") % chunkLen); 
    373                         logDebug(boost::format("content = %s") % content); 
    374                         return; 
    375                 } 
    376         } 
    377         logMsg(boost::format("HTTP reply from tracker: %d %s") % rc % rcText); 
    378 #ifndef NDEBUG 
    379         std::string tmpContent(contentData); 
    380         // get rid of non-printable characters 
    381         for (uint32_t i = 0; i < tmpContent.size(); ++i) { 
    382                 if (tmpContent[i] < 32 || tmpContent[i] > 126) { 
    383                         tmpContent.replace(i, 1, "."); 
    384                 } 
    385         } 
    386         logTrace(TORRENT, "Content data: " + tmpContent); 
    387 #endif 
    388         parseContent(contentData); 
    389 
    390  
    391 void Torrent::parseContent(const std::string &data) { 
    392         INIT_PARSER(); 
    393  
    394         std::string errorMsg, warningMsg, cpList; 
    395  
    396         std::vector<Peer> peerList; 
    397         Peer tmpPeer; 
    398         rule<> peer_list = 'l' >> *( 
    399                 'd' >> *( ("7:peer id" >> BSTR(tmpPeer.m_id)) 
    400                         | ("2:ip"      >> BSTR(tmpPeer.m_ip)) 
    401                         | ("4:port"    >> BINT(tmpPeer.m_port)) 
    402                         | unknown 
    403                         ) 
    404                 >> ch_p('e')[push_back_a(peerList, tmpPeer)][clear_a(tmpPeer)] 
    405         ) >> 'e'; 
    406  
    407         parse_info<> info = parse( 
    408                 data.data(), data.data() + data.size(), 
    409                 'd' >> *( ("14:failure reason"  >> BSTR(errorMsg)) 
    410                         | ("15:warning message" >> BSTR(warningMsg)) 
    411                         | ("8:interval"         >> BINT(m_interval)) 
    412                         | ("12:min interval"    >> BINT(m_minInterval)) 
    413                         | ("10:tracker id"      >> BSTR(m_trackerId)) 
    414                         | ("8:complete"         >> BINT(m_completeSrc)) 
    415                         | ("10:incomplete"      >> BINT(m_partialSrc)) 
    416                         | ("5:peers"            >> (peer_list | BSTR(cpList))) 
    417                         | unknown 
    418                         ) 
    419                 >> 'e' 
    420         ); 
    421         if (!info.full) { 
    422                 logTrace(TORRENT, 
    423                         boost::format("Tracker response:\n%s")  
    424                         % Utils::hexDump(data) 
    425                 ); 
    426                 logTrace(TORRENT, 
    427                         boost::format("Parsing failed at: %s")  
    428                         % Utils::hexDump(info.stop) 
    429                 ); 
    430                 return; 
    431         } 
    432  
    433         if (errorMsg.size()) { 
    434                 logError(getName() + ": " + errorMsg); 
    435         } 
    436         if (warningMsg.size()) { 
    437                 logWarning(getName() + ": " + warningMsg); 
    438         } 
    439         if (cpList.size() && !peerList.size()) { 
    440                 CHECK(cpList.size() % 6 == 0); 
    441                 std::istringstream i(cpList); 
    442                 tmpPeer.clear(); 
    443                 for (uint32_t j = 0; j < cpList.size() / 6; ++j) { 
    444                         tmpPeer.m_cip = Utils::getVal<uint32_t>(i); 
    445                         tmpPeer.m_port = Utils::getVal<uint16_t>(i); 
    446                         tmpPeer.m_port = SWAP16_ON_LE(tmpPeer.m_port); 
    447                         peerList.push_back(tmpPeer); 
    448                 } 
    449         } 
    450         if (m_minInterval) { 
    451                 logMsg( 
    452                         boost::format("Minimum tracker reask interval: %dm%ds") 
    453                         % (m_minInterval / 60) % (m_minInterval % 60) 
    454                 ); 
    455         } 
    456         if (m_interval) { 
    457                 logMsg( 
    458                         boost::format("Tracker reask interval:         %dm%ds") 
    459                         % (m_interval / 60) % (m_interval % 60) 
    460                 ); 
    461         } 
    462         if (m_completeSrc) { 
    463                 logMsg( 
    464                         boost::format("Complete sources:               %d") 
    465                         % m_completeSrc 
    466                 ); 
    467         } 
    468         if (m_partialSrc) { 
    469                 logMsg( 
    470                         boost::format("Partial sources:                %d") 
    471                         % m_partialSrc 
    472                 ); 
    473         } 
    474         if (peerList.size()) { 
    475                 logMsg( 
    476                         boost::format("Received %d peers from tracker.") 
    477                         % peerList.size() 
    478                 ); 
    479                 for (uint32_t i = 0; i < peerList.size(); ++i) { 
    480                         IPV4Address addr; 
    481                         if (peerList[i].m_cip) { 
    482                                 addr.setAddr(peerList[i].m_cip); 
    483                         } else { 
    484                                 addr.setAddr(peerList[i].m_ip); 
    485                         } 
    486                         addr.setPort(peerList[i].m_port); 
    487                         try { 
    488                                 createClient(addr); 
    489                         } catch (std::exception &e) { 
    490                                 logDebug( 
    491                                         boost::format( 
    492                                                 "Error while creating BT " 
    493                                                 "peer connection: %s" 
    494                                         ) % e.what() 
    495                                 ); 
    496                         } 
    497                 } 
    498         } 
    499         if (!m_interval) { 
    500                 m_interval = 60; 
    501         } 
    502  
    503         Utils::timedCallback( 
    504                 boost::bind(&Torrent::connectToTracker, this, *m_curIp), 
    505                 m_interval * 1000 
    506         ); 
    507         m_socket->disconnect(); 
    508         m_socket.reset(); 
    509         m_inBuffer.clear(); 
     133        for_each(m_trackers.begin(),m_trackers.end(),bind(delete_ptr(), __1)); 
    510134} 
    511135 
  • hydranode/hncore/bt/torrent.h

    r2775 r2913  
    2929#include <hncore/bt/types.h> 
    3030#include <hncore/bt/client.h> 
     31#include <boost/utility.hpp> 
    3132 
    3233namespace Bt { 
     
    3536        EVT_DESTROY = 1 
    3637}; 
     38 
     39class Tracker; 
    3740 
    3841/** 
     
    6770         */ 
    6871        //!@{ 
    69         Hash<SHA1Hash> getInfoHash()  const { return m_info.getInfoHash();  } 
    70         uint64_t       getChunkSize() const { return m_info.getChunkSize(); } 
    71         uint32_t       getChunkCnt()  const { return m_info.getChunkCnt();  } 
    72         std::string    getName()      const { return m_info.getName();      } 
     72        Hash<SHA1Hash> getInfoHash()   const { return m_info.getInfoHash();  } 
     73        uint64_t       getChunkSize()  const { return m_info.getChunkSize(); } 
     74        uint32_t       getChunkCnt()   const { return m_info.getChunkCnt();  } 
     75        std::string    getName()       const { return m_info.getName();      } 
     76        uint64_t       getUploaded()   const { return m_uploaded;            } 
     77        uint64_t       getDownloaded() const { return m_downloaded;          } 
     78        PartData*      getPartData()   const { return m_partData;            } 
    7379        //!@} 
    7480 
     
    154160         */ 
    155161        //!@{ 
    156         void onResolverEvent(HostInfo info); 
    157         void onSocketEvent(TcpSocket *sock, SocketEvent evt); 
    158162        void onPartDataEvent(PartData *file, int evt); 
    159163        void onSharedFileEvent(SharedFile *file, int evt); 
     
    170174 
    171175        /** 
    172          * Sends a HTTP GET request to tracker 
    173          * 
    174          * \pre   m_socket exists and is connected to a tracker 
    175          */ 
    176         void sendGetRequest(); 
    177  
    178         /** 
    179          * Parses current input buffer (tracker responses) 
    180          */ 
    181         void parseBuffer(); 
    182  
    183         /** 
    184          * Parses the content field of tracker HTTP responses 
    185          * 
    186          * @param data         CONTENT field of HTTP response from tracker 
    187          */ 
    188         void parseContent(const std::string &data); 
    189  
    190         //! Performs a DNS lookup on tracker host (m_trackerHost) 
    191         void lookupTrackerHost(); 
    192  
    193         //! Handles DNS lookup timeouts 
    194         void hostLookupTimeout(); 
    195  
    196         //! Attempts to establish connection with tracker 
    197         void connectToTracker(IPV4Address addr); 
    198  
    199         /** 
    200176         * Creates and attaches a peer to this torrent. 
    201177         * 
     
    210186        PartData                    *m_partData;  //!< Downloaded file(optional) 
    211187        TorrentInfo                  m_info;      //!< Info about this torrent 
    212         boost::scoped_ptr<TcpSocket> m_socket;    //!< Tracker connection 
    213         std::string                  m_inBuffer;  //!< Socket input buffer 
    214  
    215         std::string m_trackerHost; //!< Tracker host part, e.g. www.tracker.com 
    216         std::string m_trackerUrl;  //!< Tracker URL part, e.g. /announce 
    217         uint16_t    m_trackerPort; //!< Tracker port, e.g. 80 
    218         std::vector<IPV4Address> m_trackerIp;  //!< Tracker IP addresses 
    219         std::vector<IPV4Address>::iterator m_curIp;     //!< Current active IP 
    220  
    221         uint32_t    m_interval;    //!< Tracker reask interval 
    222         uint32_t    m_minInterval; //!< Minimum tracker reask interval 
    223         std::string m_trackerId;   //!< ID sent by tracker 
    224         uint32_t    m_completeSrc; //!< Number of complete sources 
    225         uint32_t    m_partialSrc;  //!< Number of partial sources 
     188 
     189        std::set<Tracker*>            m_trackers; 
    226190 
    227191        uint64_t    m_uploaded;    //!< How much we have downloaded this session 
  • hydranode/hncore/bt/torrentinfo.h

    r2613 r2913  
    3636class TorrentInfo { 
    3737public: 
     38        //! Announce urls iterator 
     39        typedef std::vector<std::string>::const_iterator AIter; 
     40 
    3841        /** 
    3942         * TorrentFile represents a single file in a multi-file torrent object 
     
    106109        std::vector<TorrentFile> getFiles()    const { return m_files;         } 
    107110        std::vector<IPV4Address> getNodes()    const { return m_nodes;         } 
     111        AIter announceBegin()           const { return m_announceList.begin(); } 
     112        AIter announceEnd()             const { return m_announceList.end();   } 
    108113        //@} 
    109114