Main Page | Namespace List | Class Hierarchy | Class List | Directories | File List | Namespace Members | Class Members | File Members

DownloadWithTorrent.cpp

Go to the documentation of this file.
00001 //
00002 // DownloadWithTorrent.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Network.h"
00026 #include "BTPacket.h"
00027 #include "BTClient.h"
00028 #include "BTClients.h"
00029 #include "Download.h"
00030 #include "DownloadTask.h"
00031 #include "DownloadSource.h"
00032 #include "DownloadWithTorrent.h"
00033 #include "DownloadTransferBT.h"
00034 #include "UploadTransferBT.h"
00035 #include "BTTrackerRequest.h"
00036 #include "FragmentedFile.h"
00037 #include "Buffer.h"
00038 #include "SHA.h"
00039 #include "LibraryFolders.h"
00040 #include "GProfile.h"
00041 #include "Uploads.h"
00042 #include "UploadTransfer.h"
00043 
00044 #ifdef _DEBUG
00045 #undef THIS_FILE
00046 static char THIS_FILE[]=__FILE__;
00047 #define new DEBUG_NEW
00048 #endif
00049 
00050 
00052 // CDownloadWithTorrent construction
00053 
00054 CDownloadWithTorrent::CDownloadWithTorrent()
00055 {
00056         m_bTorrentRequested             = FALSE;
00057         m_bTorrentStarted               = FALSE;
00058         m_tTorrentTracker               = 0;
00059         m_nTorrentUploaded              = 0;
00060         m_nTorrentDownloaded    = 0;
00061         m_bTorrentEndgame               = FALSE;
00062         m_bTorrentTrackerError  = FALSE;
00063         m_nTorrentTrackerErrors = 0;
00064         
00065         m_pTorrentBlock                 = NULL;
00066         m_nTorrentBlock                 = 0;
00067         m_nTorrentSize                  = 0;
00068         m_nTorrentSuccess               = 0;
00069         m_bSeeding                              = FALSE;
00070         
00071         m_tTorrentChoke                 = 0;
00072         m_tTorrentSources               = 0;
00073         ZeroMemory(m_pPeerID.n, 20);
00074 
00075         // Generate random Key value
00076         m_sKey = _T("");
00077         srand( GetTickCount() );
00078         for ( int nChar = 1 ; nChar < 6 ; nChar++ ) 
00079         {
00080                 m_sKey += GenerateCharacter();
00081         }
00082 
00083         m_nStartTorrentDownloads= dtAlways;
00084 }
00085 
00086 CDownloadWithTorrent::~CDownloadWithTorrent()
00087 {
00088         if ( m_bTorrentRequested ) CBTTrackerRequest::SendStopped( this );
00089         CloseTorrentUploads();
00090         if ( m_pTorrentBlock != NULL ) delete [] m_pTorrentBlock;
00091 }
00092 
00094 // CDownloadWithTorrent serialize
00095 
00096 void CDownloadWithTorrent::Serialize(CArchive& ar, int nVersion)
00097 {
00098         CDownloadWithFile::Serialize( ar, nVersion );
00099         
00100         if ( nVersion < 22 ) return;
00101         
00102         m_pTorrent.Serialize( ar );
00103         
00104         if ( ar.IsLoading() && m_pTorrent.IsAvailable() )
00105         {
00106                 m_bBTH = TRUE;
00107                 m_bBTHTrusted = TRUE;
00108                 m_pBTH = m_pTorrent.m_pInfoSHA1;
00109         }
00110 
00111         if ( nVersion >= 23 && m_pTorrent.IsAvailable() )
00112         {
00113                 if ( ar.IsStoring() )
00114                 {
00115                         ar << m_nTorrentSuccess;
00116                         ar.Write( m_pTorrentBlock, sizeof(BYTE) * m_nTorrentBlock );
00117                 }
00118                 else
00119                 {
00120                         m_nTorrentSize  = m_pTorrent.m_nBlockSize;
00121                         m_nTorrentBlock = m_pTorrent.m_nBlockCount;
00122                         
00123                         ar >> m_nTorrentSuccess;
00124                         m_pTorrentBlock = new BYTE[ m_nTorrentBlock ];
00125                         ar.Read( m_pTorrentBlock, sizeof(BYTE) * m_nTorrentBlock );
00126                 }
00127         }
00128 }
00129 
00131 // CDownloadWithTorrent set torrent
00132 
00133 BOOL CDownloadWithTorrent::SetTorrent(CBTInfo* pTorrent)
00134 {
00135         if ( pTorrent == NULL ) return FALSE;
00136         if ( m_pTorrent.IsAvailable() ) return FALSE;
00137         if ( ! pTorrent->IsAvailable() ) return FALSE;
00138         
00139         m_pTorrent.Copy( pTorrent );
00140         
00141         m_bBTH = TRUE;
00142         m_pBTH = m_pTorrent.m_pInfoSHA1;
00143         
00144         m_nTorrentSize  = m_pTorrent.m_nBlockSize;
00145         m_nTorrentBlock = m_pTorrent.m_nBlockCount;
00146         m_pTorrentBlock = new BYTE[ m_nTorrentBlock ];
00147         
00148         ZeroMemory( m_pTorrentBlock, sizeof(BYTE) * m_nTorrentBlock );
00149         SetModified();
00150         
00151         CreateDirectory( Settings.Downloads.TorrentPath, NULL );//Create/set up torrents folder
00152         LibraryFolders.AddFolder( Settings.Downloads.TorrentPath, FALSE );
00153         pTorrent->SaveTorrentFile( Settings.Downloads.TorrentPath );
00154 
00155         if ( ! Settings.BitTorrent.AdvancedInterfaceSet )
00156         {
00157                 // If this is the first time the user has downloaded a torrent, turn the extra interface on.
00158                 Settings.BitTorrent.AdvancedInterfaceSet        = TRUE;
00159                 Settings.BitTorrent.AdvancedInterface           = TRUE;
00160         }
00161         
00162         return TRUE;
00163 }
00164 
00166 // CDownloadWithTorrent run
00167 
00168 BOOL CDownloadWithTorrent::RunTorrent(DWORD tNow)
00169 {
00170         if ( ! m_pTorrent.IsAvailable() ) return TRUE;
00171         if ( m_bDiskFull ) return FALSE;
00172         
00173         if ( tNow > m_tTorrentChoke && tNow - m_tTorrentChoke >= 10000 ) ChokeTorrent( tNow );
00174         
00175         if ( m_pFile != NULL && m_pFile->IsOpen() == FALSE )
00176         {
00177                 BOOL bCreated = ( m_sLocalName.IsEmpty() ||
00178                                                 GetFileAttributes( m_sLocalName ) == 0xFFFFFFFF );
00179                 
00180                 if ( ! PrepareFile() ) return FALSE;
00181                 
00182                 ASSERT( m_pTask == NULL );
00183                 if ( bCreated ) m_pTask = new CDownloadTask( (CDownload*)this, CDownloadTask::dtaskAllocate );
00184         }
00185         
00186         if ( m_pTask != NULL ) return FALSE;
00187         
00188         BOOL bLive = ( ! IsPaused() ) && ( IsTrying() ) && ( Network.IsConnected() );
00189         
00190         if ( bLive && ! m_bTorrentStarted )
00191         {
00192                 if ( ! m_bTorrentRequested || tNow > m_tTorrentTracker )
00193                 {
00194                         theApp.Message( MSG_DEFAULT, _T("Sending initial announce for %s"), m_pTorrent.m_sName );
00195 
00196                         GenerateTorrentDownloadID();
00197 
00198                         m_bTorrentRequested             = TRUE;
00199                         m_bTorrentStarted               = FALSE;
00200                         m_tTorrentTracker               = tNow + Settings.BitTorrent.DefaultTrackerPeriod;
00201                         m_nTorrentUploaded              = 0;
00202                         m_nTorrentDownloaded    = 0;
00203                         
00204                         if ( GetSourceCount(TRUE, TRUE) < Settings.BitTorrent.DownloadConnections + 10 )
00205                                 CBTTrackerRequest::SendStarted( this, Settings.BitTorrent.DownloadConnections + 10 );
00206                         else
00207                                 CBTTrackerRequest::SendStarted( this );
00208                 }
00209         }
00210         else if ( ! bLive && m_bTorrentRequested )
00211         {
00212                 theApp.Message( MSG_DEFAULT, _T("Sending final announce for %s"), m_pTorrent.m_sName );
00213 
00214                 CBTTrackerRequest::SendStopped( this );
00215                 
00216                 m_bTorrentRequested = m_bTorrentStarted = FALSE;
00217                 m_tTorrentTracker = 0;
00218                 //ZeroMemory(m_pPeerID.n, 20);  // Okay to use the same one in a single session
00219         }
00220         
00221         if ( m_bTorrentStarted && tNow > m_tTorrentTracker )
00222         {
00223                 // Regular tracker update
00224                 theApp.Message( MSG_DEFAULT, _T("Performing tracker update for %s"), m_pTorrent.m_sName );
00225 
00226                 int nSources = GetBTSourceCount();
00227                 int nSourcesWanted = (int)( Settings.BitTorrent.DownloadConnections * 1.5 );
00228                 nSourcesWanted = max( nSourcesWanted, Settings.Downloads.SourcesWanted / 10 );
00229                 m_tTorrentTracker = tNow + Settings.BitTorrent.DefaultTrackerPeriod;
00230                 if ( IsMoving() )
00231                 {       // We are seeding or completed, base requests on BT uploads
00232                         // If we're still moving the file, not firewalled, have enough sources or have maxxed out uploads
00233                         if ( ( ! IsCompleted() ) || ( Settings.Connection.FirewallStatus == CONNECTION_OPEN ) ||  ( nSources > (nSourcesWanted / 2) ) || ( Uploads.GetTorrentUploadCount() >= Settings.BitTorrent.UploadCount ) )
00234                                 CBTTrackerRequest::SendUpdate( this, 0 );       // We don't need to request peers.
00235                         else
00236                                 CBTTrackerRequest::SendUpdate( this, 10 );      // We might need more peers to 'push seed' to.
00237                 }
00238                 else if ( ( GetTransferCount( dtsCountTorrentAndActive ) ) > ( Settings.BitTorrent.DownloadConnections ) ) 
00239                 {       // We have enough transfers
00240                         if ( nSources > nSourcesWanted )
00241                                 CBTTrackerRequest::SendUpdate( this, 0 );       // we have enough sources and transfers, don't get any more.
00242                         else
00243                                 CBTTrackerRequest::SendUpdate( this, 10 );      // We should request a few sources, just in case some existing ones drop. 
00244                 }
00245                 else
00246                 {       // We need more transfers
00247                         if ( nSources > nSourcesWanted )
00248                                 CBTTrackerRequest::SendUpdate( this, 5 );       // We have many sources, but not enough transfers. Get a few new ones, so we have some fresh ones. 
00249                         else
00250                                 CBTTrackerRequest::SendUpdate( this );          // We need source and transfers. Take the tracker default. (It should be an appropriate number.)
00251                 }
00252 
00253         }
00254         
00255         return TRUE;
00256 }
00257 
00259 // CDownloadWithTorrent GenerateTorrentDownloadID (Called 'Peer ID', but seperate for each download and *not* retained between sessions)
00260 
00261 BOOL CDownloadWithTorrent::GenerateTorrentDownloadID()
00262 {
00263         theApp.Message( MSG_DEBUG, _T("Creating BitTorrent Peer ID") );
00264 
00265         int nByte;
00266 
00267         //Check ID is not in use
00268         for ( nByte = 0 ; nByte < 20 ; nByte++ )
00269         {
00270                 if ( m_pPeerID.n[ nByte ] != 0 ) 
00271                 {
00272                         theApp.Message( MSG_DEBUG, _T("Attempted to re-create an in-use Peer ID") );
00273                         return FALSE;
00274                 }
00275         }
00276 
00277         // Client ID
00278         if ( Settings.BitTorrent.StandardPeerID )
00279         {
00280                 // Use the new (but not official) peer ID style.
00281                 m_pPeerID.n[ 0 ] = '-';
00282                 m_pPeerID.n[ 1 ] = BT_ID1;
00283                 m_pPeerID.n[ 2 ] = BT_ID2;
00284                 m_pPeerID.n[ 3 ] = (BYTE)theApp.m_nVersion[0] + '0';
00285                 m_pPeerID.n[ 4 ] = (BYTE)theApp.m_nVersion[1] + '0';
00286                 m_pPeerID.n[ 5 ] = (BYTE)theApp.m_nVersion[2] + '0';
00287                 m_pPeerID.n[ 6 ] = (BYTE)theApp.m_nVersion[3] + '0';
00288                 m_pPeerID.n[ 7 ] = '-';
00289 
00290                 // Random characters for ID
00291                 srand( GetTickCount() );
00292                 for ( nByte = 8 ; nByte < 16 ; nByte++ ) 
00293                 {
00294                         m_pPeerID.n[ nByte ] += rand();
00295                 }
00296                 for ( nByte = 16 ; nByte < 20 ; nByte++ )
00297                 {
00298                         m_pPeerID.n[ nByte ]    = m_pPeerID.n[ nByte % 16 ]
00299                                                                         ^ m_pPeerID.n[ 15 - ( nByte % 16 ) ];
00300                 }
00301         }
00302         else
00303         {
00304                 // Old style ID 
00305                 for ( nByte = 0 ; nByte < 20 ; nByte++ )
00306                 {
00307                         m_pPeerID.n[ nByte ] += rand();
00308                 }
00309         }
00310 
00311         return TRUE;
00312 }
00313 
00315 // CDownloadWithTorrent tracker event handler
00316 
00317 void CDownloadWithTorrent::OnTrackerEvent(BOOL bSuccess, LPCTSTR pszReason)
00318 {
00319         if ( bSuccess )
00320         {
00321                 // Success! Reset and error conditions and continue
00322                 m_bTorrentTrackerError = FALSE;
00323                 m_sTorrentTrackerError.Empty();
00324                 m_nTorrentTrackerErrors = 0;
00325         }
00326         else
00327         {
00328                 // There was a problem with the tracker
00329 
00330                 m_bTorrentTrackerError = TRUE;
00331                 m_sTorrentTrackerError.Empty();
00332                 m_nTorrentTrackerErrors ++;
00333                 
00334                 if ( pszReason != NULL )
00335                 {
00336                         // If the tracker responded with an error, accept it and continue
00337                         m_sTorrentTrackerError = pszReason;
00338                         m_tTorrentTracker = GetTickCount() + 60 * 60 * 1000;
00339                 }
00340                 else if ( m_bTorrentTrackerError )
00341                 {
00342                         // ToDo: Multitracker: switch trackers here
00343 
00344 
00345                         // If we couldn't contact the tracker, check if we should re-try
00346                         if ( m_nTorrentTrackerErrors <= Settings.BitTorrent.MaxTrackerRetry )
00347                         {
00348                                 // Tracker or connection may have just glitched. Re-try in 10-30 seconds.
00349                                 DWORD tRetryTime;
00350                                 if ( m_nTorrentTrackerErrors <= 3 )
00351                                         tRetryTime = m_nTorrentTrackerErrors * 10 * 1000;               // nErrors * 10 seconds
00352                                 else if ( m_nTorrentTrackerErrors <= 6 )
00353                                         tRetryTime = m_nTorrentTrackerErrors * 1 * 60 * 1000;   // nErrors * 1 minute
00354                                 else if ( m_nTorrentTrackerErrors <= 15 )
00355                                         tRetryTime = m_nTorrentTrackerErrors * 2 * 60 * 1000;   // nErrors * 2 minutes
00356                                 else
00357                                         tRetryTime = 30 * 60 * 1000;                                                    // 30 minutes
00358                                 m_tTorrentTracker = GetTickCount() + tRetryTime;
00359 
00360                                 // Load the error message string
00361                                 CString strErrorMessage;
00362                                 LoadString( strErrorMessage, IDS_BT_TRACKER_RETRY );
00363                                 m_sTorrentTrackerError.Format( strErrorMessage, m_nTorrentTrackerErrors, Settings.BitTorrent.MaxTrackerRetry );
00364                         }
00365                         else
00366                         {
00367                                 // This tracker is probably down. Don't hammer it.
00368                                 m_tTorrentTracker = GetTickCount() + 30 * 60 * 1000;
00369                                 LoadString( m_sTorrentTrackerError, IDS_BT_TRACKER_DOWN );
00370                         }
00371                 }
00372         }
00373 }
00374 
00376 // CDownloadWithTorrent download transfer linking
00377 
00378 CDownloadTransferBT* CDownloadWithTorrent::CreateTorrentTransfer(CBTClient* pClient)
00379 {
00380         if ( IsMoving() || IsPaused() ) return NULL;
00381         
00382         CDownloadSource* pSource = NULL;
00383         
00384         for ( pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00385         {
00386                 if ( pSource->m_nProtocol == PROTOCOL_BT &&
00387                          memcmp( &pSource->m_pGUID, &pClient->m_pGUID, 16 ) == 0 ) break;
00388         }
00389         
00390         if ( pSource == NULL )
00391         {
00392                 pSource = new CDownloadSource( (CDownload*)this, &pClient->m_pGUID,
00393                         &pClient->m_pHost.sin_addr, htons( pClient->m_pHost.sin_port ) );
00394                 pSource->m_bPushOnly = TRUE;
00395                 
00396                 if ( ! AddSourceInternal( pSource ) ) return NULL;
00397         }
00398                 
00399         if ( pSource->m_pTransfer != NULL ) 
00400         {
00401                 // A download transfer already exists
00402                 return NULL;
00403         }
00404         
00405         pSource->m_pTransfer = new CDownloadTransferBT( pSource, pClient );
00406         
00407         return (CDownloadTransferBT*)pSource->m_pTransfer;
00408 }
00409 
00410 void CDownloadWithTorrent::OnFinishedTorrentBlock(DWORD nBlock)
00411 {
00412         for ( CDownloadTransferBT* pTransfer = (CDownloadTransferBT*)GetFirstTransfer() ; pTransfer ; pTransfer = (CDownloadTransferBT*)pTransfer->m_pDlNext )
00413         {
00414                 if ( pTransfer->m_nProtocol == PROTOCOL_BT )
00415                 {
00416                         pTransfer->SendFinishedBlock( nBlock );
00417                 }
00418         }
00419 }
00420 
00422 // CDownloadWithTorrent create bitfield
00423 
00424 CBTPacket* CDownloadWithTorrent::CreateBitfieldPacket()
00425 {
00426         ASSERT( m_pTorrent.IsAvailable() );
00427         
00428         CBTPacket* pPacket = CBTPacket::New( BT_PACKET_BITFIELD );
00429         int nCount = 0;
00430         
00431         for ( QWORD nBlock = 0 ; nBlock < m_nTorrentBlock ; )
00432         {
00433                 BYTE nByte = 0;
00434                 
00435                 for ( int nBit = 7 ; nBit >= 0 && nBlock < m_nTorrentBlock ; nBit--, nBlock++ )
00436                 {
00437                         if ( m_pTorrentBlock[ nBlock ] )
00438                         {
00439                                 nByte |= ( 1 << nBit );
00440                                 nCount++;
00441                         }
00442                 }
00443                 
00444                 pPacket->WriteByte( nByte );
00445         }
00446         
00447         if ( nCount > 0 ) return pPacket;
00448         pPacket->Release();
00449         
00450         return NULL;
00451 }
00452 
00454 // CDownloadWithTorrent upload linking
00455 
00456 void CDownloadWithTorrent::AddUpload(CUploadTransferBT* pUpload)
00457 {
00458         if ( m_pTorrentUploads.Find( pUpload ) == NULL )
00459                 m_pTorrentUploads.AddTail( pUpload );
00460 }
00461 
00462 void CDownloadWithTorrent::RemoveUpload(CUploadTransferBT* pUpload)
00463 {
00464         if ( POSITION pos = m_pTorrentUploads.Find( pUpload ) )
00465                 m_pTorrentUploads.RemoveAt( pos );
00466 }
00467 
00468 void CDownloadWithTorrent::CloseTorrentUploads()
00469 {
00470         for ( POSITION pos = m_pTorrentUploads.GetHeadPosition() ; pos ; )
00471         {
00472                 CUploadTransferBT* pUpload = (CUploadTransferBT*)m_pTorrentUploads.GetNext( pos );
00473                 pUpload->Close();
00474         }
00475 }
00476 
00478 // CDownloadWithTorrent choking
00479 
00480 void CDownloadWithTorrent::ChokeTorrent(DWORD tNow)
00481 {
00482         BOOL bChooseRandom = TRUE;
00483         int nTotalRandom = 0;
00484         CPtrList pSelected;
00485         
00486         if ( ! tNow ) tNow = GetTickCount();
00487         if ( tNow > m_tTorrentChoke && tNow - m_tTorrentChoke < 2000 ) return;
00488         m_tTorrentChoke = tNow;
00489 
00490         // Check if a firewalled seeding client needs to start some new connections
00491         if ( ( IsCompleted() ) && ( Settings.Connection.FirewallStatus == CONNECTION_FIREWALLED ) )
00492         {
00493                 // We might need to 'push' a connection if we don't have enough upload connections
00494                 if ( m_pTorrentUploads.GetCount() < max( Settings.BitTorrent.UploadCount * 2, 5 ) )
00495                 {
00496                         if ( CanStartTransfers( tNow ) )
00497                         {
00498                                 theApp.Message( MSG_DEBUG, _T("Attempting to push-start a BitTorrent upload")  ); 
00499                                 StartNewTransfer( tNow );
00500                         }
00501                 }
00502         }
00503 
00504         
00505         for ( POSITION pos = m_pTorrentUploads.GetHeadPosition() ; pos ; )
00506         {
00507                 CUploadTransferBT* pTransfer = (CUploadTransferBT*)m_pTorrentUploads.GetNext( pos );
00508                 if ( pTransfer->m_nProtocol != PROTOCOL_BT ) continue;
00509                 
00510                 if ( pTransfer->m_nRandomUnchoke == 2 )
00511                 {
00512                         if ( tNow - pTransfer->m_tRandomUnchoke >= Settings.BitTorrent.RandomPeriod )
00513                         {
00514                                 pTransfer->m_nRandomUnchoke = 1;
00515                         }
00516                         else
00517                         {
00518                                 bChooseRandom = FALSE;
00519                         }
00520                 }
00521                 
00522                 if ( pTransfer->m_bInterested )
00523                         nTotalRandom += ( pTransfer->m_nRandomUnchoke == 0 ) ? 3 : 1;
00524         }
00525         
00526         if ( bChooseRandom && nTotalRandom > 0 )
00527         {
00528                 nTotalRandom = rand() % nTotalRandom;
00529                 
00530                 for ( POSITION pos = m_pTorrentUploads.GetHeadPosition() ; pos ; )
00531                 {
00532                         CUploadTransferBT* pTransfer = (CUploadTransferBT*)m_pTorrentUploads.GetNext( pos );
00533                         if ( pTransfer->m_nProtocol != PROTOCOL_BT ) continue;
00534                         if ( pTransfer->m_bInterested == FALSE ) continue;
00535                         
00536                         int nWeight = ( pTransfer->m_nRandomUnchoke == 0 ) ? 3 : 1;
00537                         
00538                         if ( nTotalRandom < nWeight )
00539                         {
00540                                 pTransfer->m_nRandomUnchoke = 2;
00541                                 pTransfer->m_tRandomUnchoke = tNow;
00542                                 pSelected.AddTail( pTransfer );
00543                                 break;
00544                         }
00545                         else
00546                         {
00547                                 nTotalRandom -= nWeight;
00548                         }
00549                 }
00550         }
00551         
00552         while ( pSelected.GetCount() < Settings.BitTorrent.UploadCount )
00553         {
00554                 CUploadTransferBT* pBest = NULL;
00555                 DWORD nBest = 0;
00556                 
00557                 for ( POSITION pos = m_pTorrentUploads.GetHeadPosition() ; pos ; )
00558                 {
00559                         CUploadTransferBT* pTransfer = (CUploadTransferBT*)m_pTorrentUploads.GetNext( pos );
00560                         
00561                         if (    pTransfer->m_nProtocol == PROTOCOL_BT &&
00562                                         pTransfer->m_bInterested &&
00563                                         pSelected.Find( pTransfer->m_pClient ) == NULL &&
00564                                         pTransfer->GetAverageSpeed() >= nBest )
00565                         {
00566                                 pBest = pTransfer;
00567                                 nBest = pTransfer->GetAverageSpeed();
00568                         }
00569                 }
00570                 
00571                 if ( pBest == NULL ) break;
00572                 pSelected.AddTail( pBest->m_pClient );
00573         }
00574         
00575         while ( pSelected.GetCount() < Settings.BitTorrent.UploadCount )
00576         {
00577                 CDownloadTransferBT* pBest = NULL;
00578                 DWORD nBest = 0;
00579                 
00580                 for ( CDownloadTransferBT* pTransfer = (CDownloadTransferBT*)GetFirstTransfer()
00581                                 ; pTransfer ; pTransfer = (CDownloadTransferBT*)pTransfer->m_pDlNext )
00582                 {
00583                         if (    pTransfer->m_nProtocol == PROTOCOL_BT &&
00584                                         pSelected.Find( pTransfer->m_pClient ) == NULL &&
00585                                         pTransfer->m_nState == dtsDownloading &&
00586                                         pTransfer->m_pClient->m_pUpload->m_bInterested &&
00587                                         pTransfer->GetAverageSpeed() >= nBest )
00588                         {
00589                                 pBest = pTransfer;
00590                                 nBest = pTransfer->GetAverageSpeed();
00591                         }
00592                 }
00593                 
00594                 if ( pBest == NULL ) break;
00595                 pSelected.AddTail( pBest->m_pClient );
00596         }
00597         
00598         for ( POSITION pos = m_pTorrentUploads.GetHeadPosition() ; pos ; )
00599         {
00600                 CUploadTransferBT* pTransfer = (CUploadTransferBT*)m_pTorrentUploads.GetNext( pos );
00601                 if ( pTransfer->m_nProtocol != PROTOCOL_BT ) continue;
00602                 
00603                 pTransfer->SetChoke(    pTransfer->m_bInterested == TRUE &&
00604                                                                 pSelected.Find( pTransfer->m_pClient ) == NULL );
00605         }
00606 }
00607 
00609 // CDownloadWithTorrent search -> tracker link
00610 
00611 BOOL CDownloadWithTorrent::FindMoreSources()
00612 {
00613         if ( m_pFile != NULL && m_bTorrentRequested )
00614         {
00615                 ASSERT( m_pTorrent.IsAvailable() );
00616                 
00617                 if ( GetTickCount() - m_tTorrentSources > 15000 )
00618                 {
00619                         m_tTorrentTracker = GetTickCount() + Settings.BitTorrent.DefaultTrackerPeriod;
00620                         m_tTorrentSources = GetTickCount();
00621                         CBTTrackerRequest::SendUpdate( this, min ( ( Settings.BitTorrent.DownloadConnections * 2 ), 100 ) );
00622                         return TRUE;
00623                 }
00624         }
00625         
00626         return FALSE;
00627 }
00628 
00630 // CDownloadWithTorrent seed
00631 
00632 BOOL CDownloadWithTorrent::SeedTorrent(LPCTSTR pszTarget)
00633 {
00634         CDownload* pDownload = reinterpret_cast<CDownload*>(this);
00635         
00636         if ( IsMoving() || IsCompleted() ) return FALSE;
00637         if ( m_sLocalName == pszTarget ) return FALSE;
00638         
00639         ASSERT( m_pFile != NULL );
00640         if ( m_pFile == NULL ) return FALSE;
00641         ASSERT( m_pFile->IsOpen() == FALSE );
00642         if ( m_pFile->IsOpen() ) return FALSE;
00643         delete m_pFile;
00644         m_pFile = NULL;
00645 
00646         GenerateTorrentDownloadID();
00647         
00648         pDownload->m_bSeeding   = TRUE;
00649         pDownload->m_bComplete  = TRUE;
00650         pDownload->m_tCompleted = GetTickCount();
00651         
00652         memset( m_pTorrentBlock, TS_TRUE, m_nTorrentBlock );
00653         m_nTorrentSuccess = m_nTorrentBlock;
00654         
00655         if ( m_sLocalName.GetLength() > 0 )
00656         {
00657                 ASSERT( FALSE );
00658 		::DeleteFile( m_sLocalName );
00659 		::DeleteFile( m_sLocalName + _T(".sd") );
00660         }
00661         
00662         m_sLocalName = pszTarget;
00663         SetModified();
00664         
00665         m_tTorrentTracker               = GetTickCount() + ( 60 * 1000 );
00666         m_bTorrentRequested             = TRUE;
00667         m_bTorrentStarted               = FALSE;
00668         m_nTorrentUploaded              = 0;
00669         m_nTorrentDownloaded    = 0;
00670 
00671         if ( ( Settings.Connection.FirewallStatus == CONNECTION_FIREWALLED ) && ( GetSourceCount() < 40 ) )
00672                 CBTTrackerRequest::SendStarted( this );
00673         else
00674                 CBTTrackerRequest::SendStarted( this, 0 );      
00675         
00676         return TRUE;
00677 }
00678 
00680 // CDownloadWithTorrent Close
00681 
00682 void CDownloadWithTorrent::CloseTorrent()
00683 {
00684         if ( m_bTorrentRequested ) CBTTrackerRequest::SendStopped( this );
00685         m_bTorrentRequested             = FALSE;
00686         m_bTorrentStarted               = FALSE;
00687         CloseTorrentUploads();
00688         //ZeroMemory(m_pPeerID.n, 20);
00689 }
00690 
00691 
00693 // CDownloadWithTorrent stats
00694 
00695 float CDownloadWithTorrent::GetRatio() const
00696 {
00697         if ( m_nTorrentUploaded == 0 || m_nTorrentDownloaded == 0 ) return 0;
00698         return (float)m_nTorrentUploaded / (float)m_nTorrentDownloaded;
00699 }
00700 
00702 // CDownloadWithTorrent Check if it's okay to start a new download transfer
00703 
00704 BOOL CDownloadWithTorrent::CheckTorrentRatio() const
00705 {
00706         if ( ! m_bBTH ) return TRUE;                                                            //Not a torrent
00707         
00708         if ( m_nStartTorrentDownloads == dtAlways ) return TRUE;        //Torrent is set to download as needed
00709 
00710         if ( m_nStartTorrentDownloads == dtWhenRatio )                          //Torrent is set to download only when ratio is okay
00711         {
00712                 if ( m_nTorrentUploaded > m_nTorrentDownloaded ) return TRUE;   //Ratio OK
00713                 if ( GetVolumeComplete() < 5 * 1024 * 1024 ) return TRUE;               //Always get at least 5 MB so you have something to upload      
00714         }
00715 
00716         return FALSE;
00717 }
00718 
00720 // CDownloadWithTorrent check if upload exists
00721 
00722 BOOL CDownloadWithTorrent::UploadExists(in_addr* pIP) const
00723 {
00724         for ( POSITION pos = m_pTorrentUploads.GetHeadPosition() ; pos ; )
00725         {
00726                 CUploadTransferBT* pTransfer = (CUploadTransferBT*)m_pTorrentUploads.GetNext( pos );
00727 
00728                 if ( ( pTransfer->m_nProtocol == PROTOCOL_BT ) &&
00729                          ( pTransfer->m_nState != upsNull ) &&
00730                          ( pTransfer->m_pHost.sin_addr.S_un.S_addr == pIP->S_un.S_addr ) )
00731                         return TRUE;
00732         }
00733         return FALSE;
00734 }
00735 
00736 BOOL CDownloadWithTorrent::UploadExists(SHA1* pGUID) const
00737 {
00738         for ( POSITION pos = m_pTorrentUploads.GetHeadPosition() ; pos ; )
00739         {
00740                 CUploadTransferBT* pTransfer = (CUploadTransferBT*)m_pTorrentUploads.GetNext( pos );
00741 
00742                 if ( ( pTransfer->m_nProtocol == PROTOCOL_BT ) &&
00743                          ( pTransfer->m_nState != upsNull ) &&
00744                          ( memcmp( pGUID, &pTransfer->m_pClient->m_pGUID, 16 ) == 0 ) )
00745                         return TRUE;
00746         }
00747         return FALSE;
00748 }

Generated on Thu Dec 15 10:39:41 2005 for Shareaza 2.2.1.0 by  doxygen 1.4.2