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

NeighboursWithConnect.cpp

Go to the documentation of this file.
00001 //
00002 // NeighboursWithConnect.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Network.h"
00026 #include "Datagrams.h"
00027 #include "Security.h"
00028 #include "HostCache.h"
00029 #include "Downloads.h"
00030 #include "DiscoveryServices.h"
00031 #include "NeighboursWithConnect.h"
00032 #include "ShakeNeighbour.h"
00033 #include "EDNeighbour.h"
00034 #include "Neighbours.h"
00035 
00036 #ifdef _DEBUG
00037 #undef THIS_FILE
00038 static char THIS_FILE[]=__FILE__;
00039 #define new DEBUG_NEW
00040 #endif
00041 
00042 
00044 // CNeighboursWithConnect construction
00045 
00046 CNeighboursWithConnect::CNeighboursWithConnect()
00047 {
00048         ZeroMemory( m_tPresent, sizeof(m_tPresent) );
00049 
00050         m_bG2Leaf                       = FALSE;
00051         m_bG2Hub                        = FALSE;
00052         m_bG1Leaf                       = FALSE;
00053         m_bG1Ultrapeer          = FALSE;
00054 
00055         m_tHubG2Promotion       = 0;
00056 }
00057 
00058 CNeighboursWithConnect::~CNeighboursWithConnect()
00059 {
00060 }
00061 
00063 // CNeighboursWithConnect connection initiation
00064 
00065 CNeighbour* CNeighboursWithConnect::ConnectTo(IN_ADDR* pAddress, WORD nPort, PROTOCOLID nProtocol, BOOL bAutomatic, BOOL bNoUltraPeer)
00066 {
00067         CSingleLock pLock( &Network.m_pSection, TRUE );
00068         
00069         if ( Get( pAddress ) )
00070         {
00071                 if ( bAutomatic ) return NULL;
00072                 theApp.Message( MSG_ERROR, IDS_CONNECTION_ALREADY_ABORT,
00073                         (LPCTSTR)CString( inet_ntoa( *pAddress ) ) );
00074                 return NULL;
00075         }
00076         
00077         // Don't connect to blocked addresses
00078         if ( Security.IsDenied( pAddress ) )
00079         {
00080                 if ( bAutomatic ) return NULL;
00081                 theApp.Message( MSG_ERROR, IDS_NETWORK_SECURITY_OUTGOING,
00082                         (LPCTSTR)CString( inet_ntoa( *pAddress ) ) );
00083                 return NULL;
00084         }
00085         
00086         if ( bAutomatic && Network.IsFirewalledAddress( &pAddress, TRUE ) ) return NULL;
00087         
00088         if ( ! Network.Connect() ) return NULL;
00089         
00090         if ( ! bAutomatic )
00091         {       // Activate appropriate network (if required)
00092                 switch ( nProtocol )
00093                 {
00094                 case PROTOCOL_G1:
00095                         Settings.Gnutella1.EnableToday = TRUE;
00096                         break;
00097                 case PROTOCOL_G2:
00098                         Settings.Gnutella2.EnableToday = TRUE;
00099                         break;
00100                 case PROTOCOL_ED2K:
00101                         Settings.eDonkey.EnableToday = TRUE;
00102                         CloseDonkeys();
00103                         break;
00104                 }
00105         }
00106         
00107         if ( nProtocol == PROTOCOL_ED2K )
00108         {
00109                 CEDNeighbour* pNeighbour = new CEDNeighbour();
00110                 if ( pNeighbour->ConnectTo( pAddress, nPort, bAutomatic ) ) 
00111                 {
00112                         // Started connecting to an ed2k neighbour
00113                         return pNeighbour;
00114                 }
00115                 delete pNeighbour;
00116         }
00117         else
00118         {
00119                 CShakeNeighbour* pNeighbour = new CShakeNeighbour();
00120                 if ( pNeighbour->ConnectTo( pAddress, nPort, bAutomatic, bNoUltraPeer ) ) 
00121                 {
00122                         // Started connecting to a G1/G2 neighbour
00123 
00124                         // If we only want G1 connections now, specify that to begin with.
00125                         if ( ( Settings.Gnutella.SpecifyProtocol ) && ( nProtocol == PROTOCOL_G1 ) && ( ! Neighbours.NeedMoreHubs( PROTOCOL_G2 ) ) )
00126                                 pNeighbour->m_nProtocol = PROTOCOL_G1;
00127                         return pNeighbour;
00128                 }
00129                 delete pNeighbour;
00130         }
00131         
00132         // Wasn't able to connect
00133         return NULL;
00134 }
00135 
00137 // CNeighboursWithConnect accept a connection
00138 
00139 CNeighbour* CNeighboursWithConnect::OnAccept(CConnection* pConnection)
00140 {
00141         CSingleLock pLock( &Network.m_pSection );
00142         if ( ! pLock.Lock( 250 ) ) return NULL;
00143         
00144         CShakeNeighbour* pNeighbour = new CShakeNeighbour();
00145         pNeighbour->AttachTo( pConnection );
00146         
00147         return pNeighbour;
00148 }
00149 
00151 // CNeighboursWithConnect
00152 
00153 void CNeighboursWithConnect::PeerPrune(PROTOCOLID nProtocol)
00154 {       // This function trims PEERS after you get a HUB. (eg: You have been demoted to a leaf for this protocol)
00155         BOOL bNeedMore = NeedMoreHubs( nProtocol );
00156         BOOL bNeedMoreAnyProtocol = NeedMoreHubs( PROTOCOL_NULL );
00157 
00158         for ( POSITION pos = GetIterator() ; pos ; )                            // Loop through all neighbours
00159         {       
00160                 CNeighbour* pNeighbour = GetNext( pos );
00161                 if ( pNeighbour->m_nProtocol == nProtocol )                             // If we're pruning this protocol
00162                 {       
00163                         if ( pNeighbour->m_nNodeType != ntHub )                         // And it's not a hub
00164                         {       
00165                                 if ( ! bNeedMore || pNeighbour->m_nState == nrsConnected )      // And either we don't need any more hubs, OR it's finished connecting (so we know it won't be a hub)
00166                                         pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );          // Then drop it
00167                         }
00168                 }
00169                 else if ( pNeighbour->m_nProtocol == PROTOCOL_NULL )    // Else if this neighbour doesn't have a protocol
00170                 {       // If a neighbour protocol is unknown, it must be a G1 or G2 client in the 
00171                         // middle of connecting. (It hasn't finished the handshake yet.)
00172                         if ( pNeighbour->m_bInitiated ) // If we initiated the connection
00173                         {       // If it's a connection we initiated, we know it's not a leaf trying to contact us
00174                                 // Therefore, it is probably a hub connection attempt.
00175                                 if ( ! bNeedMoreAnyProtocol )   // If we don't need more hubs (on any protocol)
00176                                         pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );          // Then drop it
00177                         }
00178                 }
00179         }
00180 }
00181 
00183 // CNeighboursWithConnect hub states
00184 /*
00185 BOOL CNeighboursWithConnect::IsLeaf(PROTOCOLID nProtocol)
00186 {
00187         ASSERT ( nProtocol==PROTOCOL_G1 ||  nProtocol==PROTOCOL_G2 );
00188         return Network.m_bEnabled && GetCount( nProtocol, nrsConnected, ntHub ) > 0;
00189 }
00190 
00191 BOOL CNeighboursWithConnect::IsHub(PROTOCOLID nProtocol)
00192 {
00193         ASSERT ( nProtocol==PROTOCOL_G1 ||  nProtocol==PROTOCOL_G2 );
00194         return Network.m_bEnabled && GetCount( nProtocol, nrsConnected, ntLeaf ) > 0;
00195 }
00196 */
00197 
00198 
00199 BOOL CNeighboursWithConnect::IsG2Leaf()
00200 {
00201         //return Network.m_bEnabled && GetCount( PROTOCOL_G2, nrsConnected, ntHub ) > 0;
00202         return ( Network.m_bEnabled && m_bG2Leaf );
00203 }
00204 
00205 BOOL CNeighboursWithConnect::IsG2Hub()
00206 {
00207         //return Network.m_bEnabled && GetCount( PROTOCOL_G2, nrsConnected, ntLeaf ) > 0;
00208         return ( Network.m_bEnabled && m_bG2Hub );
00209 }
00210 
00211 DWORD CNeighboursWithConnect::IsG2HubCapable(BOOL bDebug)
00212 {       // Determine if this client can be a G2 hub
00213         
00214         DWORD nRating = 0; // Zero means this node can not be a hub.
00215         // Higher numbers indicate it is likely to be a better hub.
00216 
00217         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("IsHubCapable():") );
00218 
00219         // Can't be a G2 hub if you don't connect to G2
00220         if ( ! Settings.Gnutella2.EnableToday )
00221         {       
00222                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: G2 not enabled") );
00223                 return FALSE;
00224         }
00225         //
00226         
00227         // Win95, Win98 and WinMe cannot support enough connections to make a good hub
00228         if ( ! theApp.m_bNT )
00229         {       
00230                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: OS is not NT based") );
00231                 return FALSE;
00232         }
00233         else
00234         {
00235                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: OS is NT based") );
00236         }
00237         //
00238         
00239         // User can disable hub mode G2 settings
00240         if ( Settings.Gnutella2.ClientMode == MODE_LEAF )
00241         {       
00242                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: hub mode disabled") );
00243                 return FALSE;
00244         }
00245         
00246         // Check if we are a leaf
00247         if ( IsG2Leaf() )
00248         {
00249                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: leaf") );
00250                 return FALSE;
00251         }
00252         else
00253         {
00254                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: not a leaf") );
00255         }
00256         //
00257 
00258         // Check the G2 hub settings
00259         if ( Settings.Gnutella2.NumPeers < 4 )
00260         {
00261                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 4x G2 hub to hub") );
00262                 return FALSE;
00263         }
00264         if ( Settings.Gnutella2.NumLeafs < 50 )
00265         {
00266                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 50x G2 hub to leaf") );
00267                 return FALSE;
00268         }
00269         //
00270         
00271         // Check if hub mode is forced in the G2 settings.
00272         if ( Settings.Gnutella2.ClientMode == MODE_HUB )
00273         {       
00274                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("YES: hub mode forced") );
00275         }
00276         else
00277         {
00278                 // Additional checks (if user has *not* forced hub mode)
00279 
00280                 // Check amount of memory installed in the machine
00281                 if ( theApp.m_nPhysicalMemory < 250*1024*1024 )
00282                 {       
00283                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 250 MB RAM") );
00284                         return FALSE;
00285                 }
00286                 else
00287                 {
00288                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: more than 250 MB RAM") );
00289                 }
00290                 //
00291                 
00292                 // Check the connection
00293                 if ( Settings.Connection.InSpeed < 200 )        // Check inbound speed
00294                 {
00295                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 200 Kb/s in") );
00296                         return FALSE;
00297                 }       
00298                 if ( Settings.Connection.OutSpeed < 200 )       // Check outbound speed
00299                 {
00300                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 200 Kb/s out") );
00301                         return FALSE;
00302                 }
00303                 /* //Might create problems with scheduler/slider. Check that before enabling
00304                 if ( ( Settings.Bandwidth.Uploads <= 4096 ) && ( Settings.Bandwidth.Uploads != 0 ) ) //Check limit
00305                 {
00306                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: Upload limit set too low") );
00307                         return FALSE;
00308                 }*/
00309                 //
00310 
00311                 // Confirm how long the node has been running.
00312                 if ( Settings.Gnutella2.HubVerified )
00313                 {
00314                         // Systems that have been good hubs before can promote in 2 hours
00315                         if ( Network.GetStableTime() < 7200 )
00316                         {
00317                                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: not stable for 2 hours") );
00318                                 return FALSE;
00319                         }
00320                         else
00321                         {
00322                                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: stable for 2 hours") );
00323                         }
00324                 }
00325                 else
00326                 {
00327                         // Untested hubs need 3 hours uptime to be considered
00328                         if ( Network.GetStableTime() < 10800 )
00329                         {
00330                                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: not stable for 3 hours") );
00331                                 return FALSE;
00332                         }
00333                         else
00334                         {
00335                                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: stable for 3 hours") );
00336                         }
00337                 }
00338 
00339                 if ( ! Datagrams.IsStable() )
00340                 {
00341                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: datagram not stable") );
00342                         return FALSE;
00343                 }
00344                 else
00345                 {
00346                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: datagram stable") );
00347                 }
00348                 //
00349 
00350                 // Check the scheduler
00351                 if ( Settings.Scheduler.Enable && ! Settings.Scheduler.AllowHub )
00352                 {       
00353                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: scheduler active") );
00354                         return FALSE;
00355                 }
00356                 else
00357                 {       
00358                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: scheduler OK") );
00359                 }
00360                 //
00361                 
00362                 // This node meets the minimum requirements to be a hub.
00363                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("YES: hub capable by test") );
00364         }
00365         nRating = 1;
00366 
00367         // Now, evaluate how good a hub it's likely to be
00368         // The higher the rating, the better the hub.
00369 
00370         // Check amount of memory installed in the machine
00371         if ( theApp.m_nPhysicalMemory > 600*1024*1024 )
00372         {
00373                 nRating++;      // More than half a gig of RAM is good
00374                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("More than 600 MB RAM") );
00375         }
00376         //
00377 
00378         // Check connection type
00379         if ( Settings.Connection.InSpeed > 1000 )
00380         {
00381                 nRating++;      // More than 1Mb inbound
00382                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("More than 1 Mb/s in") );
00383         }
00384         if ( Settings.Connection.OutSpeed > 1000 )
00385         {
00386                 nRating++;      // More than 1Mb outbound
00387                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("More than 1 Mb/s out") );
00388         }
00389         //
00390 
00391         // Check how many other networks are connected
00392         if ( ! Settings.eDonkey.EnableToday )
00393         {
00394                 nRating++;      // Not running ed2k improves hub performance
00395                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("eDonkey not enabled") );
00396         }
00397         if ( ! Settings.BitTorrent.AdvancedInterfaceSet )
00398         {
00399                 nRating++;      // This user hasn't ever used BitTorrent, so probably won't be using bandwidth for that
00400                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("BT is not in use") );
00401         }
00402         if ( ! Settings.Gnutella1.EnableToday )
00403         {
00404                 nRating++;      // No G1 means more resources for a hub
00405                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("G1 not enabled") );
00406         }
00407         //
00408 
00409         // Check how long the node has been up
00410         if ( Network.GetStableTime() > 28800 )
00411         {
00412                 nRating++;      // 8 hours uptime is pretty good.
00413                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("Stable for 8 hours") );
00414         }
00415         //
00416 
00417         // Check scheduler.
00418         if ( ! Settings.Scheduler.Enable )
00419         {
00420                 // ToDo : If this node is scheduled to shut down at any time, it's not going to be a great
00421                 // choice for a hub. If it's going down in the next few hours, don't be a hub at all.
00422                 nRating++;
00423         }
00424         //
00425 
00426         // Check CPU.
00427                 // ToDo: Add a CPU check. Faster CPU is better
00428         
00429         // Check if behind a router.
00430                 // ToDo: Add a behind router check. (Some routers have problems with the traffic caused)
00431 
00432         // Check how much is shared and upload/download usage.
00433                 // ToDo : Clients not uploading much make better hubs.
00434 
00435         // If debug mode is enabled, display the Hub rating in the log/system window
00436         if ( bDebug )
00437         {
00438                 CString strRating;
00439                 strRating.Format( _T("Hub rating: %d"), nRating );
00440                 theApp.Message( MSG_DEBUG, strRating );
00441         }
00442         //
00443 
00444         return nRating;
00445 }
00446 
00447 BOOL CNeighboursWithConnect::IsG1Leaf()
00448 {
00449         //return Network.m_bEnabled && GetCount( PROTOCOL_G1, nrsConnected, ntHub ) > 0;
00450         return ( Network.m_bEnabled && m_bG1Leaf );
00451 }
00452 
00453 BOOL CNeighboursWithConnect::IsG1Ultrapeer()
00454 {
00455         //return Network.m_bEnabled && GetCount( PROTOCOL_G1, nrsConnected, ntLeaf ) > 0;
00456         return ( Network.m_bEnabled && m_bG1Ultrapeer );
00457 }
00458 
00459 DWORD CNeighboursWithConnect::IsG1UltrapeerCapable(BOOL bDebug) 
00460 {       //Check if this node can be a G1 Ultrapeer
00461 
00462         DWORD nRating = 0; //Zero means this node can not be an ultrapeer.
00463         //Higher numbers indicate it is likely to be a better ultrapeer.
00464 
00465         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("IsUltrapeerCapable():") );
00466 
00467         // Can't be an ultrapeer if you don't connect to Gnutella1
00468         if ( ! Settings.Gnutella1.EnableToday )
00469         {       
00470                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: Gnutella1 not enabled") );
00471                 return FALSE;
00472         }
00473         //
00474         
00475         //Win95, Win98 and WinMe cannot support enough connections to make a good ultrapeer
00476         if ( ! theApp.m_bNT )
00477         {       
00478                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: OS is not NT based") );
00479                 return FALSE;
00480         }
00481         else
00482         {
00483                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: OS is NT based") );
00484         }
00485         //
00486         
00487         //Check if has disabled ultrapeer mode in gnutella settings
00488         if ( Settings.Gnutella1.ClientMode == MODE_LEAF )
00489         {       
00490                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: ultrapeer mode disabled") );
00491                 return FALSE;
00492         }
00493         //
00494 
00495         //Check if node is a leaf
00496         if ( IsG1Leaf() )
00497         {
00498                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: leaf") );
00499                 return FALSE;
00500         }
00501         else
00502         {
00503                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: not a leaf") );
00504         }
00505         //
00506         
00507         // Check if this node has ultrapeer mode forced in the gnutella settings.
00508         if ( Settings.Gnutella1.ClientMode == MODE_ULTRAPEER )
00509         {
00510                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("YES: ultrapeer mode forced") );
00511         }
00512         else
00513         {
00514                 // Additional checks (if user has *not* forced ultrapeer mode)
00515 
00516                 // Check if node is already a G2 hub
00517                 //      ToDo: Check what sort of machine can handle being both a HUB and UP
00518                 if ( IsG2Hub() )
00519                 {
00520                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: Acting as a G2 hub") );
00521                         return FALSE;
00522                 }
00523                 else
00524                 {
00525                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: not a G2 hub") );
00526                 }
00527                 //
00528 
00529                 // Check amount of memory installed in the machine
00530                 if ( theApp.m_nPhysicalMemory < 250*1024*1024 )
00531                 {       
00532                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 250 MB RAM") );
00533                         return FALSE;
00534                 }
00535                 else
00536                 {
00537                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: more than 250 MB RAM") );
00538                 }
00539                 //
00540                 
00541                 // Check the connection
00542                 if ( Settings.Connection.InSpeed < 200 )        // Check inbound speed
00543                 {
00544                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 200 Kb/s in") );
00545                         return FALSE;
00546                 }
00547                 if ( Settings.Connection.OutSpeed < 200 )       // Check outbound speed
00548                 {
00549                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 200 Kb/s out") );
00550                         return FALSE;
00551                 }
00552                 if ( ( Settings.Bandwidth.Uploads <= 4096 ) && ( Settings.Bandwidth.Uploads != 0 ) ) // Check limit
00553                 {
00554                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: Upload limit set too low") );
00555                         return FALSE;
00556                 }
00557                 //
00558                 
00559                 // Check the various UP settings. (They should always be higher than this anyway)
00560                 if ( Settings.Gnutella1.NumPeers < 4 )
00561                 {
00562                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 4x G1 peer to peer") );
00563                         return FALSE;
00564                 }
00565                 if ( Settings.Gnutella1.NumLeafs < 5 )
00566                 {
00567                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: less than 5x G1 ultrapeer to leaf") );
00568                         return FALSE;
00569                 }
00570                 //
00571                 
00572                 // Confirm how long the node has been running. (Takes a while for UPs to get leafs- stability is important)
00573                 if ( Network.GetStableTime() < 14400 )
00574                 {
00575                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: not stable for 4 hours") );
00576                         return FALSE;
00577                 }
00578                 else
00579                 {
00580                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: stable for 4 hours") );
00581                 }
00582                 if ( ! Datagrams.IsStable() )
00583                 {
00584                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: datagram not stable") );
00585                         return FALSE;
00586                 }
00587                 else
00588                 {
00589                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: datagram stable") );
00590                 }
00591                 //
00592 
00593                 // Check scheduler
00594                 if ( Settings.Scheduler.Enable && ! Settings.Scheduler.AllowHub )
00595                 {       
00596                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("NO: scheduler active") );
00597                         return FALSE;
00598                 }
00599                 else
00600                 {       
00601                         if ( bDebug ) theApp.Message( MSG_DEBUG, _T("OK: scheduler OK") );
00602                 }
00603                 //
00604                         
00605                 // This node meets the minimum requirements to be an ultrapeer.
00606                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("YES: ultrapeer capable by test") );
00607         }
00608         nRating = 1;
00609 
00610         // Now, evaluate how good an ultrapeer it's likely to be
00611         // The higher the rating, the better the UP.
00612 
00613         // Check amount of memory installed in the machine
00614         if ( theApp.m_nPhysicalMemory > 600*1024*1024 )
00615         {
00616                 nRating++;      // More than half a gig of RAM is good
00617                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("More than 600 MB RAM") );
00618         }
00619         //
00620 
00621         // Check connection type
00622         if ( Settings.Connection.InSpeed > 1000 )
00623         {
00624                 nRating++;      // More than 1Mb inbound
00625                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("More than 1 Mb/s in") );
00626         }
00627         if ( Settings.Connection.OutSpeed > 1000 )
00628         {
00629                 nRating++;      // More than 1Mb outbound
00630                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("More than 1 Mb/s out") );
00631         }
00632         //
00633 
00634         // Check how many other networks are connected
00635         if ( ! Settings.eDonkey.EnableToday )
00636         {
00637                 nRating++;      // Not running ed2k improves ultrapeer performance
00638                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("eDonkey not enabled") );
00639         }
00640         if ( ! Settings.BitTorrent.AdvancedInterface )
00641         {
00642                 nRating++;      // This user hasn't ever used BitTorrent, so probably won't be using bandwidth for that
00643                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("BT is not in use") );
00644         }
00645         if ( ! Settings.Gnutella2.EnableToday )
00646         {
00647                 nRating++;      // No G2 means more resources for an ultrapeer
00648                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("G2 not enabled") );
00649         }
00650         //
00651 
00652         // Check how long the node has been up
00653         if ( Network.GetStableTime() > 28800 )
00654         {
00655                 nRating++;      // 8 hours uptime is pretty good.
00656                 if ( bDebug ) theApp.Message( MSG_DEBUG, _T("Stable for 8 hours") );
00657         }
00658         //
00659 
00660         // Check scheduler.
00661         if ( ! Settings.Scheduler.Enable )
00662         {
00663                 // ToDo : If this node is scheduled to shut down at any time, it's not going to be a great
00664                 // choice for an ultrapeer. If it's going down in the next few hours, don't be an UP at all.
00665                 nRating++;
00666         }
00667         //
00668 
00669         // Check CPU.
00670                 // ToDo: Add a CPU check. Faster CPU is better
00671         
00672         // Check if behind a router.
00673                 // ToDo: Add a behind router check. (Some routers have problems with the traffic caused)
00674                 // Note: This check *may* only be necessary for G2, due to the UDP traffic. Check that.
00675 
00676         // Check how much is shared and upload/download usage.
00677                 // ToDo : Clients not uploading much make better ultrapeers.
00678 
00679         // If debug mode is enabled, display the Ultrapeer rating in the log/system window
00680         if ( bDebug )
00681         {
00682                 CString strRating;
00683                 strRating.Format( _T("Ultrapeer rating: %d"), nRating );
00684                 theApp.Message( MSG_DEBUG, strRating );
00685         }
00686         //
00687 
00688         return nRating;
00689 }
00690 
00691 
00693 // CNeighboursWithConnect connection capacity
00694 
00695 BOOL CNeighboursWithConnect::NeedMoreHubs(PROTOCOLID nProtocol)
00696 {       // Check if the specified protocol need more hubs (Hubs, Ultrapeers, Peers)
00697         if ( ! Network.IsConnected() ) return FALSE;
00698         
00699         int nConnected[4] = { 0, 0, 0, 0 };
00700         
00701         // Count number of hubs (hub/up/peer)
00702         for ( POSITION pos = GetIterator() ; pos ; )
00703         {
00704                 CNeighbour* pNeighbour = GetNext( pos );
00705 
00706                 if ( pNeighbour->m_nState == nrsConnected && pNeighbour->m_nNodeType != ntLeaf )
00707                 {
00708                         nConnected[ pNeighbour->m_nProtocol ] ++;
00709                 }
00710         }
00711         
00712         switch ( nProtocol )
00713         {
00714         case PROTOCOL_NULL:     // Do we need more hubs/UPs on either protocol?
00715                 return ( ( Settings.Gnutella1.EnableToday ) && ( ( nConnected[1] ) < ( IsG1Leaf() ? Settings.Gnutella1.NumHubs : Settings.Gnutella1.NumPeers ) ) ||
00716                                  ( Settings.Gnutella2.EnableToday ) && ( ( nConnected[2] ) < ( IsG2Leaf() ? Settings.Gnutella2.NumHubs : Settings.Gnutella2.NumPeers ) ) );
00717         case PROTOCOL_G1:       // Do we need more Gnutella 1 Ultrapeers?
00718                 if ( Settings.Gnutella1.EnableToday == FALSE ) return FALSE;
00719                 return ( nConnected[1] ) < ( IsG1Leaf() ? Settings.Gnutella1.NumHubs : Settings.Gnutella1.NumPeers );
00720         case PROTOCOL_G2:       // Do we need more Gnutella 2 Hubs?
00721                 if ( Settings.Gnutella2.EnableToday == FALSE ) return FALSE;
00722                 return ( nConnected[2] ) < ( IsG2Leaf() ? Settings.Gnutella2.NumHubs : Settings.Gnutella2.NumPeers );
00723         default:
00724                 return FALSE;
00725         }
00726 }
00727 
00728 BOOL CNeighboursWithConnect::NeedMoreLeafs(PROTOCOLID nProtocol)
00729 {       // Check if the specified protocol need more leafs
00730         if ( ! Network.IsConnected() ) return FALSE;
00731         
00732         int nConnected[4] = { 0, 0, 0, 0 };
00733         
00734         // Count number of leafs
00735         for ( POSITION pos = GetIterator() ; pos ; )
00736         {
00737                 CNeighbour* pNeighbour = GetNext( pos );
00738                 
00739                 if ( pNeighbour->m_nState == nrsConnected && pNeighbour->m_nNodeType == ntLeaf )
00740                 {
00741                         nConnected[ pNeighbour->m_nProtocol ] ++;
00742                 }
00743         }
00744         
00745         switch ( nProtocol )
00746         {
00747         case PROTOCOL_NULL:     // Do we need more Leafs of either sort?
00748                 return ( ( ( Settings.Gnutella1.EnableToday ) && ( ( nConnected[1] ) < Settings.Gnutella1.NumLeafs ) ) ||
00749                                  ( ( Settings.Gnutella2.EnableToday ) && ( ( nConnected[2] ) < Settings.Gnutella2.NumLeafs ) ) );
00750         case PROTOCOL_G1:       // Do we need more Gnutella 1 Leafs?
00751                 if ( Settings.Gnutella1.EnableToday == FALSE ) return FALSE;
00752                 return ( nConnected[1] ) < Settings.Gnutella1.NumLeafs;
00753         case PROTOCOL_G2:       // Do we need more Gnutella 2 Leafs?
00754                 if ( Settings.Gnutella2.EnableToday == FALSE ) return FALSE;
00755                 return ( nConnected[2] ) < Settings.Gnutella2.NumLeafs;
00756         default:
00757                 return FALSE;
00758         }
00759 }
00760 
00761 BOOL CNeighboursWithConnect::IsHubLoaded(PROTOCOLID nProtocol)
00762 {       // Is this hub 'loaded'. (At least 75% capacity)
00763         int nConnected[4] = { 0, 0, 0, 0 };
00764         
00765         // Count number of leafs
00766         for ( POSITION pos = GetIterator() ; pos ; )
00767         {
00768                 CNeighbour* pNeighbour = GetNext( pos );
00769                 
00770                 if ( pNeighbour->m_nState == nrsConnected && pNeighbour->m_nNodeType == ntLeaf )
00771                 {
00772                         nConnected[ pNeighbour->m_nProtocol ] ++;
00773                 }
00774         }
00775         
00776         switch ( nProtocol )
00777         {
00778         case PROTOCOL_NULL:     // Are we at 75% of G1 and G2 combined?
00779                 return ( nConnected[1] + nConnected[2] ) >= ( Settings.Gnutella1.NumLeafs + Settings.Gnutella2.NumLeafs ) * 3 / 4;
00780         case PROTOCOL_G1:       // Do we have 75% of G1 capacity?
00781                 if ( Settings.Gnutella1.EnableToday == FALSE ) return FALSE;
00782                 return ( nConnected[1] ) > Settings.Gnutella1.NumLeafs * 3 / 4;
00783         case PROTOCOL_G2:       // Do we have 75% of G2 capacity?
00784                 if ( Settings.Gnutella2.EnableToday == FALSE ) return FALSE;
00785                 return ( nConnected[2] ) > Settings.Gnutella2.NumLeafs * 3 / 4;
00786         default:
00787                 return FALSE;
00788         }
00789 }
00790 
00792 // CNeighboursWithConnect run event
00793 
00794 void CNeighboursWithConnect::OnRun()
00795 {
00796         CNeighboursWithRouting::OnRun();
00797 
00798         if ( Network.m_pSection.Lock( 50 ) )
00799         {
00800                 if ( Network.m_bEnabled && Network.m_bAutoConnect )
00801                 {
00802                         Maintain();
00803                 }
00804                 
00805                 Network.m_pSection.Unlock();
00806         }
00807 }
00808 
00810 // CNeighboursWithConnect maintain connection
00811 
00812 void CNeighboursWithConnect::Maintain()
00813 {
00814         int nCount[4][3], nLimit[4][3];
00815         DWORD tTimer = GetTickCount();
00816         DWORD tNow = time( NULL );
00817         
00818         // Check connection throttle
00819         if ( Settings.Connection.ConnectThrottle != 0 )
00820         {
00821                 if ( tTimer < Network.m_tLastConnect ) return;
00822                 if ( tTimer - Network.m_tLastConnect < Settings.Connection.ConnectThrottle ) return;
00823         }
00824         
00825         // Initialise counters
00826         ZeroMemory( nCount, sizeof(int) * 4 * 3 );
00827         ZeroMemory( nLimit, sizeof(int) * 4 * 3 );
00828         
00829         // Determine our node status
00830         m_bG2Leaf               = FALSE;
00831         m_bG2Hub                = FALSE;
00832         m_bG1Leaf               = FALSE;
00833         m_bG1Ultrapeer  = FALSE;
00834         for ( POSITION pos = GetIterator() ; pos ; )
00835         {
00836                 CNeighbour* pNeighbour = GetNext( pos );
00837                 
00838                 if ( pNeighbour->m_nState == nrsConnected )     // If this neighbour is connected
00839                 {
00840                         if ( pNeighbour->m_nProtocol == PROTOCOL_G2 )
00841                         {
00842                                 if ( pNeighbour->m_nNodeType == ntHub ) 
00843                                         m_bG2Leaf = TRUE;
00844                                 else if ( pNeighbour->m_nNodeType == ntLeaf ) 
00845                                         m_bG2Hub = TRUE;
00846                         }
00847                         else if ( pNeighbour->m_nProtocol == PROTOCOL_G1 )
00848                         {
00849                                 if ( pNeighbour->m_nNodeType == ntHub ) 
00850                                         m_bG1Leaf = TRUE;
00851                                 else if ( pNeighbour->m_nNodeType == ntLeaf ) 
00852                                         m_bG1Ultrapeer = TRUE;
00853                         }
00854                 }
00855         }
00856 
00857         // Count and prune neighbours
00858         for ( POSITION pos = GetIterator() ; pos ; )
00859         {
00860                 CNeighbour* pNeighbour = GetNext( pos );
00861                 
00862                 if ( pNeighbour->m_nState == nrsConnected )     // If this neighbour is connected
00863                 {
00864                         if ( pNeighbour->m_nNodeType != ntHub && m_bG2Leaf && pNeighbour->m_nProtocol == PROTOCOL_G2 )
00865                         {       // If it's not a hub and we are a G2 leaf
00866                                 pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );  // Close the connection
00867                         }
00868                         else if ( pNeighbour->m_nNodeType != ntHub && m_bG1Leaf && pNeighbour->m_nProtocol == PROTOCOL_G1 )
00869                         {       // If it's not an ultrapeer and we are a G1 leaf
00870                                 pNeighbour->Close( IDS_CONNECTION_PEERPRUNE );  // Close the connection
00871                         }
00872                         else if ( pNeighbour->m_nNodeType != ntLeaf )   // If it's a peer/hub/UP
00873                         {       
00874                                 if ( tNow - pNeighbour->m_tConnected > 8000 )
00875                                 {
00876                                         nCount[ pNeighbour->m_nProtocol ][ ntHub ] ++;  // Count hubs
00877                                 }
00878                         }
00879                         else
00880                         {
00881                                 nCount[ pNeighbour->m_nProtocol ][ ntLeaf ] ++; // Count leafs
00882                         }
00883                 }
00884                 else if ( pNeighbour->m_nState < nrsConnected )         // If it's still conecting, we aren't sure of the protocol
00885                 {
00886                         nCount[ pNeighbour->m_nProtocol ][ 0 ] ++;
00887                 }
00888         }
00889 
00890         // Set our "promoted to hub" timer
00891         if ( m_bG2Hub == FALSE )
00892                 m_tHubG2Promotion = 0;                  // If we're not a hub, time promoted is 0
00893         else if ( m_tHubG2Promotion == 0 ) 
00894                 m_tHubG2Promotion = tNow;               // If we've just been promoted, set the timer
00895 
00896         // Check if we have verified if we make a good G2 hub
00897         if ( ( Settings.Gnutella2.HubVerified == FALSE ) && ( m_tHubG2Promotion > 0 ) && ( Network.m_bEnabled ) )
00898         {
00899                 // If we have been a hub for at least 8 hours
00900                 if ( ( tNow - m_tHubG2Promotion ) > ( 8 * 60 * 60 ) )
00901                 {
00902                         // And we're loaded ( 75% capacity )
00903                         if ( ( nCount[ PROTOCOL_G2 ][ ntHub ] ) > ( Settings.Gnutella2.NumLeafs * 3 / 4 ) )
00904                         {
00905                                 // Then we probably make a pretty good hub
00906                                 Settings.Gnutella2.HubVerified = TRUE;
00907                         }
00908                 }
00909         }
00910         
00911         // Set numbers of neighbours (G1)
00912         if ( Settings.Gnutella1.EnableToday == FALSE )
00913         {
00914                 nLimit[ PROTOCOL_G1 ][ ntHub ] = nLimit[ PROTOCOL_G1 ][ ntLeaf ] = 0;
00915         }
00916         else if ( m_bG1Leaf )
00917         {
00918                 nLimit[ PROTOCOL_G1 ][ ntHub ]  = min( Settings.Gnutella1.NumHubs, 2 );
00919         }
00920         else
00921         {
00922                 nLimit[ PROTOCOL_G1 ][ ntHub ]  = max( Settings.Gnutella1.NumPeers, Settings.Gnutella1.NumHubs );
00923                 nLimit[ PROTOCOL_G1 ][ ntLeaf ] = Settings.Gnutella1.NumLeafs;
00924         }
00925 
00926 
00927 
00928         // Set numbers of neighbours (G2)
00929         if ( Settings.Gnutella2.EnableToday == FALSE )
00930         {
00931                 nLimit[ PROTOCOL_G2 ][ ntHub ] = nLimit[ PROTOCOL_G2 ][ ntLeaf ] = 0;
00932         }
00933         else if ( m_bG2Leaf )
00934         {
00935                 nLimit[ PROTOCOL_G2 ][ ntHub ]  = min( Settings.Gnutella2.NumHubs, 3 );
00936         }
00937         else
00938         {
00939                 nLimit[ PROTOCOL_G2 ][ ntHub ]  = max( Settings.Gnutella2.NumPeers, Settings.Gnutella2.NumHubs );
00940                 nLimit[ PROTOCOL_G2 ][ ntLeaf ] = Settings.Gnutella2.NumLeafs;
00941         }
00942         
00943 
00944         
00945         // Set numbers of neighbours (ED2K)
00946         if ( Settings.eDonkey.EnableToday )
00947         {
00948                 nLimit[ PROTOCOL_ED2K ][ ntHub ] = min( DWORD(1), Settings.eDonkey.NumServers );
00949         }
00950         
00951         nCount[ PROTOCOL_G1 ][0] += nCount[ PROTOCOL_NULL ][0];
00952         nCount[ PROTOCOL_G2 ][0] += nCount[ PROTOCOL_NULL ][0];
00953         
00954         // Maintain neighbour connections
00955         for ( int nProtocol = 3 ; nProtocol >= 1 ; nProtocol-- )                // Loop through protocols. (ED2K, G2, then G1))
00956         {
00957                 if ( nCount[ nProtocol ][ ntHub ] > 0 ) m_tPresent[ nProtocol ] = tNow;
00958                 
00959                 if ( nCount[ nProtocol ][ ntHub ] < nLimit[ nProtocol ][ ntHub ] )
00960                 {       // We don't have enough hubs
00961 
00962                         // Don't try to connect to G1 right away- wait a few seconds to reduce the number of connections
00963                         if ( ( nProtocol == PROTOCOL_G1 ) && ( Settings.Gnutella2.EnableToday == TRUE ) )
00964                         {
00965                                 // Wait 4 seconds before trying G1
00966                                 if ( ! Network.ReadyToTransfer( tTimer ) ) return;
00967 
00968                                 // If connections are limited (XP sp2), then wait until we're stable
00969                                 // if ( ( Settings.Connection.SlowConnect ) && ( Network.GetStableTime() < 15 ) ) return;
00970                 
00971                         }
00972 
00973                         CHostCacheList* pCache = HostCache.ForProtocol( nProtocol );
00974                         
00975                         int nAttempt;
00976                         if ( nProtocol != PROTOCOL_ED2K )
00977                         {
00978                                 // For G1 and G2 we try connecting to free slots * ConnectFactor
00979                                 nAttempt = ( nLimit[ nProtocol ][ ntHub ] - nCount[ nProtocol ][ ntHub ] );
00980                                 nAttempt *=  Settings.Gnutella.ConnectFactor;
00981                         }
00982                         else
00983                         {
00984                                 // For ed2k we try one attempt at a time to begin with, but we can step up to 
00985                                 // 2 at a time after a few seconds if the FastConnect option is selected. 
00986                                 if ( ( Settings.eDonkey.FastConnect ) && ( Network.ReadyToTransfer( tTimer ) ) )
00987                                         nAttempt = 2;
00988                                 else
00989                                         nAttempt = 1;
00990                         }
00991 
00992                         // Prevent XP sp2 from maxing out half open connections
00993                         nAttempt = min(nAttempt, ( Settings.Downloads.MaxConnectingSources - 2 ) ); 
00994                         
00995                         // Handle priority ed2k servers
00996                         if ( nProtocol == PROTOCOL_ED2K )
00997                         {
00998                                 for (   CHostCacheHost* pHost = pCache->GetNewest() ;
00999                                                 pHost && nCount[ nProtocol ][0] < nAttempt ; pHost = pHost->m_pPrevTime )
01000                                 {
01001                                         if ( pHost->m_bPriority && pHost->CanConnect( tNow ) && pHost->ConnectTo( TRUE ) )
01002                                         {
01003                                                 ASSERT( pHost->m_nProtocol == nProtocol );
01004                                                 nCount[ nProtocol ][0] ++;
01005 
01006                                                 // Prevent queries while we log on
01007                                                 pHost->m_tQuery = tNow;
01008                                                 
01009                                                 if ( Settings.Connection.ConnectThrottle != 0 )
01010                                                 {
01011                                                         // Throttle new connections and downloads
01012                                                         Network.m_tLastConnect = tTimer;
01013                                                         Downloads.m_tLastConnect = tTimer;
01014                                                         return;
01015                                                 }
01016                                         }
01017                                 }
01018                         }
01019                         
01020                         // Connect to regular hosts (neighbours)
01021                         for (   CHostCacheHost* pHost = pCache->GetNewest() ;
01022                                         pHost && nCount[ nProtocol ][0] < nAttempt ; pHost = pHost->m_pPrevTime )
01023                         {
01024                                 if ( pHost->CanConnect( tNow ) && pHost->ConnectTo( TRUE ) )
01025                                 {
01026                                         ASSERT( pHost->m_nProtocol == nProtocol );
01027                                         nCount[ nProtocol ][0] ++;
01028 
01029                                         if ( nProtocol == PROTOCOL_ED2K )
01030                                         {
01031                                                 // Prevent queries while we log on
01032                                                 pHost->m_tQuery = tNow;
01033                                         }
01034                                         
01035                                         if ( Settings.Connection.ConnectThrottle != 0 )
01036                                         {
01037                                                 // Throttle new connections and downloads
01038                                                 Network.m_tLastConnect = tTimer;
01039                                                 Downloads.m_tLastConnect = tTimer;
01040                                                 return;
01041                                         }
01042                                 }
01043                         }
01044                         
01045                         if ( Network.m_bAutoConnect )
01046                         {
01047                                 if ( nCount[ nProtocol ][ 0 ] == 0 || tNow - m_tPresent[ nProtocol ] >= 30 )
01048                                 {
01049                                         if ( nProtocol == PROTOCOL_G2 )
01050                                         {
01051                                                 DiscoveryServices.Execute( TRUE );
01052                                         }
01053                                         else if ( nProtocol == PROTOCOL_G1 )
01054                                         {
01055                                                 if ( pCache->GetOldest() == NULL ) DiscoveryServices.Execute( TRUE );
01056                                         }
01057                                 }
01058                         }
01059                 }
01060                 else if ( nCount[ nProtocol ][ ntHub ] > nLimit[ nProtocol ][ ntHub ] )
01061                 {       // We have too many hubs
01062                         CNeighbour* pNewest = NULL;
01063                         
01064                         // Find the most recently added
01065                         for ( POSITION pos = GetIterator() ; pos ; )
01066                         {
01067                                 CNeighbour* pNeighbour = GetNext( pos );
01068                                 
01069                                 if ( pNeighbour->m_nNodeType != ntLeaf &&
01070                                          pNeighbour->m_nProtocol == nProtocol &&
01071                                          ( pNeighbour->m_bAutomatic || ! pNeighbour->m_bInitiated || nLimit[ nProtocol ][ ntHub ] == 0 ) )
01072                                 {
01073                                         if ( pNewest == NULL || pNeighbour->m_tConnected > pNewest->m_tConnected )
01074                                                 pNewest = pNeighbour;
01075                                 }
01076                         }
01077 
01078                         // Drop it
01079                         if ( pNewest != NULL ) pNewest->Close();
01080                 }
01081                 
01082                 if ( nCount[ nProtocol ][ ntLeaf ] > nLimit[ nProtocol ][ ntLeaf ] )
01083                 {       // We have too many Leafs
01084                         CNeighbour* pNewest = NULL;
01085                         
01086                         // Find the most recently added
01087                         for ( POSITION pos = GetIterator() ; pos ; )
01088                         {
01089                                 CNeighbour* pNeighbour = GetNext( pos );
01090                                 
01091                                 if ( pNeighbour->m_nNodeType == ntLeaf && pNeighbour->m_nProtocol == nProtocol )
01092                                 {
01093                                         if ( pNewest == NULL || pNeighbour->m_tConnected > pNewest->m_tConnected )
01094                                                 pNewest = pNeighbour;
01095                                 }
01096                         }
01097                         
01098                         // Drop it
01099                         if ( pNewest != NULL ) pNewest->Close();
01100                 }
01101         }
01102 }

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