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

DownloadWithTransfers.cpp

Go to the documentation of this file.
00001 //
00002 // DownloadWithTransfers.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 "Download.h"
00026 #include "Downloads.h"
00027 #include "Transfers.h"
00028 #include "DownloadWithTransfers.h"
00029 #include "DownloadSource.h"
00030 #include "DownloadTransferHTTP.h"
00031 //#include "DownloadTransferFTP.h"
00032 #include "DownloadTransferED2K.h"
00033 #include "DownloadTransferBT.h"
00034 #include "Network.h"
00035 #include "EDClient.h"
00036 
00037 #ifdef _DEBUG
00038 #undef THIS_FILE
00039 static char THIS_FILE[]=__FILE__;
00040 #define new DEBUG_NEW
00041 #endif
00042 
00043 
00045 // CDownloadWithTransfers construction
00046 
00047 CDownloadWithTransfers::CDownloadWithTransfers()
00048 {
00049         m_pTransferFirst        = NULL;
00050         m_pTransferLast         = NULL;
00051         m_nTransferCount        = 0;
00052         m_tTransferStart        = 0;
00053 }
00054 
00055 CDownloadWithTransfers::~CDownloadWithTransfers()
00056 {
00057         CloseTransfers();
00058 }
00059 
00061 // CDownloadWithTransfers counting
00062 
00063 int CDownloadWithTransfers::GetTransferCount() const
00064 {
00065         int nCount = 0;
00066 
00067         for ( CDownloadTransfer* pTransfer = m_pTransferFirst; pTransfer; pTransfer = pTransfer->m_pDlNext )
00068     {
00069                 if ( ( pTransfer->m_nProtocol != PROTOCOL_ED2K ) ||
00070                 ( static_cast< CDownloadTransferED2K* >( pTransfer )->m_pClient &&
00071                 static_cast< CDownloadTransferED2K* >( pTransfer )->m_pClient->m_bConnected ) )
00072                 {
00073                         
00074                         ++nCount;
00075                 }
00076         }
00077         return nCount;
00078 }
00079 
00080 
00081 // This macro is used to clean up the function below and make it more readable. It's the first 
00082 // condition in any IF statement that checks if the current transfer should be counted
00083 #define VALID_TRANSFER ( ! pAddress || pAddress->S_un.S_addr == pTransfer->m_pHost.sin_addr.S_un.S_addr ) &&    \
00084                                            ( ( pTransfer->m_nProtocol != PROTOCOL_ED2K ) ||                                                                                     \
00085                                                  ( static_cast< CDownloadTransferED2K* >( pTransfer )->m_pClient &&                                             \
00086                                                    static_cast< CDownloadTransferED2K* >( pTransfer )->m_pClient->m_bConnected ) )
00087 
00088 
00089 int CDownloadWithTransfers::GetTransferCount(int nState, IN_ADDR* pAddress) const
00090 {
00091     int nCount = 0;
00092 
00093     switch ( nState )
00094     {
00095     case dtsCountAll:
00096         for ( CDownloadTransfer* pTransfer = m_pTransferFirst; pTransfer; pTransfer = pTransfer->m_pDlNext )
00097         {
00098                     if ( VALID_TRANSFER )
00099             {
00100                 ++nCount;
00101             }
00102         }
00103         return nCount;
00104     case dtsCountNotQueued:
00105             for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00106             {   
00107                     if ( VALID_TRANSFER && ( ( pTransfer->m_nState != dtsQueued ) && 
00108                                 ( ! ( pTransfer->m_nState == dtsTorrent && static_cast< CDownloadTransferBT* >(pTransfer)->m_bChoked ) ) ) )
00109                  
00110             {
00111                 ++nCount;
00112             }
00113         }
00114         return nCount;
00115     case dtsCountNotConnecting:
00116             for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00117             {   
00118                     if ( ( ! pAddress || pAddress->S_un.S_addr == pTransfer->m_pHost.sin_addr.S_un.S_addr ) && 
00119                                  ( pTransfer->m_nState > dtsConnecting ) )
00120             {
00121                 ++nCount;
00122             }
00123         }
00124         return nCount;
00125     case dtsCountTorrentAndActive:
00126             for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00127             {   
00128                     if ( VALID_TRANSFER )
00129                     {
00130                 switch( pTransfer->m_nState )
00131                 {
00132                 case dtsTorrent:
00133                 case dtsRequesting:
00134                 case dtsDownloading:
00135                     ++nCount;
00136                 }
00137             }
00138         }
00139         return nCount;
00140     default:
00141             for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00142             {   
00143                     if ( VALID_TRANSFER && ( pTransfer->m_nState == nState ) )
00144             {
00145                 ++nCount;
00146                         }
00147                 }
00148         return nCount;
00149         }
00150 }
00151 
00153 // GetAmountDownloadedFrom total volume from an IP
00154 
00155 QWORD CDownloadWithTransfers::GetAmountDownloadedFrom(IN_ADDR* pAddress) const
00156 {
00157         QWORD nTotal = 0;
00158 
00159         for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00160         {       
00161                 if ( pAddress->S_un.S_addr == pTransfer->m_pHost.sin_addr.S_un.S_addr )
00162                         nTotal += pTransfer->m_nDownloaded;
00163         }
00164 
00165         return nTotal;
00166 }
00167 
00169 // CDownloadWithTransfers consider starting more transfers
00170 
00171 // This function checks if it's okay to try opening a new download. (Download throttle, etc)
00172 BOOL CDownloadWithTransfers::CanStartTransfers(DWORD tNow)
00173 {
00174         if ( tNow == 0 ) tNow = GetTickCount();
00175         
00176         if ( tNow - m_tTransferStart < 100 ) return FALSE;
00177         m_tTransferStart = tNow;
00178 
00179         // Make sure the network is ready
00180         if ( ! Network.ReadyToTransfer( tNow ) ) return FALSE;
00181         
00182         // Limit the connection rate
00183         if ( Settings.Downloads.ConnectThrottle != 0 )
00184         {
00185                 if ( tNow < Downloads.m_tLastConnect ) return FALSE;
00186                 if ( tNow - Downloads.m_tLastConnect <= Settings.Downloads.ConnectThrottle ) return FALSE;
00187         }
00188 
00189         // Limit the amount of connecting (half-open) sources. (Very important for XP sp2)
00190         if ( Downloads.GetConnectingTransferCount() >= Settings.Downloads.MaxConnectingSources )
00191         {
00192                 return FALSE;
00193         }
00194 
00195         return TRUE;
00196 }
00197 
00198 // This functions starts a new download transfer if needed and allowed.
00199 BOOL CDownloadWithTransfers::StartTransfersIfNeeded(DWORD tNow)
00200 {
00201         if ( tNow == 0 ) tNow = GetTickCount();
00202 
00203         // Check connection throttles, max open connections, etc
00204         if ( ! CanStartTransfers( tNow ) ) return FALSE;
00205         
00206         //BitTorrent limiting
00207         if ( m_bBTH )
00208         {
00209                 // Max connections
00210                 if ( ( GetTransferCount( dtsCountTorrentAndActive ) ) > Settings.BitTorrent.DownloadConnections ) return FALSE; 
00211         }
00212 
00213         int nTransfers = GetTransferCount( dtsDownloading );
00214 
00215         if ( nTransfers < Settings.Downloads.MaxFileTransfers &&
00216                  ( ! Settings.Downloads.StaggardStart ||
00217                  nTransfers == GetTransferCount( dtsCountAll ) ) )
00218         {
00219                 if ( Downloads.m_bAllowMoreDownloads || m_pTransferFirst != NULL )
00220                 {
00221                         if ( Downloads.m_bAllowMoreTransfers )
00222                         {
00223                                 // Start a new download
00224                                 if ( StartNewTransfer( tNow ) )
00225                                 {
00226                                         Downloads.UpdateAllows( TRUE );
00227                                         return TRUE;
00228                                 }
00229                         }
00230                 }
00231         }
00232         
00233         return FALSE;
00234 }
00235 
00237 // CDownloadSource check (INLINE)
00238 
00239 BOOL CDownloadSource::CanInitiate(BOOL bNetwork, BOOL bEstablished) const
00240 {
00241         if ( Settings.Connection.RequireForTransfers )
00242         {
00243                 switch ( m_nProtocol )
00244                 {
00245                 case PROTOCOL_G1:
00246                         if ( ! Settings.Gnutella1.EnableToday ) return FALSE;
00247                         break;
00248                 case PROTOCOL_G2:
00249                         if ( ! Settings.Gnutella2.EnableToday ) return FALSE;
00250                         break;
00251                 case PROTOCOL_ED2K:
00252                         if ( ! Settings.eDonkey.EnableToday ) return FALSE;
00253                         if ( ! bNetwork ) return FALSE;
00254                         break;
00255                 case PROTOCOL_HTTP:
00256                         if ( m_nGnutella == 2 )
00257                         {
00258                                 if ( ! Settings.Gnutella2.EnableToday ) return FALSE;
00259                         }
00260                         else if ( m_nGnutella == 1 )
00261                         {
00262                                 if ( ! Settings.Gnutella1.EnableToday ) return FALSE;
00263                         }
00264                         else
00265                         {
00266                                 if ( ! Settings.Gnutella1.EnableToday &&
00267                                          ! Settings.Gnutella2.EnableToday ) return FALSE;
00268                         }
00269                         break;
00270                 case PROTOCOL_FTP:
00271                         if ( ! bNetwork ) return FALSE;
00272                         break;
00273                 case PROTOCOL_BT:
00274                         if ( ! bNetwork ) return FALSE;
00275                         break;
00276                 default:
00277                         theApp.Message( MSG_ERROR, _T("Source with invalid protocol found") );
00278                         return FALSE;
00279                 }
00280         }
00281 
00282         if ( ( Settings.Connection.IgnoreOwnIP ) && ( m_pAddress.S_un.S_addr == Network.m_pHost.sin_addr.S_un.S_addr ) ) 
00283                 return FALSE;
00284         
00285         return bEstablished || Downloads.AllowMoreTransfers( (IN_ADDR*)&m_pAddress );
00286 }
00287 
00289 // CDownloadWithTransfers start a new transfer
00290 
00291 BOOL CDownloadWithTransfers::StartNewTransfer(DWORD tNow)
00292 {
00293         if ( tNow == 0 ) tNow = GetTickCount();
00294         
00295         BOOL bConnected = Network.IsConnected();
00296         CDownloadSource* pConnectHead = NULL;
00297         CDownloadSource* pPushHead = NULL;
00298 
00299         // If BT preferencing is on, check them first
00300         if ( ( m_bBTH ) && ( Settings.BitTorrent.PreferenceBTSources ) )
00301         {
00302                 for ( CDownloadSource* pSource = m_pSourceFirst ; pSource ; )
00303                 {
00304                         CDownloadSource* pNext = pSource->m_pNext;
00305                         
00306                         if ( ( pSource->m_pTransfer == NULL ) &&                // does not have a transfer
00307                                  ( pSource->m_bPushOnly == FALSE ) &&           // Not push
00308                                  ( pSource->m_nProtocol == PROTOCOL_BT ) &&     // Is a BT source
00309                                  ( pSource->m_tAttempt == 0 ) )                         // Is a "fresh" source from the tracker
00310                         {
00311                                 if ( pSource->CanInitiate( bConnected, FALSE ) )
00312                                 {
00313                                         CDownloadTransfer* pTransfer = pSource->CreateTransfer();
00314                                         return pTransfer != NULL && pTransfer->Initiate();
00315                                 }
00316                         }       
00317                         pSource = pNext;
00318                 }
00319         }
00320         
00321         for ( CDownloadSource* pSource = m_pSourceFirst ; pSource ; )
00322         {
00323                 CDownloadSource* pNext = pSource->m_pNext;
00324                 
00325                 if ( pSource->m_pTransfer != NULL )
00326                 {
00327                         // Already has a transfer
00328                 }
00329                 else if ( pSource->m_bPushOnly == FALSE )
00330                 {
00331                         if ( pSource->m_tAttempt == 0 )
00332                         {
00333                                 if ( pSource->CanInitiate( bConnected, FALSE ) )
00334                                 {
00335                                         CDownloadTransfer* pTransfer = pSource->CreateTransfer();
00336                                         return pTransfer != NULL && pTransfer->Initiate();
00337                                 }
00338                         }
00339                         else if ( pSource->m_tAttempt > 0 && pSource->m_tAttempt <= tNow )
00340                         {
00341                                 if ( pConnectHead == NULL || ( pConnectHead->m_nProtocol != PROTOCOL_HTTP && pSource->m_nProtocol == PROTOCOL_HTTP ) )
00342                                 {
00343                                         if ( pSource->CanInitiate( bConnected, FALSE ) ) pConnectHead = pSource;
00344                                 }
00345                         }
00346                 }
00347                 else
00348                 {
00349                         if ( pSource->m_tAttempt == 0 )
00350                         {
00351                                 if ( pPushHead == NULL && pSource->CanInitiate( bConnected, FALSE ) ) pPushHead = pSource;
00352                         }
00353                         else if ( pSource->m_tAttempt <= tNow )
00354                         {
00355                                 if ( ! Settings.Downloads.NeverDrop ) pSource->Remove( TRUE, TRUE );
00356                         }
00357                 }
00358                 
00359                 pSource = pNext;
00360         }
00361         
00362         if ( pConnectHead != NULL )
00363         {
00364                 CDownloadTransfer* pTransfer = pConnectHead->CreateTransfer();
00365                 return pTransfer != NULL && pTransfer->Initiate();
00366         }
00367         
00368         if ( pPushHead != NULL )
00369         {
00370                 if( Network.GetStableTime() < 15 ) return FALSE;
00371                 if ( pPushHead->PushRequest() ) return FALSE;
00372                 if ( ! Settings.Downloads.NeverDrop ) pPushHead->Remove( TRUE, TRUE );
00373         }
00374         
00375         return FALSE;
00376 }
00377 
00379 // CDownloadWithTransfers close
00380 
00381 void CDownloadWithTransfers::CloseTransfers()
00382 {
00383         BOOL bBackup = Downloads.m_bClosing;
00384         Downloads.m_bClosing = TRUE;
00385         
00386         for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; )
00387         {
00388                 CDownloadTransfer* pNext = pTransfer->m_pDlNext;
00389                 pTransfer->Close( TS_TRUE );
00390                 pTransfer = pNext;
00391         }
00392         
00393         ASSERT( m_nTransferCount == 0 );
00394         
00395         Downloads.m_bClosing = bBackup;
00396 }
00397 
00399 // CDownloadWithTransfers average speed
00400 
00401 DWORD CDownloadWithTransfers::GetAverageSpeed() const
00402 {
00403         DWORD nSpeed = 0;
00404         
00405         for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00406         {
00407                 if ( pTransfer->m_nState == dtsDownloading ) nSpeed += pTransfer->GetAverageSpeed();
00408         }
00409         
00410         return nSpeed;
00411 }
00412 
00414 // CDownloadWithTransfers measured speed
00415 
00416 DWORD CDownloadWithTransfers::GetMeasuredSpeed() const
00417 {
00418         DWORD nSpeed = 0;
00419         
00420         for ( CDownloadTransfer* pTransfer = m_pTransferFirst ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00421         {
00422                 if ( pTransfer->m_nState == dtsDownloading )
00423                         nSpeed += pTransfer->GetMeasuredSpeed();
00424         }
00425         
00426         return nSpeed;
00427 }
00428 
00430 // CDownloadWithTransfers push handler
00431 
00432 BOOL CDownloadWithTransfers::OnAcceptPush(GGUID* pClientID, CConnection* pConnection)
00433 {
00434         CDownload* pDownload = (CDownload*)this;
00435         if ( pDownload->IsMoving() || pDownload->IsPaused() ) return FALSE;
00436         
00437         CDownloadSource* pSource = NULL;
00438         
00439         for ( pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00440         {
00441                 if ( pSource->m_nProtocol == PROTOCOL_HTTP && pSource->CheckPush( pClientID ) ) break;
00442         }
00443         
00444         if ( pSource == NULL ) return FALSE;
00445         
00446         if ( pSource->m_pTransfer != NULL )
00447         {
00448                 if ( pSource->m_pTransfer->m_nState > dtsConnecting ) return FALSE;
00449                 pSource->m_pTransfer->Close( TS_TRUE );
00450         }
00451         
00452         if ( pConnection->m_hSocket == INVALID_SOCKET ) return FALSE;
00453         
00454         CDownloadTransferHTTP* pTransfer = (CDownloadTransferHTTP*)pSource->CreateTransfer();
00455         ASSERT( pTransfer->m_nProtocol == PROTOCOL_HTTP );
00456         return pTransfer->AcceptPush( pConnection );
00457 }
00458 
00460 // CDownloadWithTransfers eDonkey2000 callback handler
00461 
00462 BOOL CDownloadWithTransfers::OnDonkeyCallback(CEDClient* pClient, CDownloadSource* pExcept)
00463 {
00464         CDownload* pDownload = (CDownload*)this;
00465         if ( pDownload->IsMoving() || pDownload->IsPaused() ) return FALSE;
00466         
00467         CDownloadSource* pSource = NULL;
00468         DWORD tNow = GetTickCount();
00469         
00470         for ( pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00471         {
00472                 if ( pExcept != pSource && pSource->CheckDonkey( pClient ) ) break;
00473         }
00474         
00475         if ( pSource == NULL ) return FALSE;
00476         
00477         if ( pSource->m_pTransfer != NULL )
00478         {
00479                 if ( pSource->m_pTransfer->m_nState > dtsConnecting ) return FALSE;
00480                 pSource->m_pTransfer->Close( TS_TRUE );
00481         }
00482         
00483         CDownloadTransferED2K* pTransfer = (CDownloadTransferED2K*)pSource->CreateTransfer();
00484         ASSERT( pTransfer->m_nProtocol == PROTOCOL_ED2K );
00485         return pTransfer->Initiate();
00486 }
00487 
00489 // CDownloadWithTransfers add and remove transfers
00490 
00491 void CDownloadWithTransfers::AddTransfer(CDownloadTransfer* pTransfer)
00492 {
00493         m_nTransferCount ++;
00494         pTransfer->m_pDlPrev = m_pTransferLast;
00495         pTransfer->m_pDlNext = NULL;
00496         
00497         if ( m_pTransferLast != NULL )
00498         {
00499                 m_pTransferLast->m_pDlNext = pTransfer;
00500                 m_pTransferLast = pTransfer;
00501         }
00502         else
00503         {
00504                 m_pTransferFirst = m_pTransferLast = pTransfer;
00505         }
00506 }
00507 
00508 void CDownloadWithTransfers::RemoveTransfer(CDownloadTransfer* pTransfer)
00509 {
00510         ASSERT( m_nTransferCount > 0 );
00511         m_nTransferCount --;
00512         
00513         if ( pTransfer->m_pDlPrev != NULL )
00514                 pTransfer->m_pDlPrev->m_pDlNext = pTransfer->m_pDlNext;
00515         else
00516                 m_pTransferFirst = pTransfer->m_pDlNext;
00517         
00518         if ( pTransfer->m_pDlNext != NULL )
00519                 pTransfer->m_pDlNext->m_pDlPrev = pTransfer->m_pDlPrev;
00520         else
00521                 m_pTransferLast = pTransfer->m_pDlPrev;
00522         
00523         delete pTransfer;
00524 }

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