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 <limits>
00024 #include "Shareaza.h"
00025 #include "Settings.h"
00026 #include "BTClients.h"
00027 #include "BTClient.h"
00028 #include "BTPacket.h"
00029 #include "Download.h"
00030 #include "Downloads.h"
00031 #include "DownloadSource.h"
00032 #include "DownloadTransferBT.h"
00033 #include "FragmentedFile.h"
00034 #include "Network.h"
00035 #include "Buffer.h"
00036 #include "BENode.h"
00037
00038 #ifdef _DEBUG
00039 #undef THIS_FILE
00040 static char THIS_FILE[]=__FILE__;
00041 #define new DEBUG_NEW
00042 #endif
00043
00045
00046
00047 CDownloadTransferBT::CDownloadTransferBT(CDownloadSource* pSource, CBTClient* pClient) : CDownloadTransfer( pSource, PROTOCOL_BT )
00048 {
00049 ASSERT( m_pDownload->m_bBTH );
00050 ASSERT( m_pDownload->m_nSize != SIZE_UNKNOWN );
00051
00052 m_pClient = pClient;
00053 m_nState = pClient ? dtsConnecting : dtsNull;
00054 m_sUserAgent = _T("BitTorrent");
00055
00056 m_bChoked = TRUE;
00057 m_bInterested = FALSE;
00058
00059 m_pAvailable = NULL;
00060
00061 m_tRunThrottle = 0;
00062 m_tSourceRequest = GetTickCount();
00063 }
00064
00065 CDownloadTransferBT::~CDownloadTransferBT()
00066 {
00067 ASSERT( m_pClient == NULL );
00068 if ( m_pAvailable != NULL ) delete [] m_pAvailable;
00069 }
00070
00072
00073
00074 BOOL CDownloadTransferBT::Initiate()
00075 {
00076 ASSERT( m_pClient == NULL );
00077 ASSERT( m_nState == dtsNull );
00078 m_pClient = new CBTClient();
00079 if ( ! m_pClient->Connect( this ) )
00080 {
00081 delete m_pClient;
00082 m_pClient = NULL;
00083 Close( TS_FALSE );
00084 return FALSE;
00085 }
00086 SetState( dtsConnecting );
00087 m_tConnected = GetTickCount();
00088 m_pHost = m_pClient->m_pHost;
00089 m_sAddress = m_pClient->m_sAddress;
00090
00091 return TRUE;
00092 }
00093
00095
00096
00097 void CDownloadTransferBT::Close(TRISTATE bKeepSource)
00098 {
00099 if ( m_pClient != NULL )
00100 {
00101 m_pClient->m_pDownloadTransfer = NULL;
00102 if ( m_pClient->IsOnline() )
00103 {
00104 m_pClient->Send( CBTPacket::New( BT_PACKET_NOT_INTERESTED ) );
00105 }
00106 else
00107 {
00108 m_pClient->Close();
00109 }
00110 m_pClient = NULL;
00111 }
00112 CDownloadTransfer::Close( bKeepSource );
00113 }
00114
00116
00117
00118 void CDownloadTransferBT::Boost()
00119 {
00120 if ( m_pClient == NULL ) return;
00121 m_pClient->m_mInput.pLimit = NULL;
00122 }
00123
00124 DWORD CDownloadTransferBT::GetAverageSpeed()
00125 {
00126 return m_pSource->m_nSpeed = GetMeasuredSpeed();
00127 }
00128
00129 DWORD CDownloadTransferBT::GetMeasuredSpeed()
00130 {
00131 if ( m_pClient == NULL ) return 0;
00132 m_pClient->Measure();
00133 return m_pClient->m_mInput.nMeasure;
00134 }
00135
00136 CString CDownloadTransferBT::GetStateText(BOOL bLong)
00137 {
00138 if ( m_nState == dtsTorrent )
00139 {
00140 CString str;
00141 if ( ! m_bInterested ) LoadString( str, IDS_STATUS_UNINTERESTED );
00142 else if ( m_bChoked ) LoadString( str, IDS_STATUS_CHOKED );
00143 else LoadString( str, IDS_STATUS_REQUESTING );
00144 return str;
00145 }
00146 return CDownloadTransfer::GetStateText( bLong );
00147 }
00148
00150
00151
00152 void CDownloadTransferBT::Send(CBTPacket* pPacket, BOOL bRelease)
00153 {
00154 ASSERT( m_pClient != NULL );
00155 m_pClient->Send( pPacket, bRelease );
00156 }
00157
00159
00160
00161 BOOL CDownloadTransferBT::OnRun()
00162 {
00163 DWORD tNow = GetTickCount();
00164 if ( tNow - m_tRunThrottle >= 2000 )
00165 {
00166 m_tRunThrottle = tNow;
00167 ShowInterest();
00168 if ( m_nState == dtsTorrent || m_nState == dtsRequesting || m_nState == dtsDownloading )
00169 {
00170 if ( ! SendRequests() ) return FALSE;
00171 }
00172 }
00173 if ( m_pClient->m_bExchange && tNow - m_tSourceRequest >= Settings.BitTorrent.SourceExchangePeriod * 60000 )
00174 {
00175 Send( CBTPacket::New( BT_PACKET_SOURCE_REQUEST ) );
00176 m_tSourceRequest = tNow;
00177 }
00178 return CDownloadTransfer::OnRun();
00179 }
00180
00182
00183
00184 BOOL CDownloadTransferBT::OnConnected()
00185 {
00186 ASSERT( m_pClient != NULL );
00187 ASSERT( m_pSource != NULL );
00188
00189 if( m_pDownload->IsCompleted() )
00190 {
00191
00192 theApp.Message( MSG_DEFAULT, _T("Initiated push start for upload to %s"), (LPCTSTR)m_sAddress );
00193 Close( TS_FALSE );
00194 return FALSE;
00195 }
00196 else
00197 {
00198
00199 SetState( dtsTorrent );
00200 m_pHost = m_pClient->m_pHost;
00201 m_sAddress = m_pClient->m_sAddress;
00202 m_pSource->SetLastSeen();
00203 m_pClient->m_mInput.pLimit = &Downloads.m_nLimitGeneric;
00204 theApp.Message( MSG_DEFAULT, IDS_DOWNLOAD_CONNECTED, (LPCTSTR)m_sAddress );
00205 if ( ! m_pDownload->PrepareFile() )
00206 {
00207 Close( TS_TRUE );
00208 return FALSE;
00209 }
00210 return TRUE;
00211 }
00212 }
00213
00215
00216
00217 BOOL CDownloadTransferBT::OnBitfield(CBTPacket* pPacket)
00218 {
00219 QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
00220 DWORD nBlockCount = m_pDownload->m_pTorrent.m_nBlockCount;
00221
00222 m_pSource->m_oAvailable.clear();
00223
00224 if ( m_pAvailable != NULL ) delete [] m_pAvailable;
00225 m_pAvailable = NULL;
00226
00227 if ( nBlockSize == 0 || nBlockCount == 0 ) return TRUE;
00228
00229 m_pAvailable = new BYTE[ nBlockCount ];
00230 ZeroMemory( m_pAvailable, nBlockCount );
00231
00232 for ( DWORD nBlock = 0 ; nBlock < nBlockCount && pPacket->GetRemaining() ; )
00233 {
00234 BYTE nByte = pPacket->ReadByte();
00235
00236 for ( int nBit = 7 ; nBit >= 0 && nBlock < nBlockCount ; nBit--, nBlock++ )
00237 {
00238 if ( nByte & ( 1 << nBit ) )
00239 {
00240 QWORD nOffset = nBlockSize * nBlock;
00241 QWORD nLength = min( nBlockSize, m_pDownload->m_nSize - nOffset );
00242 m_pSource->m_oAvailable.insert( m_pSource->m_oAvailable.end(),
00243 FF::SimpleFragment( nOffset, nOffset + nLength ) );
00244 m_pAvailable[ nBlock ] = TRUE;
00245 }
00246 }
00247 }
00248
00249 ShowInterest();
00250 return TRUE;
00251 }
00252
00254
00255
00256 void CDownloadTransferBT::SendFinishedBlock(DWORD nBlock)
00257 {
00258 if ( m_pClient == NULL || ! m_pClient->IsOnline() ) return;
00259 CBTPacket* pPacket = CBTPacket::New( BT_PACKET_HAVE );
00260 pPacket->WriteLongBE( nBlock );
00261 Send( pPacket );
00262 }
00263
00264 BOOL CDownloadTransferBT::OnHave(CBTPacket* pPacket)
00265 {
00266 if ( pPacket->GetRemaining() != sizeof(int) ) return TRUE;
00267 QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
00268 DWORD nBlockCount = m_pDownload->m_pTorrent.m_nBlockCount;
00269 DWORD nBlock = pPacket->ReadLongBE();
00270 if ( nBlock >= nBlockCount ) return TRUE;
00271 QWORD nOffset = nBlockSize * nBlock;
00272 QWORD nLength = min( nBlockSize, m_pDownload->m_nSize - nOffset );
00273 m_pSource->m_oAvailable.insert( FF::SimpleFragment( nOffset, nOffset + nLength ) );
00274
00275 if ( m_pAvailable == NULL )
00276 {
00277 m_pAvailable = new BYTE[ nBlockCount ];
00278 ZeroMemory( m_pAvailable, nBlockCount );
00279 }
00280
00281 m_pAvailable[ nBlock ] = TRUE;
00282 ShowInterest();
00283 return TRUE;
00284 }
00285
00287
00288
00289 void CDownloadTransferBT::ShowInterest()
00290 {
00291 BOOL bInterested = FALSE;
00292
00293
00294
00295
00296 if ( m_pAvailable == NULL )
00297 {
00298
00299
00300 }
00301 else if ( QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize )
00302 {
00303 for ( FF::SimpleFragmentList::ConstIterator pFragment
00304 = m_pDownload->GetEmptyFragmentList().begin();
00305 !bInterested && pFragment != m_pDownload->GetEmptyFragmentList().end();
00306 ++pFragment )
00307 {
00308 DWORD nBlock = DWORD( pFragment->begin() / nBlockSize );
00309
00310 for ( DWORD nEnd = DWORD( ( pFragment->end() - 1 ) / nBlockSize );
00311 nBlock <= nEnd; ++nBlock )
00312 {
00313 if ( m_pAvailable[ nBlock ] )
00314 {
00315 bInterested = TRUE;
00316 break;
00317 }
00318 }
00319 }
00320 }
00321
00322 if ( bInterested != m_bInterested )
00323 {
00324 m_bInterested = bInterested;
00325 Send( CBTPacket::New( bInterested ? BT_PACKET_INTERESTED : BT_PACKET_NOT_INTERESTED ) );
00326
00327 if ( ! bInterested )
00328 {
00329 m_oRequested.clear();
00330 }
00331 }
00332 }
00333
00335
00336
00337 BOOL CDownloadTransferBT::OnChoked(CBTPacket* pPacket)
00338 {
00339 if ( m_bChoked ) return TRUE;
00340 m_bChoked = TRUE;
00341 SetState( dtsTorrent );
00342 theApp.Message( MSG_DEBUG, _T("Download from %s was choked."), (LPCTSTR)m_sAddress );
00343 for ( FF::SimpleFragmentQueue::ConstIterator pFragment = m_oRequested.begin();
00344 pFragment != m_oRequested.end() ; ++pFragment )
00345 {
00346 CBTPacket* pPacket = CBTPacket::New( BT_PACKET_CANCEL );
00347 pPacket->WriteLongBE( (DWORD)( pFragment->begin() / m_pDownload->m_pTorrent.m_nBlockSize ) );
00348 pPacket->WriteLongBE( (DWORD)( pFragment->begin() % m_pDownload->m_pTorrent.m_nBlockSize ) );
00349 pPacket->WriteLongBE( (DWORD)pFragment->length() );
00350 Send( pPacket );
00351 }
00352 m_oRequested.clear();
00353 return TRUE;
00354 }
00355
00356 BOOL CDownloadTransferBT::OnUnchoked(CBTPacket* pPacket)
00357 {
00358 m_bChoked = FALSE;
00359 SetState( dtsTorrent );
00360 m_oRequested.clear();
00361
00362 theApp.Message( MSG_DEBUG, _T("Download from %s was Unchoked."), (LPCTSTR)m_sAddress );
00363
00364 return SendRequests();
00365 }
00366
00368
00369
00370 BOOL CDownloadTransferBT::SendRequests()
00371 {
00372 ASSERT( m_nState == dtsTorrent || m_nState == dtsRequesting || m_nState == dtsDownloading );
00373 if ( m_bChoked || ! m_bInterested )
00374 {
00375 if ( m_oRequested.empty() ) SetState( dtsTorrent );
00376 return TRUE;
00377 }
00378 if ( m_oRequested.size() >= (int)Settings.BitTorrent.RequestPipe )
00379 {
00380 if ( m_nState != dtsDownloading ) SetState( dtsRequesting );
00381 return TRUE;
00382 }
00383 QWORD nBlockSize = m_pDownload->m_pTorrent.m_nBlockSize;
00384 ASSERT( nBlockSize != 0 );
00385 if ( nBlockSize == 0 ) return TRUE;
00386
00387 FF::SimpleFragmentList oPossible( m_pDownload->GetEmptyFragmentList() );
00388
00389 if ( ! m_pDownload->m_bTorrentEndgame )
00390 {
00391 for ( CDownloadTransfer* pTransfer = m_pDownload->GetFirstTransfer() ; pTransfer && !oPossible.empty() ; pTransfer = pTransfer->m_pDlNext )
00392 {
00393 pTransfer->SubtractRequested( oPossible );
00394 }
00395 }
00396 while ( m_oRequested.size() < (int)Settings.BitTorrent.RequestPipe )
00397 {
00398 QWORD nOffset, nLength;
00399 if ( SelectFragment( oPossible, nOffset, nLength ) )
00400 {
00401 ChunkifyRequest( &nOffset, &nLength, Settings.BitTorrent.RequestSize, FALSE );
00402
00403 FF::SimpleFragment Selected( nOffset, nOffset + nLength );
00404 oPossible.erase( Selected );
00405
00406 m_oRequested.pushBack( Selected );
00407
00408 int nType = ( m_nDownloaded == 0 || ( nOffset % nBlockSize ) == 0 )
00409 ? MSG_DEFAULT : MSG_DEBUG;
00410 theApp.Message( nType, IDS_DOWNLOAD_FRAGMENT_REQUEST,
00411 nOffset, nOffset + nLength - 1,
00412 (LPCTSTR)m_pDownload->GetDisplayName(), (LPCTSTR)m_sAddress );
00413 #ifdef _DEBUG
00414 DWORD ndBlock1 = (DWORD)( nOffset / nBlockSize );
00415 DWORD ndBlock2 = (DWORD)( ( nOffset + nLength - 1 ) / nBlockSize );
00416 ASSERT( ndBlock1 < m_pDownload->m_pTorrent.m_nBlockCount );
00417 ASSERT( ndBlock1 == ndBlock2 );
00418 ASSERT( nLength <= nBlockSize );
00419 #endif
00420 CBTPacket* pPacket = CBTPacket::New( BT_PACKET_REQUEST );
00421 pPacket->WriteLongBE( (DWORD)( nOffset / nBlockSize ) );
00422 pPacket->WriteLongBE( (DWORD)( nOffset % nBlockSize ) );
00423 pPacket->WriteLongBE( (DWORD)nLength );
00424 Send( pPacket );
00425 }
00426 else
00427 {
00428 break;
00429 }
00430 }
00431
00432 if ( oPossible.empty() && Settings.BitTorrent.Endgame && ! m_pDownload->m_bTorrentEndgame )
00433 {
00434
00435 if ( m_pDownload->GetProgress() > 0.95 )
00436 {
00437
00438 m_pDownload->m_bTorrentEndgame = TRUE;
00439 theApp.Message( MSG_DEBUG, _T("Torrent EndGame mode activated for %s"), m_pDownload->m_sLocalName );
00440 }
00441 }
00442
00443 if ( !m_oRequested.empty() && m_nState != dtsDownloading ) SetState( dtsRequesting );
00444 if ( m_oRequested.empty() ) SetState( dtsTorrent );
00445 return TRUE;
00446 }
00447
00449
00450
00451 BOOL CDownloadTransferBT::SelectFragment(const FF::SimpleFragmentList& oPossible, QWORD& nOffset, QWORD& nLength)
00452 {
00453 FF::SimpleFragment oSelection( selectBlock( oPossible,
00454 m_pDownload->m_pTorrent.m_nBlockSize, m_pAvailable ) );
00455
00456 if ( oSelection.end() == ::std::numeric_limits< FF::SimpleFragment::SizeType >::max() ) return FALSE;
00457
00458 nOffset = oSelection.begin();
00459 nLength = oSelection.length();
00460
00461 return TRUE;
00462 }
00463
00465
00466
00467 BOOL CDownloadTransferBT::SubtractRequested(FF::SimpleFragmentList& ppFragments)
00468 {
00469 if ( m_oRequested.empty() || m_bChoked ) return FALSE;
00470 ppFragments.erase( m_oRequested.begin(), m_oRequested.end() );
00471 return TRUE;
00472 }
00473
00474 BOOL CDownloadTransferBT::UnrequestRange(QWORD nOffset, QWORD nLength)
00475 {
00476 if ( m_oRequested.empty() ) return FALSE;
00477 ASSERT( m_pDownload->m_pTorrent.m_nBlockSize != 0 );
00478 if ( m_pDownload->m_pTorrent.m_nBlockSize == 0 ) return FALSE;
00479
00480 FF::SimpleFragmentQueue oUnrequests = extractRange( m_oRequested,
00481 FF::SimpleFragment( nOffset, nOffset + nLength ) );
00482
00483 for ( FF::SimpleFragmentQueue::ConstIterator pFragment
00484 = oUnrequests.begin(); pFragment != oUnrequests.end(); ++pFragment )
00485 {
00486 CBTPacket* pPacket = CBTPacket::New( BT_PACKET_CANCEL );
00487 pPacket->WriteLongBE( (DWORD)( pFragment->begin() / m_pDownload->m_pTorrent.m_nBlockSize ) );
00488 pPacket->WriteLongBE( (DWORD)( pFragment->begin() % m_pDownload->m_pTorrent.m_nBlockSize ) );
00489 pPacket->WriteLongBE( (DWORD)pFragment->length() );
00490 Send( pPacket );
00491 }
00492
00493 return !oUnrequests.empty();
00494 }
00495
00497
00498
00499 BOOL CDownloadTransferBT::OnPiece(CBTPacket* pPacket)
00500 {
00501 ASSERT( m_pClient != NULL );
00502 if ( pPacket->GetRemaining() < 8 ) return TRUE;
00503 if ( m_nState != dtsRequesting && m_nState != dtsDownloading ) return TRUE;
00504 SetState( dtsDownloading );
00505 DWORD nBlock = pPacket->ReadLongBE();
00506 QWORD nOffset = pPacket->ReadLongBE();
00507 QWORD nLength = pPacket->GetRemaining();
00508 nOffset += (QWORD)nBlock * m_pDownload->m_pTorrent.m_nBlockSize;
00509 m_nDownloaded += nLength;
00510 m_pDownload->m_nTorrentDownloaded += nLength;
00511 m_pSource->AddFragment( nOffset, nLength );
00512 m_pSource->SetValid();
00513 m_oRequested.erase( FF::SimpleFragment( nOffset, nOffset + nLength ) );
00514
00515 m_pDownload->SubmitData( nOffset,
00516 pPacket->m_pBuffer + pPacket->m_nPosition, nLength );
00517
00518
00519 ShowInterest();
00520 return SendRequests();
00521 }
00522
00524
00525
00526 BOOL CDownloadTransferBT::OnSourceResponse(CBTPacket* pPacket)
00527 {
00528 CBuffer pInput;
00529 pInput.Add( pPacket->m_pBuffer, pPacket->GetRemaining() );
00530 CBENode* pRoot = CBENode::Decode( &pInput );
00531 if ( pRoot == NULL ) return TRUE;
00532 CBENode* pPeers = pRoot->GetNode( "peers" );
00533 if ( ! pPeers->IsType( CBENode::beList ) )
00534 {
00535 delete pRoot;
00536 return TRUE;
00537 }
00538
00539 int nCount = 0;
00540
00541 for ( int nPeer = 0 ; nPeer < pPeers->GetCount() ; nPeer++ )
00542 {
00543 CBENode* pPeer = pPeers->GetNode( nPeer );
00544 if ( ! pPeer->IsType( CBENode::beDict ) ) continue;
00545
00546 CBENode* pURL = pPeer->GetNode( "url" );
00547
00548 if ( pURL->IsType( CBENode::beString ) )
00549 {
00550 nCount += m_pDownload->AddSourceURL( pURL->GetString(), TRUE );
00551 }
00552 else
00553 {
00554 CBENode* pID = pPeer->GetNode( "peer id" );
00555 if ( ! pID->IsType( CBENode::beString ) || pID->m_nValue != sizeof(SHA1) ) continue;
00556
00557 CBENode* pIP = pPeer->GetNode( "ip" );
00558 if ( ! pIP->IsType( CBENode::beString ) ) continue;
00559
00560 CBENode* pPort = pPeer->GetNode( "port" );
00561 if ( ! pPort->IsType( CBENode::beInt ) ) continue;
00562
00563 SOCKADDR_IN saPeer;
00564 if ( ! Network.Resolve( pIP->GetString(), (int)pPort->GetInt(), &saPeer ) ) continue;
00565
00566 theApp.Message( MSG_DEBUG, _T("CDownloadTransferBT::OnSourceResponse(): %s: %s:%i"),
00567 (LPCTSTR)m_sAddress,
00568 (LPCTSTR)CString( inet_ntoa( saPeer.sin_addr ) ), htons( saPeer.sin_port ) );
00569
00570 nCount += m_pDownload->AddSourceBT( (SHA1*)pID->m_pValue,
00571 &saPeer.sin_addr, htons( saPeer.sin_port ) );
00572 }
00573 }
00574
00575 delete pRoot;
00576
00577 theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_EXCHANGE, nCount, (LPCTSTR)m_sAddress );
00578
00579 return TRUE;
00580 }