summaryrefslogtreecommitdiffstats
path: root/libktorrent/torrent/udptracker.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libktorrent/torrent/udptracker.cpp')
-rw-r--r--libktorrent/torrent/udptracker.cpp291
1 files changed, 291 insertions, 0 deletions
diff --git a/libktorrent/torrent/udptracker.cpp b/libktorrent/torrent/udptracker.cpp
new file mode 100644
index 0000000..2dd4a01
--- /dev/null
+++ b/libktorrent/torrent/udptracker.cpp
@@ -0,0 +1,291 @@
+/***************************************************************************
+ * 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 <stdlib.h>
+#include <kresolver.h>
+#include <util/functions.h>
+#include <util/log.h>
+#include <ksocketaddress.h>
+#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,SIGNAL(timeout()),this,SLOT(onConnTimeout()));
+ connect(socket,SIGNAL(announceRecieved(Int32, const QByteArray &)),
+ this,SLOT(announceRecieved(Int32, const QByteArray& )));
+ connect(socket,SIGNAL(connectRecieved(Int32, Int64 )),
+ this,SLOT(connectRecieved(Int32, Int64 )));
+ connect(socket,SIGNAL(error(Int32, const QString& )),
+ this,SLOT(onError(Int32, const QString& )));
+
+ KResolver::resolveAsync(this,SLOT(onResolverResults(KResolverResults )),
+ url.host(),QString::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 QByteArray & 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(QString("%1.%2.%3.%4")
+ .arg((ip & (0xFF000000)) >> 24)
+ .arg((ip & (0x00FF0000)) >> 16)
+ .arg((ip & (0x0000FF00)) >> 8)
+ .arg(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 QString & 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);
+ QString 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"