You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
223 lines
5.9 KiB
223 lines
5.9 KiB
/***************************************************************************
|
|
* 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 <time.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <util/array.h>
|
|
#include <ksocketaddress.h>
|
|
#include <kdatagramsocket.h>
|
|
#include <ksocketdevice.h>
|
|
#include <net/portlist.h>
|
|
#include <util/log.h>
|
|
#include <util/functions.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include "globals.h"
|
|
#include "udptrackersocket.h"
|
|
|
|
using namespace KNetwork;
|
|
|
|
namespace bt
|
|
{
|
|
Uint16 UDPTrackerSocket::port = 4444;
|
|
|
|
UDPTrackerSocket::UDPTrackerSocket()
|
|
{
|
|
sock = new KNetwork::KDatagramSocket(this);
|
|
sock->setAddressReuseable(true);
|
|
connect(sock,TQT_SIGNAL(readyRead()),this,TQT_SLOT(dataReceived()));
|
|
int i = 0;
|
|
if (port == 0)
|
|
port = 4444;
|
|
|
|
bool bound = false;
|
|
|
|
while (!(bound = sock->bind(TQString(),TQString::number(port + i))) && i < 10)
|
|
{
|
|
Out() << "Failed to bind socket to port " << (port+i) << endl;
|
|
i++;
|
|
}
|
|
|
|
|
|
if (!bound)
|
|
{
|
|
KMessageBox::error(0,
|
|
i18n("Cannot bind to udp port %1 or the 10 following ports.").tqarg(port));
|
|
}
|
|
else
|
|
{
|
|
port = port + i;
|
|
Globals::instance().getPortList().addNewPort(port,net::UDP,true);
|
|
}
|
|
}
|
|
|
|
|
|
UDPTrackerSocket::~UDPTrackerSocket()
|
|
{
|
|
Globals::instance().getPortList().removePort(port,net::UDP);
|
|
delete sock;
|
|
}
|
|
|
|
void UDPTrackerSocket::sendConnect(Int32 tid,const KNetwork::KSocketAddress & addr)
|
|
{
|
|
Int64 cid = 0x41727101980LL;
|
|
Uint8 buf[16];
|
|
|
|
WriteInt64(buf,0,cid);
|
|
WriteInt32(buf,8,CONNECT);
|
|
WriteInt32(buf,12,tid);
|
|
|
|
sock->send(KDatagramPacket((char*)buf,16,addr));
|
|
transactions.insert(tid,CONNECT);
|
|
}
|
|
|
|
void UDPTrackerSocket::sendAnnounce(Int32 tid,const Uint8* data,const KNetwork::KSocketAddress & addr)
|
|
{
|
|
transactions.insert(tid,ANNOUNCE);
|
|
sock->send(KDatagramPacket((char*)data,98,addr));
|
|
}
|
|
|
|
void UDPTrackerSocket::cancelTransaction(Int32 tid)
|
|
{
|
|
transactions.remove(tid);
|
|
}
|
|
|
|
void UDPTrackerSocket::handleConnect(const TQByteArray & data)
|
|
{
|
|
const Uint8* buf = (const Uint8*)data.data();
|
|
|
|
// Read the transaction_id and check it
|
|
Int32 tid = ReadInt32(buf,4);
|
|
TQMap<Int32,Action>::iterator i = transactions.tqfind(tid);
|
|
// if we can't find the transaction, just return
|
|
if (i == transactions.end())
|
|
{
|
|
return;
|
|
}
|
|
|
|
// check wether the transaction is a CONNECT
|
|
if (i.data() != CONNECT)
|
|
{
|
|
transactions.erase(i);
|
|
error(tid,TQString());
|
|
return;
|
|
}
|
|
|
|
// everything ok, emit signal
|
|
transactions.erase(i);
|
|
connectRecieved(tid,ReadInt64(buf,8));
|
|
}
|
|
|
|
void UDPTrackerSocket::handleAnnounce(const TQByteArray & data)
|
|
{
|
|
const Uint8* buf = (const Uint8*)data.data();
|
|
|
|
// Read the transaction_id and check it
|
|
Int32 tid = ReadInt32(buf,4);
|
|
TQMap<Int32,Action>::iterator i = transactions.tqfind(tid);
|
|
// if we can't find the transaction, just return
|
|
if (i == transactions.end())
|
|
return;
|
|
|
|
// check wether the transaction is a ANNOUNCE
|
|
if (i.data() != ANNOUNCE)
|
|
{
|
|
transactions.erase(i);
|
|
error(tid,TQString());
|
|
return;
|
|
}
|
|
|
|
// everything ok, emit signal
|
|
transactions.erase(i);
|
|
announceRecieved(tid,data);
|
|
}
|
|
|
|
void UDPTrackerSocket::handleError(const TQByteArray & data)
|
|
{
|
|
const Uint8* buf = (const Uint8*)data.data();
|
|
// Read the transaction_id and check it
|
|
Int32 tid = ReadInt32(buf,4);
|
|
TQMap<Int32,Action>::iterator it = transactions.tqfind(tid);
|
|
// if we can't find the transaction, just return
|
|
if (it == transactions.end())
|
|
return;
|
|
|
|
// extract error message
|
|
transactions.erase(it);
|
|
TQString msg;
|
|
for (Uint32 i = 8;i < data.size();i++)
|
|
msg += (char)buf[i];
|
|
|
|
// emit signal
|
|
error(tid,msg);
|
|
}
|
|
|
|
void UDPTrackerSocket::dataReceived()
|
|
{
|
|
if (sock->bytesAvailable() == 0)
|
|
{
|
|
Out(SYS_TRK|LOG_NOTICE) << "0 byte UDP packet " << endl;
|
|
// KDatagramSocket wrongly handles UDP packets with no payload
|
|
// so we need to deal with it oursleves
|
|
int fd = sock->socketDevice()->socket();
|
|
char tmp;
|
|
read(fd,&tmp,1);
|
|
return;
|
|
}
|
|
|
|
KDatagramPacket pck = sock->receive();
|
|
const TQByteArray & data = pck.data();
|
|
const Uint8* buf = (const Uint8*)data.data();
|
|
Uint32 type = ReadUint32(buf,0);
|
|
switch (type)
|
|
{
|
|
case CONNECT:
|
|
handleConnect(data);
|
|
break;
|
|
case ANNOUNCE:
|
|
handleAnnounce(data);
|
|
break;
|
|
case ERROR:
|
|
handleError(data);
|
|
break;
|
|
}
|
|
}
|
|
|
|
Int32 UDPTrackerSocket::newTransactionID()
|
|
{
|
|
Int32 transaction_id = rand() * time(0);
|
|
while (transactions.tqcontains(transaction_id))
|
|
transaction_id++;
|
|
return transaction_id;
|
|
}
|
|
|
|
void UDPTrackerSocket::setPort(Uint16 p)
|
|
{
|
|
port = p;
|
|
}
|
|
|
|
Uint16 UDPTrackerSocket::getPort()
|
|
{
|
|
return port;
|
|
}
|
|
}
|
|
|
|
#include "udptrackersocket.moc"
|