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

Datagrams.cpp

Go to the documentation of this file.
00001 //
00002 // Datagrams.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 "Statistics.h"
00026 #include "Network.h"
00027 #include "Datagrams.h"
00028 #include "Datagram.h"
00029 #include "DatagramPart.h"
00030 #include "Buffer.h"
00031 
00032 #include "Handshakes.h"
00033 #include "Neighbours.h"
00034 #include "Neighbour.h"
00035 #include "RouteCache.h"
00036 #include "LocalSearch.h"
00037 #include "SearchManager.h"
00038 #include "QuerySearch.h"
00039 #include "QueryHit.h"
00040 #include "GProfile.h"
00041 #include "CrawlSession.h"
00042 
00043 #include "G2Neighbour.h"
00044 #include "G2Packet.h"
00045 #include "EDClients.h"
00046 #include "EDPacket.h"
00047 #include "Security.h"
00048 #include "HostCache.h"
00049 #include "QueryKeys.h"
00050 #include "LibraryMaps.h"
00051 
00052 #ifdef _DEBUG
00053 #undef THIS_FILE
00054 static char THIS_FILE[]=__FILE__;
00055 #define new DEBUG_NEW
00056 #endif
00057 
00058 #define HASH_SIZE               32
00059 #define HASH_MASK               31
00060 
00061 #define TEMP_BUFFER             4096
00062 #define METER_MINIMUM   100
00063 #define METER_LENGTH    24
00064 #define METER_PERIOD    2000
00065 #define METER_SECOND    1000
00066 
00067 CDatagrams Datagrams;
00068 
00069 
00071 // CDatagrams construction
00072 
00073 CDatagrams::CDatagrams()
00074 {
00075         m_hSocket       = INVALID_SOCKET;
00076         m_nSequence     = 0;
00077         m_bStable       = FALSE;
00078 
00079         ZeroMemory( &m_mInput, sizeof(m_mInput) );
00080         ZeroMemory( &m_mOutput, sizeof(m_mOutput) );
00081 
00082         m_nInBandwidth  = m_nInFrags    = m_nInPackets  = 0;
00083         m_nOutBandwidth = m_nOutFrags   = m_nOutPackets = 0;
00084 }
00085 
00086 CDatagrams::~CDatagrams()
00087 {
00088         Disconnect();
00089 }
00090 
00092 // CDatagrams listen
00093 
00094 BOOL CDatagrams::Listen()
00095 {
00096         if ( m_hSocket != INVALID_SOCKET ) return FALSE;
00097 
00098         m_hSocket = socket( PF_INET, SOCK_DGRAM, IPPROTO_UDP );
00099         if ( m_hSocket == INVALID_SOCKET ) return FALSE;
00100 
00101         SOCKADDR_IN saHost;
00102 
00103         if ( Network.Resolve( Settings.Connection.InHost, Settings.Connection.InPort, &saHost ) )
00104         {
00105                 // Inbound resolved
00106                 if ( ! Settings.Connection.InBind ) saHost.sin_addr.S_un.S_addr = 0;
00107         }
00108         else if ( Network.Resolve( Settings.Connection.OutHost, Settings.Connection.InPort, &saHost ) )
00109         {
00110                 // Outbound resolved
00111         }
00112         else
00113         {
00114                 saHost = Network.m_pHost;
00115                 if ( ! Settings.Connection.InBind ) saHost.sin_addr.S_un.S_addr = 0;
00116         }
00117 
00118         if ( bind( m_hSocket, (SOCKADDR*)&saHost, sizeof(saHost) ) == 0 )
00119         {
00120                 theApp.Message( MSG_DEFAULT, IDS_NETWORK_LISTENING_UDP,
00121                         (LPCTSTR)CString( inet_ntoa( saHost.sin_addr ) ), htons( saHost.sin_port ) );
00122         }
00123 
00124         WSAEventSelect( m_hSocket, Network.m_pWakeup, FD_READ );
00125 
00126         m_nBufferBuffer = Settings.Gnutella2.UdpBuffers; // 256;
00127         m_pBufferBuffer = new CBuffer[ m_nBufferBuffer ];
00128         m_pBufferFree   = m_pBufferBuffer;
00129         m_nBufferFree   = m_nBufferBuffer;
00130 
00131         CBuffer* pBuffer = m_pBufferBuffer;
00132 
00133         for ( DWORD nPos = m_nBufferBuffer ; nPos ; nPos--, pBuffer++ )
00134         {
00135                 pBuffer->m_pNext = ( nPos == 1 ) ? NULL : ( pBuffer + 1 );
00136         }
00137 
00138         m_nInputBuffer  = Settings.Gnutella2.UdpInFrames; // 128;
00139         m_pInputBuffer  = new CDatagramIn[ m_nInputBuffer ];
00140         m_pInputFree    = m_pInputBuffer;
00141 
00142         CDatagramIn* pDGI = m_pInputBuffer;
00143 
00144         for ( DWORD nPos = m_nInputBuffer ; nPos ; nPos--, pDGI++ )
00145         {
00146                 pDGI->m_pNextHash = ( nPos == 1 ) ? NULL : ( pDGI + 1 );
00147         }
00148 
00149         m_nOutputBuffer = Settings.Gnutella2.UdpOutFrames; // 128;
00150         m_pOutputBuffer = new CDatagramOut[ m_nOutputBuffer ];
00151         m_pOutputFree   = m_pOutputBuffer;
00152 
00153         CDatagramOut* pDGO = m_pOutputBuffer;
00154 
00155         for ( DWORD nPos = m_nOutputBuffer ; nPos ; nPos--, pDGO++ )
00156         {
00157                 pDGO->m_pNextHash = ( nPos == 1 ) ? NULL : ( pDGO + 1 );
00158         }
00159 
00160         ZeroMemory( m_pInputHash,  sizeof(CDatagramIn*) * HASH_SIZE );
00161         ZeroMemory( m_pOutputHash, sizeof(CDatagramIn*) * HASH_SIZE );
00162 
00163         m_pInputFirst   = m_pInputLast  = NULL;
00164         m_pOutputFirst  = m_pOutputLast = NULL;
00165 
00166         m_tLastWrite = 0;
00167 
00168         m_nInFrags      = m_nInPackets = 0;
00169         m_nOutFrags     = m_nOutPackets = 0;
00170 
00171         return TRUE;
00172 }
00173 
00175 // CDatagrams disconnect
00176 
00177 void CDatagrams::Disconnect()
00178 {
00179         if ( m_hSocket == INVALID_SOCKET ) return;
00180 
00181         closesocket( m_hSocket );
00182         m_hSocket = INVALID_SOCKET;
00183 
00184         delete [] m_pOutputBuffer;
00185         m_pOutputBuffer = NULL;
00186         m_nOutputBuffer = 0;
00187         m_pOutputFirst = m_pOutputLast = m_pOutputFree = NULL;
00188 
00189         delete [] m_pInputBuffer;
00190         m_pInputBuffer = NULL;
00191         m_nInputBuffer = 0;
00192         m_pInputFirst = m_pInputLast = m_pInputFree = NULL;
00193 
00194         delete [] m_pBufferBuffer;
00195         m_pBufferBuffer = NULL;
00196         m_nBufferBuffer = 0;
00197 
00198         m_nInBandwidth  = m_nInFrags    = m_nInPackets  = 0;
00199         m_nOutBandwidth = m_nOutFrags   = m_nOutPackets = 0;
00200 }
00201 
00203 // CDatagrams stable test
00204 
00205 BOOL CDatagrams::IsStable()
00206 {
00207         if ( m_hSocket == INVALID_SOCKET ) return FALSE;
00208         if ( ! Network.IsListening() ) return FALSE;
00209 
00210         if ( Settings.Connection.FirewallStatus == CONNECTION_FIREWALLED )
00211                 return FALSE;                   // We know we are firewalled
00212         else if ( Settings.Connection.FirewallStatus == CONNECTION_OPEN )
00213                 return TRUE;                    // We know we are not firewalled
00214         else // ( Settings.Connection.FirewallStatus == CONNECTION_AUTO )
00215                 return m_bStable;               // Use detected state
00216 }
00217 
00219 // CDatagrams send
00220 
00221 BOOL CDatagrams::Send(IN_ADDR* pAddress, WORD nPort, CPacket* pPacket, BOOL bRelease, LPVOID pToken, BOOL bAck)
00222 {
00223         SOCKADDR_IN pHost;
00224 
00225         pHost.sin_family        = PF_INET;
00226         pHost.sin_addr          = *pAddress;
00227         pHost.sin_port          = htons( nPort );
00228 
00229         return Send( &pHost, pPacket, bRelease, pToken, bAck );
00230 }
00231 
00232 BOOL CDatagrams::Send(SOCKADDR_IN* pHost, CPacket* pPacket, BOOL bRelease, LPVOID pToken, BOOL bAck)
00233 {
00234         ASSERT( pHost != NULL && pPacket != NULL );
00235 
00236         if ( m_hSocket == INVALID_SOCKET || Security.IsDenied( &pHost->sin_addr ) )
00237         {
00238                 if ( bRelease ) pPacket->Release();
00239                 return FALSE;
00240         }
00241 
00242         if ( pPacket->m_nProtocol == PROTOCOL_ED2K )
00243         {
00244                 CBuffer pBuffer;
00245 
00246                 ((CEDPacket*)pPacket)->ToBufferUDP( &pBuffer );
00247                 pPacket->SmartDump( NULL, &pHost->sin_addr, TRUE );
00248                 if ( bRelease ) pPacket->Release();
00249 
00250                 if ( ntohs( pHost->sin_port ) != 4669 ) // Hack
00251                 {
00252                         sendto( m_hSocket, (LPSTR)pBuffer.m_pBuffer, pBuffer.m_nLength, 0,
00253                                 (SOCKADDR*)pHost, sizeof(SOCKADDR_IN) );
00254                 }
00255 
00256                 return TRUE;
00257         }
00258         else if ( pPacket->m_nProtocol != PROTOCOL_G2 )
00259         {
00260                 if ( bRelease ) pPacket->Release();
00261                 return FALSE;
00262         }
00263 
00264         if ( m_pOutputFree == NULL || m_pBufferFree == NULL )
00265         {
00266                 if ( m_pOutputLast == NULL )
00267                 {
00268                         if ( bRelease ) pPacket->Release();
00269                         theApp.Message( MSG_DEBUG, _T("CDatagrams output frames exhausted.") );
00270                         return FALSE;
00271                 }
00272                 Remove( m_pOutputLast );
00273         }
00274 
00275         if ( m_pBufferFree == NULL )
00276         {
00277                 if ( bRelease ) pPacket->Release();
00278                 theApp.Message( MSG_DEBUG, _T("CDatagrams output frames really exhausted.") );
00279                 return FALSE;
00280         }
00281 
00282         CDatagramOut* pDG = m_pOutputFree;
00283         m_pOutputFree = m_pOutputFree->m_pNextHash;
00284 
00285         if ( m_nInFrags < 1 ) bAck = FALSE;
00286 
00287         pDG->Create( pHost, (CG2Packet*)pPacket, m_nSequence++, m_pBufferFree, bAck );
00288 
00289         m_pBufferFree = m_pBufferFree->m_pNext;
00290         m_nBufferFree--;
00291 
00292         pDG->m_pToken           = pToken;
00293         pDG->m_pNextTime        = NULL;
00294         pDG->m_pPrevTime        = m_pOutputFirst;
00295 
00296         if ( m_pOutputFirst )
00297                 m_pOutputFirst->m_pNextTime = pDG;
00298         else
00299                 m_pOutputLast = pDG;
00300 
00301         m_pOutputFirst = pDG;
00302 
00303         BYTE nHash      = pHost->sin_addr.S_un.S_un_b.s_b1
00304                                 + pHost->sin_addr.S_un.S_un_b.s_b2
00305                                 + pHost->sin_addr.S_un.S_un_b.s_b3
00306                                 + pHost->sin_addr.S_un.S_un_b.s_b4
00307                                 + pHost->sin_port
00308                                 + pDG->m_nSequence;
00309 
00310         CDatagramOut** pHash = m_pOutputHash + ( nHash & HASH_MASK );
00311 
00312         if ( *pHash ) (*pHash)->m_pPrevHash = &pDG->m_pNextHash;
00313         pDG->m_pNextHash = *pHash;
00314         pDG->m_pPrevHash = pHash;
00315         *pHash = pDG;
00316 
00317         m_nOutPackets++;
00318 
00319         pPacket->SmartDump( NULL, &pHost->sin_addr, TRUE );
00320 
00321 #ifdef DEBUG_UDP
00322         pPacket->Debug( _T("UDP Out") );
00323         theApp.Message( MSG_DEBUG, _T("UDP: Queued (#%i) x%i for %s:%lu"),
00324                 pDG->m_nSequence, pDG->m_nCount,
00325                 (LPCTSTR)CString( inet_ntoa( pDG->m_pHost.sin_addr ) ),
00326                 htons( pDG->m_pHost.sin_port ) );
00327 #endif
00328 
00329         if ( bRelease ) pPacket->Release();
00330 
00331         TryWrite();
00332 
00333         return TRUE;
00334 }
00335 
00337 // CDatagrams purge outbound fragments with a specified token
00338 
00339 void CDatagrams::PurgeToken(LPVOID pToken)
00340 {
00341         CSingleLock pLock( &Network.m_pSection );
00342         if ( ! pLock.Lock( 100 ) ) return;
00343 
00344         int nCount = 0;
00345 
00346         for ( CDatagramOut* pDG = m_pOutputLast ; pDG ; )
00347         {
00348                 CDatagramOut* pNext = pDG->m_pNextTime;
00349 
00350                 if ( pDG->m_pToken == pToken )
00351                 {
00352                         Remove( pDG );
00353                         nCount++;
00354                 }
00355 
00356                 pDG = pNext;
00357         }
00358 
00359         if ( nCount ) theApp.Message( MSG_DEBUG, _T("CDatagrams::PurgeToken() = %i"), nCount );
00360 }
00361 
00363 // CDatagrams run event handler
00364 
00365 void CDatagrams::OnRun()
00366 {
00367         if ( m_hSocket == INVALID_SOCKET ) return;
00368 
00369         TryWrite();
00370         ManageOutput();
00371 
00372         do
00373         {
00374                 ManagePartials();
00375         }
00376         while ( TryRead() );
00377 
00378         Measure();
00379 }
00380 
00382 // CDatagrams measure
00383 
00384 void CDatagrams::Measure()
00385 {
00386         DWORD tCutoff           = GetTickCount() - METER_PERIOD;
00387         DWORD* pInHistory       = m_mInput.pHistory;
00388         DWORD* pInTime          = m_mInput.pTimes;
00389         DWORD* pOutHistory      = m_mOutput.pHistory;
00390         DWORD* pOutTime         = m_mOutput.pTimes;
00391         DWORD nInput            = 0;
00392         DWORD nOutput           = 0;
00393 
00394         for ( int tNow = METER_LENGTH ; tNow ; tNow-- )
00395         {
00396                 if ( *pInTime >= tCutoff ) nInput += *pInHistory;
00397                 if ( *pOutTime >= tCutoff ) nOutput += *pOutHistory;
00398                 pInHistory++, pInTime++;
00399                 pOutHistory++, pOutTime++;
00400         }
00401 
00402         m_nInBandwidth  = m_mInput.nMeasure             = nInput * 1000 / METER_PERIOD;
00403         m_nOutBandwidth = m_mOutput.nMeasure    = nOutput * 1000 / METER_PERIOD;
00404 }
00405 
00407 // CDatagrams write datagrams
00408 
00409 BOOL CDatagrams::TryWrite()
00410 {
00411         DWORD tNow              = GetTickCount();
00412         DWORD nLimit    = 0xFFFFFFFF;
00413         DWORD nTotal    = 0;
00414 
00415         if ( Settings.Live.BandwidthScale <= 100 )
00416         {
00417                 DWORD tCutoff   = tNow - METER_SECOND;
00418                 DWORD* pHistory = m_mOutput.pHistory;
00419                 DWORD* pTime    = m_mOutput.pTimes;
00420                 DWORD nUsed             = 0;
00421 
00422                 for ( int nSeek = METER_LENGTH ; nSeek ; nSeek--, pHistory++, pTime++ )
00423                 {
00424                         if ( *pTime >= tCutoff ) nUsed += *pHistory;
00425                 }
00426 
00427                 nLimit = Settings.Connection.OutSpeed * 128;
00428                 if ( Settings.Bandwidth.UdpOut != 0 ) nLimit = Settings.Bandwidth.UdpOut;
00429 
00430                 if ( Settings.Live.BandwidthScale < 100 )
00431                 {
00432                         nLimit = nLimit * Settings.Live.BandwidthScale / 100;
00433                 }
00434 
00435                 nLimit = ( nUsed >= nLimit ) ? 0 : ( nLimit - nUsed );
00436         }
00437 
00438         DWORD nLastHost = 0;
00439 
00440         while ( nLimit > 0 )
00441         {
00442         CDatagramOut* pDG = m_pOutputFirst;
00443                 for ( ; pDG ; pDG = pDG->m_pPrevTime )
00444                 {
00445                         BYTE* pPacket;
00446                         DWORD nPacket;
00447 
00448                         if ( nLastHost == pDG->m_pHost.sin_addr.S_un.S_addr )
00449                         {
00450                                 // Same host, skip it
00451                         }
00452                         else if ( pDG->GetPacket( tNow, &pPacket, &nPacket, m_nInFrags > 0 ) )
00453                         {
00454                                 sendto( m_hSocket, (LPCSTR)pPacket, nPacket, 0,
00455                                         (SOCKADDR*)&pDG->m_pHost, sizeof(SOCKADDR_IN) );
00456 
00457                                 nLastHost = pDG->m_pHost.sin_addr.S_un.S_addr;
00458 
00459                                 if ( nLimit >= nPacket )
00460                                         nLimit -= nPacket;
00461                                 else
00462                                         nLimit = 0;
00463 
00464                                 m_tLastWrite = GetTickCount();
00465                                 nTotal += nPacket;
00466                                 m_nOutFrags++;
00467 
00468 #ifdef DEBUG_UDP
00469                                 SGP_HEADER* pTemp = (SGP_HEADER*)pPacket;
00470                                 theApp.Message( MSG_DEBUG, _T("UDP: Sending (#%i) %i of %i to %s:%lu"),
00471                                         pDG->m_nSequence, pTemp->nPart, pTemp->nCount,
00472                                         (LPCTSTR)CString( inet_ntoa( pDG->m_pHost.sin_addr ) 0,
00473                                         htons( pDG->m_pHost.sin_port ) );
00474 #endif
00475 
00476                                 break;
00477                         }
00478                 }
00479 
00480                 if ( pDG == NULL ) break;
00481         }
00482 
00483         if ( m_mOutput.pHistory && nTotal )
00484         {
00485                 if ( tNow - m_mOutput.tLastSlot < METER_MINIMUM )
00486                 {
00487                         m_mOutput.pHistory[ m_mOutput.nPosition ]       += nTotal;
00488                 }
00489                 else
00490                 {
00491                         m_mOutput.nPosition = ( m_mOutput.nPosition + 1 ) % METER_LENGTH;
00492                         m_mOutput.pTimes[ m_mOutput.nPosition ]         = tNow;
00493                         m_mOutput.pHistory[ m_mOutput.nPosition ]       = nTotal;
00494                         m_mOutput.tLastSlot = tNow;
00495                 }
00496         }
00497 
00498         m_mOutput.nTotal += nTotal;
00499         Statistics.Current.Bandwidth.Outgoing += nTotal;
00500 
00501         return TRUE;
00502 }
00503 
00505 // CDatagrams manage output queue datagrams
00506 
00507 void CDatagrams::ManageOutput()
00508 {
00509         DWORD tNow = GetTickCount();
00510 
00511         for ( CDatagramOut* pDG = m_pOutputLast ; pDG ; )
00512         {
00513                 CDatagramOut* pNext = pDG->m_pNextTime;
00514 
00515                 if ( tNow - pDG->m_tSent > Settings.Gnutella2.UdpOutExpire )
00516                 {
00517                         Remove( pDG );
00518                 }
00519 
00520                 pDG = pNext;
00521         }
00522 }
00523 
00525 // CDatagrams remove output datagrams
00526 
00527 void CDatagrams::Remove(CDatagramOut* pDG)
00528 {
00529         if ( pDG->m_pBuffer )
00530         {
00531                 pDG->m_pBuffer->m_pNext = m_pBufferFree;
00532                 m_pBufferFree = pDG->m_pBuffer;
00533                 m_pBufferFree->Clear();
00534                 pDG->m_pBuffer = NULL;
00535                 m_nBufferFree++;
00536         }
00537 
00538         if ( pDG->m_pNextHash ) pDG->m_pNextHash->m_pPrevHash = pDG->m_pPrevHash;
00539         *(pDG->m_pPrevHash) = pDG->m_pNextHash;
00540 
00541         if ( pDG->m_pNextTime )
00542                 pDG->m_pNextTime->m_pPrevTime = pDG->m_pPrevTime;
00543         else
00544                 m_pOutputFirst = pDG->m_pPrevTime;
00545 
00546         if ( pDG->m_pPrevTime )
00547                 pDG->m_pPrevTime->m_pNextTime = pDG->m_pNextTime;
00548         else
00549                 m_pOutputLast = pDG->m_pNextTime;
00550 
00551         pDG->m_pNextHash = m_pOutputFree;
00552         m_pOutputFree = pDG;
00553 }
00554 
00556 // CDatagrams read datagram
00557 
00558 #define TEMP_BUFFER 4096
00559 
00560 BOOL CDatagrams::TryRead()
00561 {
00562         static BYTE pBuffer[ TEMP_BUFFER ];
00563         int nLength, nFromLen;
00564         SOCKADDR_IN pFrom;
00565 
00566         nFromLen = sizeof(pFrom);
00567         nLength = recvfrom( m_hSocket, (LPSTR)pBuffer, TEMP_BUFFER, 0,
00568                                                 (SOCKADDR*)&pFrom, &nFromLen );
00569 
00570         if ( nLength < 1 ) return FALSE;
00571 
00572         if ( m_mInput.pHistory && nLength > 0 )
00573         {
00574                 DWORD tNow = GetTickCount();
00575 
00576                 if ( tNow - m_mInput.tLastSlot < METER_MINIMUM )
00577                 {
00578                         m_mInput.pHistory[ m_mInput.nPosition ] += nLength;
00579                 }
00580                 else
00581                 {
00582                         m_mInput.nPosition = ( m_mInput.nPosition + 1 ) % METER_LENGTH;
00583                         m_mInput.pTimes[ m_mInput.nPosition ]   = tNow;
00584                         m_mInput.pHistory[ m_mInput.nPosition ] = nLength;
00585                         m_mInput.tLastSlot = tNow;
00586                 }
00587         }
00588 
00589         m_mInput.nTotal += nLength;
00590         Statistics.Current.Bandwidth.Incoming += nLength;
00591 
00592         if ( Security.IsAccepted( &pFrom.sin_addr ) )
00593         {
00594                 OnDatagram( &pFrom, pBuffer, nLength );
00595         }
00596 
00597         return TRUE;
00598 }
00599 
00601 // CDatagrams datagram handler
00602 
00603 BOOL CDatagrams::OnDatagram(SOCKADDR_IN* pHost, BYTE* pBuffer, DWORD nLength)
00604 {
00605         ED2K_UDP_HEADER* pMULE = (ED2K_UDP_HEADER*)pBuffer;
00606 
00607         if ( nLength > sizeof(*pMULE) && (
00608                  pMULE->nProtocol == ED2K_PROTOCOL_EDONKEY ||
00609                  pMULE->nProtocol == ED2K_PROTOCOL_EMULE ||
00610                  pMULE->nProtocol == ED2K_PROTOCOL_PACKED ) )
00611         {
00612                 CEDPacket* pPacket = CEDPacket::New( pMULE, nLength );
00613 
00614                 if ( ! pPacket->InflateOrRelease( ED2K_PROTOCOL_EMULE ) )
00615                 {
00616                         pPacket->SmartDump( NULL, &pHost->sin_addr, FALSE );
00617                         EDClients.OnUDP( pHost, pPacket );
00618                         pPacket->Release();
00619                 }
00620 
00621                 return TRUE;
00622         }
00623 
00624         SGP_HEADER* pSGP = (SGP_HEADER*)pBuffer;
00625 
00626         if ( nLength >= sizeof(*pSGP) && strncmp( pSGP->szTag, SGP_TAG_2, 3 ) == 0 )
00627         {
00628                 if ( pSGP->nPart == 0 ) return FALSE;
00629                 if ( pSGP->nCount && pSGP->nPart > pSGP->nCount ) return FALSE;
00630 
00631                 nLength -= sizeof(*pSGP);
00632 
00633                 if ( pSGP->nCount )
00634                 {
00635                         OnReceiveSGP( pHost, pSGP, nLength );
00636                 }
00637                 else
00638                 {
00639                         OnAcknowledgeSGP( pHost, pSGP, nLength );
00640                 }
00641 
00642                 return TRUE;
00643         }
00644 
00645         return FALSE;
00646 }
00647 
00649 // CDatagrams SGP receive handler
00650 
00651 BOOL CDatagrams::OnReceiveSGP(SOCKADDR_IN* pHost, SGP_HEADER* pHeader, DWORD nLength)
00652 {
00653 #ifdef DEBUG_UDP
00654         theApp.Message( MSG_DEBUG, _T("UDP: Received (#%i) %i of %i from %s"),
00655                 pHeader->nSequence, pHeader->nPart, pHeader->nCount,
00656                 (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ) );
00657 #endif
00658 
00659         m_nInFrags++;
00660 
00661         if ( pHeader->nFlags & SGP_ACKNOWLEDGE )
00662         {
00663                 SGP_HEADER pAck;
00664 
00665                 strncpy( pAck.szTag, SGP_TAG_2, 3 );
00666                 pAck.nFlags             = 0;
00667                 pAck.nSequence  = pHeader->nSequence;
00668                 pAck.nPart              = pHeader->nPart;
00669                 pAck.nCount             = 0;
00670 
00671                 sendto( m_hSocket, (LPCSTR)&pAck, sizeof(pAck), 0,
00672                         (SOCKADDR*)pHost, sizeof(SOCKADDR_IN) );
00673         }
00674 
00675         BYTE nHash      = pHost->sin_addr.S_un.S_un_b.s_b1
00676                                 + pHost->sin_addr.S_un.S_un_b.s_b2
00677                                 + pHost->sin_addr.S_un.S_un_b.s_b3
00678                                 + pHost->sin_addr.S_un.S_un_b.s_b4
00679                                 + pHost->sin_port
00680                                 + pHeader->nSequence;
00681 
00682         CDatagramIn** pHash = m_pInputHash + ( nHash & HASH_MASK );
00683 
00684     CDatagramIn* pDG = *pHash;
00685         for ( ; pDG ; pDG = pDG->m_pNextHash )
00686         {
00687                 if (    pDG->m_pHost.sin_addr.S_un.S_addr == pHost->sin_addr.S_un.S_addr &&
00688                                 pDG->m_pHost.sin_port == pHost->sin_port &&
00689                                 pDG->m_nSequence == pHeader->nSequence &&
00690                                 pDG->m_nCount == pHeader->nCount )
00691                 {
00692                         if ( pDG->Add( pHeader->nPart, &pHeader[1], nLength ) )
00693                         {
00694                                 if ( CG2Packet* pPacket = pDG->ToG2Packet() )
00695                                 {
00696                                         try
00697                                         {
00698                                                 OnPacket( pHost, pPacket );
00699                                         }
00700                                         catch ( CException* pException )
00701                                         {
00702                                                 pException->Delete();
00703                                         }
00704 
00705                                         pPacket->Release();
00706                                 }
00707 
00708                                 // Keep it to check sequence numbers
00709                                 // Remove( pDG );
00710                         }
00711 
00712                         return TRUE;
00713                 }
00714         }
00715 
00716         while ( m_pInputFree == NULL || m_nBufferFree < pHeader->nCount )
00717         {
00718                 if ( m_pInputLast == NULL ) return FALSE;
00719                 Remove( m_pInputLast );
00720         }
00721 
00722         if ( m_nBufferFree < pHeader->nCount ) return FALSE;
00723 
00724         pDG = m_pInputFree;
00725 
00726         pDG->Create( pHost, pHeader->nFlags, pHeader->nSequence, pHeader->nCount );
00727 
00728         for ( WORD nPart = 0 ; nPart < pDG->m_nCount ; nPart++ )
00729         {
00730                 ASSERT( pDG->m_pBuffer[ nPart ] == NULL );
00731                 pDG->m_pBuffer[ nPart ] = m_pBufferFree;
00732                 m_pBufferFree = m_pBufferFree->m_pNext;
00733                 m_nBufferFree--;
00734         }
00735 
00736         if ( pDG->Add( pHeader->nPart, &pHeader[1], nLength ) )
00737         {
00738                 if ( CG2Packet* pPacket = pDG->ToG2Packet() )
00739                 {
00740                         try
00741                         {
00742                                 OnPacket( pHost, pPacket );
00743                         }
00744                         catch ( CException* pException )
00745                         {
00746                                 pException->Delete();
00747                         }
00748                         pPacket->Release();
00749                 }
00750 
00751                 // Don't remove it, keep it to check sequence numbers
00752                 // Remove( pDG, TRUE );
00753         }
00754 
00755         // Always add it to the list
00756 
00757         pDG->m_pNextTime = NULL;
00758         pDG->m_pPrevTime = m_pInputFirst;
00759 
00760         if ( m_pInputFirst )
00761                 m_pInputFirst->m_pNextTime = pDG;
00762         else
00763                 m_pInputLast = pDG;
00764 
00765         m_pInputFirst = pDG;
00766         m_pInputFree = pDG->m_pNextHash;
00767 
00768         if ( *pHash ) (*pHash)->m_pPrevHash = &pDG->m_pNextHash;
00769         pDG->m_pNextHash = *pHash;
00770         pDG->m_pPrevHash = pHash;
00771         *pHash = pDG;
00772 
00773         return TRUE;
00774 }
00775 
00777 // CDatagrams SGP acknowledgement handler
00778 
00779 BOOL CDatagrams::OnAcknowledgeSGP(SOCKADDR_IN* pHost, SGP_HEADER* pHeader, DWORD nLength)
00780 {
00781 #ifdef DEBUG_UDP
00782         theApp.Message( MSG_DEBUG, _T("UDP: Received ack (#%i) %i from %s"),
00783                 pHeader->nSequence, pHeader->nPart, (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ) );
00784 #endif
00785 
00786         BYTE nHash      = pHost->sin_addr.S_un.S_un_b.s_b1
00787                                 + pHost->sin_addr.S_un.S_un_b.s_b2
00788                                 + pHost->sin_addr.S_un.S_un_b.s_b3
00789                                 + pHost->sin_addr.S_un.S_un_b.s_b4
00790                                 + pHost->sin_port
00791                                 + pHeader->nSequence;
00792 
00793         CDatagramOut** pHash = m_pOutputHash + ( nHash & HASH_MASK );
00794 
00795         for ( CDatagramOut* pDG = *pHash ; pDG ; pDG = pDG->m_pNextHash )
00796         {
00797                 if (    pDG->m_pHost.sin_addr.S_un.S_addr == pHost->sin_addr.S_un.S_addr &&
00798                                 pDG->m_pHost.sin_port == pHost->sin_port &&
00799                                 pDG->m_nSequence == pHeader->nSequence )
00800                 {
00801                         if ( pDG->Acknowledge( pHeader->nPart ) ) Remove( pDG );
00802                         return TRUE;
00803                 }
00804         }
00805 
00806         return FALSE;
00807 }
00808 
00810 // CDatagrams manage partial datagrams
00811 
00812 void CDatagrams::ManagePartials()
00813 {
00814         DWORD tNow = GetTickCount();
00815 
00816         for ( CDatagramIn* pDG = m_pInputLast ; pDG ; )
00817         {
00818                 CDatagramIn* pNext = pDG->m_pNextTime;
00819 
00820                 if ( tNow - pDG->m_tStarted > Settings.Gnutella2.UdpInExpire )
00821                 {
00822                         Remove( pDG );
00823                 }
00824 
00825                 pDG = pNext;
00826         }
00827 }
00828 
00830 // CDatagrams remove a partiallly received datagram
00831 
00832 void CDatagrams::Remove(CDatagramIn* pDG, BOOL bReclaimOnly)
00833 {
00834         for ( int nPart = 0 ; nPart < pDG->m_nCount ; nPart++ )
00835         {
00836                 if ( pDG->m_pBuffer[ nPart ] )
00837                 {
00838                         pDG->m_pBuffer[ nPart ]->m_pNext = m_pBufferFree;
00839                         m_pBufferFree = pDG->m_pBuffer[ nPart ];
00840                         m_pBufferFree->Clear();
00841                         pDG->m_pBuffer[ nPart ] = NULL;
00842                         m_nBufferFree++;
00843                 }
00844         }
00845 
00846         if ( bReclaimOnly ) return;
00847 
00848         if ( pDG->m_pNextHash ) pDG->m_pNextHash->m_pPrevHash = pDG->m_pPrevHash;
00849         *(pDG->m_pPrevHash) = pDG->m_pNextHash;
00850 
00851         if ( pDG->m_pNextTime )
00852                 pDG->m_pNextTime->m_pPrevTime = pDG->m_pPrevTime;
00853         else
00854                 m_pInputFirst = pDG->m_pPrevTime;
00855 
00856         if ( pDG->m_pPrevTime )
00857                 pDG->m_pPrevTime->m_pNextTime = pDG->m_pNextTime;
00858         else
00859                 m_pInputLast = pDG->m_pNextTime;
00860 
00861         pDG->m_pNextHash = m_pInputFree;
00862         m_pInputFree = pDG;
00863 }
00864 
00866 // CDatagrams packet handler
00867 
00868 BOOL CDatagrams::OnPacket(SOCKADDR_IN* pHost, CG2Packet* pPacket)
00869 {
00870         pPacket->SmartDump( NULL, &pHost->sin_addr, FALSE );
00871 
00872         m_nInPackets++;
00873 
00874         if ( Network.RoutePacket( pPacket ) ) return TRUE;
00875 
00876         if ( pPacket->IsType( G2_PACKET_QUERY ) )
00877         {
00878                 return OnQuery( pHost, pPacket );
00879         }
00880         else if ( pPacket->IsType( G2_PACKET_QUERY_KEY_REQ ) )
00881         {
00882                 return OnQueryKeyRequest( pHost, pPacket );
00883         }
00884         else if ( pPacket->IsType( G2_PACKET_HIT ) )
00885         {
00886                 return OnHit( pHost, pPacket );
00887         }
00888         else if ( pPacket->IsType( G2_PACKET_HIT_WRAP ) )
00889         {
00890                 return OnHit( pHost, pPacket );
00891         }
00892         else if ( pPacket->IsType( G2_PACKET_QUERY_ACK ) )
00893         {
00894                 return OnQueryAck( pHost, pPacket );
00895         }
00896         else if ( pPacket->IsType( G2_PACKET_QUERY_KEY_ANS ) )
00897         {
00898                 return OnQueryKeyAnswer( pHost, pPacket );
00899         }
00900         else if ( pPacket->IsType( G2_PACKET_PING ) )
00901         {
00902                 return OnPing( pHost, pPacket );
00903         }
00904         else if ( pPacket->IsType( G2_PACKET_PONG ) )
00905         {
00906                 return OnPong( pHost, pPacket );
00907         }
00908         else if ( pPacket->IsType( G2_PACKET_PUSH ) )
00909         {
00910                 return OnPush( pHost, pPacket );
00911         }
00912         else if ( pPacket->IsType( G2_PACKET_CRAWL_REQ ) )
00913         {
00914                 return OnCrawlRequest( pHost, pPacket );
00915         }
00916         else if ( pPacket->IsType( G2_PACKET_CRAWL_ANS ) )
00917         {
00918                 return OnCrawlAnswer( pHost, pPacket );
00919         }
00920 
00921         return FALSE;
00922 }
00923 
00925 // CDatagrams PING packet handler
00926 
00927 BOOL CDatagrams::OnPing(SOCKADDR_IN* pHost, CG2Packet* pPacket)
00928 {
00929         Send( pHost, CG2Packet::New( G2_PACKET_PONG ) );
00930         return TRUE;
00931 }
00932 
00934 // CDatagrams PONG packet handler
00935 
00936 BOOL CDatagrams::OnPong(SOCKADDR_IN* pHost, CG2Packet* pPacket)
00937 {
00938         if ( ! pPacket->m_bCompound ) return TRUE;
00939 
00940         BOOL bRelayed = FALSE;
00941         CHAR szType[9];
00942         DWORD nLength;
00943 
00944         while ( pPacket->ReadPacket( szType, nLength ) )
00945         {
00946                 DWORD nOffset = pPacket->m_nPosition + nLength;
00947                 if ( strcmp( szType, "RELAY" ) == 0 ) bRelayed = TRUE;
00948                 pPacket->m_nPosition = nOffset;
00949         }
00950 
00951         if ( ! bRelayed ) return TRUE;
00952 
00953         if ( ! Network.IsConnectedTo( &pHost->sin_addr ) ) m_bStable = TRUE;
00954 
00955         /*
00956         CString str = inet_ntoa( pHost->sin_addr );
00957         theApp.Message( MSG_ERROR, _T("Relayed Pong from %s:%u"), str, pHost->sin_port );
00958         */
00959 
00960         return TRUE;
00961 }
00962 
00964 // CDatagrams QUERY packet handler
00965 
00966 BOOL CDatagrams::OnQuery(SOCKADDR_IN* pHost, CG2Packet* pPacket)
00967 {
00968         CQuerySearch* pSearch = CQuerySearch::FromPacket( pPacket, pHost );
00969 
00970         if ( pSearch == NULL || ! pSearch->m_bUDP )
00971         {
00972                 if ( pSearch ) delete pSearch;
00973                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_BAD_QUERY,
00974                         (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ) );
00975                 Statistics.Current.Gnutella2.Dropped++;
00976                 return FALSE;
00977         }
00978 
00979         if ( Security.IsDenied( &pSearch->m_pEndpoint.sin_addr ) )
00980         {
00981                 delete pSearch;
00982                 Statistics.Current.Gnutella2.Dropped++;
00983                 return FALSE;
00984         }
00985 
00986         if ( ! Network.QueryKeys->Check( pSearch->m_pEndpoint.sin_addr.S_un.S_addr, pSearch->m_nKey ) )
00987         {
00988                 DWORD nKey = Network.QueryKeys->Create( pSearch->m_pEndpoint.sin_addr.S_un.S_addr );
00989 
00990                 CString strNode = inet_ntoa( pSearch->m_pEndpoint.sin_addr );
00991                 theApp.Message( MSG_DEBUG, _T("Issuing correction for node %s's query key for %s"),
00992                         (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), (LPCTSTR)strNode );
00993 
00994                 CG2Packet* pAnswer = CG2Packet::New( G2_PACKET_QUERY_KEY_ANS, TRUE );
00995                 pAnswer->WritePacket( "QK", 4 );
00996                 pAnswer->WriteLongBE( nKey );
00997 
00998                 if ( pHost->sin_addr.S_un.S_addr != pSearch->m_pEndpoint.sin_addr.S_un.S_addr )
00999                 {
01000                         pAnswer->WritePacket( "SNA", 4 );
01001                         pAnswer->WriteLongLE( pHost->sin_addr.S_un.S_addr );
01002                 }
01003 
01004                 Send( &pSearch->m_pEndpoint, pAnswer, TRUE );
01005 
01006                 delete pSearch;
01007                 return TRUE;
01008         }
01009 
01010         if ( ! Network.QueryRoute->Add( &pSearch->m_pGUID, &pSearch->m_pEndpoint ) )
01011         {
01012                 CG2Packet* pAnswer = CG2Packet::New( G2_PACKET_QUERY_ACK, TRUE );
01013                 pAnswer->WritePacket( "D", 8 );
01014                 pAnswer->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
01015                 pAnswer->WriteShortBE( htons( Network.m_pHost.sin_port ) );
01016                 pAnswer->WriteShortBE( 0 );
01017                 pAnswer->WriteByte( 0 );
01018                 pAnswer->Write( &pSearch->m_pGUID, sizeof(GGUID) );
01019                 Send( &pSearch->m_pEndpoint, pAnswer, TRUE );
01020 
01021                 delete pSearch;
01022                 Statistics.Current.Gnutella2.Dropped++;
01023                 return TRUE;
01024         }
01025 
01026         Neighbours.RouteQuery( pSearch, pPacket, NULL, TRUE );
01027 
01028         Network.OnQuerySearch( pSearch );
01029 
01030         CLocalSearch pLocal( pSearch, &pSearch->m_pEndpoint );
01031         pLocal.Execute();
01032 
01033         Send( &pSearch->m_pEndpoint, Neighbours.CreateQueryWeb( &pSearch->m_pGUID ), TRUE );
01034 
01035         delete pSearch;
01036 
01037         return TRUE;
01038 }
01039 
01041 // CDatagrams QUERY ACK packet handler
01042 
01043 BOOL CDatagrams::OnQueryAck(SOCKADDR_IN* pHost, CG2Packet* pPacket)
01044 {
01045         CHostCacheHost* pCache = HostCache.Gnutella2.Add( &pHost->sin_addr, htons( pHost->sin_port ) );
01046         if ( pCache ) pCache->m_tAck = pCache->m_nFailures = 0;
01047 
01048         GGUID pGUID;
01049 
01050         if ( SearchManager.OnQueryAck( pPacket, pHost, &pGUID ) )
01051         {
01052                 CNeighbour* pNeighbour = NULL;
01053                 SOCKADDR_IN pEndpoint;
01054 
01055                 if ( Network.QueryRoute->Lookup( &pGUID, &pNeighbour, &pEndpoint ) )
01056                 {
01057                         // TODO: Add a "FR" from tag
01058 
01059                         if ( pNeighbour != NULL && pNeighbour->m_nNodeType == ntLeaf )
01060                         {
01061                                 pNeighbour->Send( pPacket, FALSE, FALSE );
01062                         }
01063                         else
01064                         {
01065                                 // Don't route it on via UDP
01066                         }
01067                 }
01068         }
01069 
01070         return TRUE;
01071 }
01072 
01074 // CDatagrams HIT packet handler
01075 
01076 BOOL CDatagrams::OnHit(SOCKADDR_IN* pHost, CG2Packet* pPacket)
01077 {
01078         int nHops = 0;
01079         CQueryHit* pHits = CQueryHit::FromPacket( pPacket, &nHops );
01080 
01081         if ( pHits == NULL )
01082         {
01083                 pPacket->Debug( _T("BadHit") );
01084                 theApp.Message( MSG_ERROR, IDS_PROTOCOL_BAD_HIT,
01085                         (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ) );
01086                 Statistics.Current.Gnutella2.Dropped++;
01087                 return FALSE;
01088         }
01089 
01090         if ( Security.IsDenied( &pHits->m_pAddress ) || nHops > (int)Settings.Gnutella1.MaximumTTL )
01091         {
01092                 pHits->Delete();
01093                 Statistics.Current.Gnutella2.Dropped++;
01094                 return FALSE;
01095         }
01096 
01097         Network.NodeRoute->Add( &pHits->m_pClientID, pHost );
01098 
01099         if ( SearchManager.OnQueryHits( pHits ) )
01100         {
01101                 Network.RouteHits( pHits, pPacket );
01102         }
01103 
01104         Network.OnQueryHits( pHits );
01105 
01106         return TRUE;
01107 }
01108 
01110 // CDatagrams QUERY KEY REQUEST packet handler
01111 
01112 BOOL CDatagrams::OnQueryKeyRequest(SOCKADDR_IN* pHost, CG2Packet* pPacket)
01113 {
01114         if ( ! Neighbours.IsG2Hub() ) return FALSE;
01115 
01116         DWORD nRequestedAddress = pHost->sin_addr.S_un.S_addr;
01117         WORD nRequestedPort = ntohs( pHost->sin_port );
01118         DWORD nSendingAddress = pHost->sin_addr.S_un.S_addr;
01119 
01120         if ( pPacket->m_bCompound )
01121         {
01122                 CHAR szType[9];
01123                 DWORD nLength;
01124 
01125                 while ( pPacket->ReadPacket( szType, nLength ) )
01126                 {
01127                         DWORD nOffset = pPacket->m_nPosition + nLength;
01128 
01129                         if ( strcmp( szType, "RNA" ) == 0 && nLength >= 6 )
01130                         {
01131                                 nRequestedAddress       = pPacket->ReadLongLE();
01132                                 nRequestedPort          = pPacket->ReadShortBE();
01133                         }
01134                         else if ( strcmp( szType, "SNA" ) == 0 && nLength >= 4 )
01135                         {
01136                                 nSendingAddress         = pPacket->ReadLongLE();
01137                         }
01138 
01139                         pPacket->m_nPosition = nOffset;
01140                 }
01141         }
01142 
01143         CString strNode = inet_ntoa( *(IN_ADDR*)&nRequestedAddress );
01144         theApp.Message( MSG_DEBUG, _T("Node %s asked for a query key for node %s:%i"),
01145                 (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), (LPCTSTR)strNode, nRequestedPort );
01146 
01147         if ( Network.IsFirewalledAddress( &nRequestedAddress, TRUE ) || 0 == nRequestedPort ) return TRUE;
01148 
01149         DWORD nKey = Network.QueryKeys->Create( nRequestedAddress );
01150 
01151         CG2Packet* pAnswer = CG2Packet::New( G2_PACKET_QUERY_KEY_ANS, TRUE );
01152 
01153         pAnswer->WritePacket( "QK", 4 );
01154         pAnswer->WriteLongBE( nKey );
01155 
01156         if ( nRequestedAddress != nSendingAddress )
01157         {
01158                 pAnswer->WritePacket( "SNA", 4 );
01159                 pAnswer->WriteLongLE( nSendingAddress );
01160         }
01161 
01162         Send( (IN_ADDR*)&nRequestedAddress, nRequestedPort, pAnswer, TRUE );
01163 
01164         return TRUE;
01165 }
01166 
01168 // CDatagrams QUERY KEY ANSWER packet handler
01169 
01170 BOOL CDatagrams::OnQueryKeyAnswer(SOCKADDR_IN* pHost, CG2Packet* pPacket)
01171 {
01172         if ( ! pPacket->m_bCompound ) return FALSE;
01173 
01174         DWORD nKey = 0, nAddress = 0;
01175 
01176         CHAR szType[9];
01177         DWORD nLength;
01178 
01179         while ( pPacket->ReadPacket( szType, nLength ) )
01180         {
01181                 DWORD nOffset = pPacket->m_nPosition + nLength;
01182 
01183                 if ( strcmp( szType, "QK" ) == 0 && nLength >= 4 )
01184                 {
01185                         nKey = pPacket->ReadLongBE();
01186                 }
01187                 else if ( strcmp( szType, "SNA" ) == 0 && nLength >= 4 )
01188                 {
01189                         nAddress = pPacket->ReadLongLE();
01190                 }
01191 
01192                 pPacket->m_nPosition = nOffset;
01193         }
01194 
01195         theApp.Message( MSG_DEBUG, _T("Got a query key for %s:%lu: 0x%x"),
01196                 (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), htons( pHost->sin_port ), nKey );
01197 
01198         CHostCacheHost* pCache = HostCache.Gnutella2.Add(
01199                 &pHost->sin_addr, htons( pHost->sin_port ) );
01200 
01201         if ( pCache != NULL ) pCache->SetKey( nKey );
01202 
01203         if ( nAddress != 0 && nAddress != Network.m_pHost.sin_addr.S_un.S_addr )
01204         {
01205                 if ( CNeighbour* pNeighbour = Neighbours.Get( (IN_ADDR*)&nAddress ) )
01206                 {
01207                         BYTE* pOut = pPacket->WriteGetPointer( 11, 0 );
01208 
01209                         *pOut++ = 0x50;
01210                         *pOut++ = 6;
01211                         *pOut++ = 'Q';
01212                         *pOut++ = 'N';
01213                         *pOut++ = 'A';
01214                         *pOut++ = pHost->sin_addr.S_un.S_un_b.s_b1;
01215                         *pOut++ = pHost->sin_addr.S_un.S_un_b.s_b2;
01216                         *pOut++ = pHost->sin_addr.S_un.S_un_b.s_b3;
01217                         *pOut++ = pHost->sin_addr.S_un.S_un_b.s_b4;
01218 
01219                         if ( pPacket->m_bBigEndian )
01220                         {
01221                                 *pOut++ = (BYTE)( pHost->sin_port & 0xFF );
01222                                 *pOut++ = (BYTE)( pHost->sin_port >> 8 );
01223                         }
01224                         else
01225                         {
01226                                 *pOut++ = (BYTE)( pHost->sin_port >> 8 );
01227                                 *pOut++ = (BYTE)( pHost->sin_port & 0xFF );
01228                         }
01229 
01230                         pNeighbour->Send( pPacket, FALSE, FALSE );
01231                 }
01232         }
01233 
01234         return TRUE;
01235 }
01236 
01238 // CDatagrams PUSH packet handler
01239 
01240 BOOL CDatagrams::OnPush(SOCKADDR_IN* pHost, CG2Packet* pPacket)
01241 {
01242         DWORD nLength = pPacket->GetRemaining();
01243 
01244         if ( ! pPacket->SkipCompound( nLength, 6 ) )
01245         {
01246                 pPacket->Debug( _T("BadPush") );
01247                 Statistics.Current.Gnutella2.Dropped++;
01248                 return FALSE;
01249         }
01250 
01251         DWORD nAddress  = pPacket->ReadLongLE();
01252         WORD nPort              = pPacket->ReadShortBE();
01253 
01254         if ( Security.IsDenied( (IN_ADDR*)&nAddress ) ||
01255                  Network.IsFirewalledAddress( &nAddress ) )
01256         {
01257                 Statistics.Current.Gnutella2.Dropped++;
01258                 return TRUE;
01259         }
01260 
01261         Handshakes.PushTo( (IN_ADDR*)&nAddress, nPort );
01262 
01263         return TRUE;
01264 }
01265 
01267 // CDatagrams CRAWL packet handler
01268 
01269 BOOL CDatagrams::OnCrawlRequest(SOCKADDR_IN* pHost, CG2Packet* pPacket)
01270 {
01271         if ( ! pPacket->m_bCompound ) return FALSE;
01272 
01273         BOOL bWantLeaves        = FALSE;
01274         BOOL bWantNames         = FALSE;
01275         BOOL bWantGPS           = FALSE;
01276         BOOL bWantREXT          = FALSE;
01277         BOOL bIsHub                     = ( ! Neighbours.IsG2Leaf() ) && ( Neighbours.IsG2Hub() || Neighbours.IsG2HubCapable() );
01278 
01279         CHAR szType[9];
01280         DWORD nLength;
01281 
01282         while ( pPacket->ReadPacket( szType, nLength ) )
01283         {
01284                 DWORD nNext = pPacket->m_nPosition + nLength;
01285 
01286                 if ( strcmp( szType, "RLEAF" ) == 0 )
01287                 {
01288                         bWantLeaves = TRUE;
01289                 }
01290                 else if ( strcmp( szType, "RNAME" ) == 0 )
01291                 {
01292                         bWantNames = TRUE;
01293                 }
01294                 else if ( strcmp( szType, "RGPS" ) == 0 )
01295                 {
01296                         bWantGPS = TRUE;
01297                 }
01298                 else if ( strcmp( szType, "REXT" ) == 0 )
01299                 {
01300                         bWantREXT = TRUE;
01301                 }
01302 
01303                 pPacket->m_nPosition = nNext;
01304         }
01305 
01306         pPacket = CG2Packet::New( G2_PACKET_CRAWL_ANS, TRUE );
01307 
01308         CString strNick;
01309         DWORD nGPS = 0;
01310         CString vendorCode;
01311         CString currentVersion;
01312 
01313         if ( bWantNames ) strNick = MyProfile.GetNick().Left( 255 ); //trim if over 255 characters
01314 
01315         if ( bWantGPS ) nGPS = MyProfile.GetPackedGPS();
01316 
01317         if ( bWantREXT )
01318         {
01319                 vendorCode = VENDOR_CODE;
01320                 currentVersion = CLIENT_NAME;
01321                 currentVersion += " ";
01322                 currentVersion += theApp.m_sVersion;
01323         }
01324 
01325         pPacket->WritePacket(
01326                 "SELF",
01327                 16 + ( strNick.GetLength() ? pPacket->GetStringLen( strNick ) + 6 : 0 ) +
01328                         ( nGPS ? 5 + 4 : 0 ) + (vendorCode.GetLength() ? pPacket->GetStringLen( vendorCode ) + 3 : 0 ) +
01329                 (currentVersion.GetLength() ? pPacket->GetStringLen( currentVersion ) + 4 : 0 ) +
01330                 (bIsHub ? 5 : 6),
01331                 TRUE );
01332 
01333         pPacket->WritePacket( "NA", 6 );
01334         pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
01335         pPacket->WriteShortBE( htons( Network.m_pHost.sin_port ) );
01336 
01337         pPacket->WritePacket( "HS", 2 );
01338         pPacket->WriteShortBE( Neighbours.GetCount( PROTOCOL_G2, -1, ntLeaf ) );
01339 
01340         if ( strNick.GetLength() )
01341         {
01342                 pPacket->WritePacket( "NAME", pPacket->GetStringLen( strNick) );
01343                 pPacket->WriteString( strNick, FALSE );
01344         }
01345         if ( vendorCode.GetLength() )
01346         {
01347                 pPacket->WritePacket( "V", pPacket->GetStringLen( vendorCode) );
01348                 pPacket->WriteString( vendorCode, FALSE );
01349         }
01350         if ( currentVersion.GetLength() )
01351         {
01352                 pPacket->WritePacket( "CV", pPacket->GetStringLen( currentVersion) );
01353                 pPacket->WriteString( currentVersion, FALSE );
01354         }
01355 
01356         if ( bIsHub )
01357         {
01358                 pPacket->WritePacket( "HUB", 0 );
01359         }
01360         else
01361         {
01362                 pPacket->WritePacket( "LEAF", 0 );
01363         }
01364 
01365         if ( nGPS )
01366         {
01367                 pPacket->WritePacket( "GPS", 4 );
01368                 pPacket->WriteLongBE( nGPS );
01369         }
01370 
01371         for ( POSITION pos = Neighbours.GetIterator() ; pos ; )
01372         {
01373                 CNeighbour* pNeighbour = Neighbours.GetNext( pos );
01374                 if ( pNeighbour->m_nState < nrsConnected ) continue;
01375 
01376                 int nExtraLen = 0;
01377                 strNick.Empty();
01378                 nGPS = 0;
01379 
01380                 if ( pNeighbour->m_nProtocol == PROTOCOL_G2 )
01381                 {
01382                         if ( CGProfile* pProfile = ((CG2Neighbour*)pNeighbour)->m_pProfile )
01383                         {
01384                                 if ( bWantNames ) strNick = pProfile->GetNick().Left( 255 ); //Trim if over 255 characters
01385 
01386                                 if ( bWantGPS ) nGPS = pProfile->GetPackedGPS();
01387 
01388                                 if ( strNick.GetLength() ) nExtraLen += 6 + pPacket->GetStringLen( strNick );
01389                                 if ( nGPS ) nExtraLen += 9;
01390                         }
01391                 }
01392 
01393                 if ( pNeighbour->m_nProtocol == PROTOCOL_G2 &&
01394                          pNeighbour->m_nNodeType != ntLeaf )
01395                 {
01396                         pPacket->WritePacket( "NH", 16 + nExtraLen, TRUE );
01397 
01398                         pPacket->WritePacket( "NA", 6 );
01399                         pPacket->WriteLongLE( pNeighbour->m_pHost.sin_addr.S_un.S_addr );
01400                         pPacket->WriteShortBE( htons( pNeighbour->m_pHost.sin_port ) );
01401 
01402                         pPacket->WritePacket( "HS", 2 );
01403                         pPacket->WriteShortBE( (WORD)((CG2Neighbour*)pNeighbour)->m_nLeafCount );
01404                 }
01405                 else if ( pNeighbour->m_nNodeType == ntLeaf && bWantLeaves )
01406                 {
01407                         pPacket->WritePacket( "NL", 10 + nExtraLen, TRUE );
01408 
01409                         pPacket->WritePacket( "NA", 6 );
01410                         pPacket->WriteLongLE( pNeighbour->m_pHost.sin_addr.S_un.S_addr );
01411                         pPacket->WriteShortBE( htons( pNeighbour->m_pHost.sin_port ) );
01412                 }
01413                 else
01414                 {
01415                         nExtraLen = 0;
01416                 }
01417 
01418                 if ( nExtraLen > 0 )
01419                 {
01420                         if ( strNick.GetLength() )
01421                         {
01422                                 pPacket->WritePacket( "NAME", pPacket->GetStringLen( strNick ) );
01423                                 pPacket->WriteString( strNick, FALSE );
01424                         }
01425 
01426                         if ( nGPS )
01427                         {
01428                                 pPacket->WritePacket( "GPS", 4 );
01429                                 pPacket->WriteLongBE( nGPS );
01430                         }
01431                 }
01432         }
01433 
01434         Send( pHost, pPacket );
01435 
01436         return TRUE;
01437 }
01438 
01439 BOOL CDatagrams::OnCrawlAnswer(SOCKADDR_IN* pHost, CG2Packet* pPacket)
01440 {
01441         CrawlSession.OnCrawl( pHost, pPacket );
01442         return TRUE;
01443 }

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