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

Download.cpp

Go to the documentation of this file.
00001 //
00002 // Download.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 "DownloadTask.h"
00028 #include "DownloadSource.h"
00029 #include "DownloadTransfer.h"
00030 #include "DownloadGroups.h"
00031 #include "Uploads.h"
00032 
00033 #include "Library.h"
00034 #include "LibraryBuilder.h"
00035 #include "LibraryHistory.h"
00036 #include "FragmentedFile.h"
00037 #include "BTTrackerRequest.h"
00038 #include "XML.h"
00039 
00040 #ifdef _DEBUG
00041 #undef THIS_FILE
00042 static char THIS_FILE[]=__FILE__;
00043 #define new DEBUG_NEW
00044 #endif
00045 
00046 
00048 // CDownload construction
00049 
00050 CDownload::CDownload()
00051 {
00052         m_nSerID                = Downloads.GetFreeSID();
00053         m_bExpanded             = Settings.Downloads.AutoExpand;
00054         m_bSelected             = FALSE;
00055         m_bVerify               = TS_UNKNOWN;
00056         
00057         m_nRunCookie    = 0;
00058         m_nSaveCookie   = 0;
00059         m_nGroupCookie  = 0;
00060         
00061         m_bPaused               = FALSE;
00062         m_bBoosted              = FALSE;
00063         m_bShared               = Settings.Uploads.SharePartials;
00064         m_bComplete             = FALSE;
00065         m_tCompleted    = 0;
00066         m_tSaved                = 0;
00067         m_tBegan                = 0;
00068 
00069         m_bDownloading  = FALSE;
00070         
00071         DownloadGroups.Link( this );
00072 }
00073 
00074 CDownload::~CDownload()
00075 {
00076         if ( m_pTask != NULL ) m_pTask->Abort();
00077         DownloadGroups.Unlink( this );
00078         
00079         if ( m_pTorrent.m_nFiles > 1 && m_bComplete )
00080         {
00081                 CloseTransfers();
00082                 CloseTorrentUploads();
00083                 Uploads.OnRename( m_sLocalName, NULL );
00084                 if ( ! ::DeleteFile( m_sLocalName ) )
00085                         theApp.WriteProfileString( _T("Delete"), m_sLocalName, _T("") );
00086         }
00087 }
00088 
00090 // CDownload control : pause
00091 
00092 void CDownload::Pause()
00093 {
00094         if ( m_bComplete || m_bPaused ) return;
00095         
00096         theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_PAUSED, (LPCTSTR)GetDisplayName() );
00097         
00098         StopTrying();
00099 
00100         m_bPaused = TRUE;
00101 }
00102 
00104 // CDownload control : resume
00105 
00106 void CDownload::Resume()
00107 {
00108         if ( m_bComplete ) return;
00109         if ( ! m_bPaused ) 
00110         {
00111                 if ( ( m_tBegan == 0 ) && ( GetSourceCount() < 2 ) ) FindMoreSources();
00112                 SetStartTimer();
00113                 return;
00114         }
00115         
00116         theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_RESUMED, (LPCTSTR)GetDisplayName() );
00117         
00118         if ( m_pFile != NULL )
00119         {
00120                 for ( CDownloadSource* pSource = GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00121                 {
00122                         pSource->OnResume();
00123                 }
00124         }
00125         
00126         m_bPaused                               = FALSE;
00127         m_bDiskFull                             = FALSE;
00128         m_tReceived                             = GetTickCount();
00129         m_bTorrentTrackerError  = FALSE;
00130         m_nTorrentTrackerErrors = 0;
00131 
00132         if( m_bBTH )
00133         {
00134                 if ( Downloads.GetTryingCount( TRUE ) < Settings.BitTorrent.DownloadTorrents ) 
00135                         SetStartTimer();
00136         }
00137         else
00138         {
00139                 if ( Downloads.GetTryingCount( FALSE ) < ( Settings.Downloads.MaxFiles + Settings.Downloads.MaxFileSearches ) )
00140                         SetStartTimer();
00141         }
00142 
00143         SetModified();
00144         CloseTorrentUploads();
00145 }
00146 
00148 // CDownload control : remove
00149 
00150 void CDownload::Remove(BOOL bDelete)
00151 {
00152         CloseTorrentUploads();
00153         CloseTransfers();
00154         CloseFile();
00155         
00156         if ( m_pTask != NULL )
00157         {
00158                 m_pTask->Abort();
00159                 ASSERT( m_pTask == NULL );
00160         }
00161         
00162         if ( bDelete || ! IsCompleted() )
00163         {
00164                 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_REMOVE, (LPCTSTR)GetDisplayName() );
00165         }
00166         
00167         DeleteFile( bDelete );
00168         DeletePreviews();
00169 	
00170 	::DeleteFile( m_sLocalName + _T(".sd") );
00171         
00172         Downloads.Remove( this );
00173 }
00174 
00176 // CDownload control : boost
00177 
00178 void CDownload::Boost()
00179 {
00180         if ( m_pFile == NULL || m_bBoosted ) return;
00181         
00182         theApp.Message( MSG_SYSTEM, IDS_DOWNLOAD_BOOST, (LPCTSTR)GetDisplayName() );
00183         
00184         for ( CDownloadTransfer* pTransfer = GetFirstTransfer() ; pTransfer ; pTransfer = pTransfer->m_pDlNext )
00185         {
00186                 pTransfer->Boost();
00187         }
00188         
00189         m_bBoosted = TRUE;
00190         SetModified();
00191 }
00192 
00194 // CDownload control : sharing
00195 
00196 void CDownload::Share(BOOL bShared)
00197 {
00198         m_bShared = bShared;
00199         SetModified();
00200 }
00201 
00203 // CDownload control : rename
00204 
00205 BOOL CDownload::Rename(LPCTSTR pszName)
00206 {
00207         if ( m_sRemoteName == pszName ) return FALSE;
00208         m_sRemoteName = pszName;
00209         SetModified();
00210         return TRUE;
00211 }
00212 
00214 // CDownload control : Stop trying
00215 
00216 void CDownload::StopTrying()
00217 {
00218         if ( m_bComplete ) return;
00219         m_tBegan                = 0;
00220         m_bDownloading  = FALSE;
00221 
00222         if ( m_bBTH ) CloseTorrent();
00223         CloseTransfers();
00224         CloseFile();
00225         StopSearch();
00226         SetModified();
00227 }
00228 
00230 // CDownload control : SetStartTimer
00231 
00232 void CDownload::SetStartTimer()
00233 {
00234         m_tBegan = GetTickCount();
00235         SetModified();
00236 }
00237 
00239 // CDownload control : GetStartTimer
00240 
00241 DWORD CDownload::GetStartTimer() const
00242 {
00243         return( m_tBegan );
00244 }
00245 
00247 // CDownload state checks
00248 
00249 BOOL CDownload::IsStarted() const
00250 {
00251         return ( GetVolumeComplete() > 0 );
00252 }
00253 
00254 BOOL CDownload::IsPaused() const
00255 {
00256         return m_bPaused;
00257 }
00258 
00259 BOOL CDownload::IsDownloading() const
00260 {
00261         return m_bDownloading;
00262 }
00263 
00264 BOOL CDownload::IsMoving() const
00265 {
00266         return ( m_pFile == NULL );
00267 }
00268 
00269 BOOL CDownload::IsCompleted() const
00270 {
00271         return m_bComplete;
00272 }
00273 
00274 BOOL CDownload::IsBoosted() const
00275 {
00276         return m_bBoosted;
00277 }
00278 
00279 BOOL CDownload::IsTrying() const
00280 {
00281         return ( m_tBegan != 0 );
00282 }
00283 
00284 BOOL CDownload::IsShared() const
00285 {
00286         return m_bShared || m_bBTH || Settings.eDonkey.EnableToday;
00287 }
00288 
00290 // CDownload run handler
00291 
00292 void CDownload::OnRun()
00293 {
00294         DWORD tNow = GetTickCount();
00295         BOOL bDownloading = FALSE;
00296 
00297         if ( ! m_bPaused )
00298         {
00299                 if ( m_bDiskFull  ) Pause();
00300                 else if ( IsTrying() )
00301                 {       //This download is trying to download
00302 
00303                         //'Dead download' check- if download appears dead, give up and allow another to start.
00304                         if ( ( ! m_bComplete ) && ( tNow - GetStartTimer() ) > ( 3 * 60 * 60 * 1000 )  )        
00305                         {       //If it's not complete, and we've been trying for at least 3 hours
00306 
00307                                 DWORD tHoursToTry = min ( ( GetSourceCount() + 49 ) / 50 , 9 ) + Settings.Downloads.StarveGiveUp;
00308 
00309                                 if (  ( tNow - m_tReceived ) > ( tHoursToTry * 60 * 60 * 1000 ) )
00310                                 {       //And have had no new data for 5-14 hours       
00311 
00312                                         if( m_bBTH )    //If it's a torrent
00313                                         {
00314                                                 if( Downloads.GetTryingCount( TRUE ) >= Settings.BitTorrent.DownloadTorrents )
00315                                                 {       //If there are other torrents that could start
00316                                                         StopTrying();           //Give up for now, try again later
00317                                                         return;
00318                                                 }
00319                                         }
00320                                         else                    //It's a regular download
00321                                         {
00322                                                 if( Downloads.GetTryingCount( FALSE ) >= ( Settings.Downloads.MaxFiles + Settings.Downloads.MaxFileSearches ) )
00323                                                 {       //If there are other downloads that could try
00324                                                         StopTrying();           //Give up for now, try again later
00325                                                         return;
00326                                                 }
00327                                         }
00328                                 }
00329                         }       //End of 'dead download' check
00330 
00331                         // Run the download
00332                         if ( RunTorrent( tNow ) )
00333                         {
00334                                 RunSearch( tNow );
00335                                 
00336                                 if ( m_bSeeding )
00337                                 {
00338                                         RunValidation( TRUE );
00339                                 }
00340                                 else if ( m_pFile != NULL )
00341                                 {
00342                                         RunValidation( FALSE );
00343                                         
00344                                         if ( RunFile( tNow ) )
00345                                         {
00346                                                 if ( ValidationCanFinish() ) OnDownloaded();
00347                                         }
00348                                         else
00349                                         {
00350                                                 if ( CheckTorrentRatio() ) StartTransfersIfNeeded( tNow );
00351                                         }
00352                                 }
00353                                 else if ( m_pFile == NULL && ! m_bComplete && m_pTask == NULL )
00354                                 {
00355                                         OnDownloaded();
00356                                 }
00357                         }
00358 
00359                         // Calculate the currently downloading state
00360                         if( GetTransferCount() > 0 ) bDownloading = TRUE;
00361 
00362                 }
00363                 else if ( ! m_bComplete )
00364                 {       //If this download isn't trying to download, see if it can try
00365                         if( m_bBTH )
00366                         {       //Torrents only try when 'ready to go'. (Reduce tracker load)
00367                                 if( Downloads.GetTryingCount( TRUE ) < Settings.BitTorrent.DownloadTorrents )
00368                                         SetStartTimer();
00369                         }
00370                         else
00371                         {       //We have extra regular downloads 'trying' so when a new slot is ready, a download
00372                                 //has sources and is ready to go.       
00373                                 if( Downloads.GetTryingCount( FALSE ) < ( Settings.Downloads.MaxFiles + Settings.Downloads.MaxFileSearches ) )
00374                                         SetStartTimer();
00375                         }
00376                 }
00377         }
00378 
00379         // Set the currently downloading state (Used to optimise display in Ctrl/Wnd functions)
00380         m_bDownloading = bDownloading;
00381         
00382         // Don't save Downloads with many sources too often, since it's slow
00383         if ( tNow - m_tSaved >=
00384                 ( m_nSourceCount > 20 ? 5 * Settings.Downloads.SaveInterval : Settings.Downloads.SaveInterval ) )
00385         {
00386                 if ( m_pFile != NULL && m_pFile->Flush() )
00387                 {
00388                         m_tSaved = tNow;
00389                 }
00390                 
00391                 if ( m_nCookie != m_nSaveCookie )
00392                 {
00393                         Save();
00394                         m_tSaved = tNow;
00395                 }
00396         }
00397 }
00398 
00400 // CDownload download complete handler
00401 
00402 void CDownload::OnDownloaded()
00403 {
00404         ASSERT( m_bComplete == FALSE );
00405         
00406         theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_COMPLETED, (LPCTSTR)GetDisplayName() );
00407         m_tCompleted = GetTickCount();
00408         m_bDownloading = FALSE;
00409         
00410         CloseTransfers();
00411         
00412         if ( m_pFile != NULL )
00413         {
00414                 m_pFile->Close();
00415                 delete m_pFile;
00416                 m_pFile = NULL;
00417                 AppendMetadata();
00418         }
00419         
00420         ASSERT( m_pTask == NULL );
00421         m_pTask = new CDownloadTask( this, CDownloadTask::dtaskCopySimple );
00422         
00423         SetModified();
00424 }
00425 
00427 // CDownload task completion
00428 
00429 void CDownload::OnTaskComplete(CDownloadTask* pTask)
00430 {
00431         ASSERT( m_pTask == pTask );
00432         m_pTask = NULL;
00433         
00434         if ( pTask->WasAborted() ) return;
00435         
00436         if ( pTask->m_nTask == CDownloadTask::dtaskAllocate )
00437         {
00438                 // allocate complete
00439         }
00440         else
00441         {
00442                 OnMoved( pTask );
00443         }
00444 }
00445 
00447 // CDownload moved handler
00448 
00449 void CDownload::OnMoved(CDownloadTask* pTask)
00450 {
00451         CString strLocalName = m_sLocalName;
00452         ASSERT( m_pFile == NULL );
00453         
00454         if ( pTask->m_bSuccess )
00455         {
00456                 m_sLocalName = pTask->m_sFilename;
00457                 
00458                 theApp.Message( MSG_DOWNLOAD, IDS_DOWNLOAD_MOVED,
00459                         (LPCTSTR)GetDisplayName(), (LPCTSTR)m_sLocalName );
00460                 
00461                 if ( m_pXML != NULL && Settings.Downloads.Metadata )
00462                         WriteMetadata( pTask->m_sPath );
00463         }
00464         else
00465         {
00466                 theApp.Message( MSG_ERROR, IDS_DOWNLOAD_CANT_MOVE,
00467                         (LPCTSTR)GetDisplayName(), (LPCTSTR)pTask->m_sPath );
00468                 
00469                 if ( m_pTorrent.IsAvailable() )
00470                 {
00471                         m_bDiskFull = TRUE;
00472                         return;
00473                 }
00474         }
00475         
00476         m_bComplete             = TRUE;
00477         m_tCompleted    = GetTickCount();
00478 	
00479 	::DeleteFile( strLocalName + _T(".sd") );
00480         
00481         if ( m_nTorrentBlock > 0 && m_nTorrentSuccess >= m_nTorrentBlock )
00482         {
00483                 CBTTrackerRequest::SendCompleted( this );
00484         }
00485         
00486         LibraryBuilder.RequestPriority( m_sLocalName );
00487         
00488         if ( m_bSHA1 || m_bED2K )
00489         {
00490                 LibraryHistory.Add( m_sLocalName, m_bSHA1 ? &m_pSHA1 : NULL,
00491                         m_bED2K ? &m_pED2K : NULL, GetSourceURLs( NULL, 0, PROTOCOL_NULL, NULL ) );
00492         }
00493         else
00494         {
00495                 LibraryHistory.Add( m_sLocalName, NULL, NULL, NULL );
00496         }
00497         
00498         ClearSources();
00499         SetModified();
00500         
00501         if ( IsFullyVerified() ) OnVerify( m_sLocalName, TRUE );
00502 }
00503 
00505 // CDownload verification handler
00506 
00507 BOOL CDownload::OnVerify(LPCTSTR pszPath, BOOL bVerified)
00508 {
00509         if ( m_bVerify != TS_UNKNOWN ) return FALSE;
00510         if ( m_pFile != NULL ) return FALSE;
00511         
00512         if ( pszPath != (LPCTSTR)m_sLocalName &&
00513                  m_sLocalName.CompareNoCase( pszPath ) != 0 ) return FALSE;
00514         
00515         m_bVerify = bVerified ? TS_TRUE : TS_FALSE;
00516         SetModified();
00517         
00518         return TRUE;
00519 }
00520 
00522 // CDownload load and save
00523 
00524 BOOL CDownload::Load(LPCTSTR pszName)
00525 {
00526         BOOL bSuccess = FALSE;
00527         CFile pFile;
00528         
00529         m_sLocalName = pszName;
00530         m_sLocalName = m_sLocalName.Left( m_sLocalName.GetLength() - 3 );
00531         
00532         if ( pFile.Open( m_sLocalName + _T(".sd"), CFile::modeRead ) )
00533         {
00534                 try
00535                 {
00536                         CArchive ar( &pFile, CArchive::load );
00537                         Serialize( ar, 0 );
00538                         bSuccess = TRUE;
00539                 }
00540                 catch ( CException* pException )
00541                 {
00542                         pException->Delete();
00543                 }
00544                 
00545                 pFile.Close();
00546         }
00547         
00548         if ( ! bSuccess && pFile.Open( m_sLocalName + _T(".sd.sav"), CFile::modeRead ) )
00549         {
00550                 try
00551                 {
00552                         CArchive ar( &pFile, CArchive::load );
00553                         Serialize( ar, 0 );
00554                         bSuccess = TRUE;
00555                 }
00556                 catch ( CException* pException )
00557                 {
00558                         pException->Delete();
00559                 }
00560                 
00561                 pFile.Close();
00562                 if ( bSuccess ) Save();
00563         }
00564         
00565         m_nSaveCookie = m_nCookie;
00566         
00567         return bSuccess;
00568 }
00569 
00570 BOOL CDownload::Save(BOOL bFlush)
00571 {
00572         CFile pFile;
00573         
00574         m_nSaveCookie = m_nCookie;
00575         m_tSaved = GetTickCount();
00576         
00577         if ( m_bComplete ) return TRUE;
00578         
00579         GenerateLocalName();
00580 	::DeleteFile( m_sLocalName + _T(".sd.sav") );
00581         
00582         if ( ! pFile.Open( m_sLocalName + _T(".sd.sav"),
00583                 CFile::modeReadWrite|CFile::modeCreate|CFile::osWriteThrough ) ) return FALSE;
00584         
00585         {
00586                 BYTE pBuffer[ 65536 ];
00587                 CArchive ar( &pFile, CArchive::store, sizeof( pBuffer ), pBuffer );
00588                 Serialize( ar, 0 );
00589                 ar.Close();
00590         }
00591         
00592         if ( Settings.Downloads.FlushSD || bFlush ) pFile.Flush();
00593         pFile.SeekToBegin();
00594         CHAR szID[3] = { 0, 0, 0 };
00595         pFile.Read( szID, 3 );
00596         pFile.Close();
00597         
00598         if ( szID[0] == 'S' && szID[1] == 'D' && szID[2] == 'L' )
00599         {
00600 		::DeleteFile( m_sLocalName + _T(".sd") );
00601                 MoveFile( m_sLocalName + _T(".sd.sav"), m_sLocalName + _T(".sd") );
00602                 return TRUE;
00603         }
00604         else
00605         {
00606 		::DeleteFile( m_sLocalName + _T(".sd.sav") );
00607                 return FALSE;
00608         }
00609 }
00610 
00612 // CDownload serialize
00613 
00614 #define DOWNLOAD_SER_VERSION    32
00615 
00616 void CDownload::Serialize(CArchive& ar, int nVersion)
00617 {
00618         ASSERT( ! m_bComplete );
00619         
00620         if ( nVersion == 0 )
00621         {
00622                 nVersion = DOWNLOAD_SER_VERSION;
00623                 
00624                 if ( ar.IsStoring() )
00625                 {
00626                         ar.Write( "SDL", 3 );
00627                         ar << nVersion;
00628                 }
00629                 else
00630                 {
00631                         CHAR szID[3];
00632                         ar.Read( szID, 3 );
00633                         if ( strncmp( szID, "SDL", 3 ) ) AfxThrowUserException();
00634                         ar >> nVersion;
00635                         if ( nVersion <= 0 || nVersion > DOWNLOAD_SER_VERSION ) AfxThrowUserException();
00636                 }
00637         }
00638         else if ( nVersion < 11 && ar.IsLoading() )
00639         {
00640                 SerializeOld( ar, nVersion );
00641                 return;
00642         }
00643                         
00644         CDownloadWithExtras::Serialize( ar, nVersion );
00645         
00646         if ( ar.IsStoring() )
00647         {
00648                 ar << m_bExpanded;
00649                 ar << m_bPaused;
00650                 ar << m_bBoosted;
00651                 ar << m_bShared;
00652                 
00653                 ar << m_nSerID;
00654         }
00655         else
00656         {
00657                 ar >> m_bExpanded;
00658                 ar >> m_bPaused;
00659                 ar >> m_bBoosted;
00660                 if ( nVersion >= 14 ) ar >> m_bShared;
00661                 if ( nVersion >= 26 ) ar >> m_nSerID;
00662                 
00663                 DownloadGroups.Link( this );
00664         }
00665 }
00666 
00667 void CDownload::SerializeOld(CArchive& ar, int nVersion)
00668 {
00669         ASSERT( ar.IsLoading() );
00670         
00671         ar >> m_sLocalName;
00672         ar >> m_sRemoteName;
00673         
00674         DWORD nSize;
00675         ar >> nSize;
00676         m_nSize = nSize;
00677         
00678         ar >> m_bSHA1;
00679         if ( m_bSHA1 ) ar.Read( &m_pSHA1, sizeof(SHA1) );
00680         
00681         ar >> m_bPaused;
00682         ar >> m_bExpanded;
00683         if ( nVersion >= 6 ) ar >> m_bBoosted;
00684         
00685         m_pFile->Serialize( ar, nVersion );
00686         GenerateLocalName();
00687         
00688         for ( int nSources = ar.ReadCount() ; nSources ; nSources-- )
00689         {
00690                 CDownloadSource* pSource = new CDownloadSource( this );
00691                 pSource->Serialize( ar, nVersion );
00692                 AddSourceInternal( pSource );
00693         }
00694         
00695         if ( nVersion >= 3 && ar.ReadCount() )
00696         {
00697                 m_pXML = new CXMLElement();
00698                 m_pXML->Serialize( ar );
00699         }
00700 }

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