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

EDNeighbour.cpp

Go to the documentation of this file.
00001 //
00002 // EDNeighbour.cpp
00003 //
00004 // Copyright (c) Shareaza Development Team, 2002-2005.
00005 // This file is part of SHAREAZA (www.shareaza.com)
00006 //
00007 // Shareaza is free software; you can redistribute it
00008 // and/or modify it under the terms of the GNU General Public License
00009 // as published by the Free Software Foundation; either version 2 of
00010 // the License, or (at your option) any later version.
00011 //
00012 // Shareaza is distributed in the hope that it will be useful,
00013 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015 // GNU General Public License for more details.
00016 //
00017 // You should have received a copy of the GNU General Public License
00018 // along with Shareaza; if not, write to the Free Software
00019 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00020 //
00021 
00022 #include "StdAfx.h"
00023 #include "Shareaza.h"
00024 #include "Settings.h"
00025 #include "Network.h"
00026 #include "Statistics.h"
00027 #include "Neighbours.h"
00028 #include "EDNeighbour.h"
00029 #include "EDPacket.h"
00030 #include "Security.h"
00031 #include "GProfile.h"
00032 #include "HostCache.h"
00033 #include "EDClients.h"
00034 
00035 #include "Library.h"
00036 #include "SharedFile.h"
00037 #include "Transfers.h"
00038 #include "Downloads.h"
00039 #include "Download.h"
00040 #include "QuerySearch.h"
00041 #include "QueryHit.h"
00042 
00043 #include "UploadQueues.h"
00044 #include "Schema.h"
00045 #include "XML.h"
00046 
00047 #ifdef _DEBUG
00048 #undef THIS_FILE
00049 static char THIS_FILE[]=__FILE__;
00050 #define new DEBUG_NEW
00051 #endif
00052 
00053 
00055 // CEDNeighbour construction
00056 
00057 CEDNeighbour::CEDNeighbour() : CNeighbour( PROTOCOL_ED2K )
00058 {
00059         m_nNodeType             = ntHub;
00060         m_nClientID             = 0;
00061         m_nUserCount    = 0;
00062         m_nUserLimit    = 0;
00063         m_nFileLimit    = 1000;
00064         m_nTCPFlags             = 0;
00065         m_nUDPFlags             = 0;
00066         m_nFilesSent    = 0;
00067         m_pMoreResultsGUID = NULL;
00068 }
00069 
00070 CEDNeighbour::~CEDNeighbour()
00071 {
00072         for ( POSITION pos = m_pQueries.GetHeadPosition() ; pos ; )
00073         {
00074                 delete (GGUID*)m_pQueries.GetNext( pos );
00075         }
00076 
00077         if ( m_pMoreResultsGUID != NULL ) delete m_pMoreResultsGUID;
00078 }
00079 
00081 // CEDNeighbour connect to
00082 
00083 BOOL CEDNeighbour::ConnectTo(IN_ADDR* pAddress, WORD nPort, BOOL bAutomatic)
00084 {
00085         if ( CConnection::ConnectTo( pAddress, nPort ) )
00086         {
00087                 WSAEventSelect( m_hSocket, Network.m_pWakeup, FD_CONNECT|FD_READ|FD_WRITE|FD_CLOSE );
00088                 
00089                 theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_CONNECTING,
00090                         (LPCTSTR)m_sAddress, htons( m_pHost.sin_port ) );
00091         }
00092         else
00093         {
00094                 theApp.Message( MSG_ERROR, IDS_CONNECTION_CONNECT_FAIL,
00095                         (LPCTSTR)CString( inet_ntoa( m_pHost.sin_addr ) ) );
00096                 return FALSE;
00097         }
00098         
00099         m_nState                = nrsConnecting;
00100         m_bAutomatic    = bAutomatic;
00101         
00102         Neighbours.Add( this );
00103         
00104         return TRUE;
00105 }
00106 
00108 // CEDNeighbour send packet
00109 
00110 BOOL CEDNeighbour::Send(CPacket* pPacket, BOOL bRelease, BOOL bBuffered)
00111 {
00112         BOOL bSuccess = FALSE;
00113         
00114         if ( ( m_nState == nrsHandshake1 || m_nState >= nrsConnected ) &&
00115                  pPacket->m_nProtocol == PROTOCOL_ED2K )
00116         {
00117                 m_nOutputCount++;
00118                 Statistics.Current.eDonkey.Outgoing++;
00119                 
00120                 pPacket->ToBuffer( m_pZOutput ? m_pZOutput : m_pOutput );
00121                 QueueRun();
00122                 
00123                 pPacket->SmartDump( this, NULL, TRUE );
00124                 // pPacket->Debug( _T("DonkeyOut") );
00125                 bSuccess = TRUE;
00126         }
00127         
00128         if ( bRelease ) pPacket->Release();
00129         
00130         return bSuccess;
00131 }
00132 
00134 // CEDNeighbour run event
00135 
00136 BOOL CEDNeighbour::OnRun()
00137 {
00138         DWORD tNow = GetTickCount();
00139         
00140         if ( m_nState != nrsConnected )
00141         {
00142                 if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
00143                 {
00144                         Close( IDS_CONNECTION_TIMEOUT_CONNECT );
00145                         return FALSE;
00146                 }
00147         }
00148         else if ( m_nClientID == 0 )
00149         {
00150                 if ( tNow - m_tConnected > Settings.Connection.TimeoutHandshake )
00151                 {
00152                         Close( IDS_HANDSHAKE_TIMEOUT );
00153                         return FALSE;
00154                 }
00155         }
00156         else
00157         {
00158                 if ( tNow - m_tLastPacket > 20 * 60 * 1000 )
00159                 {
00160                         Close( IDS_CONNECTION_TIMEOUT_TRAFFIC );
00161                         return FALSE;
00162                 }
00163         }
00164         
00165         return TRUE;
00166 }
00167 
00169 // CEDNeighbour connection event
00170 
00171 BOOL CEDNeighbour::OnConnected()
00172 {
00173         DWORD nVersion =  ( ( ( ED2K_COMPATIBLECLIENT_ID & 0xFF ) << 24 ) | 
00174                                                         ( ( theApp.m_nVersion[0] & 0x7F ) << 17 ) | 
00175                                                         ( ( theApp.m_nVersion[1] & 0x7F ) << 10 ) |
00176                                                         ( ( theApp.m_nVersion[2] & 0x07 ) << 7  ) |
00177                                                         ( ( theApp.m_nVersion[3] & 0x7F )       ) );
00178 
00179         theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_CONNECTED, (LPCTSTR)m_sAddress );
00180         
00181         CEDPacket* pPacket = CEDPacket::New(  ED2K_C2S_LOGINREQUEST );
00182         
00183         GGUID pGUID     = MyProfile.GUID;
00184         pGUID.n[5]      = 14;
00185         pGUID.n[14]     = 111;
00186         pPacket->Write( &pGUID, 16 );
00187         
00188         pPacket->WriteLongLE( m_nClientID );
00189         pPacket->WriteShortLE( htons( Network.m_pHost.sin_port ) );
00190 
00191         pPacket->WriteLongLE( 5 );      // Number of tags
00192         
00193         // Tags sent to the server
00194 
00195         // User name
00196         CEDTag( ED2K_CT_NAME, MyProfile.GetNick().Left( 255 ) ).Write( pPacket, 0 );
00197         // Version ('ed2k version')
00198         CEDTag( ED2K_CT_VERSION, ED2K_VERSION ).Write( pPacket, 0 );
00199         // Port
00200         CEDTag( ED2K_CT_PORT, htons( Network.m_pHost.sin_port ) ).Write( pPacket, 0 );
00201         // Software Version ('Client Version'). 
00202         CEDTag( ED2K_CT_SOFTWAREVERSION, nVersion ).Write( pPacket, 0 );
00203         // Flags indicating capability
00204         CEDTag( ED2K_CT_FLAGS, ED2K_SERVER_TCP_DEFLATE | ED2K_SERVER_TCP_SMALLTAGS | ED2K_SERVER_TCP_UNICODE ).Write( pPacket, 0 );
00205 
00206         m_nState = nrsHandshake1;
00207         Send( pPacket );
00208         
00209         return TRUE;
00210 }
00211 
00212 void CEDNeighbour::OnDropped(BOOL bError)
00213 {
00214         if ( m_nState < nrsConnected )
00215         {
00216                 HostCache.OnFailure( &m_pHost.sin_addr, htons( m_pHost.sin_port ) );
00217         }
00218         
00219         if ( m_nState == nrsConnecting )
00220         {
00221                 Close( IDS_CONNECTION_REFUSED );
00222         }
00223         else
00224         {
00225                 Close( IDS_CONNECTION_DROPPED );
00226         }
00227 }
00228 
00230 // CEDNeighbour read event
00231 
00232 BOOL CEDNeighbour::OnRead()
00233 {
00234         BOOL bSuccess = TRUE;
00235         CEDPacket* pPacket;
00236         
00237         CNeighbour::OnRead();
00238         
00239         while ( pPacket = CEDPacket::ReadBuffer( m_pZInput ? m_pZInput : m_pInput, ED2K_PROTOCOL_EDONKEY ) )
00240         {
00241                 try
00242                 {
00243                         bSuccess = OnPacket( pPacket );
00244                 }
00245                 catch ( CException* pException )
00246                 {
00247                         pException->Delete();
00248                 }
00249                 
00250                 pPacket->Release();
00251                 if ( ! bSuccess ) break;
00252         }
00253         
00254         return bSuccess;
00255 }
00256 
00258 // CEDNeighbour packet handler
00259 
00260 BOOL CEDNeighbour::OnPacket(CEDPacket* pPacket)
00261 {
00262         pPacket->SmartDump( this, NULL, FALSE );
00263         // pPacket->Debug( _T("DonkeyIn") );
00264         
00265         m_nInputCount++;
00266         Statistics.Current.eDonkey.Incoming++;
00267         m_tLastPacket = GetTickCount();
00268         
00269         switch ( pPacket->m_nType )
00270         {
00271         case ED2K_S2C_REJECTED:
00272                 return OnRejected( pPacket );
00273         case ED2K_S2C_SERVERMESSAGE:
00274                 return OnServerMessage( pPacket );
00275         case ED2K_S2C_IDCHANGE:
00276                 return OnIdChange( pPacket );
00277         case ED2K_S2C_SERVERLIST:
00278                 return OnServerList( pPacket );
00279         case ED2K_S2C_SERVERSTATUS:
00280                 return OnServerStatus( pPacket );
00281         case ED2K_S2C_SERVERIDENT:
00282                 return OnServerIdent( pPacket );
00283         case ED2K_S2C_CALLBACKREQUESTED:
00284                 return OnCallbackRequest( pPacket );
00285         case ED2K_S2C_SEARCHRESULTS:
00286                 return OnSearchResults( pPacket );
00287         case ED2K_S2C_FOUNDSOURCES:
00288                 return OnFoundSources( pPacket );
00289         default:
00290                 {
00291                 pPacket->Debug( _T("Unknown") );
00292                 break;
00293                 }
00294         }
00295         
00296         return TRUE;
00297 }
00298 
00300 // CEDNeighbour server packets
00301 
00302 BOOL CEDNeighbour::OnRejected(CEDPacket* pPacket)
00303 {
00304         Close( IDS_ED2K_SERVER_REJECTED );
00305         return FALSE;
00306 }
00307 
00308 BOOL CEDNeighbour::OnServerMessage(CEDPacket* pPacket)
00309 {
00310         if ( pPacket->GetRemaining() < 4 ) return TRUE;
00311         
00312         CString strMessage = pPacket->ReadEDString( m_nTCPFlags );
00313         
00314         while ( strMessage.GetLength() > 0 )
00315         {
00316                 CString strLine = strMessage.SpanExcluding( _T("\r\n") );
00317                 
00318                 if ( strLine.GetLength() > 0 )
00319                 {
00320                         strMessage = strMessage.Mid( strLine.GetLength() );
00321                         theApp.Message( MSG_SYSTEM, IDS_ED2K_SERVER_MESSAGE,
00322                                 (LPCTSTR)m_sAddress, (LPCTSTR)strLine );
00323                 }
00324                 
00325                 if ( strMessage.GetLength() > 0 ) strMessage = strMessage.Mid( 1 );
00326         }
00327         
00328         return TRUE;
00329 }
00330 
00331 BOOL CEDNeighbour::OnIdChange(CEDPacket* pPacket)
00332 {
00333         if ( pPacket->GetRemaining() < 4 ) return TRUE;
00334         
00335         DWORD nClientID = pPacket->ReadLongLE();
00336         
00337         if ( nClientID == 0 )
00338         {
00339                 Close( IDS_ED2K_SERVER_REFUSED );
00340                 return FALSE;
00341         }
00342         
00343         if ( pPacket->GetRemaining() >= 4 )
00344         {
00345                 m_nTCPFlags = pPacket->ReadLongLE();
00346         }
00347         
00348         if ( m_nClientID == 0 )
00349         {
00350                 theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_ONLINE, (LPCTSTR)m_sAddress, nClientID );
00351                 SendSharedFiles();
00352                 Send( CEDPacket::New(  ED2K_C2S_GETSERVERLIST ) );
00353                 HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) );
00354         }
00355         else
00356         {
00357                 theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_IDCHANGE, (LPCTSTR)m_sAddress, m_nClientID, nClientID );
00358         }
00359         
00360         m_nState        = nrsConnected;
00361         m_nClientID     = nClientID;
00362         
00363         if ( ! CEDPacket::IsLowID( m_nClientID ) )
00364         {
00365                 if ( Settings.Connection.InHost.IsEmpty() )
00366                 {
00367                         Network.m_pHost.sin_addr.S_un.S_addr = m_nClientID;
00368                 }
00369         }
00370 
00371         CString strServerFlags;
00372         strServerFlags.Format(
00373         _T( "Server Flags: Zlib: %d Short Tags: %d Unicode: %d GetSources2: %d (64): %d  (128): %d" ), 
00374                 m_nTCPFlags & ED2K_SERVER_TCP_DEFLATE,
00375         m_nTCPFlags & ED2K_SERVER_TCP_SMALLTAGS,
00376         m_nTCPFlags & ED2K_SERVER_TCP_UNICODE,
00377         m_nTCPFlags & ED2K_SERVER_TCP_GETSOURCES2,
00378         m_nTCPFlags & 0x00000040,
00379         m_nTCPFlags & 0x00000080 );
00380         theApp.Message( MSG_DEBUG, strServerFlags );
00381         
00382         
00383         return TRUE;
00384 }
00385 
00386 BOOL CEDNeighbour::OnServerList(CEDPacket* pPacket)
00387 {
00388         if ( pPacket->GetRemaining() < 1 ) return TRUE;
00389         
00390         int nCount = pPacket->ReadByte();
00391         if ( pPacket->GetRemaining() < nCount * 6 ) return TRUE;
00392         
00393         while ( nCount-- > 0 )
00394         {
00395                 DWORD nAddress  = pPacket->ReadLongLE();
00396                 WORD nPort              = pPacket->ReadShortLE();
00397                 
00398                 theApp.Message( MSG_DEBUG, _T("CEDNeighbour::OnServerList(): %s: %s:%i"),
00399                         (LPCTSTR)m_sAddress,
00400                         (LPCTSTR)CString( inet_ntoa( (IN_ADDR&)nAddress ) ), nPort );
00401                 
00402                 if ( Settings.eDonkey.LearnNewServers )
00403                 {
00404                         HostCache.eDonkey.Add( (IN_ADDR*)&nAddress, nPort );
00405                 }
00406         }
00407         
00408         HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) );
00409         
00410         return TRUE;
00411 }
00412 
00413 BOOL CEDNeighbour::OnServerStatus(CEDPacket* pPacket)
00414 {
00415         if ( pPacket->GetRemaining() < 8 ) return TRUE;
00416         
00417         m_nUserCount    = pPacket->ReadLongLE();
00418         m_nFileCount    = pPacket->ReadLongLE();
00419         
00420         if ( CHostCacheHost* pHost = HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) ) )
00421         {
00422                 // pHost->m_nUserCount = max( pHost->m_nUserCount, m_nUserCount );
00423                 pHost->m_nUserCount = m_nUserCount;
00424                 pHost->m_nUserLimit = max( pHost->m_nUserLimit, m_nUserCount );
00425         }
00426         
00427         return TRUE;
00428 }
00429 
00430 BOOL CEDNeighbour::OnServerIdent(CEDPacket* pPacket)
00431 {
00432         if ( pPacket->GetRemaining() < sizeof(GGUID) + 6 + 4 ) return TRUE;
00433         
00434         m_bGUID = TRUE;
00435         pPacket->Read( &m_pGUID, sizeof(GGUID) );
00436         
00437         pPacket->ReadLongLE();  // IP
00438         pPacket->ReadShortLE(); // Port
00439         
00440         DWORD nTags = pPacket->ReadLongLE();
00441         CString strDescription;
00442         
00443         while ( nTags-- > 0 && pPacket->GetRemaining() > 1 )
00444         {
00445                 CEDTag pTag;
00446                 if ( ! pTag.Read( pPacket, m_nTCPFlags ) ) break;
00447 
00448                 switch ( pTag.m_nKey )
00449                 {
00450                 case ED2K_ST_SERVERNAME:
00451                         // if ( pTag.m_nType == ED2K_TAG_STRING ) // "Short strings" may be possible...
00452                         m_sServerName = pTag.m_sValue;
00453                         break;
00454                 case ED2K_ST_DESCRIPTION:
00455                         strDescription = pTag.m_sValue;
00456                         break;
00457                 case ED2K_ST_MAXUSERS:
00458                         m_nUserLimit = pTag.m_nValue;
00459                         break;
00460 /*
00461                 case ED2K_ST_MAXFILES:
00462                         nMaxFiles = pTag.m_nValue;
00463                         break;
00464                 case ED2K_ST_UDPFLAGS:
00465                         nUDPFlags = pTag.m_nValue;
00466                         break;
00467 */
00468                 default:
00469                         CString str;
00470                         str.Format( _T("Unrecognised packet - IP: %s - opcode: 0x%x - in CEDNeighbour::OnServerIdent"),
00471                                 LPCTSTR( m_sAddress ), int( pTag.m_nKey ) );
00472                         theApp.Message( MSG_DEBUG, LPCTSTR( str ) );
00473                 }
00474         }
00475 
00476         if ( (DWORD&)m_pGUID == 0x2A2A2A2A )
00477                 m_sUserAgent = _T("eFarm Server");
00478         else
00479                 m_sUserAgent = _T("eDonkey2000 Server");
00480         
00481         if ( CHostCacheHost* pHost = HostCache.eDonkey.Add( &m_pHost.sin_addr, htons( m_pHost.sin_port ) ) )
00482         {
00483                 pHost->m_sName                  = m_sServerName;
00484                 pHost->m_sDescription   = strDescription;
00485                 pHost->m_nUserLimit             = m_nUserLimit;
00486                 pHost->m_nTCPFlags              = m_nTCPFlags;
00487 
00488                 // We can assume some UDP flags based on TCP flags
00489                 if ( m_nTCPFlags & ED2K_SERVER_TCP_DEFLATE )
00490                 {
00491                         pHost->m_nUDPFlags |= ED2K_SERVER_UDP_GETSOURCES;
00492                         pHost->m_nUDPFlags |= ED2K_SERVER_UDP_GETFILES;
00493                 }
00494                 if ( m_nTCPFlags & ED2K_SERVER_TCP_UNICODE )
00495                         pHost->m_nUDPFlags |= ED2K_SERVER_UDP_UNICODE;
00496                 if ( m_nTCPFlags & ED2K_SERVER_TCP_GETSOURCES2 )
00497                         pHost->m_nUDPFlags |= ED2K_SERVER_UDP_GETSOURCES2;
00498 
00499         }
00500         
00501         theApp.Message( MSG_DEFAULT, IDS_ED2K_SERVER_IDENT, (LPCTSTR)m_sAddress, (LPCTSTR)m_sServerName );
00502         
00503         return TRUE;
00504 }
00505 
00506 BOOL CEDNeighbour::OnCallbackRequest(CEDPacket* pPacket)
00507 {
00508         if ( pPacket->GetRemaining() < 6 ) return TRUE;
00509         
00510         DWORD nAddress  = pPacket->ReadLongLE();
00511         WORD nPort              = pPacket->ReadShortLE();
00512         
00513         if ( Network.IsFirewalledAddress( &nAddress ) ) return TRUE;
00514         
00515         EDClients.PushTo( nAddress, nPort );
00516         
00517         return TRUE;
00518 }
00519 
00520 BOOL CEDNeighbour::OnSearchResults(CEDPacket* pPacket)
00521 {
00522         if ( m_pQueries.GetCount() == 0 )
00523         {
00524                 Statistics.Current.eDonkey.Dropped++;
00525                 m_nDropCount++;
00526                 return TRUE;
00527         }
00528 
00529         GGUID* pGUID            = (GGUID*)m_pQueries.RemoveHead();
00530         CQueryHit* pHits        = CQueryHit::FromPacket( pPacket, &m_pHost, m_nTCPFlags, pGUID );
00531         
00532         if ( pHits == NULL )
00533         {
00534                 delete pGUID;
00535                 
00536                 if ( pPacket->m_nLength != 17 && pPacket->m_nLength != 5 )
00537                 {
00538                         pPacket->Debug( _T("BadSearchResult") );
00539                         theApp.Message( MSG_ERROR, IDS_PROTOCOL_BAD_HIT, (LPCTSTR)m_sAddress );
00540                         Statistics.Current.eDonkey.Dropped++;
00541                         m_nDropCount++;
00542                 }
00543                 
00544                 return TRUE;
00545         }
00546         
00547         // Process the 'more results available' packet.
00548         if ( pPacket->m_nType == ED2K_S2C_SEARCHRESULTS && pPacket->GetRemaining() == 1 && m_pQueries.IsEmpty() )
00549         {
00550                 if ( pPacket->ReadByte() == TRUE )
00551                 {       // This will be remembered by the neighbour, and if the search continues, more results can be requested.
00552                         m_pMoreResultsGUID = pGUID;
00553                         pGUID = NULL;
00554                         theApp.Message( MSG_DEBUG, _T("Additional results packet received.") );
00555                 }
00556         }
00557         
00558         Network.OnQueryHits( pHits );
00559         
00560         if ( pGUID != NULL ) delete pGUID;
00561         
00562         return TRUE;
00563 }
00564 
00565 BOOL CEDNeighbour::OnFoundSources(CEDPacket* pPacket)
00566 {
00567         CQueryHit* pHits        = CQueryHit::FromPacket( pPacket, &m_pHost, m_nTCPFlags );
00568         
00569         if ( pHits == NULL )
00570         {
00571                 
00572                 if ( pPacket->m_nLength != 17 && pPacket->m_nLength != 5 )
00573                 {
00574                         pPacket->Debug( _T("BadSearchResult") );
00575                         theApp.Message( MSG_ERROR, IDS_PROTOCOL_BAD_HIT, (LPCTSTR)m_sAddress );
00576                         Statistics.Current.eDonkey.Dropped++;
00577                         m_nDropCount++;
00578                 }
00579                 
00580                 return TRUE;
00581         }
00582         
00583         Network.OnQueryHits( pHits );
00584         
00585         return TRUE;
00586 }
00587 
00589 // CEDNeighbour file adverising
00590 
00591 // This function sends the list of shared files to the ed2k server. Note that it's best to
00592 // keep it as brief as possible to reduce the load. This means the metadata should be limited
00593 // to known good values, and only files that are actually available for upload right now should 
00594 // be sent.
00595 void CEDNeighbour::SendSharedFiles()
00596 {       
00597         // Set the limits for number of files sent to the ed2k server
00598         m_nFileLimit = max( Settings.eDonkey.MaxShareCount, ( (DWORD)25 ) );
00599         
00600         CHostCacheHost *pServer = HostCache.eDonkey.Find( &m_pHost.sin_addr );
00601         if ( pServer && ( pServer->m_nFileLimit > 10 ) )
00602         {
00603                 m_nFileLimit = min( m_nFileLimit, pServer->m_nFileLimit );
00604         }
00605 
00606         CEDPacket* pPacket = CEDPacket::New( ED2K_C2S_OFFERFILES );
00607         POSITION pos;
00608         
00609         m_nFilesSent = 0;
00610         
00611         pPacket->WriteLongLE( m_nFilesSent );           //Write number of files. (update this later)
00612         
00613         
00614         CSingleLock pTransfersLock( &Transfers.m_pSection );
00615         CSingleLock pLibraryLock( &Library.m_pSection );
00616 
00617         //Send files on download list to ed2k server (partials)
00618         pTransfersLock.Lock();
00619         for ( pos = Downloads.GetIterator() ; pos != NULL && ( m_nFilesSent < m_nFileLimit ) ; )
00620         {
00621                 CDownload* pDownload = Downloads.GetNext( pos );
00622                 
00623                 //If the file has an ed2k hash, has started, has a known size and a hashset, etc...
00624                 if ( ( pDownload->m_bED2K ) && ( pDownload->IsStarted() ) && ( pDownload->m_nSize != SIZE_UNKNOWN ) &&
00625                          ( pDownload->NeedHashset() == FALSE ) && ( ! pDownload->IsMoving() ) ) 
00626                 {
00627                         //Send the file hash to the ed2k server
00628                         pPacket->Write( &pDownload->m_pED2K, sizeof(MD4) );
00629 
00630                         //If we have a 'new' ed2k server
00631                         if ( m_nTCPFlags & ED2K_SERVER_TCP_DEFLATE )
00632                         {
00633                                 //Tell the server this is a partial using special code
00634                                 pPacket->WriteLongLE( 0xFCFCFCFC );
00635                                 pPacket->WriteShortLE ( 0xFCFC );
00636                         }
00637                         else
00638                         {       //Send IP stuff. (Doesn't seem to be used for anything)
00639                                 if ( CEDPacket::IsLowID( m_nClientID ) )        //If we have a low ID
00640                                 {       //Send 0
00641                                         pPacket->WriteLongLE( 0 );
00642                                         pPacket->WriteShortLE ( 0 );
00643                                 }
00644                                 else    //High ID
00645                                 {       //send our IP
00646                                         pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
00647                                         pPacket->WriteShortLE ( Network.m_pHost.sin_port );
00648                                 }
00649                         }
00650 
00651                         //Send tags
00652                         pPacket->WriteLongLE( 2 ); //Number of Tags
00653 
00654                         //Send the file name to the ed2k server
00655                         CEDTag( ED2K_FT_FILENAME, pDownload->m_sRemoteName ).Write( pPacket, m_nTCPFlags );
00656                         //Send the file size to the ed2k server
00657                         CEDTag( ED2K_FT_FILESIZE, (DWORD)pDownload->m_nSize ).Write( pPacket, m_nTCPFlags );
00658                         //Send the file type to the ed2k server
00659                         //CEDTag( ED2K_FT_FILETYPE, strType ).Write( pPacket ); // We don't know it for certain with
00660                         // incomplete files. Might be okay to assume from the extention, since they are usually correct.
00661 
00662                         // Don't send metadata for incomplete files, since we have not verified it yet.
00663                         // We should be careful not propagate unchecked metadata over ed2k, since there seems
00664                         // to be a bit of a problem with bad data there... (Possibly old clients?)
00665 
00666                         //Increment count of files sent
00667                         m_nFilesSent++;
00668                 }
00669         }
00670         pTransfersLock.Unlock();
00671         
00672         //Send files in library to ed2k server (Complete files)
00673         pLibraryLock.Lock();
00674         for ( pos = LibraryMaps.GetFileIterator() ; pos != NULL && ( m_nFilesSent < m_nFileLimit ) ; )
00675         {
00676                 CLibraryFile* pFile = LibraryMaps.GetNextFile( pos );
00677                 
00678                 if ( pFile->IsShared() && pFile->m_bED2K )      //If file is shared and has an ed2k hash
00679                 {
00680                         if ( ( Settings.eDonkey.MinServerFileSize == 0 ) || ( pFile->GetSize() > Settings.eDonkey.MinServerFileSize * 1024 * 1024 ) ) // If file is large enough to meet minimum requirement
00681                         {
00682                                 if ( UploadQueues.CanUpload( PROTOCOL_ED2K, pFile ) ) // Check if a queue exists
00683                                 {
00684                                         // Initialise variables
00685                                         DWORD nTags;
00686                                         CString strType(_T("")), strCodec(_T(""));
00687                                         DWORD nBitrate = 0, nLength = 0;
00688                                         BYTE nRating = 0;
00689 
00690                                         // Send the file hash to the ed2k server
00691                                         pPacket->Write( &pFile->m_pED2K, sizeof(MD4) );
00692 
00693                                         //Send client ID stuff
00694                                         if ( m_nTCPFlags & ED2K_SERVER_TCP_DEFLATE ) // If we have a 'new' ed2k server
00695                                         {
00696                                                 //Tell the server this is a complete file using the special code
00697                                                 pPacket->WriteLongLE( 0xFBFBFBFB );
00698                                                 pPacket->WriteShortLE ( 0xFBFB );
00699                                         }
00700                                         else    //'old' server
00701                                         {       //Send IP stuff. (unused?)
00702                                                 if ( CEDPacket::IsLowID( m_nClientID ) )        //If we have a low ID
00703                                                 {       //Send 0
00704                                                         pPacket->WriteLongLE( 0 );
00705                                                         pPacket->WriteShortLE ( 0 );
00706                                                 }
00707                                                 else    //High ID
00708                                                 {       // send our IP
00709                                                         pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
00710                                                         pPacket->WriteShortLE ( Network.m_pHost.sin_port );
00711                                                 }
00712                                         }
00713 
00715 
00716                                         // First, figure out what tags should be sent.
00717                                         nTags = 2; // File name and size are always present
00718                                         if ( pFile->m_pSchema != NULL ) // We need a schema to have extended details
00719                                         {
00720                                                 // Do we have a file type?
00721                                                 if ( pFile->m_pSchema->m_sDonkeyType.GetLength() )
00722                                                 {
00723                                                         strType = pFile->m_pSchema->m_sDonkeyType;
00724                                                         nTags ++;
00725                                                 }
00726 
00727                                                 //Does this server support the new tags?
00728                                                 if ( m_nTCPFlags & ED2K_SERVER_TCP_SMALLTAGS )  
00729                                                 {                                       
00730                                                         if ( pFile->IsSchemaURI( CSchema::uriAudio ) )  //If it's an audio file
00731                                                         {
00732                                                                 // Bitrate
00733                                                                 if ( pFile->m_pMetadata->GetAttributeValue( _T("bitrate") ).GetLength() )       //And has a bitrate
00734                                                                 {       //Read in the bitrate
00735                                                                         _stscanf( pFile->m_pMetadata->GetAttributeValue( _T("bitrate") ), _T("%i"), &nBitrate );
00736                                                                         if ( nBitrate ) nTags ++;
00737                                                                 }
00738 
00739                                                                 // Length
00740                                                                 if ( pFile->m_pMetadata->GetAttributeValue( _T("seconds") ).GetLength() )       //And has seconds
00741                                                                 {       //Read in the no. seconds
00742                                                                         _stscanf( pFile->m_pMetadata->GetAttributeValue( _T("seconds") ), _T("%i"), &nLength );
00743                                                                         if ( nLength ) nTags ++;
00744                                                                 }
00745                                                         }
00746 
00747                                                         
00748                                                         if ( pFile->IsSchemaURI( CSchema::uriVideo ) )  //If it's a video file
00749                                                         {
00750                                                                 // Codec
00751                                                                 if ( pFile->m_pMetadata->GetAttributeValue( _T("codec") ).GetLength() ) //And has a codec
00752                                                                 {
00753                                                                         strCodec = pFile->m_pMetadata->GetAttributeValue( _T("codec") );
00754                                                                         if ( strCodec.GetLength() ) nTags ++;
00755                                                                 }
00756 
00757                                                                 // Length
00758                                                                 if ( pFile->m_pMetadata->GetAttributeValue( _T("minutes") ).GetLength() )       //And has minutes
00759                                                                 {       
00760                                                                         double nMins;
00761                                                                         //Read in the no. seconds
00762                                                                         _stscanf( pFile->m_pMetadata->GetAttributeValue( _T("minutes") ), _T("%.3lf"), &nMins );
00763                                                                         nLength = (DWORD)( nMins * (double)60 );        //Convert to seconds
00764                                                                         if ( nLength ) nTags ++;
00765                                                                 }
00766                                                         }
00767                                                 }
00768                                         }
00769 
00770                                         // Only newer servers support file ratings
00771                                         if ( ( m_nTCPFlags & ED2K_SERVER_TCP_SMALLTAGS ) && ( pFile->m_nRating ) )
00772                                         {
00773                                                 nRating = min ( pFile->m_nRating, 5 );
00774                                                 nTags ++;
00775                                         }
00776 
00778 
00779                                         // Set the number of tags present
00780                                         pPacket->WriteLongLE( nTags );
00781         
00782                                         // Send the file name to the ed2k server
00783                                         CEDTag( ED2K_FT_FILENAME, pFile->m_sName ).Write( pPacket, m_nTCPFlags );
00784                                         // Send the file size to the ed2k server
00785                                         CEDTag( ED2K_FT_FILESIZE, (DWORD)pFile->GetSize() ).Write( pPacket, m_nTCPFlags );
00786                                         // Send the file type to the ed2k server
00787                                         if ( strType.GetLength() ) CEDTag( ED2K_FT_FILETYPE, strType ).Write( pPacket, m_nTCPFlags );
00788                                         // Send the bitrate to the ed2k server
00789                                         if ( nBitrate ) CEDTag( ED2K_FT_BITRATE, nBitrate ).Write( pPacket, m_nTCPFlags );
00790                                         // Send the length to the ed2k server
00791                                         if ( nLength )  CEDTag( ED2K_FT_LENGTH, nLength ).Write( pPacket, m_nTCPFlags );
00792                                         // Send the codec to the ed2k server
00793                                         if ( strCodec.GetLength() ) CEDTag( ED2K_FT_CODEC, strCodec ).Write( pPacket, m_nTCPFlags );
00794                                         // Send the file rating to the ed2k server
00795                                         if ( nRating ) CEDTag( ED2K_FT_FILERATING, nRating ).Write( pPacket, m_nTCPFlags );
00796 
00797                                         // Increment count of files sent
00798                                         m_nFilesSent++;
00799                                 }
00800                         }
00801                 }
00802         }
00803         pLibraryLock.Unlock();
00804 
00805         *(DWORD*)pPacket->m_pBuffer = m_nFilesSent;     // Correct the number of files sent
00806         
00807         if ( m_nTCPFlags & ED2K_SERVER_TCP_DEFLATE ) pPacket->Deflate();        // ZLIB compress if available
00808 
00809         Send( pPacket );        // Send the packet
00810 }
00811 
00812 // This function adds a download to the ed2k server file list.
00813 BOOL CEDNeighbour::SendSharedDownload(CDownload* pDownload)
00814 {
00815         // Don't send this file if we aren't properly connected yet, don't have an ed2k hash/hashset,
00816         // or have already sent too many files.
00817         if ( m_nState < nrsConnected ) return FALSE;
00818         if ( ! pDownload->m_bED2K || pDownload->NeedHashset() ) return FALSE;
00819         if ( pDownload->m_nSize == SIZE_UNKNOWN ) return FALSE;
00820         if ( m_nFilesSent >= m_nFileLimit ) return FALSE;
00821         
00822         
00823         CEDPacket* pPacket = CEDPacket::New(  ED2K_C2S_OFFERFILES );
00824         pPacket->WriteLongLE( 1 );              // Number of files that will be sent
00825 
00826         // Send the file hash to the ed2k server
00827         pPacket->Write( &pDownload->m_pED2K, sizeof(MD4) );
00828 
00829         // If we have a 'new' ed2k server
00830         if ( m_nTCPFlags & ED2K_SERVER_TCP_DEFLATE )
00831         {
00832                 // Tell the server this is a partial using special code
00833                 pPacket->WriteLongLE( 0xFCFCFCFC );
00834                 pPacket->WriteShortLE ( 0xFCFC );
00835         }
00836         else
00837         {       // Send IP stuff. (Doesn't seem to be used for anything)
00838                 if ( CEDPacket::IsLowID( m_nClientID ) )        // If we have a low ID
00839                 {       // Send 0
00840                         pPacket->WriteLongLE( 0 );
00841                         pPacket->WriteShortLE ( 0 );
00842                 }
00843                 else    //High ID
00844                 {       //send our IP
00845                         pPacket->WriteLongLE( Network.m_pHost.sin_addr.S_un.S_addr );
00846                         pPacket->WriteShortLE ( Network.m_pHost.sin_port );
00847                 }
00848         }
00849 
00850         //Send tags
00851         pPacket->WriteLongLE( 2 ); // Number of Tags
00852 
00853         // Send the file name to the ed2k server
00854         CEDTag( ED2K_FT_FILENAME, pDownload->m_sRemoteName ).Write( pPacket, m_nTCPFlags );
00855         // Send the file size to the ed2k server
00856         CEDTag( ED2K_FT_FILESIZE, (DWORD)pDownload->m_nSize ).Write( pPacket, m_nTCPFlags );
00857 
00858         // Compress if the server supports it
00859         if ( m_nTCPFlags & ED2K_SERVER_TCP_DEFLATE ) pPacket->Deflate();
00860         Send( pPacket );
00861 
00862         // Increment the number of files sent
00863         m_nFilesSent ++;
00864         
00865         return TRUE;
00866 }
00867 
00869 // CEDNeighbour file adverising
00870 
00871 BOOL CEDNeighbour::SendQuery(CQuerySearch* pSearch, CPacket* pPacket, BOOL bLocal)
00872 {
00873         if ( m_nState != nrsConnected || m_nClientID == 0 )
00874         {
00875                 return FALSE;   // We're not ready
00876         }
00877         else if ( pPacket == NULL || pPacket->m_nProtocol != PROTOCOL_ED2K || ! bLocal )
00878         {
00879                 return FALSE;   // Packet is bad
00880         }
00881 
00882         // Don't add the GUID for GetSources
00883         if ( ( ! pSearch->m_bED2K ) || ( pSearch->m_bWantDN && Settings.eDonkey.MagnetSearch ) )
00884                 m_pQueries.AddTail( new GGUID( pSearch->m_pGUID ) );
00885 
00886         Send( pPacket, FALSE, FALSE );
00887         
00888         return TRUE;
00889 }

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