00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Network.h"
00026 #include "BENode.h"
00027 #include "BTClients.h"
00028 #include "BTTrackerRequest.h"
00029 #include "Transfers.h"
00030 #include "Downloads.h"
00031 #include "Download.h"
00032 #include "SHA.h"
00033
00034 #ifdef _DEBUG
00035 #define new DEBUG_NEW
00036 #undef THIS_FILE
00037 static char THIS_FILE[] = __FILE__;
00038 #endif
00039
00040 BEGIN_MESSAGE_MAP(CBTTrackerRequest, CWinThread)
00041
00042
00043 END_MESSAGE_MAP()
00044
00045
00047
00048
00049 CBTTrackerRequest::CBTTrackerRequest(CDownload* pDownload, LPCTSTR pszVerb, BOOL bProcess, WORD nNumWant)
00050 {
00051 ASSERT( pDownload != NULL );
00052 ASSERT( pDownload->m_pTorrent.IsAvailable() );
00053
00054 m_bAutoDelete = TRUE;
00055 m_pDownload = pDownload;
00056 m_bProcess = bProcess;
00057
00058 CString strURL;
00059
00060 strURL.Format( _T("%s?info_hash=%s&peer_id=%s&port=%i&uploaded=%I64i&downloaded=%I64i&left=%I64i&compact=1"),
00061 (LPCTSTR)pDownload->m_pTorrent.m_sTracker,
00062 (LPCTSTR)Escape( &pDownload->m_pBTH ),
00063 (LPCTSTR)Escape( &m_pDownload->m_pPeerID ),
00064 Network.m_pHost.sin_port ? (int)htons( Network.m_pHost.sin_port ) : (int)Settings.Connection.InPort,
00065 (QWORD)pDownload->m_nTorrentUploaded,
00066 (QWORD)pDownload->m_nTorrentDownloaded,
00067 (QWORD)pDownload->GetVolumeRemaining() );
00068
00069
00070 if ( Network.m_pHost.sin_addr.S_un.S_addr != 0 )
00071 {
00072 strURL += _T("&ip=");
00073 strURL += inet_ntoa( Network.m_pHost.sin_addr );
00074
00075 }
00076
00077
00078 if ( pszVerb != NULL )
00079 {
00080 strURL += _T("&event=");
00081 strURL += pszVerb;
00082
00083 }
00084
00085
00086 if ( nNumWant < 300 )
00087 {
00088 CString strNumWant;
00089 strNumWant.Format( _T("&numwant=%i"), nNumWant );
00090 strURL += strNumWant;
00091
00092
00093
00094 }
00095
00096
00097 if ( ( pDownload->m_sKey.GetLength() > 4 ) && ( Settings.BitTorrent.TrackerKey ) )
00098 {
00099 ASSERT ( pDownload->m_sKey.GetLength() < 20 );
00100
00101 strURL += _T("&key=");
00102 strURL += pDownload->m_sKey;
00103 }
00104
00105 m_pRequest.SetURL( strURL );
00106
00107 m_pRequest.AddHeader( _T("Accept-Encoding"), _T("gzip") );
00108
00109 if ( Settings.BitTorrent.StandardPeerID )
00110 {
00111 CString strUserAgent = Settings.SmartAgent();
00112 m_pRequest.SetUserAgent( strUserAgent );
00113 }
00114
00115
00116
00117
00118
00119 BTClients.Add( this );
00120 CreateThread();
00121 }
00122
00123 CBTTrackerRequest::~CBTTrackerRequest()
00124 {
00125 BTClients.Remove( this );
00126 }
00127
00129
00130
00131 void CBTTrackerRequest::SendStarted(CDownloadBase* pDownload, WORD nNumWant)
00132 {
00133 if ( ((CDownload*)pDownload)->m_pTorrent.m_sTracker.IsEmpty() ) return;
00134 new CBTTrackerRequest( (CDownload*)pDownload, _T("started"), TRUE, nNumWant );
00135 }
00136
00137 void CBTTrackerRequest::SendUpdate(CDownloadBase* pDownload, WORD nNumWant)
00138 {
00139 if ( ((CDownload*)pDownload)->m_pTorrent.m_sTracker.IsEmpty() ) return;
00140 new CBTTrackerRequest( (CDownload*)pDownload, NULL , TRUE, nNumWant );
00141 }
00142
00143 void CBTTrackerRequest::SendCompleted(CDownloadBase* pDownload)
00144 {
00145 if ( ((CDownload*)pDownload)->m_pTorrent.m_sTracker.IsEmpty() ) return;
00146 new CBTTrackerRequest( (CDownload*)pDownload, _T("completed"), TRUE, 0 );
00147 }
00148
00149 void CBTTrackerRequest::SendStopped(CDownloadBase* pDownload)
00150 {
00151 if ( ((CDownload*)pDownload)->m_pTorrent.m_sTracker.IsEmpty() ) return;
00152 new CBTTrackerRequest( (CDownload*)pDownload, _T("stopped"), FALSE, 0xFFFF );
00153 }
00154
00156
00157
00158 CString CBTTrackerRequest::Escape(SHA1* pSHA1)
00159 {
00160 static LPCTSTR pszHex = _T("0123456789ABCDEF");
00161
00162 CString str;
00163 LPTSTR psz = str.GetBuffer( sizeof(SHA1) * 3 + 1 );
00164
00165 for ( int nByte = 0 ; nByte < sizeof(SHA1) ; nByte++ )
00166 {
00167 int nValue = (int)(unsigned char)pSHA1->n[ nByte ];
00168
00169 if ( ( nValue >= '0' && nValue <= '9' ) ||
00170 ( nValue >= 'a' && nValue <= 'z' ) ||
00171 ( nValue >= 'A' && nValue <= 'Z' ) )
00172 {
00173 *psz++ = (TCHAR)nValue;
00174 }
00175 else
00176 {
00177 *psz++ = '%';
00178 *psz++ = pszHex[ ( nValue >> 4 ) & 15 ];
00179 *psz++ = pszHex[ nValue & 15 ];
00180 }
00181 }
00182
00183 *psz = 0;
00184 str.ReleaseBuffer();
00185
00186 return str;
00187 }
00188
00190
00191
00192 BOOL CBTTrackerRequest::InitInstance()
00193 {
00194 return TRUE;
00195 }
00196
00197 int CBTTrackerRequest::Run()
00198 {
00199 if ( m_bProcess )
00200 {
00201 Process( m_pRequest.Execute( FALSE ) );
00202 }
00203 else
00204 {
00205 m_pRequest.Execute( FALSE );
00206 }
00207
00208 return 0;
00209 }
00210
00211 void CBTTrackerRequest::Process(BOOL bRequest)
00212 {
00213 CSingleLock pLock( &Transfers.m_pSection );
00214
00215 if ( ! pLock.Lock( 250 ) ) return;
00216 if ( ! Downloads.Check( m_pDownload ) ) return;
00217 if ( ! m_pDownload->m_bTorrentRequested ) return;
00218
00219 if ( ! bRequest )
00220 {
00221 m_pDownload->OnTrackerEvent( FALSE );
00222 return;
00223 }
00224
00225 if ( ! m_pRequest.InflateResponse() )
00226 {
00227 theApp.Message( MSG_ERROR, IDS_BT_TRACK_PARSE_ERROR );
00228 return;
00229 }
00230
00231 CBuffer* pBuffer = m_pRequest.GetResponseBuffer();
00232 if ( pBuffer == NULL ) return;
00233
00234 CBENode* pRoot = CBENode::Decode( pBuffer );
00235
00236 if ( pRoot->IsType( CBENode::beDict ) )
00237 {
00238 Process( pRoot );
00239 }
00240 else if ( pRoot->IsType( CBENode::beString ) )
00241 {
00242 CString str = pRoot->GetString();
00243 theApp.Message( MSG_ERROR, IDS_BT_TRACK_ERROR,
00244 (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)str );
00245 m_pDownload->OnTrackerEvent( FALSE, str );
00246 }
00247 else
00248 {
00249 theApp.Message( MSG_ERROR, IDS_BT_TRACK_PARSE_ERROR );
00250 m_pDownload->OnTrackerEvent( FALSE );
00251 }
00252
00253 if ( pRoot != NULL ) delete pRoot;
00254 }
00255
00256 BOOL CBTTrackerRequest::Process(CBENode* pRoot)
00257 {
00258 CString strError;
00259
00260
00261 if ( CBENode* pError = pRoot->GetNode( "failure reason" ) )
00262 {
00263 strError = pError->GetString();
00264 theApp.Message( MSG_ERROR, IDS_BT_TRACK_ERROR,
00265 (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)strError );
00266 m_pDownload->OnTrackerEvent( FALSE, strError );
00267 return FALSE;
00268 }
00269
00270
00271 CBENode* pInterval = pRoot->GetNode( "interval" );
00272 if ( ! pInterval->IsType( CBENode::beInt ) )
00273 {
00274 LoadString( strError, IDS_BT_TRACK_PARSE_ERROR );
00275 m_pDownload->OnTrackerEvent( FALSE, strError );
00276 return FALSE;
00277 }
00278 int nInterval = (int)(DWORD)pInterval->GetInt();
00279
00280
00281 nInterval = max( nInterval, 60*2 );
00282 nInterval = min( nInterval, 60*60 );
00283
00284 m_pDownload->m_tTorrentTracker = GetTickCount() + 1000 * nInterval;
00285 m_pDownload->m_bTorrentStarted = TRUE;
00286
00287
00288 CBENode* pPeers = pRoot->GetNode( "peers" );
00289 int nCount = 0;
00290
00291 if ( pPeers->IsType( CBENode::beList ) && ( ( ! m_pDownload->IsMoving() ) || ( Settings.Connection.FirewallStatus == CONNECTION_FIREWALLED ) ) )
00292 {
00293 for ( int nPeer = 0 ; nPeer < pPeers->GetCount() ; nPeer++ )
00294 {
00295 CBENode* pPeer = pPeers->GetNode( nPeer );
00296 if ( ! pPeer->IsType( CBENode::beDict ) ) continue;
00297
00298 CBENode* pID = pPeer->GetNode( "peer id" );
00299
00300 CBENode* pIP = pPeer->GetNode( "ip" );
00301 if ( ! pIP->IsType( CBENode::beString ) ) continue;
00302
00303 CBENode* pPort = pPeer->GetNode( "port" );
00304 if ( ! pPort->IsType( CBENode::beInt ) ) continue;
00305
00306 SOCKADDR_IN saPeer;
00307 if ( ! Network.Resolve( pIP->GetString(), (int)pPort->GetInt(), &saPeer ) ) continue;
00308
00309 theApp.Message( MSG_DEBUG, _T("Tracker: %s:%i"),
00310 (LPCTSTR)CString( inet_ntoa( saPeer.sin_addr ) ), htons( saPeer.sin_port ) );
00311
00312 if ( pID->IsType( CBENode::beString ) && pID->m_nValue == sizeof(SHA1) )
00313 {
00314 nCount += m_pDownload->AddSourceBT( (SHA1*)pID->m_pValue,
00315 &saPeer.sin_addr, ntohs( saPeer.sin_port ) );
00316 }
00317 else
00318 {
00319 nCount += m_pDownload->AddSourceBT( NULL,
00320 &saPeer.sin_addr, ntohs( saPeer.sin_port ) );
00321 }
00322 }
00323 }
00324 else if ( pPeers->IsType( CBENode::beString ) && ( ( ! m_pDownload->IsMoving() ) || ( Settings.Connection.FirewallStatus == CONNECTION_FIREWALLED ) ) )
00325 {
00326 if ( 0 == ( pPeers->m_nValue % 6 ) )
00327 {
00328 BYTE* pPointer = (BYTE*)pPeers->m_pValue;
00329
00330 for ( int nPeer = (int)pPeers->m_nValue / 6 ; nPeer > 0 ; nPeer --, pPointer += 6 )
00331 {
00332 IN_ADDR* pAddress = (IN_ADDR*)pPointer;
00333 WORD nPort = *(WORD*)( pPointer + 4 );
00334
00335 nCount += m_pDownload->AddSourceBT( NULL, pAddress, ntohs( nPort ) );
00336 }
00337 }
00338 }
00339
00340
00341 m_pDownload->OnTrackerEvent( TRUE );
00342
00343 theApp.Message( MSG_DEFAULT, IDS_BT_TRACK_SUCCESS,
00344 (LPCTSTR)m_pDownload->GetDisplayName(), nCount );
00345 return TRUE;
00346 }
00347