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

DiscoveryServices.cpp

Go to the documentation of this file.
00001 //
00002 // DiscoveryServices.cpp
00003 //
00004 //      Date:                   "$Date: 2005/10/04 02:44:01 $"
00005 //      Revision:               "$Revision: 1.38 $"
00006 //  Last change by:     "$Author: mogthecat $"
00007 //
00008 // Copyright (c) Shareaza Development Team, 2002-2005.
00009 // This file is part of SHAREAZA (www.shareaza.com)
00010 //
00011 // Shareaza is free software; you can redistribute it
00012 // and/or modify it under the terms of the GNU General Public License
00013 // as published by the Free Software Foundation; either version 2 of
00014 // the License, or (at your option) any later version.
00015 //
00016 // Shareaza is distributed in the hope that it will be useful,
00017 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00018 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 // GNU General Public License for more details.
00020 //
00021 // You should have received a copy of the GNU General Public License
00022 // along with Shareaza; if not, write to the Free Software
00023 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00024 //
00025 
00026 #include "StdAfx.h"
00027 #include "Shareaza.h"
00028 #include "Settings.h"
00029 #include "DiscoveryServices.h"
00030 #include "Network.h"
00031 #include "HostCache.h"
00032 #include "Neighbours.h"
00033 #include "Neighbour.h"
00034 #include "Packet.h"
00035 #include "Buffer.h"
00036 
00037 #ifdef _DEBUG
00038 #undef THIS_FILE
00039 static char THIS_FILE[]=__FILE__;
00040 #define new DEBUG_NEW
00041 #endif
00042 
00043 CDiscoveryServices DiscoveryServices;
00044 
00046 // CDiscoveryServices construction
00047 
00048 CDiscoveryServices::CDiscoveryServices()
00049 {
00050         m_hThread               = NULL;
00051         m_hInternet             = NULL;
00052         m_hRequest              = NULL;
00053         m_pWebCache             = NULL;
00054         m_nWebCache             = 0;
00055         m_tQueried              = 0;
00056         m_nLastQueryProtocol = PROTOCOL_NULL;
00057         m_tUpdated              = 0;
00058         m_nLastUpdateProtocol = PROTOCOL_NULL;
00059         m_tExecute              = 0;
00060         m_bFirstTime    = TRUE;
00061         m_tMetQueried   = 0;
00062 }
00063 
00064 CDiscoveryServices::~CDiscoveryServices()
00065 {
00066         Clear();
00067 }
00068 
00070 // CDiscoveryServices list access
00071 
00072 POSITION CDiscoveryServices::GetIterator() const
00073 {
00074         return m_pList.GetHeadPosition();
00075 }
00076 
00077 CDiscoveryService* CDiscoveryServices::GetNext(POSITION& pos) const
00078 {
00079         return (CDiscoveryService*)m_pList.GetNext( pos );
00080 }
00081 
00082 BOOL CDiscoveryServices::Check(CDiscoveryService* pService, int nType) const
00083 {
00084         if ( pService == NULL ) return FALSE;
00085         if ( m_pList.Find( pService ) == NULL ) return FALSE;
00086         return ( nType < 0 ) || ( pService->m_nType == nType );
00087 }
00088 
00089 int CDiscoveryServices::GetCount(int nType, PROTOCOLID nProtocol) const
00090 {
00091         int nCount = 0;
00092         CDiscoveryService* ptr;
00093 
00094         for ( POSITION pos = GetIterator() ; pos ; )
00095         {
00096                 ptr = GetNext( pos );
00097                 if ( ( nType == CDiscoveryService::dsNull ) || ( ptr->m_nType == nType ) )      // If we're counting all types, or it matches
00098                 {
00099                         if ( ( nProtocol == PROTOCOL_NULL ) ||                                                                  // If we're counting all protocols
00100                            ( ( nProtocol == PROTOCOL_G1   ) && ptr->m_bGnutella1 ) ||                   // Or we're counting G1 and it matches
00101                            ( ( nProtocol == PROTOCOL_G2   ) && ptr->m_bGnutella2 ) ||                   // Or we're counting G2 and it matches
00102                            ( ( nProtocol == PROTOCOL_ED2K ) && ptr->m_nType == CDiscoveryService::dsServerMet ) ) // Or we're counting ED2K
00103                         {
00104                            nCount++;
00105                         }
00106                 }
00107         }
00108         return nCount;
00109 }
00110 
00112 // CDiscoveryServices list modification
00113 
00114 CDiscoveryService* CDiscoveryServices::Add(LPCTSTR pszAddress, int nType, PROTOCOLID nProtocol)
00115 {
00116         CString strAddress( pszAddress );
00117 
00118         // Trim any excess whitespace.
00119         strAddress.TrimLeft();
00120         strAddress.TrimRight();
00121 
00122         // Trim garbage on the end- sometimes you get "//", "./", "./." etc. (Bad caches)
00123         while ( strAddress.GetLength() >= 8 )
00124         {
00125                 if ( strAddress.Right( 2 ) == _T("//") )
00126                         strAddress = strAddress.Left( strAddress.GetLength() - 1 );
00127                 else if ( strAddress.Right( 2 ) == _T("./") )
00128                         strAddress = strAddress.Left( strAddress.GetLength() - 2 );
00129                 else if ( strAddress.GetAt( strAddress.GetLength() - 1 ) == '.' )
00130                         strAddress = strAddress.Left( strAddress.GetLength() - 1 );
00131                 else break;
00132 
00133         }
00134 
00135         /*
00136         // Although this is part of the spec, it was removed at the request of the GDF.
00137         // Trim trailing '/'
00138         if ( strAddress.GetAt( strAddress.GetLength() - 1 ) == '/' )
00139                 strAddress = strAddress.Left( strAddress.GetLength() - 1 );
00140         */
00141 
00142         // Reject impossibly short services
00143         if ( strAddress.GetLength() < 8 ) return NULL;
00144 
00145         CSingleLock pNetworkLock( &Network.m_pSection );
00146         if ( ! pNetworkLock.Lock( 250 ) ) return NULL;
00147         
00148         if ( GetByAddress( strAddress ) != NULL ) return NULL;
00149 
00150         CDiscoveryService* pService = NULL;
00151 
00152         switch ( nType )
00153         {
00154         case CDiscoveryService::dsWebCache:
00155                 if ( CheckWebCacheValid( pszAddress ) )
00156                         pService = new CDiscoveryService( CDiscoveryService::dsWebCache, strAddress );
00157                 break;
00158 
00159         case CDiscoveryService::dsServerMet:
00160                 if ( CheckWebCacheValid( pszAddress ) )
00161                         pService = new CDiscoveryService( CDiscoveryService::dsServerMet, strAddress );
00162                 break;
00163 
00164         case CDiscoveryService::dsGnutella:
00165                 if ( _tcschr( pszAddress, '.' ) != NULL )
00166                         pService = new CDiscoveryService( CDiscoveryService::dsGnutella, strAddress );
00167                 break;
00168 
00169         case CDiscoveryService::dsBlocked:
00170                 pService = new CDiscoveryService( CDiscoveryService::dsBlocked, strAddress );
00171                 break;
00172         }
00173                 
00174         if ( pService == NULL ) return NULL;
00175         
00176         // Set the appropriate protocol flags
00177         switch( nProtocol )
00178         {
00179         case PROTOCOL_ED2K:
00180                 pService->m_bGnutella2 = FALSE;
00181                 pService->m_bGnutella1 = FALSE;
00182                 break;
00183         case PROTOCOL_G2:
00184                 pService->m_bGnutella2 = TRUE;
00185                 pService->m_bGnutella1 = FALSE;
00186                 break;
00187         case PROTOCOL_G1:
00188                 pService->m_bGnutella2 = FALSE;
00189                 pService->m_bGnutella1 = TRUE;
00190                 break;
00191         default:
00192                 pService->m_bGnutella2 = TRUE;
00193                 pService->m_bGnutella1 = TRUE;
00194                 break;
00195         }
00196 
00197         return Add( pService );
00198 }
00199 
00200 CDiscoveryService* CDiscoveryServices::Add(CDiscoveryService* pService)
00201 {
00202         if ( pService == NULL ) return NULL; // Can't add a null
00203 
00204         // If it's a webcache with no protocols set, assume it's for both.
00205         if ( ( pService->m_bGnutella2 == FALSE ) && ( pService->m_bGnutella1 == FALSE ) && ( pService->m_nType == CDiscoveryService::dsWebCache ) )
00206         {               
00207                 pService->m_bGnutella2 = TRUE;
00208                 pService->m_bGnutella1 = TRUE;
00209         }
00210 
00211         // Stop if we already have enough caches
00212         if ( ( pService->m_bGnutella2 && ( GetCount( PROTOCOL_G2 ) >= Settings.Discovery.CacheCount ) ) ||
00213                  ( pService->m_bGnutella1 && ( GetCount( PROTOCOL_G1 ) >= Settings.Discovery.CacheCount ) ) )
00214         {
00215                 // Check if the service is already in the list.
00216                 if ( m_pList.Find( pService ) == NULL )
00217                 {
00218                         // It's a new service, but we don't want more. We should delete it.
00219                         theApp.Message( MSG_DEBUG, _T("Maximum discovery service count reached- %s not added"), pService->m_sAddress );
00220                         delete pService;
00221                         return NULL;
00222                 }
00223                 else
00224                 {
00225                         // We already had this service on the list. Do nothing.
00226                         return pService;
00227                 }
00228         }
00229 
00230         // Add the service to the list if it's not there already
00231         if ( m_pList.Find( pService ) == NULL ) m_pList.AddTail( pService );
00232         return pService;
00233 }
00234 
00235 void CDiscoveryServices::Remove(CDiscoveryService* pService, BOOL bCheck)
00236 {
00237         if ( POSITION pos = m_pList.Find( pService ) ) m_pList.RemoveAt( pos );
00238         delete pService;
00239         
00240         if ( bCheck && ! EnoughServices() )
00241         {
00242                 AddDefaults();
00243         }
00244 }
00245 
00246 
00247 BOOL CDiscoveryServices::CheckWebCacheValid(LPCTSTR pszAddress)
00248 {
00249         // Check it's long enough
00250         if ( _tcsclen( pszAddress ) < 12 ) return FALSE;
00251 
00252         // Check it's not blocked
00253         for ( POSITION pos = GetIterator() ; pos ; )
00254         {
00255                 CDiscoveryService* pService = GetNext( pos );
00256                 
00257                 if ( pService->m_nType == CDiscoveryService::dsBlocked )
00258                 {
00259                         if ( _tcsistr( pszAddress, pService->m_sAddress ) != NULL )
00260                                 return FALSE;
00261                 }
00262         }
00263 
00264         // Check it has a valid protocol
00265         if ( _tcsnicmp( pszAddress, _T("http://"),  7 ) == 0 ) 
00266                 pszAddress += 7;
00267         else if ( _tcsnicmp( pszAddress, _T("https://"), 8 ) == 0 ) 
00268                 pszAddress += 8;
00269         else
00270                  return FALSE;
00271 
00272         // Scan through, make sure there are some '.' in there.
00273         pszAddress = _tcschr( pszAddress, '.' );
00274         if ( pszAddress == NULL ) return FALSE;
00275 
00276         // And check we have a '/' as well
00277         pszAddress = _tcschr( pszAddress, '/' );
00278         if ( pszAddress == NULL ) return FALSE;
00279 
00280         // Probably okay
00281         return TRUE;
00282 }
00283 
00284 BOOL CDiscoveryServices::CheckMinimumServices()
00285 {
00286         // Add the default services if we don't have enough
00287         if ( ! EnoughServices() )
00288         {
00289                 AddDefaults();
00290                 return FALSE;
00291         }
00292 
00293         return TRUE;
00294 }
00295 
00297 // CDiscoveryServices execute a service to get hosts
00298 
00299 // WARNING: Way too agressive for general use- Be very careful where this is called!
00300 // This is a public function, and should be called once when setting up/installing the program. 
00301 // IE: In the Quickstart Wizard *only*
00302 // Using this for general querying would overload services and get you blacklisted.
00303 BOOL CDiscoveryServices::QueryForHosts( PROTOCOLID nProtocol )
00304 {
00305         CSingleLock pLock( &Network.m_pSection );
00306         if ( ! pLock.Lock( 250 ) ) return FALSE;
00307 
00308         for ( int nLoop = 0 ; nLoop < 3 ; nLoop ++ )
00309         {
00310                 if ( RequestRandomService( nProtocol ) )
00311                         return TRUE;
00312         }
00313         
00314         return FALSE;
00315 }
00316 
00317 DWORD CDiscoveryServices::MetQueried() const
00318 {
00319         return m_tMetQueried;
00320 }
00321 
00322 CDiscoveryService* CDiscoveryServices::GetByAddress(LPCTSTR pszAddress) const
00323 {
00324         for ( POSITION pos = GetIterator() ; pos ; )
00325         {
00326                 CDiscoveryService* pService = GetNext( pos );
00327                 
00328                 int nLen = pService->m_sAddress.GetLength();
00329                 if ( nLen > 20 )
00330                 {
00331                         // If it's a long webcache address, ignore the last few characters when checking
00332                         if ( _tcsnicmp( pService->m_sAddress, pszAddress, nLen - 2 ) == 0 )
00333                                 return pService;
00334                 }
00335                 else
00336                 {
00337                         if ( pService->m_sAddress.CompareNoCase( pszAddress ) == 0 )
00338                                 return pService;
00339                 }
00340         }
00341 
00342         return NULL;
00343 }
00344 
00345 void CDiscoveryServices::Clear()
00346 {
00347         Stop();
00348 
00349         for ( POSITION pos = GetIterator() ; pos ; )
00350         {
00351                 delete GetNext( pos );
00352         }
00353 
00354         m_pList.RemoveAll();
00355 }
00356 
00357 void CDiscoveryServices::Stop()
00358 {
00359         StopWebRequest();
00360 }
00361 
00362 
00364 // CDiscoveryServices load and save
00365 
00366 BOOL CDiscoveryServices::Load()
00367 {
00368         CSingleLock pLock( &Network.m_pSection, TRUE );
00369         CFile pFile;
00370         
00371         CString strFile = Settings.General.UserPath + _T("\\Data\\Discovery.dat");
00372         
00373         // Load the services from disk
00374         if ( ! pFile.Open( strFile, CFile::modeRead ) )
00375         {
00376                 AddDefaults();
00377                 Save();
00378                 return FALSE;
00379         }
00380         
00381         try
00382         {
00383                 CArchive ar( &pFile, CArchive::load );
00384                 Serialize( ar );
00385                 ar.Close();
00386         }
00387         catch ( CException* pException )
00388         {
00389                 pException->Delete();
00390                 pFile.Close();
00391                 Clear();
00392                 AddDefaults();
00393                 Save();
00394                 return FALSE;
00395         }
00396         
00397         pFile.Close();
00398         
00399         // Check we have the minimum number of services (in case of file corruption, etc)
00400         if ( ! EnoughServices() )
00401         {
00402                 AddDefaults();  // Re-add the default list
00403                 Save();                 // And save it
00404         }
00405         
00406         return TRUE;
00407 }
00408 
00409 BOOL CDiscoveryServices::Save()
00410 {
00411         CSingleLock pLock( &Network.m_pSection, TRUE );
00412         CFile pFile;
00413 
00414         CString strFile = Settings.General.UserPath + _T("\\Data\\Discovery.dat");
00415         if ( !pFile.Open( strFile, CFile::modeWrite|CFile::modeCreate ) )
00416                 return FALSE;
00417 
00418         CArchive ar( &pFile, CArchive::store );
00419         Serialize( ar );
00420         ar.Close();
00421 
00422         return TRUE;
00423 }
00424 
00426 // CDiscoveryServices serialize
00427 
00428 void CDiscoveryServices::Serialize(CArchive& ar)
00429 {
00430         int nVersion = 6;
00431         
00432         if ( ar.IsStoring() )
00433         {
00434                 ar << nVersion;
00435                 
00436                 ar.WriteCount( GetCount() );
00437                 
00438                 for ( POSITION pos = GetIterator() ; pos ; )
00439                 {
00440                         GetNext( pos )->Serialize( ar, nVersion );
00441                 }
00442         }
00443         else
00444         {
00445                 Clear();
00446                 
00447                 ar >> nVersion;
00448                 if ( nVersion < 6 ) return;
00449                 
00450                 for ( int nCount = ar.ReadCount() ; nCount > 0 ; nCount-- )
00451                 {
00452                         CDiscoveryService* pService = new CDiscoveryService();
00453                         pService->Serialize( ar, nVersion );
00454                         m_pList.AddTail( pService );
00455                 }
00456         }
00457 }
00458 
00460 // CDiscoveryServices Check we have the minimum number of services
00461 // Returns TRUE if there are enough services, or FALSE if there are not.
00462 
00463 BOOL CDiscoveryServices::EnoughServices() const
00464 {
00465         int nWebCacheCount = 0, nServerMetCount = 0;    // Types of services
00466         int nG1Count = 0, nG2Count = 0;                                 // Protocols
00467         
00468         for ( POSITION pos = GetIterator() ; pos ; )
00469         {
00470                 CDiscoveryService* pService = GetNext( pos );
00471                 if ( pService->m_nType == CDiscoveryService::dsWebCache )
00472                 {
00473                         nWebCacheCount++;
00474 
00475                         if ( pService->m_bGnutella1 ) nG1Count++;
00476                         if ( pService->m_bGnutella2 ) nG2Count++;
00477                 }
00478                 else if ( pService->m_nType == CDiscoveryService::dsServerMet )
00479                 {
00480                         nServerMetCount ++;
00481                 }
00482         }
00483 
00484         return ( ( nWebCacheCount   > 4 ) &&    // At least 5 webcaches
00485                      ( nG2Count                 > 2 ) &&        // At least 3 G2 services
00486                          ( nG1Count                     > 0 ) &&        // At least 1 G1 service
00487                          ( nServerMetCount  > 0 ) );    // At least 1 server.met
00488 }
00489 
00491 // CDiscoveryServices defaults
00492 
00493 void CDiscoveryServices::AddDefaults()
00494 {
00495         CFile pFile;
00496         CString strFile = Settings.General.Path + _T("\\Data\\DefaultServices.dat");
00497 
00498         if (  pFile.Open( strFile, CFile::modeRead ) )                  // Load default list from file if possible
00499         {
00500                 theApp.Message( MSG_DEFAULT, _T("Loading default discovery service list") );
00501 
00502                 try
00503                 {
00504                         CString strService;
00505                         CString strLine;
00506                         CBuffer pBuffer;
00507                         TCHAR cType;
00508 
00509                         pBuffer.EnsureBuffer( (DWORD)pFile.GetLength() );
00510                         pBuffer.m_nLength = (DWORD)pFile.GetLength();
00511                         pFile.Read( pBuffer.m_pBuffer, pBuffer.m_nLength );
00512                         pFile.Close();
00513 
00514                         while ( pBuffer.ReadLine( strLine ) )
00515                         {
00516                                 if ( strLine.GetLength() < 7 ) continue;                                                                        // Blank comment line
00517 
00518                                 cType = strLine.GetAt( 0 );
00519                                 strService = strLine.Right( strLine.GetLength() - 2 );
00520 
00521                                 switch( cType )
00522                                 {
00523                                 case '1': Add( strService, CDiscoveryService::dsWebCache, PROTOCOL_G1 );        // G1 service
00524                                         break;
00525                                 case '2': Add( strService, CDiscoveryService::dsWebCache, PROTOCOL_G2 );        // G2 service
00526                                         break;
00527                                 case 'M': Add( strService, CDiscoveryService::dsWebCache );                                     // Multinetwork service
00528                                         break;
00529                                 case 'D': Add( strService, CDiscoveryService::dsServerMet, PROTOCOL_ED2K );     // eDonkey service
00530                                         break;
00531                                 case 'X': Add( strService, CDiscoveryService::dsBlocked );                                      // Blocked service
00532                                         break;
00533                                 case '#':                                                                                                                                       // Comment line
00534                                         break;
00535                                 }
00536                         }
00537                 }
00538                 catch ( CException* pException )
00539                 {
00540                         if (pFile.m_hFile != CFile::hFileNull) pFile.Close(); // Check if file is still open, if yes close
00541                         pException->Delete();
00542                 }
00543         }
00544         
00545         // If file can't be used or didn't have enough services, drop back to the the in-built list
00546         if ( ! EnoughServices() )
00547         {
00548                 theApp.Message( MSG_ERROR, _T("Default discovery service load failed- using application defined list.") );
00549                 CString strServices;
00550                 strServices.LoadString( IDS_DISCOVERY_DEFAULTS );
00551         
00552                 for ( strServices += '\n' ; strServices.GetLength() ; )
00553                 {
00554                         CString strService = strServices.SpanExcluding( _T("\r\n") );
00555                         strServices = strServices.Mid( strService.GetLength() + 1 );
00556                 
00557                         if ( strService.GetLength() > 0 )
00558                         {
00559                                 if ( _tcsistr( strService, _T("server.met") ) == NULL )
00560                                         Add( strService, CDiscoveryService::dsWebCache );
00561                                 else
00562                                         Add( strService, CDiscoveryService::dsServerMet, PROTOCOL_ED2K );
00563                         }
00564                 }
00565         }
00566 }
00567 
00569 // CDiscoveryServices update
00570 
00571 BOOL CDiscoveryServices::Update()
00572 {
00573         PROTOCOLID nProtocol;
00574         DWORD tNow = (DWORD)time( NULL );
00575         
00576         // Don't update too frequently
00577         if ( tNow - m_tUpdated < Settings.Discovery.UpdatePeriod ) return FALSE;
00578         
00579         if ( m_hInternet ) return FALSE;
00580         StopWebRequest();
00581         
00582         CSingleLock pLock( &Network.m_pSection );
00583         if ( ! pLock.Lock( 250 ) ) return FALSE;
00584         
00585         // Must be up for two hours
00586         if ( Network.GetStableTime() < 7200 ) return FALSE;                             
00587 
00588         // Determine which network/protocol to update
00589         if ( Neighbours.IsG2Hub() )                                             // G2 hub mode is active
00590         {
00591                 if ( Neighbours.IsG1Ultrapeer() )                       // G2 and G1 are active
00592                 {       
00593                         // Update the one we didn't update last time
00594                         if ( m_nLastUpdateProtocol == PROTOCOL_G2 ) nProtocol = PROTOCOL_G1;
00595                         else nProtocol = PROTOCOL_G2;
00596                 }
00597                 else                                                                            // Only G2 is active
00598                         nProtocol = PROTOCOL_G2;
00599         }
00600         else if ( Neighbours.IsG1Ultrapeer() )                  // Only G1 active
00601                 nProtocol = PROTOCOL_G1;
00602         else                                                                                    // No protocols active- no updates
00603                 return FALSE;
00604 
00605         //*** ToDo: Ultrapeer mode hasn't been updated or tested in a long time
00606 
00607         ASSERT ( ( nProtocol == PROTOCOL_G1 ) || ( nProtocol == PROTOCOL_G2 ) );
00608 
00609         // Must have at least 4 peers
00610         if ( Neighbours.GetCount( nProtocol, -1, ntNode ) < 4 ) return FALSE;   
00611                 
00612         // Select a random webcache of the approprate sort
00613         CDiscoveryService* pService = GetRandomWebCache(nProtocol, TRUE, NULL, TRUE );
00614         if ( pService == NULL ) return FALSE;
00615                 
00616         // Make the update request
00617         return RequestWebCache( pService, wcmUpdate, nProtocol );
00618 
00619 }
00620 
00622 // CDiscoveryServices execute
00623 
00624 // This is called when trying to connect to a network, and at intervals while connected. 
00625 // Makes sure you have hosts available to connect to. Be very careful not to be agressive here. 
00626 // You should never query server.met files, because of the load it would create.
00627 // This is public, and will be called quite regularly.
00628 
00629 BOOL CDiscoveryServices::Execute(BOOL bSecondary)
00630 {
00631         CSingleLock pLock( &Network.m_pSection );
00632         if ( ! pLock.Lock( 250 ) ) return FALSE;
00633         DWORD tNow = time( NULL );
00634 
00635         if ( bSecondary )
00636         {
00637                 if ( m_hInternet ) return FALSE;
00638                 if ( tNow - m_tQueried < 60 ) return FALSE;
00639                 if ( tNow - m_tExecute < 10 ) return FALSE;
00640         }
00641         else
00642         {
00643                 theApp.Message( MSG_SYSTEM, IDS_DISCOVERY_BOOTSTRAP );
00644         }
00645         
00646         m_tExecute = tNow;
00647         DWORD   nG1Hosts = HostCache.Gnutella1.CountHosts();
00648         DWORD   nG2Hosts = HostCache.Gnutella2.CountHosts();
00649         BOOL    bG1Required = Settings.Gnutella1.EnableToday && ( nG1Hosts < 200 );
00650         BOOL    bG2Required = Settings.Gnutella2.EnableToday && ( nG2Hosts < 800 );
00651 
00652         if ( ! bSecondary ) // If this is a user-initiated manual query (Or the 'on-startup' query)
00653         {
00654                 ExecuteBootstraps( Settings.Discovery.BootstrapCount );
00655                 
00656                 if ( ( bG2Required ) && ( nG2Hosts < 25 ) && RequestRandomService( PROTOCOL_G2 ) )
00657                         return TRUE;
00658                 
00659                 if ( ( bG1Required ) && ( nG1Hosts < 15 ) && RequestRandomService( PROTOCOL_G1 ) )
00660                         return TRUE;
00661 
00662                 // Note: Do not enable MetAutoQuery until we have a MET file set up!
00663                 if ( ( Settings.eDonkey.EnableToday ) && ( Settings.eDonkey.MetAutoQuery ) &&
00664                          ( HostCache.eDonkey.CountHosts() < 3 ) && ( m_tMetQueried == 0 ) )
00665                 {       
00666                         m_tMetQueried = tNow;                                   // Execute this once only. (Very important)
00667                         if ( RequestRandomService( PROTOCOL_ED2K ) ) return TRUE;
00668                 }
00669                 
00670                 if ( ( bG1Required ) && ( m_nLastQueryProtocol == PROTOCOL_G2 ) )
00671                         return RequestRandomService( PROTOCOL_G1 );
00672                 else
00673                         return RequestRandomService( PROTOCOL_G2 );
00674         }
00675 
00676         // A general request. (We have to be very careful not to be too agressive here.)
00677 
00678         // Select the network protocol we want to request hosts from
00679         if ( bG1Required && bG2Required )                                       // G1 + G2 hosts are wanted
00680         {
00681                 // Select which protocol should be requested
00682                 if ( nG2Hosts < 25 )
00683                         return RequestRandomService( PROTOCOL_G2 );
00684                 else if ( nG1Hosts < 15 )
00685                         return RequestRandomService( PROTOCOL_G1 );
00686                 else if ( Neighbours.NeedMoreHubs( PROTOCOL_G2 ) || ( nG2Hosts <= nG1Hosts ) )
00687                         return RequestRandomService( PROTOCOL_G2 );
00688                 else
00689                         return RequestRandomService( PROTOCOL_G1 );
00690         }
00691         else if ( bG2Required )                                                         // Only G2
00692         {
00693                 return RequestRandomService( PROTOCOL_G2 );     
00694         }
00695         else if ( bG1Required )                                                         // Only G1
00696         {
00697                 return RequestRandomService( PROTOCOL_G1 );     
00698         }
00699 
00700         return FALSE;
00701 }
00702 
00704 // CDiscoveryServices resolve N gnutella bootstraps
00705 
00706 int CDiscoveryServices::ExecuteBootstraps(int nCount)
00707 {
00708         CPtrArray pRandom;
00709         int nSuccess;
00710 
00711         if ( nCount < 1 ) return 0;
00712 
00713         for ( POSITION pos = GetIterator() ; pos ; )
00714         {
00715                 CDiscoveryService* pService = GetNext( pos );
00716                 if ( pService->m_nType == CDiscoveryService::dsGnutella )
00717                         pRandom.Add( pService );
00718         }
00719 
00720         srand( GetTickCount() );
00721 
00722         for ( nSuccess = 0 ; nCount > 0 && pRandom.GetSize() > 0 ; )
00723         {
00724                 int nRandom = rand() % pRandom.GetSize();
00725                 CDiscoveryService* pService = (CDiscoveryService*)pRandom.GetAt( nRandom );
00726                 pRandom.RemoveAt( nRandom );
00727 
00728                 if ( pService->ResolveGnutella() )
00729                 {
00730                         nSuccess++;
00731                         nCount--;
00732                 }
00733         }
00734 
00735         return nSuccess;
00736 }
00737 
00738 void CDiscoveryServices::OnGnutellaAdded(IN_ADDR* pAddress, int nCount)
00739 {
00740         // Find this host somehow and add to m_nHosts
00741 }
00742 
00743 void CDiscoveryServices::OnGnutellaFailed(IN_ADDR* pAddress)
00744 {
00745         // Find this host and add to m_nFailures, and delete if excessive
00746 }
00747 
00748 
00750 // CDiscoveryServices RequestRandomService
00751 
00752 // Execute a random service (of any type) for any given protocol. Used to find more
00753 // hosts (to connect to a network).
00754 
00755 BOOL CDiscoveryServices::RequestRandomService(PROTOCOLID nProtocol)
00756 {
00757         //CSingleLock pLock( &Network.m_pSection );     // Note: This shouldn't be necessary, since the
00758         //if ( ! pLock.Lock( 250 ) ) return FALSE;      // calling functions should lock...
00759 
00760         CDiscoveryService* pService = GetRandomService( nProtocol );
00761 
00762         if ( pService )
00763         {
00764                 if ( pService->m_nType == CDiscoveryService::dsServerMet )
00765                 {
00766                         if ( RequestWebCache( pService, wcmServerMet, nProtocol ) ) return TRUE;
00767                 }
00768                 else
00769                 {
00770                         if ( RequestWebCache( pService, wcmHosts, nProtocol ) ) return TRUE;
00771                 }
00772         }
00773         return FALSE;
00774 }
00775 
00777 // CDiscoveryServices GetRandomService 
00778 
00779 // Selects a random discovery service of any type for any given protocol. Called by 
00780 // RequestRandomService(), and used when finding more hosts (to connect to a network).
00781 
00782 CDiscoveryService* CDiscoveryServices::GetRandomService(PROTOCOLID nProtocol)
00783 {
00784         CPtrArray pServices;
00785         DWORD tNow = time( NULL );
00786 
00787         // Loops through all services
00788         for ( POSITION pos = GetIterator() ; pos ; )
00789         {
00790                 CDiscoveryService* pService = GetNext( pos );
00791 
00792                 // If this one hasn't been recently accessed
00793                 if ( tNow - pService->m_tAccessed > pService->m_nAccessPeriod )
00794                 {
00795                         // Then add it to the possible list (if it's of the right sort)
00796                         switch ( nProtocol )
00797                         {
00798                                 case PROTOCOL_G1:
00799                                         if ( ( pService->m_nType == CDiscoveryService::dsWebCache ) && ( pService->m_bGnutella1 ) )
00800                                                 pServices.Add( pService );
00801                                         break;
00802                                 case PROTOCOL_G2:
00803                                         if ( ( pService->m_nType == CDiscoveryService::dsWebCache ) && ( pService->m_bGnutella2 ) )
00804                                                 pServices.Add( pService );
00805                                         break;
00806                                 case PROTOCOL_ED2K:
00807                                         if ( pService->m_nType == CDiscoveryService::dsServerMet )
00808                                                 pServices.Add( pService );
00809                                         break;
00810                                 default:
00811                                         break;
00812                         }
00813                 }
00814         }
00815 
00816         // Select a random service from the list of possible ones.
00817         if ( pServices.GetSize() > 0 )  // If the list of possible ones isn't empty
00818         {
00819                 // return a random service
00820                 srand( GetTickCount() );
00821                 return (CDiscoveryService*)pServices.GetAt( rand() % pServices.GetSize() );
00822         }
00823         else                                                    // else (No services available)
00824         {
00825                 // return NULL to indicate none available
00826                 return NULL;
00827         }
00828 }
00829 
00831 // CDiscoveryServices select a random webcache (For updates, etc)
00832 
00833 CDiscoveryService* CDiscoveryServices::GetRandomWebCache(PROTOCOLID nProtocol, BOOL bWorkingOnly, CDiscoveryService* pExclude, BOOL bForUpdate)
00834 {       // Select a random webcache (G1/G2 only)
00835         CPtrArray pWebCaches;
00836         DWORD tNow = time( NULL );
00837 
00838         for ( POSITION pos = GetIterator() ; pos ; )
00839         {
00840                 CDiscoveryService* pService = GetNext( pos );
00841 
00842                 if ( pService->m_nType == CDiscoveryService::dsWebCache && pService != pExclude )
00843                 {
00844                         if ( ! bWorkingOnly || ( pService->m_nAccesses > 0 && pService->m_nFailures == 0 && pService->m_nHosts > 0 ) )
00845                         {
00846                                 if ( tNow - pService->m_tAccessed > pService->m_nAccessPeriod )
00847                                 {
00848                                         if ( ! bForUpdate || tNow - pService->m_tUpdated > pService->m_nUpdatePeriod )
00849                                         {
00850                                                 switch ( nProtocol )
00851                                                 {
00852                                                         case PROTOCOL_G1:
00853                                                                 if ( ( pService->m_nType == CDiscoveryService::dsWebCache ) && ( pService->m_bGnutella1 ) )
00854                                                                         pWebCaches.Add( pService );
00855                                                                 break;
00856                                                         case PROTOCOL_G2:
00857                                                                 if ( ( pService->m_nType == CDiscoveryService::dsWebCache ) && ( pService->m_bGnutella2 ) )
00858                                                                         pWebCaches.Add( pService );
00859                                                                 break;
00860                                                         default:
00861                                                                 theApp.Message( MSG_ERROR, _T("CDiscoveryServices::GetRandomWebCache() was passed an invalid protocol") );
00862                                                                 ASSERT( FALSE );
00863                                                                 return NULL;
00864                                                 }
00865                                         }
00866                                 }
00867                         }
00868                 }
00869         }
00870         
00871         // If there are any available web caches
00872         if ( pWebCaches.GetSize() > 0 )
00873         {
00874                 // Select a random one
00875                 srand( GetTickCount() );
00876                 return (CDiscoveryService*)pWebCaches.GetAt( rand() % pWebCaches.GetSize() );
00877         }
00878         else
00879         {
00880                 // return null to indicate none available
00881                 return NULL;
00882         }
00883 }
00884 
00886 // CDiscoveryServices webcache request control
00887 
00888 BOOL CDiscoveryServices::RequestWebCache(CDiscoveryService* pService, int nMode, PROTOCOLID nProtocol)
00889 {
00890         DWORD tNow = (DWORD)time( NULL );
00891         StopWebRequest();
00892         
00893         if ( pService != NULL )
00894         {
00895                 if ( time( NULL ) - pService->m_tAccessed < pService->m_nAccessPeriod ) return FALSE;
00896         }
00897 
00898         switch ( nProtocol )
00899         {
00900         case PROTOCOL_G1:
00901                 theApp.Message( MSG_DEBUG, _T("CDiscoveryServices::RequestWebCache() seeking gnutella hosts") );
00902                 break;
00903         case PROTOCOL_G2:
00904                 theApp.Message( MSG_DEBUG, _T("CDiscoveryServices::RequestWebCache() seeking G2 hosts") );
00905                 break;
00906         case PROTOCOL_ED2K:
00907                 theApp.Message( MSG_DEBUG, _T("CDiscoveryServices::RequestWebCache() seeking ed2k hosts") );
00908                 break;
00909         default:
00910                 theApp.Message( MSG_ERROR, _T("ERROR: CDiscoveryServices::RequestWebCache() was passed an invalid protocol") );
00911                 return FALSE;
00912         }
00913         
00914         m_pWebCache     = pService;
00915         m_nWebCache     = nMode;
00916         m_hRequest      = NULL;
00917         
00918         switch ( nMode )
00919         {
00920         case wcmHosts:
00921         case wcmCaches:
00922                 if ( m_pWebCache != NULL ) 
00923                 {       
00924                         theApp.Message( MSG_SYSTEM, IDS_DISCOVERY_QUERY, (LPCTSTR)m_pWebCache->m_sAddress );
00925                         // Update the 'last queried' settings
00926                         m_tQueried = tNow;
00927                         m_nLastQueryProtocol = nProtocol;
00928                 }
00929                 break;
00930 
00931         case wcmUpdate:
00932                 m_pSubmit       = GetRandomWebCache( nProtocol, TRUE, m_pWebCache, FALSE );
00933                 if ( m_pWebCache != NULL ) 
00934                 {
00935                         theApp.Message( MSG_SYSTEM, IDS_DISCOVERY_UPDATING, (LPCTSTR)m_pWebCache->m_sAddress );
00936                         // Update the 'last updated' settings
00937                         m_tUpdated = tNow;
00938                         m_nLastUpdateProtocol = nProtocol;
00939                 }
00940                 break;
00941 
00942         case wcmSubmit:
00943                 m_pSubmit       = m_pWebCache;
00944                 m_pWebCache     = GetRandomWebCache( nProtocol, FALSE, m_pSubmit, TRUE );
00945                 if ( m_pWebCache != NULL ) 
00946                 {               
00947                         theApp.Message( MSG_SYSTEM, IDS_DISCOVERY_SUBMIT, (LPCTSTR)m_pWebCache->m_sAddress );
00948                         // Update the 'last queried' settings
00949                         m_tQueried = tNow;
00950                         m_nLastQueryProtocol = nProtocol;
00951                 }
00952                 break;
00953 
00954         case wcmServerMet:
00955                 if ( nProtocol != PROTOCOL_ED2K )
00956                 {
00957                         theApp.Message( MSG_ERROR, _T("ERROR: CDiscoveryServices::RequestWebCache() was passed wcmServerMet with non-ed2k protocol") );
00958                         ASSERT ( FALSE );
00959                         return FALSE;
00960                 }
00961                 else if ( m_pWebCache != NULL ) 
00962                 {       
00963                         theApp.Message( MSG_SYSTEM, IDS_DISCOVERY_QUERY, (LPCTSTR)m_pWebCache->m_sAddress );
00964                         // Update the 'last queried' settings
00965                         m_tQueried = tNow;
00966                         m_nLastQueryProtocol = nProtocol;
00967                 }
00968                 break;
00969         default:
00970                 theApp.Message( MSG_ERROR, _T("ERROR: CDiscoveryServices::RequestWebCache() was passed an invalid mode") );
00971                 ASSERT ( FALSE );
00972                 return FALSE;
00973         }
00974         
00975         if ( m_pWebCache == NULL ) return FALSE;
00976         
00977         CString strAgent = Settings.SmartAgent();
00978         
00979         m_hInternet = InternetOpen( strAgent, INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0 );
00980         if ( ! m_hInternet ) return FALSE;
00981         
00982         CWinThread* pThread = AfxBeginThread( ThreadStart, this, THREAD_PRIORITY_NORMAL );
00983         m_hThread = pThread->m_hThread;
00984         
00985         return TRUE;
00986 }
00987 
00988 void CDiscoveryServices::StopWebRequest()
00989 {
00990         if ( m_hInternet ) InternetCloseHandle( m_hInternet );
00991         m_hInternet = NULL;
00992         
00993         if ( m_hThread == NULL ) return;
00994         
00995     int nAttempt = 10;
00996         for ( ; nAttempt > 0 ; nAttempt-- )
00997         {
00998                 DWORD nCode;
00999 
01000                 if ( ! GetExitCodeThread( m_hThread, &nCode ) ) break;
01001                 if ( nCode != STILL_ACTIVE ) break;
01002                 Sleep( 100 );
01003         }
01004 
01005         if ( nAttempt == 0 )
01006         {
01007                 TerminateThread( m_hThread, 0 );
01008                 theApp.Message( MSG_DEBUG, _T("WARNING: Terminating CDiscoveryServices thread.") );
01009                 Sleep( 100 );
01010         }
01011 
01012         m_hThread = NULL;
01013 }
01014 
01016 // CDiscoveryServices thread bootstrap
01017 
01018 UINT CDiscoveryServices::ThreadStart(LPVOID pParam)
01019 {
01020         CDiscoveryServices* pClass = (CDiscoveryServices*)pParam;
01021         pClass->OnRun();
01022         return 0;
01023 }
01024 
01026 // CDiscoveryServices thread run
01027 
01028 void CDiscoveryServices::OnRun()
01029 {
01030         BOOL bSuccess = TRUE;
01031         
01032         if ( m_nWebCache == wcmServerMet )
01033         {
01034                 bSuccess = RunServerMet();
01035         }
01036         else if ( m_nWebCache == wcmHosts )
01037         {
01038                 bSuccess = RunWebCacheGet( FALSE );
01039                 
01040                 if ( bSuccess && m_hInternet )
01041                 {
01042                         CSingleLock pLock( &Network.m_pSection, TRUE );
01043                         
01044                         if ( m_bFirstTime || ( GetCount( CDiscoveryService::dsWebCache ) < (int)Settings.Discovery.Lowpoint ) )
01045                         {
01046                                 m_bFirstTime = FALSE;
01047                                 pLock.Unlock();
01048                                 bSuccess = RunWebCacheGet( TRUE );
01049                         }
01050                 }
01051         }
01052         else if ( m_nWebCache == wcmCaches )
01053         {
01054                 bSuccess = RunWebCacheGet( TRUE );
01055         }
01056         else if ( m_nWebCache == wcmUpdate )
01057         {
01058                 bSuccess = RunWebCacheUpdate();
01059         }
01060         else if ( m_nWebCache == wcmSubmit )
01061         {
01062                 bSuccess = RunWebCacheUpdate();
01063         }
01064         
01065         if ( m_hInternet && ! bSuccess )
01066         {
01067                 if ( m_nWebCache == wcmUpdate )
01068                 {
01069                         m_tUpdated = 0;
01070                         m_nLastUpdateProtocol = PROTOCOL_NULL;
01071                 }
01072                 else
01073                 {
01074                         m_tQueried = 0;
01075                         m_nLastQueryProtocol = PROTOCOL_NULL;
01076                 }
01077 
01078                 CSingleLock pLock( &Network.m_pSection );
01079                 if ( pLock.Lock( 250 ) && Check( m_pWebCache ) ) m_pWebCache->OnFailure();
01080         }
01081         
01082         if ( m_hInternet != NULL )
01083         {
01084                 if ( m_hRequest != NULL ) InternetCloseHandle( m_hRequest );
01085                 InternetCloseHandle( m_hInternet );
01086                 m_hInternet     = NULL;
01087                 m_hRequest      = NULL;
01088         }
01089 }
01090 
01092 // CDiscoveryServices execute hosts request
01093 
01094 BOOL CDiscoveryServices::RunWebCacheGet(BOOL bCaches)
01095 {
01096         CSingleLock pLock( &Network.m_pSection, TRUE );
01097         CString strURL, strOutput;
01098         
01099         if ( ! Check( m_pWebCache ) ) return FALSE;
01100         m_pWebCache->OnAccess();
01101         
01102         if ( bCaches )
01103                 strURL = m_pWebCache->m_sAddress + _T("?get=1&urlfile=1");
01104         else
01105                 strURL = m_pWebCache->m_sAddress + _T("?get=1&hostfile=1");
01106         
01107         if ( m_nLastQueryProtocol == PROTOCOL_G2 ) strURL += _T("&net=gnutella2");
01108         
01109         pLock.Unlock();
01110 
01111         if ( ! SendWebCacheRequest( strURL, strOutput ) ) return FALSE;
01112         pLock.Lock();
01113         
01114         if ( ! Check( m_pWebCache ) ) return FALSE;
01115         
01116         BOOL bSuccess = FALSE;
01117         int nIP[4], nIPs = 0;
01118 
01119         if ( _tcsistr( strOutput, _T("<html>") ) != NULL )
01120         {
01121                 // Error- getting HMTL response.
01122                 return FALSE;
01123         }
01124         else if ( _tcsistr( strOutput, _T("<font>") ) != NULL )
01125         {
01126                 // Error- getting HMTL response.
01127                 return FALSE;
01128         }
01129 
01130         
01131         for ( strOutput += '\n' ; strOutput.GetLength() ; )
01132         {
01133                 CString strLine = strOutput.SpanExcluding( _T("\r\n") );
01134                 strOutput               = strOutput.Mid( strLine.GetLength() + 1 );
01135                 
01136                 strLine.TrimLeft();
01137                 strLine.TrimRight();
01138                 if ( strLine.IsEmpty() ) continue;
01139 
01140                 theApp.Message( MSG_DEBUG, _T("GWebCache(get): %s"), (LPCTSTR)strLine );
01141                 
01142                 if ( _tcsnicmp( strLine, _T("h|"), 2 ) == 0 )
01143                 {
01144                         // IP ADDRESS AT: strLine.Mid( 2 )
01145                         // CORRECT (REQUESTED) NETWORK
01146                         
01147                         strLine = strLine.Mid( 2 );
01148                         int nBreak      = strLine.Find( '|' );
01149                         DWORD tSeen     = 0;
01150 
01151                         if ( nBreak > 0 )
01152                         {
01153                                 int nSeconds = 0;
01154                                 _stscanf( strLine.Mid( nBreak + 1 ), _T("%i"), &nSeconds );
01155                                 nSeconds = max( 0, min( 18000, nSeconds ) );
01156                                 strLine = strLine.Left( nBreak );
01157                                 tSeen = time( NULL ) - nSeconds;
01158                         }
01159                         
01160                         if ( m_nLastQueryProtocol == PROTOCOL_G2 )
01161                                 HostCache.Gnutella2.Add( strLine, tSeen );
01162                         else
01163                                 HostCache.Gnutella1.Add( strLine, tSeen );
01164                         
01165                         m_pWebCache->OnHostAdd();
01166                         bSuccess = TRUE;
01167                         nIPs ++;
01168                 }
01169                 else if ( _tcsnicmp( strLine, _T("u|"), 2 ) == 0 )
01170                 {
01171                         // URL ADDRESS AT: strLine.Mid( 2 )
01172                         // CORRECT (REQUESTED) NETWORK
01173                         Add( strLine.Mid( 2 ).SpanExcluding( _T("|") ), CDiscoveryService::dsWebCache, m_nLastQueryProtocol );
01174                         
01175                         m_bFirstTime = FALSE;
01176                         bSuccess = TRUE;
01177                 }
01178                 else if ( _tcsnicmp( strLine, _T("i|"), 2 ) == 0 )
01179                 {
01180                         // INFORMATIONAL
01181                         
01182                         // Don't count as success if it's only informational
01183                         // bSuccess = TRUE; 
01184                         
01185                         if ( _tcsnicmp( strLine, _T("i|access|period|"), 16 ) == 0 )
01186                         {
01187                                 _stscanf( (LPCTSTR)strLine + 16, _T("%u"), &m_pWebCache->m_nAccessPeriod );
01188                         }
01189                         else if ( strLine == _T("i|force|remove") || _tcsnicmp( strLine, _T("i|update|warning|bad url"), 24 ) == 0 )
01190                         {
01191                                 m_pWebCache->Remove();
01192                                 return FALSE;
01193                         }
01194                         
01195                         if ( _tcsistr( strLine, _T("ERROR: Network not supported") ) != NULL )
01196                         {
01197                                 // ERROR CONDITION
01198                                 if ( m_nLastQueryProtocol == PROTOCOL_G2 )
01199                                 {
01200                                         m_pWebCache->m_bGnutella1 = TRUE;
01201                                         m_pWebCache->m_bGnutella2 = FALSE;
01202                                 }
01203                                 else
01204                                 {
01205                                         m_pWebCache->m_bGnutella1 = FALSE;
01206                                         m_pWebCache->m_bGnutella2 = TRUE;
01207                                 }
01208 
01209                                 return FALSE;
01210                         }
01211                 }
01212                 else if ( _tcsistr( strLine, _T("ERROR: Network not supported") ) != NULL )
01213                 {
01214                         // Wrong network (Whoops!)
01215                         if ( m_nLastQueryProtocol == PROTOCOL_G2 )
01216                         {
01217                                 m_pWebCache->m_bGnutella1 = TRUE;
01218                                 m_pWebCache->m_bGnutella2 = FALSE;
01219                         }
01220                         else
01221                         {
01222                                 m_pWebCache->m_bGnutella1 = FALSE;
01223                                 m_pWebCache->m_bGnutella2 = TRUE;
01224                         }
01225 
01226                         return FALSE;
01227                 }
01228                 else if ( _tcsistr( strLine, _T("ERROR") ) != NULL )
01229                 {
01230                         // Misc error. (Often CGI limits error)
01231                         return FALSE;
01232                 }
01233                 else if ( _stscanf( strLine, _T("%i.%i.%i.%i"), &nIP[0], &nIP[1], &nIP[2], &nIP[3] ) == 4 )
01234                 {
01235                         // Plain IP, NOT G2
01236                         HostCache.Gnutella1.Add( strLine );
01237                         m_pWebCache->OnHostAdd();
01238                         m_pWebCache->m_bGnutella2 = FALSE;
01239                         m_pWebCache->m_bGnutella1 = TRUE;
01240                         bSuccess = TRUE;
01241                 }
01242                 else
01243                 {
01244                         // Plain URL, WRONG NETWORK
01245                         Add( strLine.SpanExcluding( _T(" ") ), CDiscoveryService::dsWebCache, PROTOCOL_G1 );
01246                         m_pWebCache->m_bGnutella2 = FALSE;
01247                         m_pWebCache->m_bGnutella1 = TRUE;
01248                         m_bFirstTime = FALSE;
01249                 }
01250         }
01251         
01252         if ( bSuccess )
01253         {
01254                 m_pWebCache->OnSuccess();
01255                 if ( HostCache.Gnutella2.GetNewest() != NULL && nIPs > 0 ) m_tQueried = time( NULL );
01256                 return TRUE;
01257         }
01258         
01259         return FALSE;
01260 }
01261 
01263 // CDiscoveryServices execute update request
01264 
01265 BOOL CDiscoveryServices::RunWebCacheUpdate()
01266 {
01267         CSingleLock pLock( &Network.m_pSection, TRUE );
01268         CString strURL, strOutput;
01269 
01270         if ( ! Check( m_pWebCache, CDiscoveryService::dsWebCache ) ) return FALSE;
01271         m_pWebCache->OnAccess();
01272         
01273         if ( m_nWebCache == wcmUpdate )
01274         {
01275                 if ( ! Network.IsListening() ) return TRUE;
01276 
01277                 strURL.Format( _T("%s?update=1&ip=%s:%hu&x.leaves=%i"),
01278                         (LPCTSTR)m_pWebCache->m_sAddress,
01279                         (LPCTSTR)CString( inet_ntoa( Network.m_pHost.sin_addr ) ),
01280                         htons( Network.m_pHost.sin_port ),
01281                         Neighbours.GetCount( -1, -1, ntLeaf ) );                //ToDo: Check this
01282         }
01283         
01284         if ( m_pSubmit != NULL && Check( m_pSubmit, CDiscoveryService::dsWebCache ) &&
01285                  m_pWebCache->m_bGnutella2 == m_pSubmit->m_bGnutella2 )
01286         {
01287                 if ( strURL.IsEmpty() )
01288                 {
01289                         strURL.Format( _T("%s?url="), (LPCTSTR)m_pWebCache->m_sAddress );
01290                 }
01291                 else
01292                 {
01293                         strURL += _T("&url=");
01294                 }
01295                 
01296                 CString strSubmit( m_pSubmit->m_sAddress );
01297                 
01298                 for ( int nSubmit = 0 ; nSubmit < strSubmit.GetLength() ; nSubmit ++ )
01299                 {
01300                         if ( (WORD)strSubmit.GetAt( nSubmit ) > 127 )
01301                         {
01302                                 strSubmit = strSubmit.Left( nSubmit );
01303                                 break;
01304                         }
01305                 }
01306                 
01307                 strURL += CConnection::URLEncode( strSubmit );
01308         }
01309         
01310         if ( m_nLastUpdateProtocol == PROTOCOL_G2 ) strURL += _T("&net=gnutella2");
01311         
01312         pLock.Unlock();
01313         
01314         if ( strURL.IsEmpty() ) return FALSE;
01315         
01316         if ( ! SendWebCacheRequest( strURL, strOutput ) ) return FALSE;
01317         
01318         pLock.Lock();
01319         if ( ! Check( m_pWebCache, CDiscoveryService::dsWebCache ) ) return FALSE;
01320         
01321         for ( strOutput += '\n' ; strOutput.GetLength() ; )
01322         {
01323                 CString strLine = strOutput.SpanExcluding( _T("\r\n") );
01324                 strOutput               = strOutput.Mid( strLine.GetLength() + 1 );
01325                 
01326                 strLine.TrimLeft();
01327                 strLine.TrimRight();
01328                 
01329                 if ( strLine.IsEmpty() ) continue;
01330                 
01331                 theApp.Message( MSG_DEBUG, _T("GWebCache(update): %s"), (LPCTSTR)strLine );
01332                 
01333                 if ( _tcsstr( strLine, _T("OK") ) )
01334                 {
01335                         m_pWebCache->m_tUpdated = (DWORD)time( NULL );
01336                         m_pWebCache->m_nUpdates++;
01337                         m_pWebCache->OnSuccess();
01338                         return TRUE;
01339                 }
01340                 else if ( _tcsstr( strLine, _T("ERROR") ) )
01341                 {
01342                         return FALSE;
01343                 }
01344                 else if ( _tcsnicmp( strLine, _T("i|access|period|"), 16 ) == 0 )
01345                 {
01346                         _stscanf( (LPCTSTR)strLine + 16, _T("%u"), &m_pWebCache->m_nAccessPeriod );
01347                 }
01348                 else if ( _tcsnicmp( strLine, _T("i|update|period|"), 16 ) == 0 )
01349                 {
01350                         _stscanf( (LPCTSTR)strLine + 16, _T("%u"), &m_pWebCache->m_nUpdatePeriod );
01351                 }
01352                 else if ( strLine == _T("i|force|remove") )
01353                 {
01354                         m_pWebCache->Remove();
01355                         break;
01356                 }
01357         }
01358         
01359         return FALSE;
01360 }
01361 
01363 // CDiscoveryServices HTTP request controllor
01364 
01365 BOOL CDiscoveryServices::SendWebCacheRequest(CString strURL, CString& strOutput)
01366 {
01367         strOutput.Empty();
01368         
01369         strURL += _T("&client=RAZA&version=");
01370         strURL += theApp.m_sVersion;
01371         
01372         theApp.Message( MSG_DEBUG, _T("DiscoveryService URL: %s"), (LPCTSTR)strURL );
01373         
01374         if ( m_hRequest ) InternetCloseHandle( m_hRequest );
01375         
01376         m_hRequest = InternetOpenUrl( m_hInternet, strURL, _T("Connection: close"), -1,
01377                 INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE|INTERNET_FLAG_NO_COOKIES, 0 );
01378         if ( m_hRequest == NULL ) return FALSE;
01379         
01380         DWORD nStatusCode = 0, nStatusLen = 32;
01381         TCHAR szStatusCode[32];
01382         
01383         if ( ! HttpQueryInfo( m_hRequest, HTTP_QUERY_STATUS_CODE, szStatusCode,
01384                 &nStatusLen, NULL ) ) return FALSE;
01385         
01386         _stscanf( szStatusCode, _T("%u"), &nStatusCode );
01387         if ( nStatusCode < 200 || nStatusCode > 299 ) return FALSE;
01388         
01389         DWORD nRemaining, nResponse = 0;
01390         LPBYTE pResponse = NULL;
01391         
01392         while ( InternetQueryDataAvailable( m_hRequest, &nRemaining, 0, 0 ) && nRemaining > 0 )
01393         {
01394                 pResponse = (LPBYTE)realloc( pResponse, nResponse + nRemaining );
01395                 InternetReadFile( m_hRequest, pResponse + nResponse, nRemaining, &nRemaining );
01396                 nResponse += nRemaining;
01397         }
01398         
01399         if ( nRemaining )
01400         {
01401                 free( pResponse );
01402                 return FALSE;
01403         }
01404         
01405         LPTSTR pszResponse = strOutput.GetBuffer( nResponse );
01406         for ( nStatusCode = 0 ; nStatusCode < nResponse ; nStatusCode++ )
01407                 pszResponse[ nStatusCode ] = (TCHAR)pResponse[ nStatusCode ];
01408         strOutput.ReleaseBuffer( nResponse );
01409         
01410         free( pResponse );
01411         
01412         return TRUE;
01413 }
01414 
01416 // CDiscoveryServices execute server.met request
01417 
01418 BOOL CDiscoveryServices::RunServerMet()
01419 {
01420         CSingleLock pLock( &Network.m_pSection, TRUE );
01421         CString strURL;
01422         
01423         if ( ! Check( m_pWebCache, CDiscoveryService::dsServerMet ) ) return FALSE;
01424         
01425         m_pWebCache->OnAccess();
01426         strURL = m_pWebCache->m_sAddress;
01427         
01428         pLock.Unlock();
01429         
01430         if ( m_hRequest != NULL ) InternetCloseHandle( m_hRequest );
01431         
01432         m_hRequest = InternetOpenUrl( m_hInternet, strURL, NULL, 0,
01433                 INTERNET_FLAG_RELOAD|INTERNET_FLAG_DONT_CACHE, 0 );
01434         
01435         if ( m_hRequest == NULL ) return FALSE;
01436         
01437         DWORD nRemaining = 0;
01438         BYTE pBuffer[1024];
01439         CMemFile pFile;
01440         
01441         while ( InternetQueryDataAvailable( m_hRequest, &nRemaining, 0, 0 ) && nRemaining > 0 )
01442         {
01443                 while ( nRemaining > 0 )
01444                 {
01445                         DWORD nBuffer = min( nRemaining, DWORD(1024) );
01446                         InternetReadFile( m_hRequest, pBuffer, nBuffer, &nBuffer );
01447                         pFile.Write( pBuffer, nBuffer );
01448                         nRemaining -= nBuffer;
01449                 }
01450         }
01451         
01452         pFile.Seek( 0, CFile::begin );
01453         
01454         pLock.Lock();
01455         
01456         if ( ! Check( m_pWebCache, CDiscoveryService::dsServerMet ) ) return FALSE;
01457         
01458         int nCount = HostCache.eDonkey.ImportMET( &pFile );
01459         
01460         if ( ! nCount ) return FALSE;
01461         
01462         HostCache.Save();
01463         m_pWebCache->OnHostAdd( nCount );
01464         m_pWebCache->OnSuccess();
01465         
01466         return TRUE;
01467 }
01468 
01469 
01471 // CDiscoveryService construction
01472 
01473 CDiscoveryService::CDiscoveryService(int nType, LPCTSTR pszAddress)
01474 {
01475         m_nType                 = nType;
01476         m_bGnutella2    = FALSE;
01477         m_bGnutella1    = FALSE;
01478         m_tCreated              = (DWORD)time( NULL );
01479         m_tAccessed             = 0;
01480         m_nAccesses             = 0;
01481         m_tUpdated              = 0;
01482         m_nUpdates              = 0;
01483         m_nFailures             = 0;
01484         m_nHosts                = 0;
01485         m_nAccessPeriod = max( Settings.Discovery.UpdatePeriod, DWORD(1800) );
01486         m_nUpdatePeriod = Settings.Discovery.DefaultUpdate;
01487         
01488         if ( pszAddress != NULL ) m_sAddress = pszAddress;
01489 }
01490 
01491 CDiscoveryService::~CDiscoveryService()
01492 {
01493 }
01494 
01496 // CDiscoveryService remove
01497 
01498 void CDiscoveryService::Remove(BOOL bCheck)
01499 {
01500         DiscoveryServices.Remove( this, bCheck );
01501 }
01502 
01504 // CDiscoveryService serialize
01505 
01506 void CDiscoveryService::Serialize(CArchive& ar, int nVersion)
01507 {
01508 
01509         if ( ar.IsStoring() )
01510         {
01511                 ar << m_nType;
01512                 ar << m_sAddress;
01513                 ar << m_bGnutella2;
01514                 ar << m_bGnutella1;
01515                 ar << m_tCreated;
01516                 ar << m_tAccessed;
01517                 ar << m_nAccesses;
01518                 ar << m_tUpdated;
01519                 ar << m_nUpdates;
01520                 ar << m_nFailures;
01521                 ar << m_nHosts;
01522                 ar << m_nAccessPeriod;
01523                 ar << m_nUpdatePeriod;
01524         }
01525         else
01526         {
01527                 ar >> m_nType;
01528                 ar >> m_sAddress;
01529                 ar >> m_bGnutella2;
01530                 ar >> m_bGnutella1;
01531                 ar >> m_tCreated;
01532                 ar >> m_tAccessed;
01533                 ar >> m_nAccesses;
01534                 ar >> m_tUpdated;
01535                 ar >> m_nUpdates;
01536                 ar >> m_nFailures;
01537                 ar >> m_nHosts;
01538                 ar >> m_nAccessPeriod;
01539                 ar >> m_nUpdatePeriod;
01540         }
01541 }
01542 
01544 // CDiscoveryService execute
01545 
01546 // Note: This is used by wndDiscovery only
01547 BOOL CDiscoveryService::Execute(int nMode)
01548 {
01549         CSingleLock pLock( &Network.m_pSection );
01550         if ( ! pLock.Lock( 250 ) ) return FALSE;
01551         
01552         if ( m_nType == dsGnutella )
01553         {
01554                 return ResolveGnutella();
01555         }
01556         else if ( m_nType == dsWebCache )
01557         {
01558                 return DiscoveryServices.RequestWebCache( this, nMode, m_bGnutella2 ? PROTOCOL_G2 : PROTOCOL_G1 );
01559         }
01560         else if ( m_nType == dsServerMet )
01561         {
01562                 return DiscoveryServices.RequestWebCache( this, CDiscoveryServices::wcmServerMet, PROTOCOL_ED2K );
01563         }
01564         
01565         return FALSE;
01566 }
01567 
01569 // CDiscoveryService resolve a gnutella node
01570 
01571 BOOL CDiscoveryService::ResolveGnutella()
01572 {
01573         CString strHost = m_sAddress;
01574         int nPort               = GNUTELLA_DEFAULT_PORT;
01575         int nPos                = strHost.Find( ':' );
01576         
01577         if ( nPos >= 0 && _stscanf( strHost.Mid( nPos + 1 ), _T("%i"), &nPort ) == 1 )
01578                 strHost = strHost.Left( nPos );
01579         
01580         if ( ! Network.Connect( FALSE ) ) return FALSE;
01581         
01582         if ( Network.AsyncResolve( strHost, (WORD)nPort, PROTOCOL_G1, 0 ) )
01583         {
01584                 OnSuccess();
01585                 return TRUE;
01586         }
01587         
01588         OnFailure();
01589         
01590         return FALSE;
01591 }
01592 
01594 // CDiscoveryService events
01595 
01596 void CDiscoveryService::OnAccess()
01597 {
01598         m_tAccessed = (DWORD)time( NULL );
01599         m_nAccesses ++;
01600 }
01601 
01602 void CDiscoveryService::OnHostAdd(int nCount)
01603 {
01604         m_nHosts += nCount;
01605         m_nFailures = 0;
01606 }
01607 
01608 void CDiscoveryService::OnSuccess()
01609 {
01610         m_nFailures = 0;
01611 
01612         if ( m_nType == dsWebCache || m_nType == dsServerMet )
01613         {
01614                 theApp.Message( MSG_DEFAULT, IDS_DISCOVERY_WEB_SUCCESS,
01615                         (LPCTSTR)m_sAddress );
01616         }
01617 }
01618 
01619 void CDiscoveryService::OnFailure()
01620 {
01621         m_nFailures++;
01622         
01623         theApp.Message( MSG_ERROR, IDS_DISCOVERY_FAILED,
01624                 (LPCTSTR)m_sAddress, m_nFailures );
01625         
01626         if ( m_nFailures >= Settings.Discovery.FailureLimit )
01627         {
01628                 theApp.Message( MSG_ERROR, IDS_DISCOVERY_FAIL_REMOVE,
01629                         (LPCTSTR)m_sAddress, m_nFailures );
01630                 Remove();
01631         }
01632 }
01633 

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