⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 discoveryservices.cpp

📁 著名的下载软件核心Shareaza
💻 CPP
📖 第 1 页 / 共 2 页
字号:
//
// 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 + -