-
Notifications
You must be signed in to change notification settings - Fork 6
/
Copy pathBTTrackerRequest.h
374 lines (299 loc) · 12 KB
/
BTTrackerRequest.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
//
// BTTrackerRequest.h
//
// This file is part of PeerProject (peerproject.org) © 2008-2012
// Portions copyright Shareaza Development Team, 2002-2008.
//
// PeerProject is free software. You may redistribute and/or modify it
// under the terms of the GNU Affero General Public License
// as published by the Free Software Foundation (fsf.org);
// version 3 or later at your option. (AGPLv3)
//
// PeerProject 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 Affero General Public License 3.0 for details:
// (http://www.gnu.org/licenses/agpl.html)
//
#pragma once
#include "Packet.h"
#include "HttpRequest.h"
class CBTTrackerRequest;
class CBTTrackerPacket;
class CBENode;
class CDownload;
#pragma warning(push)
#pragma warning(disable:4200)
#pragma pack(push,1)
// BitTorrent UDP tracker connecting packet
#define bt_connection_magic 0x41727101980
typedef struct
{
QWORD connection_id; // Must be initialized to 0x41727101980 in network byte order. This will identify the protocol.
DWORD action; // Action. in this case, 0 for connecting. See actions.
DWORD transaction_id; // Randomized by client.
} bt_udp_connecting_request_t;
typedef struct
{
DWORD action; // Describes the type of packet, in this case it should be 0, for connect. If 3 (for error) see errors.
DWORD transaction_id; // Must match the transaction_id sent from the client.
QWORD connection_id; // A connection id, used to identify you when further information is exchanged with the tracker. This id can be reused for multiple requests, but if cached for too long it will not be valid.
} bt_udp_connecting_response_t;
typedef struct
{
DWORD action; // The action, in this case 3, for error. See actions.
DWORD transaction_id; // Must match the transaction_id sent from the client.
BYTE error_string[]; // The rest of the packet is a string describing the error.
} bt_udp_error_response_t;
// BitTorrent UDP tracker announcing packet
typedef struct
{
QWORD connection_id; // The connection id acquired from establishing the connection.
DWORD action; // Action. in this case, 1 for announce. See actions.
DWORD transaction_id; // Randomized by client.
BYTE info_hash[20]; // The info-hash of the torrent you want announce yourself in.
BYTE peer_id[20]; // Your peer id.
QWORD downloaded; // The number of byte you've downloaded in this session.
QWORD left; // The number of bytes you have left to download until you're finished.
QWORD uploaded; // The number of bytes you have uploaded in this session.
DWORD event; // The event, one of: update = 0; completed = 1; started = 2; stopped = 3.
DWORD ip; // Your ip address. Set to 0 if you want the tracker to use the sender of this UDP packet.
DWORD key; // A unique key that is randomized by the client.
DWORD num_want; // The maximum number of peers you want in the reply. Use -1 for default.
WORD port; // The port you're listening on.
WORD extensions; // See extensions
} bt_udp_announcing_request_t;
typedef struct
{
DWORD ip; // The ip of a peer in the swarm.
WORD port; // The peer's listen port.
} bt_peer_t;
typedef struct
{
DWORD action; // The action this is a reply to. Should in this case be 1 for announce. If 3 (for error) see errors. See actions.
DWORD transaction_id; // Must match the transaction_id sent in the announce request.
DWORD interval; // The number of seconds you should wait until re-announcing yourself.
DWORD leechers; // The number of peers in the swarm that has not finished downloading.
DWORD seeders; // The number of peers in the swarm that has finished downloading and are seeding.
bt_peer_t peers[]; // The rest of the packet is a list of peers.
} bt_udp_announcing_response_t;
// BitTorrent UDP tracker scraping packet
typedef struct
{
BYTE info_hash[20]; // The info hash that is to be scraped.
} bt_hash_t;
typedef struct
{
QWORD connection_id; // The connection id retrieved from the establishing of the connection.
DWORD action; // The action, in this case, 2 for scrape. See actions.
DWORD transaction_id; // Randomized by client.
bt_hash_t info_hashes[]; // The rest of the packet is a list of info-hashes to scrape (limited by the MTU).
} bt_udp_scraping_request_t;
typedef struct
{
DWORD seeders; // The current number of connected seeds.
DWORD downloaded; // The number of times this torrent has been downloaded.
DWORD leechers; // The current number of connected leechers.
} bt_scrape_t;
typedef struct
{
DWORD action; // The action, should in this case be 2 for scrape. If 3 (for error) see errors.
DWORD transaction_id; // Must match the sent transaction id.
bt_scrape_t scrapes[]; // The rest of the packet contains the following structures once for each info-hash you asked in the scrape request.
} bt_udp_scraping_response_t;
// BitTorrent UDP tracker actions
enum { BTA_TRACKER_CONNECT, BTA_TRACKER_ANNOUNCE, BTA_TRACKER_SCRAPE, BTA_TRACKER_ERROR };
// BitTorrent UDP tracker events
typedef enum { BTE_TRACKER_UPDATE, BTE_TRACKER_COMPLETED, BTE_TRACKER_STARTED, BTE_TRACKER_STOPPED, BTE_TRACKER_SCRAPE } BTTrackerEvent;
#pragma pack(pop) // 1
#pragma warning(pop) // C4200
//
// BitTorrent tracker source and source list
//
class CBTTrackerSource
{
public:
CBTTrackerSource()
: m_pPeerID ()
, m_pAddress()
{
}
CBTTrackerSource(const Hashes::BtGuid& pPeerID, const SOCKADDR_IN& pAddress)
: m_pPeerID ( pPeerID )
, m_pAddress( pAddress )
{
}
CBTTrackerSource(const CBTTrackerSource& source)
: m_pPeerID ( source.m_pPeerID )
, m_pAddress( source.m_pAddress )
{
}
CBTTrackerSource& operator=(const CBTTrackerSource& source)
{
m_pPeerID = source.m_pPeerID;
m_pAddress = source.m_pAddress;
return *this;
}
Hashes::BtGuid m_pPeerID;
SOCKADDR_IN m_pAddress;
};
typedef CList< CBTTrackerSource > CBTTrackerSourceList;
//
// BitTorrent tracker packet
//
class CBTTrackerPacket : public CPacket
{
protected:
CBTTrackerPacket();
virtual ~CBTTrackerPacket();
public:
DWORD m_nAction;
DWORD m_nTransactionID;
QWORD m_nConnectionID;
virtual void Reset();
virtual void ToBuffer(CBuffer* pBuffer, bool bTCP = true) const;
static CBTTrackerPacket* ReadBuffer(CBuffer* pBuffer);
virtual void SmartDump(const SOCKADDR_IN* pAddress, BOOL bUDP, BOOL bOutgoing, DWORD_PTR nNeighbourUnique = 0) const;
virtual CString GetType() const;
virtual CString ToHex() const;
virtual CString ToASCII() const;
// Packet Pool
protected:
class CBTTrackerPacketPool : public CPacketPool
{
public:
virtual ~CBTTrackerPacketPool() { Clear(); }
protected:
virtual void NewPoolImpl(int nSize, CPacket*& pPool, int& nPitch);
virtual void FreePoolImpl(CPacket* pPool);
};
static CBTTrackerPacketPool POOL;
// Allocation
public:
static CBTTrackerPacket* New(DWORD nAction, DWORD nTransactionID, QWORD nConnectionID, const BYTE* pBuffer = NULL, DWORD nLength = 0);
static CBTTrackerPacket* New(const BYTE* pBuffer, DWORD nLength);
inline virtual void Delete()
{
POOL.Delete( this );
}
// Packet handler
virtual BOOL OnPacket(const SOCKADDR_IN* pHost);
friend class CBTTrackerPacket::CBTTrackerPacketPool;
private:
CBTTrackerPacket(const CBTTrackerPacket&);
CBTTrackerPacket& operator=(const CBTTrackerPacket&);
};
inline void CBTTrackerPacket::CBTTrackerPacketPool::NewPoolImpl(int nSize, CPacket*& pPool, int& nPitch)
{
nPitch = sizeof( CBTTrackerPacket );
pPool = new CBTTrackerPacket[ nSize ];
}
inline void CBTTrackerPacket::CBTTrackerPacketPool::FreePoolImpl(CPacket* pPacket)
{
delete [] (CBTTrackerPacket*)pPacket;
}
//
// BitTorrent tracker request event notification interface
//
class CTrackerEvent
{
public:
virtual void OnTrackerEvent(bool bSuccess, LPCTSTR pszReason, LPCTSTR pszTip, CBTTrackerRequest* pEvent) = 0;
};
//
// BitTorrent tracker request
//
class CBTTrackerRequest
{
protected:
CBTTrackerRequest(CDownload* pDownload, BTTrackerEvent nEvent, DWORD nNumWant, CTrackerEvent* pOnTrackerEvent);
virtual ~CBTTrackerRequest();
public:
ULONG AddRef();
ULONG Release();
inline BTTrackerEvent GetEvent() const { return m_nEvent; } // Tracker event (update, announce, etc.)
inline DWORD GetComplete() const { return m_nComplete; } // Seeders
inline DWORD GetIncomplete() const { return m_nIncomplete; } // Leeches
inline DWORD GetDownloaded() const { return m_nDownloaded; } // Download Count
// Tracker request interval (in seconds)
inline DWORD GetInterval() const { return min( max( m_nInterval, 60ul * 2ul ), 60ul * 60ul ); }
// Retrieve peers
inline POSITION GetSources() const { return m_pSources.GetHeadPosition(); }
inline const CBTTrackerSource& GetNextSource(POSITION& rPosition) const { return m_pSources.GetNext( rPosition ); }
static CString Escape(const Hashes::BtHash& oBTH);
static CString Escape(const Hashes::BtGuid& oGUID);
void Cancel();
BOOL OnConnect(CBTTrackerPacket* pPacket);
BOOL OnAnnounce(CBTTrackerPacket* pPacket);
BOOL OnScrape(CBTTrackerPacket* pPacket);
BOOL OnError(CBTTrackerPacket* pPacket);
protected:
volatile LONG m_dwRef; // Reference counter
bool m_bHTTP; // HTTP = TRUE, UDP = FALSE.
CDownload* m_pDownload; // Handle of owner download
CString m_sName; // Name of download
CString m_sURL; // Tracker URL
SOCKADDR_IN m_pHost; // Resolved tracker address (UDP)
Hashes::BtHash m_oBTH; // BitTorrent Info Hash (Base32)
Hashes::BtGuid m_pPeerID; // PeerProject Peer ID
CAutoPtr< CHttpRequest > m_pRequest; // HTTP request object
CTrackerEvent* m_pOnTrackerEvent; // Callback
BTTrackerEvent m_nEvent; // Tracker event (update, announce, etc.)
CEvent m_pCancel; // Cancel flag
QWORD m_nConnectionID; // UDP tracker connection ID
DWORD m_nTransactionID; // UDP tracker transaction ID
DWORD m_nNumWant; // Number of peers wanted
QWORD m_nTorrentUploaded;
QWORD m_nTorrentDownloaded;
QWORD m_nTorrentLeft;
DWORD m_nComplete; // Scrape Seeds
DWORD m_nIncomplete; // Scrape Leeches
DWORD m_nDownloaded; // Scrape Download Count
DWORD m_nInterval; // Tracker request interval (in seconds)
CBTTrackerSourceList m_pSources; // Peers
void ProcessHTTP();
void ProcessUDP();
void Process(const CBENode* pRoot);
static UINT ThreadStart(LPVOID pParam);
void OnRun();
void OnTrackerEvent(bool bSuccess, LPCTSTR pszReason, LPCTSTR pszTip = NULL);
inline bool IsCanceled() const { return ( WaitForSingleObject( m_pCancel, 0 ) != WAIT_TIMEOUT ); }
friend class CBTTrackerRequests;
private:
CBTTrackerRequest(const CBTTrackerRequest&);
CBTTrackerRequest& operator=(const CBTTrackerRequest&);
};
template<>
inline void CAutoPtr< CBTTrackerRequest >::Free() throw()
{
if ( m_p )
{
m_p->Release();
m_p = NULL;
}
}
//
// BitTorrent Tracker request manager
//
class CBTTrackerRequests
{
public:
CBTTrackerRequests();
~CBTTrackerRequests();
public:
// Create tracker request. Return transaction ID (0 if error). (Add)
DWORD Request(CDownload* pDownload, BTTrackerEvent nEvent, DWORD nNumWant = 0, CTrackerEvent* pOnTrackerEvent = NULL);
CBTTrackerRequest* Lookup(DWORD nTransactionID) const;
BOOL Check(DWORD nTransactionID) const;
void Cancel(DWORD nTransactionID); // Cancel tracker request
void Clear(); // Cancel all requests
protected:
typedef CMap< DWORD, DWORD, CBTTrackerRequest*, CBTTrackerRequest* > CBTTrackerRequestMap;
mutable CCriticalSection m_pSection;
CBTTrackerRequestMap m_pTrackerRequests; // Tracker ID to tracker pointer map
// DWORD Add(CBTTrackerRequest* pRequest);
void Remove(DWORD nTransactionID);
CBTTrackerRequest* GetFirst() const;
friend class CBTTrackerRequest;
};
extern CBTTrackerRequests TrackerRequests;