00001 // 00002 // ShakeNeighbour.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 // CShakeNeighbour reads and sends handshake headers to negotiate the Gnutella or Gnutella2 handshake 00023 // http://wiki.shareaza.com/static/Developers.Code.CShakeNeighbour 00024 00025 // Copy in the contents of these files here before compiling 00026 #include "StdAfx.h" 00027 #include "Shareaza.h" 00028 #include "Settings.h" 00029 #include "Security.h" 00030 #include "Network.h" 00031 #include "Buffer.h" 00032 #include "HostCache.h" 00033 #include "DiscoveryServices.h" 00034 #include "Neighbours.h" 00035 #include "ShakeNeighbour.h" 00036 #include "G1Neighbour.h" 00037 #include "G2Neighbour.h" 00038 #include "Packet.h" 00039 00040 // If we are compiling in debug mode, replace the text "THIS_FILE" in the code with the name of this file 00041 #ifdef _DEBUG 00042 #undef THIS_FILE 00043 static char THIS_FILE[]=__FILE__; 00044 #define new DEBUG_NEW 00045 #endif 00046 00048 // CShakeNeighbour construction 00049 00050 // Make a new CShakeNeighbour object 00051 CShakeNeighbour::CShakeNeighbour() : CNeighbour( PROTOCOL_NULL ) // Call the CNeighbour constructor first, with no protocol 00052 { 00053 // Set member variables that record headers to false 00054 m_bSentAddress = FALSE; // We haven't told the remote computer "Listen-IP: 1.2.3.4:5" 00055 m_bG2Send = FALSE; // The remote computer hasn't said "Content-Type: application/x-gnutella2" yet 00056 m_bG2Accept = FALSE; // The remote computer hasn't said "Accept: application/x-gnutella2" yet 00057 m_bDeflateSend = FALSE; // The remote computer hasn't said "Content-Encoding: deflate" yet 00058 m_bDeflateAccept = FALSE; // The remote computer hasn't said "Accept-Encoding: deflate" yet 00059 00060 //ToDo: Check this - G1 setting? 00061 // Set m_bCanDeflate to true if the checkboxes in Shareaza Settings allow us to send and receive compressed data 00062 m_bCanDeflate = Neighbours.IsG2Leaf() ? ( Settings.Gnutella.DeflateHub2Hub || Settings.Gnutella.DeflateLeaf2Hub ) : ( Settings.Gnutella.DeflateHub2Hub || Settings.Gnutella.DeflateHub2Hub ); 00063 00064 // Start out ultrapeer settings as unknown 00065 m_bUltraPeerSet = TS_UNKNOWN; // The remote computer hasn't told us if it's ultra or not yet 00066 m_bUltraPeerNeeded = TS_UNKNOWN; // The remote computer hasn't told us if it needs more ultra connections yet 00067 m_bUltraPeerLoaded = TS_UNKNOWN; // May not be in use (do) 00068 } 00069 00070 // Delete this CShakeNeighbour object 00071 CShakeNeighbour::~CShakeNeighbour() 00072 { 00073 // This virtual method will be redefined by a class that inherits from CShakeNeighbour 00074 } 00075 00077 // CShakeNeighbour connect to 00078 00079 // Called by CNeighboursWithConnect::ConnectTo 00080 // Takes an IP address and port number to connect to, the automatic setting (do), and true if (do) 00081 // Connects the socket in this object to the remote computer 00082 // Returns false if the connection could not be made 00083 BOOL CShakeNeighbour::ConnectTo(IN_ADDR* pAddress, WORD nPort, BOOL bAutomatic, BOOL bNoUltraPeer) 00084 { 00085 // Connect the socket in this object to the given ip address and port number 00086 if ( CConnection::ConnectTo( pAddress, nPort ) ) 00087 { 00088 // Have Windows signal our event when the state of the socket changes 00089 WSAEventSelect( // Associate an event object with a specified set of network events 00090 m_hSocket, // The socket 00091 Network.m_pWakeup, // Signal this event when the following network events happen 00092 FD_CONNECT | FD_READ | FD_WRITE | FD_CLOSE ); // Connection completed, ready to read or write, or socket closed 00093 00094 // Report that we are attempting this connection 00095 theApp.Message( MSG_DEFAULT, IDS_CONNECTION_ATTEMPTING, (LPCTSTR)m_sAddress, htons( m_pHost.sin_port ) ); 00096 00097 } // ConnectTo reported that the socket could not be made 00098 else 00099 { 00100 // Report the connection failure 00101 theApp.Message( MSG_ERROR, IDS_CONNECTION_CONNECT_FAIL, (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) ); 00102 return FALSE; 00103 } 00104 00105 // Initialize more member variables 00106 m_nState = nrsConnecting; // We've connected the socket, and are waiting for the connection to be made 00107 m_bAutomatic = bAutomatic; // Copy the given automatic setting into the member variable (do) 00108 m_bUltraPeerSet = bNoUltraPeer ? TS_FALSE : TS_UNKNOWN; // Set m_bUltraPeerSet to false or unknown (do) 00109 00110 // Add this CShakeNeighbour object to the list of them 00111 Neighbours.Add( this ); 00112 00113 // The connection was made without error 00114 return TRUE; 00115 } 00116 00118 // CShakeNeighbour accept from 00119 00120 // Takes pConnection, the source object to copy from 00121 // Copies the the values from inside pConnection to this CShakeNeighbour object 00122 void CShakeNeighbour::AttachTo(CConnection* pConnection) 00123 { 00124 // Call CConnection::AttachTo to copy pConnection into the CConnection core of this CShakeNeighbour object 00125 CConnection::AttachTo( pConnection ); 00126 00127 // Have Windows signal our event when the state of the socket changes 00128 WSAEventSelect( // Associate an event object with a specified set of network events 00129 m_hSocket, // The socket 00130 Network.m_pWakeup, // Signal this event when the following network events happen 00131 FD_READ | FD_WRITE | FD_CLOSE ); // Signal it when the socket is ready to read or write, or closed 00132 00133 // Put this CShakeNeighbour object into the Handshake1 state (do) 00134 m_nState = nrsHandshake1; // We've finished sending a group of headers, and await the response 00135 00136 // Add this CShakeNeighbour object to the list of them 00137 Neighbours.Add( this ); 00138 } 00139 00141 // CShakeNeighbour close 00142 00143 // Called when the socket connection has been dropped 00144 // Takes an error code that explains why 00145 // Records the failure and puts everything away 00146 void CShakeNeighbour::Close(UINT nError) 00147 { 00148 // If we initiated the connection to the remote computer 00149 if ( m_bInitiated ) 00150 { 00151 // And if the remote computer hasn't sent us any handshake headers yet 00152 if ( m_nState < nrsHandshake2 ) 00153 { 00154 // Tell the host cache that we didn't get any data from this remote computer at all 00155 HostCache.OnFailure( &m_pHost.sin_addr, htons( m_pHost.sin_port ) ); 00156 } 00157 } 00158 00159 // Have CNeighbour remove this object from the list, and put away the socket 00160 CNeighbour::Close( nError ); 00161 } 00162 00164 // CShakeNeighbour connection event 00165 00166 // CConnection::DoRun calls this when it has just opened a socket to a remote computer 00167 // Sends the remote computer our first big block of Gnutella headers 00168 // Always returns true 00169 BOOL CShakeNeighbour::OnConnected() 00170 { 00171 // This call does nothing (do) 00172 CConnection::OnConnected(); 00173 00174 // Report that this connection was made 00175 theApp.Message( MSG_DEFAULT, IDS_CONNECTION_CONNECTED, (LPCTSTR)m_sAddress ); 00176 00177 // We initiated the connection to this computer, send it our first block of handshake headers 00178 m_pOutput->Print( "GNUTELLA CONNECT/0.6\r\n" ); // Ask to connect 00179 SendPublicHeaders(); // User agent, ip addresses, Gnutella2 and deflate, advanced Gnutella features 00180 SendHostHeaders(); // Try ultrapeers 00181 m_pOutput->Print( "\r\n" ); // A blank line ends this first block of headers 00182 00183 // We've finished sending a group of headers, and await the response 00184 m_nState = nrsHandshake1; 00185 00186 // Send the output buffer to the remote computer 00187 OnWrite(); 00188 00189 // Have CConnection::DoRun keep going 00190 return TRUE; 00191 } 00192 00194 // CShakeNeighbour connection loss event 00195 00196 // CConnection::DoRun calls this when a socket connection has been refused or lost 00197 // Documents what happened, and puts everything away 00198 void CShakeNeighbour::OnDropped(BOOL bError) 00199 { 00200 // We tried to connect the socket, but are still waiting for the socket connection to be made 00201 if ( m_nState == nrsConnecting ) 00202 { 00203 // Close the connection, citing refused as the reason it didn't work out 00204 Close( IDS_CONNECTION_REFUSED ); 00205 00206 } // We are somewhere else in the chain of connecting and doing the handshake 00207 else 00208 { 00209 // Close the connection, citing dropped as the explination of what happened 00210 Close( IDS_CONNECTION_DROPPED ); 00211 } 00212 } 00213 00215 // CShakeNeighbour read and write events 00216 00217 // Reads in data from the remote computer, looks at it as the handshake, and replies to it 00218 // Returns true if we should keep talking to the remote computer, false if we should disconnect 00219 BOOL CShakeNeighbour::OnRead() 00220 { 00221 // Copy data from the remote computer that is waiting on our end of the socket into the input buffer 00222 CConnection::OnRead(); 00223 00224 // If we've finished sending a group of headers, read the remote computer's response 00225 if ( m_nState == nrsHandshake1 && ! ReadResponse() ) return FALSE; 00226 00227 // If the remote computer has sent the first line of its initial group of headers, keep reading them 00228 if ( m_nState == nrsHandshake2 && ! ReadHeaders() ) return FALSE; 00229 00230 // If we've finished sending a group of headers, read the remote computer's response 00231 if ( m_nState == nrsHandshake1 && ! ReadResponse() ) return FALSE; 00232 00233 // If the remote computer has sent the first line of its final group of headers, keep reading them 00234 if ( m_nState == nrsHandshake3 && ! ReadHeaders() ) return FALSE; 00235 00236 // If the remote computer started with "GNUTELLA/0.6", but did not say "200 OK" (do) 00237 if ( m_nState == nrsRejected && ! ReadHeaders() ) return FALSE; 00238 00239 // Keep talking to the remote computer 00240 return TRUE; 00241 } 00242 00244 // CShakeNeighbour run event 00245 00246 // CConnection::DoRun calls this 00247 // Makes sure the handshake hasn't been taking too long 00248 // Returns false to stop talking to this computer, true to keep talking to it 00249 BOOL CShakeNeighbour::OnRun() 00250 { 00251 // Get the number of milliseconds since the computer has been turned on 00252 DWORD nTimeNow = GetTickCount(); 00253 00254 // We connected the socket, and are waiting for the socket connection to be made 00255 switch ( m_nState ) { 00256 case nrsConnecting: 00257 00258 // If we've been waiting for the connection to be made longer than the connection timeout in settings 00259 if ( nTimeNow - m_tConnected > Settings.Connection.TimeoutConnect ) 00260 { 00261 // Tell discovery services that we're giving up on this one, and close the connection 00262 DiscoveryServices.OnGnutellaFailed( &m_pHost.sin_addr ); 00263 Close( IDS_CONNECTION_TIMEOUT_CONNECT ); 00264 return FALSE; 00265 } 00266 00267 break; 00268 00269 // We are exchanging handshake headers with the remote computer, and the most recent thing that's happened is 00270 case nrsHandshake1: // We've sent a complete group of headers 00271 case nrsHandshake2: // The remote computer sent the first line of its initial group of headers to us 00272 case nrsHandshake3: // The remote computer sent the first line of its final group of headers to us 00273 case nrsRejected: // The remote computer sent us a line with a 503 error code 00274 00275 // If the handshake has been going on for longer than the handshake timeout in settings 00276 if ( nTimeNow - m_tConnected > Settings.Connection.TimeoutHandshake ) 00277 { 00278 // Close the connection 00279 Close( IDS_HANDSHAKE_TIMEOUT ); 00280 return FALSE; 00281 } 00282 00283 break; 00284 00285 // DelayClose was called, it sends the write buffer to the remote computer before closing the socket 00286 case nrsClosing: 00287 00288 // Close the connection 00289 Close( 0 ); 00290 return FALSE; 00291 00292 break; 00293 } 00294 00295 // Have CConnection::DoRun keep talking to this remote computer 00296 return TRUE; 00297 } 00298 00300 // CShakeNeighbour handshake header dispatch 00301 00302 // Tell the remote computer we are Shareaza, and setup Gnutella2 or just Gnutella communications 00303 void CShakeNeighbour::SendMinimalHeaders() 00304 { 00305 // Say what program we are with a line like "User-Agent: Shareaza 1.2.3.4\r\n" 00306 CString strHeader = Settings.SmartAgent(); 00307 if ( strHeader.GetLength() ) 00308 { 00309 strHeader = _T("User-Agent: ") + strHeader + _T("\r\n"); 00310 m_pOutput->Print( strHeader ); 00311 } 00312 00313 // The user has checked the box to connect to Gnutella2 today 00314 if ( Settings.Gnutella2.EnableToday && ( m_nProtocol != PROTOCOL_G1 ) ) 00315 { 00316 // If we initiated the connection to the remote computer 00317 if ( m_bInitiated ) 00318 { 00319 // Tell the remote computer we know how to read Gnutella and Gnutella2 packets 00320 m_pOutput->Print( "Accept: application/x-gnutella2,application/x-gnutella-packets\r\n" ); 00321 } 00322 else if ( m_bG2Accept ) // The remote computer contacted us, and accepts Gnutella2 packets 00323 { 00324 // Reply by saying we accept them also, and will be sending them 00325 m_pOutput->Print( "Accept: application/x-gnutella2\r\n" ); 00326 m_pOutput->Print( "Content-Type: application/x-gnutella2\r\n" ); 00327 } 00328 } 00329 } 00330 00331 // Sends Gnutella headers to the other computer 00332 void CShakeNeighbour::SendPublicHeaders() 00333 { 00334 // Tell the remote we are running Shareza with a header like "User-Agent: Shareaza 2.1.0.97" 00335 CString strHeader = Settings.SmartAgent(); 00336 if ( strHeader.GetLength() ) 00337 { 00338 strHeader = _T("User-Agent: ") + strHeader + _T("\r\n"); 00339 m_pOutput->Print( strHeader ); 00340 } 00341 00342 // Tell the remote computer our IP address with a header like "Listen-IP: 67.176.34.172:6346" 00343 m_bSentAddress |= SendMyAddress(); // Returns true if the header is sent, set m_bSentAddress true once its sent 00344 00345 // Tell the remote computer what IP address it has from here with a header like "Remote-IP: 81.103.192.245" 00346 strHeader.Format( _T("Remote-IP: %s\r\n"), (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) ); 00347 m_pOutput->Print( strHeader ); 00348 00349 // If the settings say connect to Gnutella2 and this function got passed Gnutella2 or the unknown network 00350 if ( ( Settings.Gnutella2.EnableToday ) && ( m_nProtocol != PROTOCOL_G1 ) ) // The protocol ID is Gnutella2 or unknown 00351 { 00352 // If we initiated the connection to the remote computer 00353 if ( m_bInitiated ) 00354 { 00355 // Tell the remote computer we accept Gnutella and Gnutella2 packets 00356 m_pOutput->Print( "Accept: application/x-gnutella2,application/x-gnutella-packets\r\n" ); 00357 } 00358 else if ( m_bG2Accept ) // The remote computer contacted us, and accepts Gnutella2 packets 00359 { 00360 // Tell the remote computer we accept Gnutella2 packets and will be sending it Gnutella2 packets 00361 m_pOutput->Print( "Accept: application/x-gnutella2\r\n" ); // We can read Gnutella2 packets 00362 m_pOutput->Print( "Content-Type: application/x-gnutella2\r\n" ); // You will be getting them from us 00363 } 00364 } 00365 00366 // Shareaza Settings allow us to exchange compressed data with this computer 00367 if ( m_bCanDeflate ) 00368 { 00369 // Tell the remote computer we can accept compressed data 00370 m_pOutput->Print( "Accept-Encoding: deflate\r\n" ); 00371 00372 // If the remote computer connected to us and accepts compressed data 00373 if ( ! m_bInitiated && m_bDeflateAccept ) 00374 { 00375 // Tell it we will be sending compressed data 00376 m_pOutput->Print( "Content-Encoding: deflate\r\n" ); 00377 } 00378 } 00379 00380 // If the settings say connect to Gnutella and this function got passed Gnutella or the unknown network 00381 if ( ( Settings.Gnutella1.EnableToday ) && ( m_nProtocol != PROTOCOL_G2 ) ) // The protocol ID is Gnutella or unknown 00382 { 00383 // Tell the remote computer all the Gnutella features we support 00384 if ( Settings.Gnutella1.EnableGGEP ) m_pOutput->Print( "GGEP: 0.5\r\n" ); // We support GGEP blocks 00385 m_pOutput->Print( "Pong-Caching: 0.1\r\n" ); // We support pong caching 00386 if ( Settings.Gnutella1.VendorMsg ) m_pOutput->Print( "Vendor-Message: 0.1\r\n" ); // We support vendor-specific messages 00387 m_pOutput->Print( "X-Query-Routing: 0.1\r\n" ); // We support the query routing protocol 00388 } 00389 00390 // If we initiated the connection to the remote computer and it is not an ultrapeer 00391 if ( m_bInitiated && m_bUltraPeerSet == TS_FALSE ) 00392 { 00393 // Really, we don't know if it's an ultrapeer or not yet 00394 m_bUltraPeerSet = TS_UNKNOWN; 00395 00396 } // The remote computer called us, or we called them and it's an ultrapeer or hasn't said yet 00397 else 00398 { 00399 if ( m_nProtocol == PROTOCOL_G1 ) 00400 { 00401 // Find out if we are an ultrapeer or at least eligible to become one soon 00402 if ( Neighbours.IsG1Ultrapeer() || Neighbours.IsG1UltrapeerCapable() ) 00403 { 00404 // Tell the remote computer that we are an ultrapeer 00405 m_pOutput->Print( "X-Ultrapeer: True\r\n" ); 00406 00407 } // We are not an ultrapeer nor are we elegible, and the settings say so too 00408 else if ( Settings.Gnutella1.ClientMode != MODE_ULTRAPEER ) 00409 { 00410 // Tell the remote computer that we are not an ultrapeer, we are just a Gnutella leaf node 00411 m_pOutput->Print( "X-Ultrapeer: False\r\n" ); 00412 } 00413 } 00414 else // This protocol ID this method got passed is unknown or for something other than Gnutella 00415 { 00416 // Find out if we are a Gnutella2 hub, or at least eligible to become one soon 00417 if ( Neighbours.IsG2Hub() || Neighbours.IsG2HubCapable() ) 00418 { 00419 // Tell the remote computer that we are a hub 00420 m_pOutput->Print( "X-Ultrapeer: True\r\n" ); 00421 00422 } // We are not a hub nor are we eligible, and the settings say so too 00423 else if ( Settings.Gnutella2.ClientMode != MODE_HUB ) 00424 { 00425 // Tell the remote computer that we are a leaf 00426 m_pOutput->Print( "X-Ultrapeer: False\r\n" ); 00427 } 00428 } 00429 } 00430 } 00431 00432 // Reply to a remote computer's headers with more headers, confirming Gnutella2 packets and data compression 00433 void CShakeNeighbour::SendPrivateHeaders() 00434 { 00435 // If we haven't told the other computer our IP address yet, do it now with a header like "Listen-IP: 1.2.3.4:5" 00436 if ( ! m_bSentAddress ) m_bSentAddress = SendMyAddress(); 00437 00438 // We initiated the connection to the remote computer, it's going to send us Gnutella2 packets, and it accepts them 00439 if ( m_bInitiated && m_bG2Send && m_bG2Accept && ( m_nProtocol != PROTOCOL_G1 ) ) 00440 { 00441 // Tell it we also accept gnutella2 packets, and we're also going to send them 00442 m_pOutput->Print( "Accept: application/x-gnutella2\r\n" ); 00443 m_pOutput->Print( "Content-Type: application/x-gnutella2\r\n" ); 00444 } 00445 00446 // If we initiated the connection to the remote computer 00447 if ( m_bInitiated ) 00448 { 00449 // All the data from the remote computer is going to be compressed 00450 if ( m_bDeflateSend ) 00451 { 00452 // Tell it we accept compressed data too 00453 m_pOutput->Print( "Accept-Encoding: deflate\r\n" ); 00454 } 00455 00456 // The remote computer accepts compressed data 00457 if ( m_bDeflateAccept ) 00458 { 00459 // Tell it all the data we send it will be compressed 00460 m_pOutput->Print( "Content-Encoding: deflate\r\n" ); 00461 } 00462 } 00463 } 00464 00465 // Takes a line like "GNUTELLA/0.6 503 Need an Ultrapeer" 00466 // Sends it with the "X-Try-Ultrapeers:" header 00467 void CShakeNeighbour::SendHostHeaders(LPCTSTR pszMessage) 00468 { 00469 // Local variables 00470 DWORD nTime = time( NULL ); // The number of seconds since midnight on January 1, 1970 00471 CString strHosts, strHost; // Text to describe other computers and just one 00472 CHostCacheHost* pHost; // We'll use this to loop through host objects in the host cache 00473 00474 // If this method was given a message 00475 if ( pszMessage ) 00476 { 00477 // Send it to the remote computer, along with the minimal headers 00478 m_pOutput->Print( pszMessage ); 00479 m_pOutput->Print( "\r\n" ); 00480 SendMinimalHeaders(); // Say we are Shareaza, and understand Gnutella2 packets 00481 } 00482 00483 // Compose text with IP address and online time information to help the remote computer find more Gnutella computers 00484 int nCount = Settings.Gnutella1.PongCount; // The list can't be longer than the pong count 00485 if ( m_bG2Accept || m_bG2Send || m_bShareaza ) // The remote computer accepts Gnutella2 packets, sends them, or is Shareaza too 00486 { 00487 // Loop through the Gnutella2 host cache from newest to oldest 00488 for ( pHost = HostCache.Gnutella2.GetNewest() ; pHost && nCount > 0 ; pHost = pHost->m_pPrevTime ) 00489 { 00490 // This host is still recent enough to tell another computer about 00491 if ( pHost->CanQuote( nTime ) ) 00492 { 00493 // Compose text for one computer and add it to the string 00494 strHost = pHost->ToString(); // The host object composes text about itself 00495 if ( strHosts.GetLength() ) strHosts += _T(","); // Separate each computer's info with a comma 00496 strHosts += strHost; // Add this computer's info to the big string 00497 nCount--; // Record that we documented another computer 00498 } 00499 } 00500 } 00501 else // The remote computer is running Gnutella 00502 { 00503 // Loop through the Gnutella host cache from newest to oldest 00504 for ( pHost = HostCache.Gnutella1.GetNewest() ; pHost && nCount > 0 ; pHost = pHost->m_pPrevTime ) 00505 { 00506 // This host is still recent enough to tell another computer about 00507 if ( pHost->CanQuote( nTime ) ) 00508 { 00509 // Compose text for one computer and add it to the string 00510 strHost = pHost->ToString(); // Like "24.98.97.155:6348 2004-12-18T23:47Z" 00511 if ( strHosts.GetLength() ) strHosts += _T(","); // Separate each computer's info with a comma 00512 strHosts += strHost; // Add this computer's info to the big string 00513 nCount--; // Record that we documented another computer 00514 } 00515 } 00516 } 00517 00518 // If we have any computers to tell the remote computer about 00519 if ( strHosts.GetLength() ) 00520 { 00521 // Send the information in a header like "X-Try-Ultrapeers: 24.98.97.155:6348 2004-12-18T23:47Z," and so on 00522 m_pOutput->Print( "X-Try-Ultrapeers: " ); 00523 m_pOutput->Print( strHosts ); 00524 m_pOutput->Print( "\r\n" ); 00525 } 00526 00527 // If this method started the handshake with a message line, end it with the blank line 00528 if ( pszMessage ) m_pOutput->Print( "\r\n" ); // Sends a blank line, marking the end of the handshake 00529 } 00530 00532 // CShakeNeighbour handshake response processor 00533 00534 // Reads the first line of a new group of handshake headers from the remote computer, and sets the state to have OnRead read more 00535 // Returns true to keep reading the handshake, false if its over or you should stop 00536 BOOL CShakeNeighbour::ReadResponse() 00537 { 00538 // Read one header line from the handshake the remote computer has sent us 00539 CString strLine; // The line 00540 if ( ! m_pInput->ReadLine( strLine ) ) return TRUE; // The line is still arriving, return true to try this method again 00541 if ( strLine.GetLength() > 1024 ) strLine = _T("#LINE_TOO_LONG#"); // Make sure the line isn't too long 00542 theApp.Message( MSG_DEBUG, _T("%s: HANDSHAKE: %s"), (LPCTSTR)m_sAddress, (LPCTSTR)strLine ); // Report handshake lines 00543 00544 // If we initiated the connection to the remote computer, and now it's responding with "GNUTELLA OK" 00545 if ( strLine == _T("GNUTELLA OK") && m_bInitiated ) 00546 { 00547 // (do) 00548 OnHandshakeComplete(); // Deletes this CShakeNeighbour object 00549 return FALSE; // Tell the method that called this one not to call us again, we're done here 00550 00551 } // The line starts "GNUTELLA/0.6", and says something else after that 00552 else if ( strLine.GetLength() > 13 && strLine.Left( 12 ) == _T("GNUTELLA/0.6") ) 00553 { 00554 // It does not say "200 OK" after that 00555 if ( strLine != _T("GNUTELLA/0.6 200 OK") ) 00556 { 00557 // Clip out just the part that says why we were rejected, document it, and set the state to rejected 00558 strLine = strLine.Mid( 13 ); 00559 theApp.Message( MSG_ERROR, IDS_HANDSHAKE_REJECTED, (LPCTSTR)m_sAddress, (LPCTSTR)strLine ); 00560 m_nState = nrsRejected; // Set the neigbour state in this CShakeNeighbour object to rejected 00561 00562 } // It does say "200 OK", and the remote computer contacted us 00563 else if ( ! m_bInitiated ) 00564 { 00565 // The remote computer connected to us and sent its headers, we replied with ours, and now it's sending the final group 00566 m_nState = nrsHandshake3; // We're reading the final header group from the remote computer 00567 00568 } // It does say "200 OK", and we initiated the connection 00569 else 00570 { 00571 // We connected and sent our headers, now the remote computer is responding 00572 m_nState = nrsHandshake2; // We're reading the initial header group the remote computer has sent 00573 } 00574 00575 } // The remote computer connected to us, and wants to talk with the old 0.4 protocol 00576 else if ( strLine == _T("GNUTELLA CONNECT/0.4") && ! m_bInitiated ) 00577 { 00578 // Gnutella 0.4 is too old for us, close the connection 00579 DelayClose( IDS_HANDSHAKE_SURPLUS ); // Send the buffer then close the socket, citing the reason the connection didn't work out 00580 return FALSE; // Tell the method that called this one to stop calling us 00581 00582 } // The remote computer connected to us, and wants to talk Gnutella 00583 else if ( strLine.GetLength() > 17 && strLine.Left( 17 ) == _T("GNUTELLA CONNECT/") && ! m_bInitiated ) 00584 { 00585 // We're reading the initial header group the remote computer has sent 00586 m_nState = nrsHandshake2; 00587 00588 } // The remote computer connected to us, and said "SHAREAZABETA CONNECT/" 00589 else if ( strLine.GetLength() > 21 && strLine.Left( 21 ) == _T("SHAREAZABETA CONNECT/") && ! m_bInitiated ) 00590 { 00591 // We're reading the initial header group the remote computer has sent 00592 m_nState = nrsHandshake2; 00593 00594 } // The remote computer said something else that we aren't expecting here 00595 else 00596 { 00597 // Close the connection, citing the reason as we can't understand the handshake 00598 Close( IDS_HANDSHAKE_FAIL ); 00599 return FALSE; // Tell the calling method to stop calling us 00600 } 00601 00602 // Tell the calling method it can call us some more to read more lines from the handshake 00603 return TRUE; 00604 } 00605 00607 // CShakeNeighbour handshake header processing 00608 00609 // Takes a handshake header and value parsed from a line sent by the remote computer 00610 // Reads it and sets member variables to reflect the remote computer's capabilities 00611 // Returns true to keep going, or false to indicate the handshake is over or we should stop trying to read it 00612 BOOL CShakeNeighbour::OnHeaderLine(CString& strHeader, CString& strValue) 00613 { 00614 // Record this header 00615 theApp.Message( MSG_DEBUG, _T("%s: GNUTELLA HEADER: %s: %s"), (LPCTSTR)m_sAddress, (LPCTSTR)strHeader, (LPCTSTR)strValue ); 00616 00617 // It's the "User-Agent" header, which will tell the name and version of the remote program 00618 if ( strHeader.CompareNoCase( _T("User-Agent") ) == 0 ) 00619 { 00620 // Save the name and version of the remote program 00621 m_sUserAgent = strValue; 00622 00623 // If the text contains "Shareaza" 00624 if ( _tcsistr( m_sUserAgent, _T("Shareaza") ) ) 00625 { 00626 // Record that the remote computer is running Shareaza 00627 m_bShareaza = TRUE; 00628 } 00629 00630 // Check if it's an old version of Shareaza 00631 if ( IsClientObsolete() ) 00632 { 00633 m_bObsoleteClient = TRUE; 00634 } 00635 00636 // If the remote computer is running a client that is breaking GPL, causing problems, etc. 00637 // We don't actually ban these clients, but we don't accept them as a leaf. Can still upload, though. 00638 if ( IsClientBad() ) 00639 { 00640 // Remember this is a bad client. 00641 m_bBadClient = TRUE; 00642 } 00643 00644 // Actual leechers and hostile clients. (We do ban these) 00645 if ( IsClientBanned() ) 00646 { 00647 // Reject the handshake 00648 theApp.Message( MSG_ERROR, IDS_HANDSHAKE_REJECTED, (LPCTSTR)m_sAddress, (LPCTSTR)m_sUserAgent ); 00649 m_nState = nrsRejected; 00650 // Ban them and ignore anything else in the headers 00651 theApp.Message( MSG_ERROR, _T("Banning hostile client %s"), (LPCTSTR)m_sUserAgent ); 00652 Security.Ban( &m_pHost.sin_addr, ban2Hours, FALSE ); 00653 m_bBadClient = TRUE; 00654 return TRUE; 00655 } 00656 00657 // If the remote computer is running a client the user has blocked 00658 if ( IsAgentBlocked() ) 00659 { 00660 // Record that we're rejecting this handshake, and set the state to rejected 00661 theApp.Message( MSG_ERROR, IDS_HANDSHAKE_REJECTED, (LPCTSTR)m_sAddress, (LPCTSTR)m_sUserAgent ); 00662 m_nState = nrsRejected; 00663 return TRUE; 00664 } 00665 00666 } // The remote computer is telling us our IP address 00667 else if ( strHeader.CompareNoCase( _T("Remote-IP") ) == 0 ) 00668 { 00669 // Give the value, which is text like "1.2.3.4", to the Network object 00670 Network.AcquireLocalAddress( strValue ); 00671 00672 } // The remote computer is telling us its IP address 00673 else if ( strHeader.CompareNoCase( _T("X-My-Address") ) == 0 || 00674 strHeader.CompareNoCase( _T("Listen-IP") ) == 0 || 00675 strHeader.CompareNoCase( _T("X-Node") ) == 0 || 00676 strHeader.CompareNoCase( _T("Node") ) == 0 ) 00677 { 00678 // Find the index of the first colon in the text 00679 int nColon = strValue.Find( ':' ); 00680 if ( nColon > 0 ) // There is a colon and it's not at the start of the text 00681 { 00682 // Save the default Gnutella port, 6346, in nPort to use it if we can't read the port number from the header value text 00683 int nPort = GNUTELLA_DEFAULT_PORT; 00684 00685 // Mid clips the strValue text from beyond the colon to the end 00686 // _stscanf is like scanf, and %1u means read the text as a long unsigned number 00687 // The If block makes sure that _stscanf successfully reads 1 item, and the number it read isn't 0 00688 if (_stscanf( strValue.Mid( nColon + 1 ), _T("%lu"), &nPort ) == 1 && nPort != 0 ) 00689 { 00690 // Save the remote computer port number in the connection object's m_pHost member variable 00691 m_pHost.sin_port = htons( nPort ); // Call htons to go from PC little-endian to Internet big-endian byte order 00692 } 00693 } 00694 00695 } // The remote computer is telling us it supports Gnutella pong caching 00696 else if ( strHeader.CompareNoCase( _T("Pong-Caching") ) == 0 ) 00697 { 00698 // Record this ability in the member variable 00699 m_bPongCaching = TRUE; 00700 00701 } // The remote computer is telling us it supports vendor-specific Gnutella messages 00702 else if ( strHeader.CompareNoCase( _T("Vendor-Message") ) == 0 ) 00703 { 00704 // Record this ability in the member variable 00705 m_bVendorMsg = TRUE; 00706 00707 } // The remote computer is telling us it supports Gnutella query routing 00708 else if ( strHeader.CompareNoCase( _T("X-Query-Routing") ) == 0 ) 00709 { 00710 // Only set m_bQueryRouting true if the value isn't "0" or "0.0" 00711 m_bQueryRouting = ( strValue != _T("0") && strValue != _T("0.0") ); 00712 00713 } // The remote computer is telling us if it is an hub or a leaf 00714 else if ( strHeader.CompareNoCase( _T("X-Ultrapeer") ) == 0 || 00715 strHeader.CompareNoCase( _T("X-Hub") ) == 0 ) 00716 { 00717 // If the value is the text "True", set m_bUltraPeerSet to true, otherwise set it to false 00718 m_bUltraPeerSet = ( strValue.CompareNoCase( _T("True") ) == 0 ) ? TS_TRUE : TS_FALSE; 00719 00720 } // The remote computer is telling us if it needs more connections to ultrapeers or not 00721 else if ( strHeader.CompareNoCase( _T("X-Ultrapeer-Needed") ) == 0 || 00722 strHeader.CompareNoCase( _T("X-Hub-Needed") ) == 0 ) 00723 { 00724 // If the value is the text "True", set m_bUltraPeerNeeded to true, otherwise set it to false 00725 m_bUltraPeerNeeded = ( strValue.CompareNoCase( _T("True") ) == 0 ) ? TS_TRUE : TS_FALSE; 00726 00727 } // The remote computer is telling us the "X-Ultrapeer-Loaded" header, which may not be in use (do) 00728 else if ( strHeader.CompareNoCase( _T("X-Ultrapeer-Loaded") ) == 0 || 00729 strHeader.CompareNoCase( _T("X-Hub-Loaded") ) == 0 ) 00730 { 00731 // If the value is the text "True", set m_bUltraPeerLoaded to true, otherwise set it to false 00732 m_bUltraPeerLoaded = ( strValue.CompareNoCase( _T("True") ) == 0 ) ? TS_TRUE : TS_FALSE; 00733 00734 } // The remote computer is telling us it understands GGEP blocks 00735 else if ( strHeader.CompareNoCase( _T("GGEP") ) == 0 ) 00736 { 00737 // If we also have GGEP blocks enabled 00738 if ( Settings.Gnutella1.EnableGGEP ) 00739 { 00740 // And if the value the remote computer sent isn't "0" or "0.0", set m_bGGEP true 00741 m_bGGEP = ( strValue != _T("0") && strValue != _T("0.0") ); 00742 } 00743 00744 } // The remote computer is telling us it accepts and can understand a kind of packets 00745 else if ( strHeader.CompareNoCase( _T("Accept") ) == 0 && Settings.Gnutella2.EnableToday ) // And we're connected to Gnutella2 00746 { 00747 // Set m_bG2Accept to true if it accepts Gnutella2 or Shareaza packets 00748 m_bG2Accept |= ( strValue.Find( _T("application/x-gnutella2") ) >= 0 ); 00749 m_bG2Accept |= ( strValue.Find( _T("application/x-shareaza") ) >= 0 ); 00750 00751 } // The remote computer is telling us it is sending a kind of packets 00752 else if ( strHeader.CompareNoCase( _T("Content-Type") ) == 0 && Settings.Gnutella2.EnableToday ) // And we're connected to Gnutella2 00753 { 00754 // Set m_bG2Send to true if it is sending Gnutella2 or Shareaza packets 00755 m_bG2Send |= ( strValue.Find( _T("application/x-gnutella2") ) >= 0 ); 00756 m_bG2Send |= ( strValue.Find( _T("application/x-shareaza") ) >= 0 ); 00757 00758 } // The remote computer is telling us it can accept compressed data, and the settings allow us to do compression 00759 else if ( strHeader.CompareNoCase( _T("Accept-Encoding") ) == 0 && m_bCanDeflate ) // Settings allow us to do compression 00760 { 00761 // Look for the text "deflate", and make m_bDeflateAccept true if it's found 00762 m_bDeflateAccept |= ( strValue.Find( _T("deflate") ) >= 0 ); 00763 00764 } // The remote computer is telling us it will send compressed data, and the settings allow us to do compression 00765 else if ( strHeader.CompareNoCase( _T("Content-Encoding") ) == 0 && m_bCanDeflate ) // Settings allow us to do compression 00766 { 00767 // Look for the text "deflate", and make m_bDeflateSend true if it's found 00768 m_bDeflateSend |= ( strValue.Find( _T("deflate") ) >= 0 ); 00769 00770 } // The remote computer is giving us a list of IP addreses we can try to contact more ultrapeers 00771 else if ( strHeader.CompareNoCase( _T("X-Try-Ultrapeers") ) == 0 || 00772 strHeader.CompareNoCase( _T("X-Try-Hubs") ) == 0 ) 00773 { 00774 // Some clients send bad data here- ignore it. 00775 if ( ! m_bBadClient ) 00776 { 00777 int nCount = 0; 00778 // Append a comma onto the end of the value text once, and then loop forever 00779 for ( strValue += ',' ; ; ) // for (;;) is the same thing as forever 00780 { 00781 // Get the port number we are listening on from settings, 6346 by default 00782 int nPort = Settings.Connection.InPort; // Not used (do) 00783 00784 // Find the first comma in the value text 00785 int nPos = strValue.Find( ',' ); // Set nPos to the distance in characters from the start to the comma 00786 if ( nPos < 0 ) break; // If no comma was found, leave the loop 00787 00788 // Move the text before the comma from the value string to a new string for the host 00789 CString strHost = strValue.Left( nPos ); // Copy the text up to the comma into strHost 00790 strValue = strValue.Mid( nPos + 1 ); // Clip that text and the comma off the start of strValue 00791 00792 // The remote computer accepts Gnutella2 packets, is sending them, or is Shareaza 00793 if ( m_bG2Accept || m_bG2Send || m_bShareaza ) 00794 { 00795 // Add the host to the Gnutella2 host cache, sending the text "RAZA" along if the remote computer is Shareaza 00796 if ( HostCache.Gnutella2.Add( strHost, 0, m_bShareaza ? SHAREAZA_VENDOR_T : NULL ) ) nCount++; // Count it 00797 00798 } // This is a Gnutella connection, not Gnutella2 00799 else 00800 { 00801 // Add the host to the Gnutella2 host cache, sending the text "RAZA" along if the remote computer is Shareaza 00802 if ( HostCache.Gnutella1.Add( strHost, 0, m_bShareaza ? SHAREAZA_VENDOR_T : NULL ) ) nCount++; // Count it 00803 } 00804 } 00805 00806 // Tell discovery services the remote computer's IP address, and how many hosts it just told us about 00807 DiscoveryServices.OnGnutellaAdded( &m_pHost.sin_addr, nCount ); 00808 } 00809 } 00810 00811 // Report success 00812 return TRUE; 00813 } 00814 00816 // CShakeNeighbour handshake end of headers 00817 00818 // Called when CConnection::ReadHeaders calls ReadLine and gets a blank line, meaning a group of headers from the remote computer is done 00819 // Responds to the group of headers from the remote computer by closing the connection, sending response headers, or copying this object for a protocol 00820 // Returns false to delete this object, or true to keep reading headers and negotiating the handshake 00821 BOOL CShakeNeighbour::OnHeadersComplete() 00822 { 00823 // If the remote computer doesn't accept Gnutella2 packets, or it does but we contacted it and it's not going to send them 00824 if ( ! m_bG2Accept || ( m_bInitiated && ! m_bG2Send ) ) 00825 { 00826 // This is a Gnutella connection 00827 m_nProtocol = PROTOCOL_G1; 00828 return OnHeadersCompleteG1(); 00829 } 00830 else 00831 { 00832 // This is a G2 connection 00833 m_nProtocol = PROTOCOL_G2; 00834 return OnHeadersCompleteG2(); 00835 } 00836 } 00837 00838 // Called when CConnection::ReadHeaders calls ReadLine and gets a blank line, meaning a group of headers from the remote computer is done 00839 // Responds to the group of headers from the remote computer by closing the connection, sending response headers, or turning this into a Gnutella2 object 00840 // Returns false to delete this object, or true to keep reading headers and negotiating the handshake 00841 BOOL CShakeNeighbour::OnHeadersCompleteG2() 00842 { 00843 // Report that a set of Gnutella2 headers from a remote computer are complete 00844 theApp.Message( MSG_DEBUG, _T("Headers Complete: G2 client") ); 00845 00846 // The remote computer replied to our headers with something other than "200 OK" 00847 if ( m_nState == nrsRejected ) 00848 { 00849 // Close the connection 00850 Close( 0 ); // Don't specify an error 00851 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00852 00853 } // We've been reading response headers from a remote computer that contacted us 00854 else if ( m_nState == nrsHandshake3 ) // We were reading the final header group from the remote computer 00855 { 00856 // (do) 00857 if ( m_bUltraPeerSet == TS_FALSE // The remote computer told us it's a leaf 00858 && m_nNodeType == ntNode // And this is a connection to a hub like us 00859 && ( Neighbours.IsG2Hub() || Neighbours.IsG2HubCapable() ) ) // And we're either a hub or capable of becoming one 00860 { 00861 // Report this case 00862 theApp.Message( MSG_DEFAULT, IDS_HANDSHAKE_BACK2LEAF, (LPCTSTR)m_sAddress ); 00863 00864 // This connection is to a leaf below us 00865 m_nNodeType = ntLeaf; 00866 } 00867 00868 // Turn this CShakeNeighbour object into a CG2Neighbour object 00869 OnHandshakeComplete(); 00870 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00871 00872 } // We initiated the connection 00873 else if ( m_bInitiated ) 00874 { 00875 // We'll set this flag to true if we need to tell the remote computer we're a leaf so we can connect 00876 BOOL bFallback = FALSE; 00877 00878 // We are a Gnutella2 hub, or at least we are capable of becomming one 00879 if ( Neighbours.IsG2Hub() || Neighbours.IsG2HubCapable() ) 00880 { 00881 // The remote computer sent us a header like "X-Ultrapeer: False" 00882 if ( m_bUltraPeerSet == TS_FALSE ) 00883 { 00884 // This connection is to a leaf below us 00885 m_nNodeType = ntLeaf; 00886 00887 } // The remote computer sent us headers like "X-Ultrapeer: True" and "X-Ultrapeer-Needed: True" 00888 else if ( m_bUltraPeerSet == TS_TRUE && m_bUltraPeerNeeded == TS_TRUE ) // && Network.NeedMoreHubs() ) 00889 { 00890 // Record that we are both hubs 00891 m_nNodeType = ntNode; 00892 00893 } // The remote computer is an hub that doesn't need connections to more hubs 00894 else if ( m_bUltraPeerSet == TS_TRUE && m_bUltraPeerNeeded == TS_FALSE ) 00895 { 00896 // If we are connected to any leaves 00897 if ( Neighbours.GetCount( PROTOCOL_G2, nrsConnected, ntLeaf ) > 0 ) 00898 { 00899 // Tell the remote computer we can't connect (do) 00900 SendHostHeaders( _T("GNUTELLA/0.6 503 I have leaves") ); 00901 DelayClose( IDS_HANDSHAKE_CANTBEPEER ); // Send the buffer then close the socket 00902 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00903 } 00904 00905 // If we are a Gnutella2 hub 00906 if ( Settings.Gnutella2.ClientMode == MODE_HUB ) 00907 { 00908 // We are a hub, and the remote computer doesn't need any more hub connections, tell it we can't connect 00909 SendHostHeaders( _T("GNUTELLA/0.6 503 Ultrapeer disabled") ); 00910 DelayClose( IDS_HANDSHAKE_NOULTRAPEER ); // Send the buffer then close the socket 00911 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00912 } 00913 00914 // We are or can become an ultrapeer, and the remote computer is an ultrapeer that doesn't need any more ultrapeer connections 00915 m_nNodeType = ntHub; // Pretend this connection is to a hub above us 00916 bFallback = TRUE; // We'll tell the remote computer we're a leaf so we can still connect 00917 } 00918 00919 } // The remote computer is a hub 00920 else if ( m_bUltraPeerSet == TS_TRUE ) 00921 { 00922 // And so are we 00923 if ( Settings.Gnutella2.ClientMode == MODE_HUB ) 00924 { 00925 // (do) 00926 SendHostHeaders( _T("GNUTELLA/0.6 503 Ultrapeer disabled") ); 00927 DelayClose( IDS_HANDSHAKE_NOULTRAPEER ); // Send the buffer then close the socket 00928 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00929 } 00930 00931 // This connection is to a hub above us 00932 m_nNodeType = ntHub; 00933 00934 } // The remote computer is a leaf, or it hasn't told us yet 00935 else if ( m_bUltraPeerSet != TS_TRUE ) 00936 { 00937 // We are a leaf 00938 if ( Settings.Gnutella2.ClientMode == MODE_LEAF ) 00939 { 00940 // Tell the remote computer we can't connect because we need a hub 00941 SendHostHeaders( _T("GNUTELLA/0.6 503 Need an Ultrapeer") ); 00942 DelayClose( IDS_HANDSHAKE_NEEDAPEER ); // Send the buffer then close the socket 00943 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00944 } 00945 } 00946 00947 // If the connection doesn't fall into any of those error cases, accept it with a batch of reply headers 00948 m_pOutput->Print( "GNUTELLA/0.6 200 OK\r\n" ); // Accept the connection 00949 SendPrivateHeaders(); // Respond to each header, setting up Gnutella2 packets and compression 00950 if ( bFallback ) m_pOutput->Print( "X-Ultrapeer: False\r\n" ); // Tell it we're a leaf so we can still connect 00951 m_pOutput->Print( "\r\n" ); // Send a blank line to end this group of headers 00952 00953 // Turn this CShakeNeighbour object into a CG2Neighbour one, and delete this one 00954 OnHandshakeComplete(); 00955 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00956 00957 } // not rejected, not handshake3, not initiated (do) 00958 else 00959 { 00960 // We are a leaf 00961 if ( Neighbours.IsG2Leaf() ) 00962 { 00963 // Tell the remote computer we can't connect because we are a shielded leaf right now 00964 SendHostHeaders( _T("GNUTELLA/0.6 503 Shielded leaf node") ); 00965 DelayClose( IDS_HANDSHAKE_IAMLEAF ); // Send the buffer then close the socket 00966 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 00967 00968 } // We are a Gnutella2 hub, or at least we are capable of becomming one 00969 else if ( Neighbours.IsG2Hub() || Neighbours.IsG2HubCapable() ) 00970 { 00971 // The remote computer sent us the header "X-Ultrapeer: False" 00972 if ( m_bUltraPeerSet == TS_FALSE ) 00973 { 00974 // This connection is to a leaf below us 00975 m_nNodeType = ntLeaf; 00976 00977 } // The remote computer sent us the header "X-Ultrapeer: True" 00978 else if ( m_bUltraPeerSet == TS_TRUE ) 00979 { 00980 // Record that we are both hubs 00981 m_nNodeType = ntNode; 00982 } 00983 00984 } // The remote computer is an ultrapeer, and we are not running in hub mode 00985 else if ( m_bUltraPeerSet == TS_TRUE && ( Settings.Gnutella2.ClientMode != MODE_HUB ) ) 00986 { 00987 // This connection is to a hub above us 00988 m_nNodeType = ntHub; 00989 } 00990 00991 // If it's a leaf, check version, etc 00992 if ( m_nNodeType == ntLeaf ) 00993 { 00994 if ( m_bBadClient ) 00995 { 00996 // We don't allow these to act as a leaf. (resource use, etc) 00997 if ( m_bObsoleteClient ) 00998 { 00999 theApp.Message( MSG_ERROR, _T("Rejecting obsolete leaf client %s") , (LPCTSTR)m_sUserAgent ); 01000 m_pOutput->Print( "GNUTELLA/0.6 503 Update your client. www.shareaza.com\r\n" ); 01001 } 01002 else 01003 { 01004 theApp.Message( MSG_ERROR, _T("Rejecting bad leaf client %s") , (LPCTSTR)m_sUserAgent ); 01005 m_pOutput->Print( "GNUTELLA/0.6 503 Refused\r\n" ); 01006 } 01007 SendMinimalHeaders(); 01008 DelayClose( IDS_HANDSHAKE_SURPLUS ); 01009 return FALSE; 01010 } 01011 else if ( m_bObsoleteClient ) 01012 { 01013 // Check our loading. Old clients consume more resources, so we might not be able to accept it 01014 if ( Neighbours.GetCount(PROTOCOL_G2, nrsConnected ,ntLeaf ) > ( Settings.Gnutella2.NumLeafs / 2 ) ) 01015 { 01016 theApp.Message( MSG_ERROR, _T("Rejecting obsolete leaf %s (We are too full)") , (LPCTSTR)m_sUserAgent ); 01017 m_pOutput->Print( "GNUTELLA/0.6 503 Old client version, please update. www.shareaza.com\r\n" ); 01018 SendMinimalHeaders(); 01019 DelayClose( IDS_HANDSHAKE_SURPLUS ); 01020 return FALSE; 01021 } 01022 } 01023 else if ( ! m_bShareaza ) 01024 { 01025 // Check to see if we have enough free leaf slots. 01026 if ( Neighbours.GetCount(PROTOCOL_G2, nrsConnected ,ntLeaf ) > ( Settings.Gnutella2.NumLeafs - 5 ) ) 01027 { 01028 SendHostHeaders( _T("GNUTELLA/0.6 503 Maximum connections reached") ); 01029 DelayClose( IDS_HANDSHAKE_SURPLUS ); 01030 return FALSE; 01031 } 01032 } 01033 } 01034 01035 // If we don't need another connection to the role the remote computer is acting in 01036 if (( 01037 // If the remote computer is a leaf and we don't need any more 01038 m_nNodeType == ntLeaf // This connection is to a leaf below us 01039 && ! Neighbours.NeedMoreHubs( PROTOCOL_G2 ) // And the neighbours object says we don't need more Gnutella2 hubs or leaves 01040 && ! Neighbours.NeedMoreLeafs( PROTOCOL_G2 ) 01041 ) || ( 01042 01043 // Or, if the remote computer is a hub and we don't need any more 01044 m_nNodeType != ntLeaf // This connection isn't to a leaf below us 01045 && ! Neighbours.NeedMoreHubs( PROTOCOL_G2 ) // And the neighbours object says we don't need any more Gnutella2 hubs 01046 )) 01047 { 01048 // Tell the remote computer that we can't connect because we have too many connections already, and close the connection 01049 SendHostHeaders( _T("GNUTELLA/0.6 503 Maximum connections reached") ); // Send this error code along with some more IP addresses it can try 01050 DelayClose( IDS_HANDSHAKE_SURPLUS ); // Close the connection, but not until we've written the buffered outgoing data first 01051 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01052 01053 } // Or, if we're both in the same role on the network 01054 else if ( ( m_nNodeType == ntHub && ( Settings.Gnutella2.ClientMode == MODE_HUB ) ) || // We're both hubs 01055 ( m_nNodeType == ntLeaf && ( Settings.Gnutella2.ClientMode == MODE_LEAF ) ) ) // We're both leaves 01056 { 01057 // Tell the remote computer that we can't connect 01058 SendHostHeaders( _T("GNUTELLA/0.6 503 Ultrapeer disabled") ); // Send the error code along with more IP addresses the remote computer can try 01059 DelayClose( IDS_HANDSHAKE_NOULTRAPEER ); // Close the connection, but not until we've written the buffered outgoing data first 01060 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01061 01062 } // This connection isn't to a hub above us, and we're a leaf 01063 else if ( m_nNodeType != ntHub && ( Settings.Gnutella2.ClientMode == MODE_LEAF ) ) 01064 { 01065 // Tell the remote computer we can't connect because we need a hub 01066 SendHostHeaders( _T("GNUTELLA/0.6 503 Need an Ultrapeer") ); 01067 DelayClose( IDS_HANDSHAKE_NEEDAPEER ); // Send the buffer then close the socket 01068 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01069 01070 } // Otherwise, the connection is probably alright 01071 else 01072 { 01073 // Send reply headers to the remote computer 01074 m_pOutput->Print( "GNUTELLA/0.6 200 OK\r\n" ); // Start our group of response headers to the other computer with the 200 OK message 01075 SendPublicHeaders(); // Send the initial Gnutella2 headers 01076 SendPrivateHeaders(); // Send headers in response to those we got from the remote computer 01077 SendHostHeaders(); // Send the "X-Try-Ultrapeers" header with a list of other IP addresses running Gnutella 01078 01079 // If this connection is up to a hub or to a hub like us, and we need more hubs 01080 if ( m_nNodeType != ntLeaf && Neighbours.NeedMoreHubs( PROTOCOL_G2 ) ) 01081 { 01082 // And if we're a hub, so this connection must be to another hub 01083 if ( Settings.Gnutella2.ClientMode != MODE_LEAF ) 01084 { 01085 // Tell the remote computer we want more connections to hubs 01086 m_pOutput->Print( "X-Ultrapeer-Needed: True\r\n" ); 01087 } 01088 01089 } // This connection must be down to a leaf 01090 else 01091 { 01092 // And we're a leaf 01093 if ( Settings.Gnutella2.ClientMode != MODE_HUB ) 01094 { 01095 // Tell the remote computer we don't need any more hub connections 01096 m_pOutput->Print( "X-Ultrapeer-Needed: False\r\n" ); 01097 } 01098 } 01099 01100 // End this block of headers with a blank line 01101 m_pOutput->Print( "\r\n" ); 01102 m_nState = nrsHandshake1; // We've finished sending a group of headers, and await the response 01103 } 01104 } 01105 01106 // Have OnRead keep exchanging handshake headers with the remote computer 01107 return TRUE; 01108 } 01109 01110 // Called when CConnection::ReadHeaders calls ReadLine and gets a blank line, meaning a group of headers from the remote computer is done 01111 // Responds to the group of headers from the remote computer by closing the connection, sending response headers, or turning this into a Gnutella object 01112 // Returns false to delete this object, or true to keep reading headers and negotiating the handshake 01113 BOOL CShakeNeighbour::OnHeadersCompleteG1() 01114 { 01115 // Report that a set of Gnutella headers from a remote computer are complete 01116 theApp.Message( MSG_DEBUG, _T("Headers Complete: G1 client") ); 01117 01118 // Check if Gnutella1 is enabled before connecting to a gnutella client 01119 if ( ! Settings.Gnutella1.EnableToday && m_nState < nrsRejected ) // And make sure the state is before getting rejected 01120 { 01121 // Tell the remote computer that we're only connecting to Gnutella2 today 01122 m_pOutput->Print( "GNUTELLA/0.6 503 G2 Required\r\n" ); 01123 SendMinimalHeaders(); // Tell the remote computer we're Shareaza and we can exchange Gnutella2 packets 01124 m_pOutput->Print( "\r\n" ); // End the group of headers with a blank line 01125 01126 // Tell the host cache that this didn't work out 01127 HostCache.OnFailure( &m_pHost.sin_addr, htons( m_pHost.sin_port ) ); 01128 01129 // Close the connection citing not Gnutella2 as the reason, but send the departing buffer first 01130 DelayClose( IDS_HANDSHAKE_NOTG2 ); 01131 01132 // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01133 return FALSE; 01134 } 01135 01136 // The remote computer started with "GNUTELLA/0.6", but did not say "200 OK" 01137 if ( m_nState == nrsRejected ) 01138 { 01139 // Close the connection 01140 Close( 0 ); // Don't specify an error 01141 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01142 01143 } // We've been reading response headers from a remote computer that contacted us 01144 else if ( m_nState == nrsHandshake3 ) // We're reading the final header group from the remote computer 01145 { 01146 // If we're both leaves, and yet somehow we're also either an ultrapeer or can become one (do) 01147 if ( m_bUltraPeerSet == TS_FALSE && m_nNodeType == ntNode && // The remote computer is a hub and so are we 01148 ( Neighbours.IsG1Ultrapeer() || Neighbours.IsG1UltrapeerCapable() ) ) // And, we're either a Gnutella ultrapeer or we could become one 01149 { 01150 // Report that the handshake is back to a leaf (do), and consider this connection to be to a leaf below us 01151 theApp.Message( MSG_DEFAULT, IDS_HANDSHAKE_BACK2LEAF, (LPCTSTR)m_sAddress ); 01152 m_nNodeType = ntLeaf; // This connection is to a leaf below us 01153 } 01154 01155 // Turn this CShakeNeighbour object into a CG1Neighbour object 01156 OnHandshakeComplete(); 01157 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01158 01159 } // We initiated the connection to the remote computer 01160 else if ( m_bInitiated ) 01161 { 01162 // We'll set this flag to true if we need to tell the remote computer we're a leaf so we can connect 01163 BOOL bFallback = FALSE; 01164 01165 // We are an ultrapeer or at least we are capable of becomming one 01166 if ( Neighbours.IsG1Ultrapeer() || Neighbours.IsG1UltrapeerCapable() ) 01167 { 01168 // The remote computer told us "X-Ultrapeer: False" 01169 if ( m_bUltraPeerSet == TS_FALSE ) 01170 { 01171 // This connection is to a leaf below us 01172 m_nNodeType = ntLeaf; 01173 01174 } // The remote computer told us it's an ultrapeer and that it needs connections to more ultrapeers 01175 else if ( m_bUltraPeerSet == TS_TRUE && m_bUltraPeerNeeded == TS_TRUE ) 01176 { 01177 // Record that we are both ultrapeers 01178 m_nNodeType = ntNode; 01179 01180 } // The remote computer is an ultrapeer that doesn't need any more ultrapeer connections 01181 else if ( m_bUltraPeerSet == TS_TRUE && m_bUltraPeerNeeded == TS_FALSE ) 01182 { 01183 // (do) 01184 if ( Neighbours.GetCount( PROTOCOL_G1, nrsConnected, ntLeaf ) > 0 ) 01185 { 01186 // Tell the remote computer we can't connect (do) 01187 SendHostHeaders( _T("GNUTELLA/0.6 503 I have leaves") ); 01188 DelayClose( IDS_HANDSHAKE_CANTBEPEER ); // Send the buffer then close the socket 01189 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01190 } 01191 01192 // We are an ultrapeer 01193 if ( Settings.Gnutella1.ClientMode == MODE_ULTRAPEER ) 01194 { 01195 // Tell the remote computer we can't connect 01196 SendHostHeaders( _T("GNUTELLA/0.6 503 Ultrapeer disabled") ); 01197 DelayClose( IDS_HANDSHAKE_NOULTRAPEER ); // Send the buffer then close the socket 01198 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01199 } 01200 01201 // We are or can become an ultrapeer, and the remote computer is an ultrapeer that doesn't need any more ultrapeer connections 01202 m_nNodeType = ntHub; // Pretend this connection is to a hub above us 01203 bFallback = TRUE; // We'll tell the remote computer we're a leaf so we can still connect 01204 } 01205 01206 } // We're a leaf, and the remote computer is an ultrapeer 01207 else if ( m_bUltraPeerSet == TS_TRUE ) 01208 { 01209 // We are an ultrapeer 01210 if ( Settings.Gnutella1.ClientMode == MODE_ULTRAPEER ) 01211 { 01212 // Tell the remote computer we can't connect 01213 SendHostHeaders( _T("GNUTELLA/0.6 503 Ultrapeer disabled") ); 01214 DelayClose( IDS_HANDSHAKE_NOULTRAPEER ); // Send the buffer then close the socket 01215 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01216 } 01217 01218 // This connection is to a hub above us 01219 m_nNodeType = ntHub; 01220 01221 } // The remote computer is a leaf 01222 else if ( m_bUltraPeerSet != TS_TRUE ) 01223 { 01224 // And so are we 01225 if ( Settings.Gnutella1.ClientMode == MODE_LEAF ) 01226 { 01227 // Tell the remote computer that we can't connect because we're both leaves 01228 SendHostHeaders( _T("GNUTELLA/0.6 503 Need an Ultrapeer") ); 01229 DelayClose( IDS_HANDSHAKE_NEEDAPEER ); // Send the buffer, close the socket, cite need a peer as the reason 01230 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01231 } 01232 } 01233 01234 // Tell the remote computer that we accept the connection, and send reply headers 01235 m_pOutput->Print( "GNUTELLA/0.6 200 OK\r\n" ); // Begin our response headers with the OK message 01236 SendPrivateHeaders(); // Respond to each header, setting up Gnutella2 packets and compression 01237 01238 // If we are an ultrapeer or could become one, but the remote computer is an ultrapeer that doesn't need any more ultrapeer connections 01239 if ( bFallback ) m_pOutput->Print( "X-Ultrapeer: False\r\n" ); // Tell it we're a leaf so we can still connect 01240 01241 // Send a blank line to end this group of headers 01242 m_pOutput->Print( "\r\n" ); 01243 01244 // Turn this CShakeNeighbour object into a CG1Neighbour one, and delete this one 01245 OnHandshakeComplete(); 01246 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01247 01248 } // not rejected, not handshake3, not initiated (do) 01249 else 01250 { 01251 // We are a leaf 01252 if ( Neighbours.IsG1Leaf() ) 01253 { 01254 // Tell the remote computer we can't connect because we are a shielded leaf right now 01255 SendHostHeaders( _T("GNUTELLA/0.6 503 Shielded leaf node") ); 01256 DelayClose( IDS_HANDSHAKE_IAMLEAF ); // Send the buffer and then close the socket citing our being a leaf as the reason 01257 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01258 01259 } // We are an ultrapeer, or at least we are capable of becomming one 01260 else if ( Neighbours.IsG1Ultrapeer() || Neighbours.IsG1UltrapeerCapable() ) 01261 { 01262 // The remote computer told us it is a leaf 01263 if ( m_bUltraPeerSet == TS_FALSE ) 01264 { 01265 // This connection is to a leaf below us 01266 m_nNodeType = ntLeaf; 01267 01268 } // The remote computer told us it is an ultrapeer 01269 else if ( m_bUltraPeerSet == TS_TRUE ) 01270 { 01271 // Record that we are both ultrapeers 01272 m_nNodeType = ntNode; 01273 } 01274 01275 } // The remote computer is an ultrapeer, but we are just a leaf 01276 else if ( m_bUltraPeerSet == TS_TRUE && ( Settings.Gnutella1.ClientMode != MODE_ULTRAPEER ) ) 01277 { 01278 // This connection is to a hub above us 01279 m_nNodeType = ntHub; 01280 } 01281 01282 // If we don't need this connection 01283 if ( ( m_nNodeType == ntLeaf && ! Neighbours.NeedMoreHubs( PROTOCOL_G1 ) && // This connection is to a leaf below us, and we don't need more hubs/leaves 01284 ! Neighbours.NeedMoreLeafs( PROTOCOL_G1 ) ) || 01285 ( m_nNodeType != ntLeaf && ! Neighbours.NeedMoreHubs( PROTOCOL_G1 ) ) || // This connection is to a hub and we don't need more hubs 01286 ( ( m_nNodeType != ntHub ) && ( m_bObsoleteClient || m_bBadClient ) ) ) // This is an obsolete version of Shareaza 01287 { 01288 // Tell the remote computer we can't connect because we already have too many connections 01289 SendHostHeaders( _T("GNUTELLA/0.6 503 Maximum connections reached") ); 01290 DelayClose( IDS_HANDSHAKE_SURPLUS ); // Send the buffer then close the socket 01291 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01292 01293 } // Weed out this nonsense combination that should never happen 01294 else if ( ( m_nNodeType == ntHub && ( Settings.Gnutella1.ClientMode == MODE_ULTRAPEER ) ) || // This connection is up to a hub, and we are a hub 01295 ( m_nNodeType == ntLeaf && ( Settings.Gnutella1.ClientMode == MODE_LEAF ) ) ) // Or, this connection is down to a leaf like us 01296 { 01297 // Tell the remote computer we can't connect 01298 SendHostHeaders( _T("GNUTELLA/0.6 503 Ultrapeer disabled") ); 01299 DelayClose( IDS_HANDSHAKE_NOULTRAPEER ); // Send the buffer then close the socket 01300 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01301 01302 } // Weed out another nonsense combination that should never happen 01303 else if ( m_nNodeType != ntHub && ( Settings.Gnutella1.ClientMode == MODE_LEAF ) ) 01304 { 01305 // Tell the remote computer we can't connect 01306 SendHostHeaders( _T("GNUTELLA/0.6 503 Need an Ultrapeer") ); 01307 DelayClose( IDS_HANDSHAKE_NEEDAPEER ); // Send the buffer then close the socket 01308 return FALSE; // Return false all the way back to CHandshakes::RunHandshakes, which will delete this object 01309 01310 } // Otherwise, the connection is probably alright 01311 else 01312 { 01313 // Send reply headers to the remote computer 01314 m_pOutput->Print( "GNUTELLA/0.6 200 OK\r\n" ); // Start our group of response headers to the other computer with the 200 OK message 01315 SendPublicHeaders(); // Send the initial Gnutella headers 01316 SendPrivateHeaders(); // Send headers in response to those we got from the remote computer 01317 SendHostHeaders(); // Send the "X-Try-Ultrapeers" header with a list of other IP addresses running Gnutella 01318 01319 // If this connection is up to a hub or to a hub like us, and we need more hubs 01320 if ( m_nNodeType != ntLeaf && Neighbours.NeedMoreHubs( PROTOCOL_G1 ) ) 01321 { 01322 // And if we're a hub, so this connection must be to another hub 01323 if ( Settings.Gnutella1.ClientMode != MODE_LEAF ) 01324 { 01325 // Tell the remote computer we want more connections to hubs 01326 m_pOutput->Print( "X-Ultrapeer-Needed: True\r\n" ); 01327 } 01328 01329 } // This connection must be down to a leaf 01330 else 01331 { 01332 // And we're a leaf 01333 if ( Settings.Gnutella1.ClientMode != MODE_ULTRAPEER ) 01334 { 01335 // Tell the remote computer we don't need any more hub connections 01336 m_pOutput->Print( "X-Ultrapeer-Needed: False\r\n" ); 01337 } 01338 } 01339 01340 // End this block of headers with a blank line 01341 m_pOutput->Print( "\r\n" ); 01342 m_nState = nrsHandshake1; // We've finished sending a group of headers, and await the response 01343 } 01344 } 01345 01346 // Have OnRead keep exchanging handshake headers with the remote computer 01347 return TRUE; 01348 } 01349 01351 // CShakeNeighbour handshake completed 01352 01353 // Creates a new GC1Neighbour or CG2Neighbour object based on this one, and deletes this one 01354 void CShakeNeighbour::OnHandshakeComplete() 01355 { 01356 // Remove this CShakeNeighbour object from the list of them the neighbours object keeps 01357 Neighbours.Remove( this ); 01358 01359 // Point the bandwidth meter limits at the numbers from Shareaza Settings 01360 switch ( m_nNodeType ) { 01361 case ntHub: 01362 01363 // Point the limits at the settings for connections to hubs above us 01364 m_mInput.pLimit = &Settings.Bandwidth.HubIn; 01365 m_mOutput.pLimit = &Settings.Bandwidth.HubOut; 01366 01367 break; 01368 01369 // This connection is to a leaf below us 01370 case ntLeaf: 01371 01372 // Point the limits at the settings for connections to leaves below us 01373 m_mInput.pLimit = &Settings.Bandwidth.LeafIn; 01374 m_mOutput.pLimit = &Settings.Bandwidth.LeafOut; 01375 01376 break; 01377 01378 // We are both hubs 01379 case ntNode: 01380 01381 // Point the limits at the settings for peer hub-to-hub connections 01382 m_mInput.pLimit = &Settings.Bandwidth.PeerIn; 01383 m_mOutput.pLimit = &Settings.Bandwidth.PeerOut; 01384 01385 break; 01386 } 01387 01388 // If the remote computer supports compression, setup buffers for arriving and departing compressed data 01389 if ( m_bDeflateSend ) m_pZInput = new CBuffer(); // The remote computer said "Content-Encoding: deflate", make a buffer for compressed data coming in 01390 if ( m_bDeflateAccept ) m_pZOutput = new CBuffer(); // The remote computer said "Accept-Encoding: deflate", make a buffer for data to compress before sending 01391 01392 // If Shareaza Settings specify a size for the send buffer 01393 if ( Settings.Connection.SendBuffer ) // By default, this is 2048, which is 2 KB of space 01394 { 01395 // Tell the socket to use a 2 KB buffer for sends 01396 setsockopt( // Set a socket option 01397 m_hSocket, // The socket this CShakeNeighbour object inherited from CConnection 01398 SOL_SOCKET, // Define this option at the socket level 01399 SO_SNDBUF, // Specify the total per-socket buffer space reserved for sends 01400 (LPSTR)&Settings.Connection.SendBuffer, // Use the value from Shareaza Settings, 2 KB by default 01401 4 ); // SendBuffer is a DWORD, occupying 4 bytes of memory 01402 } 01403 01404 // Make a pointer for a new object that will be a copy of this one, but in a different place on the CConnection inheritance tree 01405 CNeighbour* pNeighbour = NULL; 01406 01407 // If the remote computer is G2, or can send and understand Gnutella2 packets and isn't G1 01408 if ( ( m_nProtocol == PROTOCOL_G2 ) || ( m_bG2Send && m_bG2Accept && ( m_nProtocol != PROTOCOL_G1 ) ) ) 01409 { 01410 // Record that the remote computer supports query routing 01411 m_bQueryRouting = TRUE; 01412 01413 // Make a new Gnutella2 neighbour object by copying values from this ShakeNeighbour one 01414 pNeighbour = new CG2Neighbour( this ); 01415 01416 } 01417 else // The remote computer is just Gnutella, not Gnutella2 01418 { 01419 // Record that the remote computer is not running Shareaza 01420 m_bShareaza = FALSE; 01421 01422 // Make a new Gnutella neighbour object by copying values from this ShakeNeighbour one 01423 pNeighbour = new CG1Neighbour( this ); 01424 } 01425 01426 // This connection is to a hub above us 01427 if ( m_nNodeType == ntHub ) 01428 { 01429 // Report that we got a ultrapeer connection 01430 theApp.Message( MSG_DEFAULT, IDS_HANDSHAKE_GOTPEER ); 01431 01432 // (do) 01433 Neighbours.PeerPrune( pNeighbour->m_nProtocol ); 01434 01435 } // This connection is to a leaf below us 01436 else if ( m_nNodeType == ntLeaf ) 01437 { 01438 // Report that we connected to a leaf 01439 theApp.Message( MSG_DEFAULT, IDS_HANDSHAKE_GOTLEAF, (LPCTSTR)m_sAddress ); 01440 } 01441 01442 // When we copied the object, the pointers to buffers were also copied, null them here so deleting this doesn't delete them 01443 m_pZInput = NULL; 01444 m_pZOutput = NULL; 01445 01446 // Delete this CShakeNeighbour object now that it has been turned into a CG1Neighbour or CG2Neighbour object 01447 delete this; 01448 } 01449 01450 01452 // CShakeNeighbour IsClientObsolete 01453 01454 // Checks the user agent to see if it's an outdated client. (An old Shareaza beta, or something) 01455 BOOL CShakeNeighbour::IsClientObsolete() 01456 { 01457 if ( m_sUserAgent.IsEmpty() ) return TRUE; 01458 01459 if ( _tcsistr( m_sUserAgent, _T("Shareaza") ) ) 01460 { 01461 // Shareaza client 01462 01463 // Check for fakes / version hacks. 01464 if (( _tcsistr( m_sUserAgent, _T("Shareaza 3.0" ) ) ) || // Fakes 01465 ( _tcsistr( m_sUserAgent, _T("Shareaza 6." ) ) ) || 01466 ( _tcsistr( m_sUserAgent, _T("Shareaza 7." ) ) ) ) 01467 return TRUE; 01468 01469 // Check for old version and betas 01470 if (( _tcsistr( m_sUserAgent, _T("Shareaza 1." ) ) ) || // Old versions 01471 ( _tcsistr( m_sUserAgent, _T("Shareaza 2.0." ) ) ) ) 01472 return TRUE; 01473 01474 // Assumed to be reasonably current 01475 return FALSE; 01476 } 01477 else if ( _tcsistr( m_sUserAgent, _T("gnucdna") ) ) 01478 { 01479 // DNA based client 01480 01481 // Assumed to be reasonably current 01482 return FALSE; 01483 } 01484 else if ( _tcsistr( m_sUserAgent, _T("trustyfiles") ) ) 01485 { 01486 // TrustyFiles- assume up to date 01487 return FALSE; 01488 } 01489 else if ( _tcsistr( m_sUserAgent, _T("adagio") ) ) 01490 { 01491 // Adagio- assume up to date 01492 return FALSE; 01493 } 01494 else if ( _tcsistr( m_sUserAgent, _T("eTomi") ) ) 01495 { 01496 // GPL violating rip- Uses outdated code 01497 return TRUE; 01498 } 01499 01500 return FALSE; 01501 } 01502 01504 // CShakeNeighbour IsClientBad 01505 01506 // Checks the user agent to see if it's a GPL breaker, or other trouble-maker 01507 BOOL CShakeNeighbour::IsClientBad() 01508 { 01509 // No user agent- assume OK 01510 if ( m_sUserAgent.IsEmpty() ) return FALSE; 01511 01512 // Known good clients 01513 if ( _tcsistr( m_sUserAgent, _T("gnucdna") ) ) return FALSE; 01514 01515 if ( _tcsistr( m_sUserAgent, _T("adagio") ) ) return FALSE; 01516 01517 if ( _tcsistr( m_sUserAgent, _T("shareaza") ) ) return FALSE; 01518 01519 if ( _tcsistr( m_sUserAgent, _T("trustyfiles") ) ) return FALSE; 01520 01521 // GPL breakers- Clients violating the GPL 01522 // See http://www.gnu.org/copyleft/gpl.html 01523 if ( _tcsistr( m_sUserAgent, _T("K-Lite") ) ) return TRUE; 01524 01525 if ( _tcsistr( m_sUserAgent, _T("SlingerX") ) ) return TRUE; 01526 01527 if ( _tcsistr( m_sUserAgent, _T("C -3.0.1") ) ) return TRUE; 01528 01529 if ( _tcsistr( m_sUserAgent, _T("vagaa") ) ) return TRUE; 01530 01531 if ( _tcsistr( m_sUserAgent, _T("mxie") ) ) return TRUE; 01532 01533 // Clients that over-query or otherwise cause problems 01534 //if ( _tcsistr( m_sUserAgent, _T("") ) ) return TRUE; 01535 01536 01537 // Unknown- Assume OK 01538 return FALSE; 01539 } 01540 01541 01543 // CShakeNeighbour IsClientBanned 01544 01545 // Checks the user agent to see if it's a leecher client, or other banned client 01546 BOOL CShakeNeighbour::IsClientBanned() 01547 { 01548 // No user agent- assume OK 01549 if ( m_sUserAgent.IsEmpty() ) return FALSE; 01550 01551 // Unknown- Assume OK 01552 return FALSE; 01553 } 01554