📄 discoveryservices.cpp
字号:
//
// DiscoveryServices.cpp
//
// Copyright (c) Shareaza Development Team, 2002-2004.
// This file is part of SHAREAZA (www.shareaza.com)
//
// Shareaza is free software; you can redistribute it
// and/or modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2 of
// the License, or (at your option) any later version.
//
// Shareaza is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Shareaza; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
#include "StdAfx.h"
#include "Shareaza.h"
#include "Settings.h"
#include "DiscoveryServices.h"
#include "Network.h"
#include "HostCache.h"
#include "Neighbours.h"
#include "Neighbour.h"
#include "Packet.h"
#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif
CDiscoveryServices DiscoveryServices;
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices construction
CDiscoveryServices::CDiscoveryServices()
{
m_hThread = NULL;
m_hInternet = NULL;
m_hRequest = NULL;
m_pWebCache = NULL;
m_nWebCache = 0;
m_tQueried = 0;
m_tUpdated = 0;
m_tExecute = 0;
m_bFirstTime = TRUE;
m_bForG2 = TRUE;
}
CDiscoveryServices::~CDiscoveryServices()
{
Clear();
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices list access
POSITION CDiscoveryServices::GetIterator() const
{
return m_pList.GetHeadPosition();
}
CDiscoveryService* CDiscoveryServices::GetNext(POSITION& pos) const
{
return (CDiscoveryService*)m_pList.GetNext( pos );
}
BOOL CDiscoveryServices::Check(CDiscoveryService* pService, int nType) const
{
if ( pService == NULL ) return FALSE;
if ( m_pList.Find( pService ) == NULL ) return FALSE;
return ( nType < 0 ) || ( pService->m_nType == nType );
}
int CDiscoveryServices::GetCount(int nType) const
{
if ( nType == CDiscoveryService::dsNull ) return m_pList.GetCount();
int nCount = 0;
for ( POSITION pos = GetIterator() ; pos ; )
{
if ( GetNext( pos )->m_nType == nType ) nCount++;
}
return nCount;
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices list modification
CDiscoveryService* CDiscoveryServices::Add(LPCTSTR pszAddress, int nType, BOOL bG2)
{
CSingleLock pLock( &Network.m_pSection );
if ( ! pLock.Lock( 250 ) ) return NULL;
CString strAddress( pszAddress );
if ( strAddress.GetLength() < 8 ) return NULL;
if ( strAddress.GetAt( strAddress.GetLength() - 1 ) == '/' )
strAddress = strAddress.Left( strAddress.GetLength() - 1 );
CDiscoveryService* pService = GetByAddress( strAddress );
if ( pService == NULL )
{
if ( nType == CDiscoveryService::dsWebCache )
{
if ( _tcsnicmp( strAddress, _T("http://"), 7 ) == 0 ||
_tcsnicmp( strAddress, _T("https://"), 8 ) == 0 )
{
if ( _tcschr( (LPCTSTR)strAddress + 8, '/' ) == NULL ) return NULL;
pService = new CDiscoveryService( CDiscoveryService::dsWebCache, strAddress );
}
}
else if ( nType == CDiscoveryService::dsServerMet )
{
if ( _tcsnicmp( strAddress, _T("http://"), 7 ) == 0 ||
_tcsnicmp( strAddress, _T("https://"), 8 ) == 0 )
{
if ( _tcschr( (LPCTSTR)strAddress + 8, '/' ) == NULL ) return NULL;
pService = new CDiscoveryService( CDiscoveryService::dsServerMet, strAddress );
}
}
else if ( nType == CDiscoveryService::dsGnutella )
{
if ( _tcschr( pszAddress, '.' ) != NULL )
{
pService = new CDiscoveryService( CDiscoveryService::dsGnutella, strAddress );
}
}
if ( pService == NULL ) return NULL;
}
if ( bG2 ) pService->m_bGnutella2 = TRUE;
return Add( pService );
}
CDiscoveryService* CDiscoveryServices::Add(CDiscoveryService* pService)
{
if ( pService && m_pList.Find( pService ) == NULL ) m_pList.AddTail( pService );
return pService;
}
void CDiscoveryServices::Remove(CDiscoveryService* pService)
{
if ( POSITION pos = m_pList.Find( pService ) ) m_pList.RemoveAt( pos );
delete pService;
int nCount[4];
ZeroMemory( nCount, sizeof(int) * 4 );
for ( POSITION pos = GetIterator() ; pos ; )
{
CDiscoveryService* pService = GetNext( pos );
nCount[ pService->m_nType ] ++;
}
if ( nCount[ CDiscoveryService::dsWebCache ] == 0 ||
nCount[ CDiscoveryService::dsServerMet ] == 0 )
{
AddDefaults();
}
}
CDiscoveryService* CDiscoveryServices::GetByAddress(LPCTSTR pszAddress) const
{
for ( POSITION pos = GetIterator() ; pos ; )
{
CDiscoveryService* pService = GetNext( pos );
if ( pService->m_sAddress.CompareNoCase( pszAddress ) == 0 )
return pService;
}
return NULL;
}
void CDiscoveryServices::Clear()
{
Stop();
for ( POSITION pos = GetIterator() ; pos ; )
{
delete GetNext( pos );
}
m_pList.RemoveAll();
}
void CDiscoveryServices::Stop()
{
StopWebRequest();
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices load and save
BOOL CDiscoveryServices::Load()
{
CSingleLock pLock( &Network.m_pSection, TRUE );
CFile pFile;
CString strFile = Settings.General.Path + _T("\\Data\\Discovery.dat");
if ( ! pFile.Open( strFile, CFile::modeRead ) )
{
AddDefaults();
Save();
return FALSE;
}
try
{
CArchive ar( &pFile, CArchive::load );
Serialize( ar );
ar.Close();
}
catch ( CException* pException )
{
pException->Delete();
pFile.Close();
Clear();
AddDefaults();
Save();
return FALSE;
}
pFile.Close();
if ( GetCount() == 0 )
{
AddDefaults();
Save();
}
return TRUE;
}
BOOL CDiscoveryServices::Save()
{
CSingleLock pLock( &Network.m_pSection, TRUE );
CFile pFile;
CString strFile = Settings.General.Path + _T("\\Data\\Discovery.dat");
if ( !pFile.Open( strFile, CFile::modeWrite|CFile::modeCreate ) )
return FALSE;
CArchive ar( &pFile, CArchive::store );
Serialize( ar );
ar.Close();
return TRUE;
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices serialize
void CDiscoveryServices::Serialize(CArchive& ar)
{
int nVersion = 5;
if ( ar.IsStoring() )
{
ar << nVersion;
ar.WriteCount( GetCount() );
for ( POSITION pos = GetIterator() ; pos ; )
{
GetNext( pos )->Serialize( ar, nVersion );
}
}
else
{
Clear();
ar >> nVersion;
if ( nVersion != 5 ) return;
for ( int nCount = ar.ReadCount() ; nCount > 0 ; nCount-- )
{
CDiscoveryService* pService = new CDiscoveryService();
pService->Serialize( ar, nVersion );
m_pList.AddTail( pService );
}
}
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices defaults
void CDiscoveryServices::AddDefaults()
{
CString strServices;
strServices.LoadString( IDS_DISCOVERY_DEFAULTS );
for ( strServices += '\n' ; strServices.GetLength() ; )
{
CString strService = strServices.SpanExcluding( _T("\r\n") );
strServices = strServices.Mid( strService.GetLength() + 1 );
if ( strService.GetLength() > 0 )
{
Add( strService,
( _tcsistr( strService, _T("server.met") ) == NULL ?
CDiscoveryService::dsWebCache : CDiscoveryService::dsServerMet ),
TRUE ); // ( _tcsistr( strService, _T("GWC2") ) != NULL || _tcsistr( strService, _T("g2cache") ) != NULL ) );
}
}
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices update
BOOL CDiscoveryServices::Update()
{
DWORD tNow = (DWORD)time( NULL );
if ( tNow - m_tUpdated < Settings.Discovery.UpdatePeriod ) return FALSE;
if ( m_hInternet ) return FALSE;
StopWebRequest();
CSingleLock pLock( &Network.m_pSection );
if ( ! pLock.Lock( 250 ) ) return FALSE;
if ( Network.GetStableTime() < 3600 ) return FALSE; // Up for an hour
if ( ! Neighbours.IsHub() ) return FALSE; // Must be a hub now
if ( Neighbours.GetCount( -1, -1, ntNode ) < 4 ) return FALSE; // Must have 4 peers
CDiscoveryService* pService = GetRandomWebCache( TRUE, NULL, TRUE );
if ( pService == NULL ) return FALSE;
m_tUpdated = tNow;
theApp.Message( MSG_DEFAULT, IDS_DISCOVERY_UPDATING, (LPCTSTR)pService->m_sAddress );
return RequestWebCache( pService, wcmUpdate );
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices execute
BOOL CDiscoveryServices::Execute(BOOL bSecondary)
{
CSingleLock pLock( &Network.m_pSection );
if ( ! pLock.Lock( 250 ) ) return FALSE;
if ( bSecondary )
{
if ( m_hInternet ) return FALSE;
if ( time( NULL ) - m_tQueried < 60 ) return FALSE;
if ( time( NULL ) - m_tExecute < 10 ) return FALSE;
}
else
{
theApp.Message( MSG_SYSTEM, IDS_DISCOVERY_BOOTSTRAP );
}
m_tExecute = time( NULL );
int nCount = 0;
if ( ! bSecondary ) nCount += ExecuteBootstraps( Settings.Discovery.BootstrapCount );
nCount += ExecuteWebCache();
if ( ! bSecondary ) m_tUpdated = 0;
return nCount > 0;
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices execute eDonkey2000
BOOL CDiscoveryServices::ExecuteDonkey()
{
CSingleLock pLock( &Network.m_pSection );
if ( ! pLock.Lock( 250 ) ) return FALSE;
for ( POSITION pos = GetIterator() ; pos ; )
{
CDiscoveryService* pService = GetNext( pos );
if ( pService->m_nType == CDiscoveryService::dsServerMet )
{
if ( RequestWebCache( pService, wcmServerMet ) ) return TRUE;
}
}
return FALSE;
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices resolve N gnutella bootstraps
int CDiscoveryServices::ExecuteBootstraps(int nCount)
{
CPtrArray pRandom;
int nSuccess;
if ( nCount < 1 ) return 0;
for ( POSITION pos = GetIterator() ; pos ; )
{
CDiscoveryService* pService = GetNext( pos );
if ( pService->m_nType == CDiscoveryService::dsGnutella )
pRandom.Add( pService );
}
srand( GetTickCount() );
for ( nSuccess = 0 ; nCount > 0 && pRandom.GetSize() > 0 ; )
{
int nRandom = rand() % pRandom.GetSize();
CDiscoveryService* pService = (CDiscoveryService*)pRandom.GetAt( nRandom );
pRandom.RemoveAt( nRandom );
if ( pService->ResolveGnutella() )
{
nSuccess++;
nCount--;
}
}
return nSuccess;
}
void CDiscoveryServices::OnGnutellaAdded(IN_ADDR* pAddress, int nCount)
{
// Find this host somehow and add to m_nHosts
}
void CDiscoveryServices::OnGnutellaFailed(IN_ADDR* pAddress)
{
// Find this host and add to m_nFailures, and delete if excessive
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices execute a random webcache service
int CDiscoveryServices::ExecuteWebCache()
{
m_bForG2 = Neighbours.NeedMoreHubs( TS_TRUE );
CDiscoveryService* pService = GetRandomWebCache( FALSE );
if ( pService == NULL ) return 0;
return RequestWebCache( pService, wcmHosts ) ? 1 : 0;
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices select a random webcache
CDiscoveryService* CDiscoveryServices::GetRandomWebCache(BOOL bWorkingOnly, CDiscoveryService* pExclude, BOOL bForUpdate)
{
CPtrArray pVersion2, pVersion1;
DWORD tNow = time( NULL );
for ( POSITION pos = GetIterator() ; pos ; )
{
CDiscoveryService* pService = GetNext( pos );
if ( pService->m_nType == CDiscoveryService::dsWebCache && pService != pExclude )
{
if ( ! bWorkingOnly || ( pService->m_nAccesses > 0 && pService->m_nFailures == 0 && pService->m_nHosts > 0 ) )
{
if ( tNow - pService->m_tAccessed > pService->m_nAccessPeriod )
{
if ( ! bForUpdate || tNow - pService->m_tUpdated > pService->m_nUpdatePeriod )
{
if ( pService->m_bGnutella2 )
{
pVersion2.Add( pService );
}
else
{
pVersion1.Add( pService );
}
}
}
}
}
}
srand( GetTickCount() );
if ( m_bForG2 && pVersion2.GetSize() > 0 )
{
return (CDiscoveryService*)pVersion2.GetAt( rand() % pVersion2.GetSize() );
}
else if ( ! m_bForG2 && pVersion1.GetSize() > 0 )
{
return (CDiscoveryService*)pVersion1.GetAt( rand() % pVersion1.GetSize() );
}
else
{
return NULL;
}
}
//////////////////////////////////////////////////////////////////////
// CDiscoveryServices webcache request control
BOOL CDiscoveryServices::RequestWebCache(CDiscoveryService* pService, int nMode)
{
StopWebRequest();
if ( pService != NULL )
{
if ( time( NULL ) - pService->m_tAccessed < pService->m_nAccessPeriod ) return FALSE;
}
m_pWebCache = pService;
m_nWebCache = nMode;
m_hRequest = NULL;
if ( nMode == wcmSubmit )
{
m_pSubmit = m_pWebCache;
m_pWebCache = GetRandomWebCache( FALSE, m_pSubmit, TRUE );
}
else if ( nMode == wcmUpdate )
{
m_pSubmit = GetRandomWebCache( TRUE, m_pWebCache );
}
if ( m_pWebCache == NULL ) return FALSE;
CString strAgent = Settings.SmartAgent( Settings.General.UserAgent );
m_hInternet = InternetOpen( strAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
if ( ! m_hInternet ) return FALSE;
CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_NORMAL );
m_hThread = pThread->m_hThread;
return TRUE;
}
void CDiscoveryServices::StopWebRequest()
{
if ( m_hInternet ) InternetCloseHandle( m_hInternet );
m_hInternet = NULL;
if ( m_hThread == NULL ) return;
for ( int nAttempt = 10 ; nAttempt > 0 ; nAttempt-- )
{
DWORD nCode;
if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
if ( nCode != STILL_ACTIVE ) break;
Sleep( 100 );
}
if ( nAttempt == 0 )
{
TerminateThread( m_hThread, 0 );
theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CDiscoveryServices thread.") );
Sleep( 100 );
}
m_hThread = NULL;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -