Usually the BT client will send a request to Tracker every few minutes. For some of the big BT sites, the pressure of Tracker is ideally known. The pressure of the Tracker is first taken into account, which is of course low network overhead. UDP protocol. So BitTorrent UDP-Tracker Protocol is born. This protocol is simple. Below is a package class that implements it:
// udptrackerclient.h: interface for the cudptrackerclient class.
//
//
#if! defined (AFX_UDPTRACKERCLIENT_H__69B6ACC8_8193_4680_81D8_925B1550E92C__included_)
#define AFX_UDPTRACKERCLIENT_H__69B6ACC8_8193_4680_81D8_925B1550E92C__included_
#iF _MSC_VER> 1000
#pragma overce
#ENDIF / / 100 m _ _
#include
#pragma comment (Lib, "WS2_32.LIB")
#ifndef _disableWarning4786_4355
#define _disableWarning4786_4355
#pragma Warning (Disable: 4786)
#pragma Warning (Disable: 4355)
#ENDIF
#ifndef _ENABLEUSESTL
#define _enableusestl
#include
#include
#include
#include
#include
#include
Using namespace std;
#ENDIF
Class CPeerhostInfo
{
PUBLIC:
DWORD IP; // Node IP
Word port; // node port
}
Class CudptrackerClient
{
PUBLIC:
CUDPTRACKERCLIENT ();
Virtual ~ cudptrackerclient ();
Void Cancelsocketoperate ();
BOOL Connect (const char * szserver, word wport = 0);
DWord Announcing (Byte * Pinfohash, Byte * PpeerID,
__int64 idownloadloaded, __ int64 left, __ int64 Iuplined,
Int Ievent,
DWORD DWIP, WORD WPORT);
Bool disconnect ();
PUBLIC:
Socket m_socket;
DWORD M_DWIP;
Word m_wport;
__INT64 m_ICONNECTION_ID;
DWORD M_DWCONNECTCI;
String m_strerror; // If the request fails, this variable saves an error message.
DWORD M_DWDONEPEERS; // seed number
DWORD M_DWNUMPEERS; // Current Downloaders
DWORD M_DWINTERVAL; / / Query Interval
List
}
#ENDIF /! Defined (AFX_UDPTRACKERCLIENT_H__69B6ACC8_8193_4680_81D8_925B1550E92C__included_)
// udptrackerclient.cpp: Implementation of the cudptrackerclient class.//
//
#include "stdafx.h"
#include "udptrackerclient.h"
#include "datastream.h"
#ifdef _Debug
#undef this_file
Static char this_file [] = __ file__;
#define new debug_new
#ENDIF
//
// construction / destruction
//
#define recvbufsize 2048
CudptrackerClient :: CUDPTRACKERCLIENT ()
{
m_socket = invalid_socket;
m_ICONNECTION_ID = 0;
m_dwconnecttick = 0;
m_dwip = 0;
m_wport = 0;
m_dwdonepeers = 0; // seed number
m_dwnumpeers = 0; // The current number of downloaders
m_dwinterval = 0; // Query interval
}
CudptrackerClient :: ~ cudptrackerclient ()
{
Disconnect ();
}
Void CudptrackerClient :: CancelsocketOperate ()
{
IF (m_socket! = invalid_socket)
{
Linger lingerstruct;
// if we're supposed to abort the connection, set the linger value
// on the socket to 0.
LINGERSTRUCT.L_ONOFF = 1;
LINGERSTRUCT.L_LINGER = 0;
Setsockopt (M_Socket, SOL_Socket, SO_LINGER,
(char *) & lingerstruct, sizeof (lingerstruct));
}
}
Bool CudptrackerClient :: disconnect ()
{
m_ICONNECTION_ID = 0;
m_dwdonepeers = 0; // seed number
m_dwnumpeers = 0; // The current number of downloaders
m_dwinterval = 0; // Query interval
IF (m_socket! = invalid_socket)
{
m_dwip = 0;
m_wport = 0;
// Now close the socket handle. This will do an abortive or
// graceful close, as Requested.
Shutdown (M_Socket, SD_BOTH);
CloseSocket (M_Socket);
m_socket = invalid_socket;
Return True;
}
Return False;
}
// SZ Server Connect the host, which can be the following form:
//easeso.com: 1000
//easeso.com
// If WPORT is not 0, SZSERVER should not contain port information.
Bool CudptrackerClient :: Connect (const char * szserver, word wport)
{
m_strerror = ""
Bool Bres = false;
IF (m_socket == invalid_socket) {
// Initialize the socket with UDP
Bool optval = true;
m_socket = socket (AF_INET, SOCK_DGRAM, 0);
IF (m_socket == invalid_socket)
Return False;
// Set timeout time
INT TIMEOUT = 10000;
INT Err = setsockopt (m_socket, sol_socket, so_rcvtimeo, (char *) & timeout, sizeof (timeout));
}
IF (m_dwip == 0)
{
CString strserver = szserver;
CString strhost;
IF (WPORT == 0)
{
INT INEXT = STRSERVER.FIND (':');
IF (INEXT> 0)
{
strHost = strserver.mid (0, INEXT);
CString Strport = strserver.mid (INEXT 1);
M_Wport = (Word) ATOI (Strport);
}
Else
Strhost = strserver;
}
Else
{
Strhost = strserver;
M_Wport = WPORT;
}
IF (m_wport == 0)
m_wport = 80;
// Check if address is an ip or a domain name
INT a = strhost [0];
IF (a> 47 && a <58)
m_dwip = inet_addr (strhost);
Else
{
Struct Hostent * Phost;
Phost = gethostByname (strhost);
IF (Phost! = NULL)
m_dwip = * ((ulong *) phost-> h_addr);
Else
m_dwip = 0;
}
}
IF ((GettickCount () - m_dwconnecttic> 30000)
{
m_dwconnecttick = 0;
m_ICONNECTION_ID = 0;
}
IF (m_socket! = INVALID_SOCKET && M_DWIP && M_WPORT && M_ICONNECTION_ID == 0)
{
DWORD DWTRANSACTION_ID = GetTickCount ();
SockAddr_in from;
Int fromLength = SizeOf (SockAddr);
Char buf [recvbufsize];
From.SIN_FAMILY = AF_INET;
From.SIN_ADDR.S_ADDR = m_dwip;
From.SIN_PORT = HTONS (m_wport);
CDataStream SendStream (BUF, 2047);
SendStream.clear ();
__INT64 ICID = 0x41727101980;
SendStream.writeInt64 (CNETWORKBYTEORDER :: Convert (ICID));
SendStream.writedword (CNETWORKBYTEORDER :: Convert (INT) 0));
SendStream.writedword (dwtransaction_id); int IRES = 0;
INT itimes = 6;
While (ITIMES> 0 && m_dwip)
{
Sendto (M_Socket, SendStream.getBuffer (), SendStream.size (), 0, (Struct Sockaddr Far *) & from, SizeOf (from));
Ires = Recvfrom (m_socket, buf, recvbufsize-1, 0, (struct sockaddr far *) & from, (int far *) & fromLomb
IF (IRES> = 0)
Break;
ITIMES -;
}
IF (IRES> = 16)
{
CDataStream Recvstream (buf, recvbufsize-1);
DWORD DWACTION = (DWORD) CNETWORKBYTEORDER :: ConvertReam.ReaddWord ());
DWORD DWTIDRESP = RecvStream.Readdword ();
IF (DWTIDRESP == DWTRANSAction_ID)
{
IF (dwaction == 0)
{
M_ICONNECTION_ID = Recvstream.Readint64 ();
// bitcomet will reply 0x16 byte data, and the last 6-byte is the local IP and UDP ports that the server is found.
}
Else if (dwaction == 3) // Get an error packet
{
BUF [IRES] = 0;
m_strerror = recvstream.readstring ();
}
}
}
}
IF (m_ICONNECTION_ID)
Bres = True;
Return Bres;
}
/ / Submit request
// Pinfohash 20 bytes of data buffer pointer
// PPEERID 20 byte data buffer pointer
// Ievent parameter value:
// none = 0
// completed = 1
// start = 2
// stopped = 3
DWORD CUDPTRACKERCLIENT :: Announcing (byte * Pinfohash, byte * ppeerid,
__int64 idownloadloaded, __ int64 left, __ int64 Iuplined,
Int Ievent,
DWORD DWIP, WORD WPORT)
{
m_listpeers.clear ();
m_dwnumpeers = 0;
m_dwdonepeers = 0;
m_strerror = ""
DWORD dwreturNCode = 0;
IF (m_iconnection_id && m_socket! = invalid_socket && m_dwip & m_wport)
{
DWORD DWTRANSACTION_ID = GetTickCount ();
// SRAND (dwtransaction_id);
// DWORD dwkey = rand ();
DWORD DWKEY = 0x3753;
SockAddr_in from;
Int fromLength = SizeOf (SockAddr);
Char buf [recvbufsize];
From.SIN_FAMILY = AF_INET;
From.SIN_ADDR.S_ADDR = m_dwip;
From.sin_port = htons (m_wport); CDataStream SendStream (Buf, Recvbufsize-1);
SendStream.clear ();
SendStream.writeInt64 (m_ICONNECTION_ID);
SendStream.writedword (CNETWORKBYTEORDER :: Convert (INT) 1));
SendStream.writeDword (dwtransaction_id);
SendStream.writeData (Pinfohash, 20);
SendStream.WriteData (PPEERID, 20);
SendStream.writeInt64 (CNETWORKBYTEORDER :: Convert (iDownloaded);
SendStream.writeInt64 (CNETWORKBYTEORDER :: Convert);
SendStream.writeInt64 (CNETWORKBYTEORDER :: Convert (iUploaded));
SendStream.writedword (CNETWORKBYTEORDER :: Convert (IEvent));
SendStream.writedword (DWIP);
SendStream.writedword (CNETWORKBYTEORDER :: Convert ((int) dwkey);
SendStream.writedword (CNETWORKBYTEORDER :: Convert ((int) 200));
SendStream.writedword (CNETWorkByteorder :: Convert (WPORT));
INT IRES = 0;
INT itimes = 2;
While (ITIMES> 0 && m_dwip)
{
Sendto (M_Socket, SendStream.getBuffer (), SendStream.size (), 0, (Struct Sockaddr Far *) & from, SizeOf (from));
Ires = Recvfrom (m_socket, buf, recvbufsize-1, 0, (struct sockaddr far *) & from, (int far *) & fromLomb
IF (IRES> = 0)
Break;
ITIMES -;
}
IF (IRES> = 20)
{
CDataStream Recvstream (buf, recvbufsize-1);
DWORD DWACTION = (DWORD) CNETWORKBYTEORDER :: ConvertReam.ReaddWord ());
DWORD DWTIDRESP = RecvStream.Readdword ();
IF (DWTIDRESP == DWTRANSAction_ID)
{
IF (dwaction == 1)
{
M_dwinterval = (dword) CNETWORKBYTEORDER :: ConvertReam.ReaddWord ());
M_dwnumpeers = (dword) CNETWORKBYTEORDER :: Convert ((int) Recvstream.Readdword ());
M_dwdonepeers = (DWORD) CNETWORKBYTEORDER :: Convert ((int) recvstream.readdword ());
CPEERHOSTINFO HI;
For (int icurpos = 20; icurpos 6 <= IRES; icurpos = 6)
{
Hi.ip = recvstream.readdword (); hi.port = (word) CNETWORKBYTEORDER :: Convertream.Readword ());
m_listpeers.push_back (hi);
}
IF (m_dwnumpeers> m_listpeers.size ())
{
IRES = 0;
ITIMES = 6;
While (ITIMES> 0 && m_dwip)
{
Ires = Recvfrom (m_socket, buf, recvbufsize-1, 0, (struct sockaddr far *) & from, (int far *) & fromLomb
IF (IRES> = 0)
Break;
ITIMES -;
}
IF (IRES> = 6)
{
For (iCurpos = 0; icurpos 6 <= IRES; ICURPOS = 6)
{
Hi.ip = Recvstream.Readdword ();
Hi.Port = (DWORD) CNETWORKBYTEORDER :: ConvertReam.Readword ());
m_listpeers.push_back (hi);
}
}
}
m_dwnumpeers = m_listpeers.size ();
dwreturncode = 200;
}
Else if (dwaction == 3) // Get an error packet
{
BUF [IRES] = 0;
m_strerror = recvstream.readstring ();
dwreturncode = 400;
}
}
}
}
/ / Reconnects to be reconnected each time
m_ICONNECTION_ID = 0;
Return dwreturncode;
}
// DataStream.h: Interface for the cdatathastream class.
//
//
#if! defined (AFX_DATASTREAM_H__D90A2534_EA73_4BEA_8B7E_87E59A3D1D26__INCLUDED_)
#define AFX_DataStream_H__d90a2534_ea73_4bea_8b7e_87e59a3d1d26__included_
#iF _MSC_VER> 1000
#pragma overce
#ENDIF / / 100 m _ _
#include
// Data flow operation function
Class CDataStream
{
PUBLIC:
CDataStream (Char * SZBUF, INT ISIZE)
{
m_isize = isize;
Buffer = szbuf;
Current = Buffer;
}
~ Cdataastream ()
{
}
void clear ()
{
Current = Buffer;
CURRENT [0] = 0;
}
/ / This function does not perform memory, and the length of the data printed should not exceed one-third of the buffer, otherwise it may result in failure.
Bool Printf (const char * format, ...)
{
IF (Current)
{
IF (Current - Buffer> (M_ISIZE * 2) / 3)
Return False;
VA_List Argptr;
VA_Start (argptr, format);
INT count = vsprintf (current, format, argptr); va_end (argptr);
Current = count;
Return True;
}
Return False;
}
// This function copy string
Bool Strcpy (const char * szstr)
{
Current && Szstr)
{
INT Ilen = lstrlen (Szstr);
IF ((m_isize- (current - buffer) <(ilen 2))
Return False;
Memcpy (Current, Szstr, Ilen 1);
CURRENT = Ilen;
Return True;
}
Return False;
}
Char * getcurrentpos ()
{
Return Current;
}
Void Move // Current Pointer Moves Ilen
{
CURRENT = Ilen;
}
Void reset ()
{
Current = Buffer;
}
Byte readbyte ()
{
CURRENT ;
Return * (Current-1);
}
Void WritebyTe (byte btvalue)
{
* current = btvalue;
CURRENT ;
}
Word readword ()
{
CURRENT = 2;
Return * ((Word *) (CURRENT-2));
}
Void WriteWord (Word Wvalue)
{
* ((Word *) current) = wvalue;
CURRENT = 2;
}
DWord readdword ()
{
CURRENT = 4;
Return * ((DWORD *) (CURRENT-4));
}
Void WriteDword (DWORD DWVALUE)
{
* ((DWORD *) CURRENT) = DWVALUE;
CURRENT = 4;
}
__int64 readint64 ()
{
CURRENT = 8;
Return * ((__ int64 *) (Current-8);
}
Void WriteInt64 (__ int64 ivalue)
{
* ((__ int64 *) current) = iValue;
CURRENT = 8;
}
BYTE * READDATA (DWORD DWLEN)
{
Current = DWLEN;
Return (Byte *) (CURRENT-DWLEN);
}
Void WriteData (Byte * PData, DWORD DWLEN)
{
Memcpy (Current, PDATA, DWLEN);
Current = DWLEN;
}
Char * readstring ()
{
Char * szres = current;
INT Ilen = Lstrlen (Current);
Current = (ilen 1);
Return szres;
}
int size ()
{
Return (int);
}
Const char * getBuffer () {return buffer;
Private:
Char * buffer;
CHAR * CURRENT;
INT M_ISIZE;
}
Class CNETWORKBYTEORDER
{
PUBLIC:
Static Unsigned Short Int Convert (Unsigned Short Ivalue)
{
UNSIGNED SHORT IDATA;
(Byte *) & idata) [0] = ((byte *) & iValue) [1];
(Byte *) & idata) [1] = ((byte *) & iValue) [0];
Return Idata;
}
Static Int Convert (int tent iValue)
{
Id Idata;
(Byte *) & idata) [0] = ((byte *) & iValue) [3];
((Byte *) & idata) [1] = ((byte *) & iValue) [2];
((Byte *) & idata) [2] = ((byte *) & ivalue) [1];
((Byte *) & idata) [3] = ((byte *) & iValue) [0];
Return Idata;
}
Static __int64 convert (__ int64 ivalue)
{
__INT64 Idata;
((Byte *) & idata) [0] = ((byte *) & iValue) [7];
(BYTE *) & iData) [1] = ((byte *) & iValue) [6];
(BYTE *) & iData) [2] = ((byte *) & iValue) [5];
((Byte *) & idata) [3] = ((byte *) & iValue) [4];
(Byte *) & idata) [4] = ((byte *) & iValue) [3];
((Byte *) & idata) [5] = ((byte *) & iValue) [2];
((Byte *) & idata) [6] = ((byte *) & iValue) [1];
((Byte *) & idata) [7] = ((byte *) & iValue) [0];
Return Idata;
}
}
#ndif //! defined (AFX_DataStream_h__d90a2534_ea73_4bea_8b7e_87e59a3d1d26__included_)
In Yi Supo (Easeso) Forum, you can download to support UDP TRACKER test programs bttrackertest. At this point, the first phase work is completed, the following is the interaction between Peer.