/*************************************************************************** * Copyright (C) 2005 by Joris Guisson * * joris.guisson@gmail.com * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program; if not, write to the * * Free Software Foundation, Inc., * * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * ***************************************************************************/ #include #include #include #include #include #include "peermanager.h" #include "udptracker.h" #include "torrentcontrol.h" #include "globals.h" #include "server.h" #include "udptrackersocket.h" using namespace kt; using namespace KNetwork; namespace bt { UDPTrackerSocket* UDPTracker::socket = 0; Uint32 UDPTracker::num_instances = 0; UDPTracker::UDPTracker(const KURL & url,kt::TorrentInterface* tor,const PeerID & id,int tier) : Tracker(url,tor,id,tier) { num_instances++; if (!socket) socket = new UDPTrackerSocket(); connection_id = 0; transaction_id = 0; interval = 0; connect(&conn_timer,TQT_SIGNAL(timeout()),this,TQT_SLOT(onConnTimeout())); connect(socket,TQT_SIGNAL(announceRecieved(Int32, const TQByteArray &)), this,TQT_SLOT(announceRecieved(Int32, const TQByteArray& ))); connect(socket,TQT_SIGNAL(connectRecieved(Int32, Int64 )), this,TQT_SLOT(connectRecieved(Int32, Int64 ))); connect(socket,TQT_SIGNAL(error(Int32, const TQString& )), this,TQT_SLOT(onError(Int32, const TQString& ))); KResolver::resolveAsync(this,TQT_SLOT(onResolverResults(KResolverResults )), url.host(),TQString::number(url.port())); } UDPTracker::~UDPTracker() { num_instances--; if (num_instances == 0) { delete socket; socket = 0; } } void UDPTracker::start() { event = STARTED; conn_timer.stop(); doRequest(); } void UDPTracker::stop(WaitJob* ) { if (!started) return; event = STOPPED; conn_timer.stop(); doRequest(); started = false; } void UDPTracker::completed() { event = COMPLETED; conn_timer.stop(); doRequest(); } void UDPTracker::manualUpdate() { conn_timer.stop(); if (!started) event = STARTED; doRequest(); } void UDPTracker::connectRecieved(Int32 tid,Int64 cid) { if (tid != transaction_id) return; connection_id = cid; n = 0; sendAnnounce(); } void UDPTracker::announceRecieved(Int32 tid,const TQByteArray & data) { if (tid != transaction_id) return; const Uint8* buf = (const Uint8*)data.data(); /* 0 32-bit integer action 1 4 32-bit integer transaction_id 8 32-bit integer interval 12 32-bit integer leechers 16 32-bit integer seeders 20 + 6 * n 32-bit integer IP address 24 + 6 * n 16-bit integer TCP port 20 + 6 * N */ interval = ReadInt32(buf,8); leechers = ReadInt32(buf,12); seeders = ReadInt32(buf,16); Uint32 nip = leechers + seeders; Uint32 j = 0; for (Uint32 i = 20;i < data.size() && j < nip;i+=6,j++) { Uint32 ip = ReadUint32(buf,i); addPeer(TQString("%1.%2.%3.%4") .tqarg((ip & (0xFF000000)) >> 24) .tqarg((ip & (0x00FF0000)) >> 16) .tqarg((ip & (0x0000FF00)) >> 8) .tqarg(ip & 0x000000FF), ReadUint16(buf,i+4)); } peersReady(this); connection_id = 0; conn_timer.stop(); if (event != STOPPED) { if (event == STARTED) started = true; event = NONE; requestOK(); } else { stopDone(); requestOK(); } } void UDPTracker::onError(Int32 tid,const TQString & error_string) { if (tid != transaction_id) return; Out(SYS_TRK|LOG_IMPORTANT) << "UDPTracker::error : " << error_string << endl; requestFailed(error_string); } bool UDPTracker::doRequest() { Out(SYS_TRK|LOG_NOTICE) << "Doing tracker request to url : " << url << endl; if (connection_id == 0) { n = 0; sendConnect(); } else sendAnnounce(); requestPending(); return true; } void UDPTracker::scrape() { } void UDPTracker::sendConnect() { transaction_id = socket->newTransactionID(); socket->sendConnect(transaction_id,address); int tn = 1; for (int i = 0;i < n;i++) tn *= 2; conn_timer.start(60000 * tn,true); } void UDPTracker::sendAnnounce() { // Out(SYS_TRK|LOG_NOTICE) << "UDPTracker::sendAnnounce()" << endl; transaction_id = socket->newTransactionID(); /* 0 64-bit integer connection_id 8 32-bit integer action 1 12 32-bit integer transaction_id 16 20-byte string info_hash 36 20-byte string peer_id 56 64-bit integer downloaded 64 64-bit integer left 72 64-bit integer uploaded 80 32-bit integer event 84 32-bit integer IP address 0 88 32-bit integer key 92 32-bit integer num_want -1 96 16-bit integer port 98 */ Uint32 ev = event; const TorrentStats & s = tor->getStats(); Uint16 port = Globals::instance().getServer().getPortInUse(); Uint8 buf[98]; WriteInt64(buf,0,connection_id); WriteInt32(buf,8,ANNOUNCE); WriteInt32(buf,12,transaction_id); const SHA1Hash & info_hash = tor->getInfoHash(); memcpy(buf+16,info_hash.getData(),20); memcpy(buf+36,peer_id.data(),20); WriteInt64(buf,56,s.trk_bytes_downloaded); if (ev == COMPLETED) WriteInt64(buf,64,0); else WriteInt64(buf,64,s.bytes_left); WriteInt64(buf,72,s.trk_bytes_uploaded); WriteInt32(buf,80,ev); TQString cip = Tracker::getCustomIP(); if (cip.isNull()) { WriteUint32(buf,84,0); } else { KNetwork::KIpAddress addr(cip); WriteUint32(buf,84,addr.IPv4Addr(true)); } WriteUint32(buf,88,key); if (ev != STOPPED) WriteInt32(buf,92,100); else WriteInt32(buf,92,0); WriteUint16(buf,96,port); socket->sendAnnounce(transaction_id,buf,address); } void UDPTracker::onConnTimeout() { if (connection_id) { connection_id = 0; n++; if (event != STOPPED) sendConnect(); else stopDone(); } else { doRequest(); } } void UDPTracker::onResolverResults(KResolverResults res) { address = res.front().address(); } } #include "udptracker.moc"