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

BTClient.cpp

Go to the documentation of this file.
00001 //
00002 // BTClient.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 "BTClient.h"
00026 #include "BTClients.h"
00027 #include "BTPacket.h"
00028 #include "BENode.h"
00029 #include "Buffer.h"
00030 #include "SHA.h"
00031 
00032 #include "Download.h"
00033 #include "Downloads.h"
00034 #include "DownloadSource.h"
00035 #include "DownloadTransferBT.h"
00036 #include "Uploads.h"
00037 #include "UploadTransferBT.h"
00038 #include "SourceURL.h"
00039 #include "GProfile.h"
00040 
00041 #ifdef _DEBUG
00042 #undef THIS_FILE
00043 static char THIS_FILE[]=__FILE__;
00044 #define new DEBUG_NEW
00045 #endif
00046 
00047 
00049 // CBTClient construction
00050 
00051 CBTClient::CBTClient()
00052 {
00053         m_bExtended                     = FALSE;
00054         m_pUpload                       = NULL;
00055         m_pDownload                     = NULL;
00056         m_pDownloadTransfer     = NULL;
00057         
00058         m_bShake                        = FALSE;
00059         m_bOnline                       = FALSE;
00060         m_bClosing                      = FALSE;
00061         m_bExchange                     = FALSE;
00062         
00063         m_sUserAgent = _T("BitTorrent");
00064         m_mInput.pLimit = m_mOutput.pLimit = &Settings.Bandwidth.Request;
00065         
00066         BTClients.Add( this );
00067 }
00068 
00069 CBTClient::~CBTClient()
00070 {
00071         ASSERT( m_hSocket == INVALID_SOCKET );
00072         ASSERT( m_pDownloadTransfer == NULL );
00073         ASSERT( m_pDownload == NULL );
00074         ASSERT( m_pUpload == NULL );
00075         
00076         BTClients.Remove( this );
00077 }
00078 
00080 // CBTClient initiate a new connection
00081 
00082 BOOL CBTClient::Connect(CDownloadTransferBT* pDownloadTransfer)
00083 {
00084         ASSERT( m_hSocket == INVALID_SOCKET );
00085         ASSERT( m_pDownload == NULL );
00086         
00087         CDownloadSource* pSource = pDownloadTransfer->m_pSource;
00088         
00089         if ( ! CTransfer::ConnectTo( &pSource->m_pAddress, pSource->m_nPort ) ) return FALSE;
00090         
00091         m_pDownload                     = pDownloadTransfer->m_pDownload;
00092         m_pDownloadTransfer     = pDownloadTransfer;
00093         
00094         theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_CONNECTING, (LPCTSTR)m_sAddress );
00095         
00096         return TRUE;
00097 }
00098 
00100 // CBTClient attach to existing connection
00101 
00102 void CBTClient::AttachTo(CConnection* pConnection)
00103 {
00104         ASSERT( m_hSocket == INVALID_SOCKET );
00105         CTransfer::AttachTo( pConnection );
00106         theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_ACCEPTED, (LPCTSTR)m_sAddress );
00107 }
00108 
00110 // CBTClient close
00111 
00112 void CBTClient::Close()
00113 {
00114         ASSERT( this != NULL );
00115         
00116         if ( m_bClosing ) return;
00117         m_bClosing = TRUE;
00118         
00119         if ( m_pUpload != NULL ) m_pUpload->Close();
00120         ASSERT( m_pUpload == NULL );
00121         
00122         if ( m_pDownloadTransfer != NULL ) 
00123         {
00124                 if ( ( m_pDownload == NULL ) || ( m_pDownload->IsCompleted() ) )
00125                         m_pDownloadTransfer->Close( TS_FALSE );
00126                 else
00127                         m_pDownloadTransfer->Close( TS_UNKNOWN );
00128         }
00129         ASSERT( m_pDownloadTransfer == NULL );
00130         
00131         m_pDownload = NULL;
00132         
00133         CTransfer::Close();
00134         
00135         delete this;
00136 }
00137 
00139 // CBTClient send a packet
00140 
00141 void CBTClient::Send(CBTPacket* pPacket, BOOL bRelease)
00142 {
00143         ASSERT( m_hSocket != INVALID_SOCKET );
00144         ASSERT( m_bOnline );
00145         
00146         if ( pPacket != NULL )
00147         {
00148                 ASSERT( pPacket->m_nProtocol == PROTOCOL_BT );
00149                 
00150                 pPacket->ToBuffer( m_pOutput );
00151                 if ( bRelease ) pPacket->Release();
00152         }
00153         
00154         OnWrite();
00155 }
00156 
00158 // CBTClient run event
00159 
00160 BOOL CBTClient::OnRun()
00161 {
00162         CTransfer::OnRun();
00163         
00164         DWORD tNow = GetTickCount();
00165         
00166         if ( ! m_bConnected )
00167         {
00168                 if ( tNow - m_tConnected > Settings.Connection.TimeoutConnect )
00169                 {
00170                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_CONNECT_TIMEOUT, (LPCTSTR)m_sAddress );
00171                         Close();
00172                         return FALSE;
00173                 }
00174         }
00175         else if ( ! m_bOnline )
00176         {
00177                 if ( tNow - m_tConnected > Settings.Connection.TimeoutHandshake )
00178                 {
00179                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_HANDSHAKE_TIMEOUT, (LPCTSTR)m_sAddress );
00180                         Close();
00181                         return FALSE;
00182                 }
00183         }
00184         else
00185         {
00186                 if ( tNow - m_mInput.tLast > Settings.BitTorrent.LinkTimeout * 2 )
00187                 {
00188                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_LOST, (LPCTSTR)m_sAddress );
00189                         Close();
00190                         return FALSE;
00191                 }
00192                 else if ( tNow - m_mOutput.tLast > Settings.BitTorrent.LinkPing / 2 && m_pOutput->m_nLength == 0 )
00193                 {
00194                         DWORD dwZero = 0;
00195                         m_pOutput->Add( &dwZero, 4 );
00196                         OnWrite();
00197                 }
00198                 
00199 
00200                 ASSERT ( m_pUpload != NULL );
00201 
00202                 if ( m_pDownloadTransfer != NULL && ! m_pDownloadTransfer->OnRun() ) return FALSE;
00203                 if ( m_pUpload == NULL || ! m_pUpload->OnRun() ) return FALSE;
00204         }
00205         
00206         return TRUE;
00207 }
00208 
00210 // CBTClient connection establishment event
00211 
00212 BOOL CBTClient::OnConnected()
00213 {
00214         theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_HANDSHAKING, (LPCTSTR)m_sAddress );
00215         SendHandshake( TRUE, TRUE );
00216         return TRUE;
00217 }
00218 
00220 // CBTClient connection loss event
00221 
00222 void CBTClient::OnDropped(BOOL bError)
00223 {
00224         if ( ! m_bConnected )
00225                 theApp.Message( MSG_ERROR, IDS_BT_CLIENT_DROP_CONNECTING, (LPCTSTR)m_sAddress );
00226         else if ( ! m_bOnline )
00227                 theApp.Message( MSG_ERROR, IDS_BT_CLIENT_DROP_HANDSHAKE, (LPCTSTR)m_sAddress );
00228         else
00229                 theApp.Message( MSG_ERROR, IDS_BT_CLIENT_DROP_CONNECTED, (LPCTSTR)m_sAddress );
00230            
00231         Close();
00232 }
00233 
00235 // CBTClient write event
00236 
00237 BOOL CBTClient::OnWrite()
00238 {
00239         CTransfer::OnWrite();
00240         return TRUE;
00241 }
00242 
00244 // CBTClient read event
00245 
00246 BOOL CBTClient::OnRead()
00247 {
00248         BOOL bSuccess = TRUE;
00249         
00250         CTransfer::OnRead();
00251         
00252         if ( m_bOnline )
00253         {
00254                 CBTPacket* pPacket;
00255                 
00256                 while ( pPacket = CBTPacket::ReadBuffer( m_pInput ) )
00257                 {
00258                         try
00259                         {
00260                                 bSuccess = OnPacket( pPacket );
00261                         }
00262                         catch ( CException* pException )
00263                         {
00264                                 pException->Delete();
00265                                 if ( ! m_bOnline ) bSuccess = FALSE;
00266                         }
00267                         
00268                         pPacket->Release();
00269                         if ( ! bSuccess ) break;
00270                 }
00271         }
00272         else
00273         {
00274                 if ( ! m_bShake && m_pInput->m_nLength >= BT_PROTOCOL_HEADER_LEN + 8 + sizeof(SHA1) )
00275                 {
00276                         bSuccess = OnHandshake1();
00277                 }
00278                 
00279                 if ( bSuccess && m_bShake && m_pInput->m_nLength >= sizeof(SHA1) )
00280                 {
00281                         bSuccess = OnHandshake2();
00282                 }/*
00283                 else if ( bSuccess && m_bShake )
00284                 {
00285                         DWORD tNow = GetTickCount();
00286                         if ( tNow - m_tConnected > Settings.Connection.TimeoutHandshake / 2 )
00287                         {
00288                                 theApp.Message( MSG_ERROR,  _T("No peer-id received, forcing connection") );
00289                                 bSuccess = OnNoHandshake2();
00290                         }
00291                 }*/
00292         }
00293         
00294         return bSuccess;
00295 }
00296 
00298 // CBTClient handshaking
00299 
00300 void CBTClient::SendHandshake(BOOL bPart1, BOOL bPart2)
00301 {
00302         ASSERT( m_pDownload != NULL );
00303         
00304         if ( bPart1 )
00305         {
00306                 DWORD dwZero = 0;
00307                 m_pOutput->Print( BT_PROTOCOL_HEADER );
00308                 m_pOutput->Add( &dwZero, 4 );
00309                 m_pOutput->Add( &dwZero, 4 );
00310                 m_pOutput->Add( &m_pDownload->m_pBTH, sizeof(SHA1) );
00311         }
00312         
00313         if ( bPart2 )
00314         {
00315                 m_pOutput->Add( &m_pDownload->m_pPeerID, sizeof(SHA1) );
00316         }
00317         
00318         OnWrite();
00319 }
00320 
00321 BOOL CBTClient::OnHandshake1()
00322 {       //First part of the handshake
00323         ASSERT( ! m_bOnline );
00324         ASSERT( ! m_bShake );
00325         
00326         LPBYTE pIn = m_pInput->m_pBuffer;
00327         
00328         // Read in the BT protocol header
00329         if ( memcmp( pIn, BT_PROTOCOL_HEADER, BT_PROTOCOL_HEADER_LEN ) != 0 )
00330         {
00331                 ASSERT( FALSE );
00332                 theApp.Message( MSG_ERROR, _T("BitTorrent coupling from %s had invalid header"), (LPCTSTR)m_sAddress );
00333                 Close();
00334                 return FALSE;
00335         }
00336         
00337         pIn += BT_PROTOCOL_HEADER_LEN + 8;
00338         
00339         // Read in the file ID
00340         SHA1 pFileHash = *(SHA1*)pIn;
00341         pIn += sizeof(SHA1);
00342         
00343         m_pInput->Remove( BT_PROTOCOL_HEADER_LEN + 8 + sizeof(SHA1) );
00344         
00345         if ( m_bInitiated )             // If we initiated the connection
00346         {
00347                 ASSERT( m_pDownload != NULL );
00348                 ASSERT( m_pDownloadTransfer != NULL );
00349                 
00350                 if ( pFileHash != m_pDownload->m_pBTH || m_pDownload->IsShared() == FALSE )
00351                 {       //Display and error and exit
00352                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_WRONG_FILE, (LPCTSTR)m_sAddress );
00353                         Close();
00354                         return FALSE;
00355                 }
00356                 else if ( ! m_pDownload->IsTrying() )
00357                 {       //Display and error and exit
00358                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_INACTIVE_FILE, (LPCTSTR)m_sAddress );
00359                         Close();
00360                         return FALSE;
00361                 }
00362         }
00363         else                                    // If we didn't initiate the connection
00364         {
00365                 ASSERT( m_pDownload == NULL );
00366                 ASSERT( m_pDownloadTransfer == NULL );
00367                 
00368                 // Find the requested file
00369                 m_pDownload = Downloads.FindByBTH( &pFileHash, TRUE );
00370                 
00371                 if ( m_pDownload == NULL )                              // If we can't find the file
00372                 {       //Display and error and exit
00373                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_UNKNOWN_FILE, (LPCTSTR)m_sAddress );
00374                         Close();
00375                         return FALSE;
00376                 }
00377                 else if ( ! m_pDownload->IsTrying() )   // If the file isn't active
00378                 {       //Display and error and exit
00379                         m_pDownload = NULL;
00380                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_INACTIVE_FILE, (LPCTSTR)m_sAddress );
00381                         Close();
00382                         return FALSE;
00383                 }
00384                 else if ( m_pDownload->UploadExists( &m_pHost.sin_addr ) )      // If there is already an upload of this file to this client
00385                 {       // Display and error and exit
00386                         m_pDownload = NULL;
00387                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_DUPLICATE, (LPCTSTR)m_sAddress );
00388                         Close();
00389                         return FALSE;
00390                 }
00391 
00392                 // Check we don't have too many active torrent connections 
00393                 // (Prevent routers overloading for very popular torrents)
00394                 if ( ( m_pDownload->GetTransferCount( dtsCountTorrentAndActive ) ) > ( Settings.BitTorrent.DownloadConnections * 1.25 ) ) 
00395                 {
00396                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_MAX_CONNECTIONS, (LPCTSTR)m_sAddress );
00397                         Close();
00398                         return FALSE;
00399                 }
00400 
00401         }
00402         
00403         // Verify a download and hash
00404         ASSERT( m_pDownload != NULL );
00405         ASSERT( m_pDownload->m_pBTH == pFileHash );
00406         
00407         // If we didn't start the connection, then send a handshake
00408         if ( ! m_bInitiated ) SendHandshake( TRUE, TRUE );
00409         m_bShake = TRUE;
00410         
00411         return TRUE;
00412 }
00413 
00414 BOOL CBTClient::OnHandshake2()
00415 {       // Second part of the handshake - Peer ID
00416         m_pGUID = *(SHA1*)m_pInput->m_pBuffer;
00417         m_pInput->Remove( sizeof(SHA1) );
00418         
00419         for ( int nByte = 0 ; nByte < 20 ; nByte++ )
00420         {
00421                 if ( nByte < 16 )
00422                 {
00423                         if ( m_pGUID.b[ nByte ] ) m_bExtended = TRUE;
00424                 }
00425                 else
00426                 {
00427                         if ( m_pGUID.b[ nByte ] != ( m_pGUID.b[ nByte % 16 ] ^ m_pGUID.b[ 15 - ( nByte % 16 ) ] ) )
00428                         {
00429                                 m_bExtended = FALSE;
00430                                 break;
00431                         }
00432                 }
00433         }
00434         
00435         ASSERT( m_pDownload != NULL );
00436         
00437         if ( m_bInitiated )
00438         {
00439                 ASSERT( m_pDownloadTransfer != NULL );
00440                 CopyMemory( &m_pDownloadTransfer->m_pSource->m_pGUID, &m_pGUID, 16 );
00441                 
00442                 /*
00443 
00444                 //ToDo: This seems to trip when it shouldn't. Should be investigated...
00445                 if ( memcmp( &m_pGUID, &m_pDownloadTransfer->m_pSource->m_pGUID, 16 ) != 0 )
00446                 {
00447                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_WRONG_GUID, (LPCTSTR)m_sAddress );
00448                         Close();
00449                         return FALSE;
00450                 }
00451                 */
00452         }
00453         else 
00454         {
00455                 if ( m_pDownload->UploadExists( &m_pGUID ) )
00456                 {
00457                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_DUPLICATE, (LPCTSTR)m_sAddress );
00458                         Close();
00459                         return FALSE;
00460                 }
00461 
00462                 if ( ! m_pDownload->IsMoving() && ! m_pDownload->IsPaused() )
00463                 {
00464                         ASSERT( m_pDownloadTransfer == NULL );
00465                         
00466                         // Download from uploaders, unless the user has turned off downloading for this torrent
00467                         if ( m_pDownload->m_nStartTorrentDownloads != dtNever ) 
00468                         {
00469                                 // This seems to be set to null sometimes... DownloadwithTorrent: if ( pSource->m_pTransfer != NULL )
00470                                 // May just be clients sending duplicate connection requests, though...
00471                                 m_pDownloadTransfer = m_pDownload->CreateTorrentTransfer( this );
00472 
00473                                 if ( m_pDownloadTransfer == NULL )
00474                                 {
00475                                         m_pDownload = NULL;
00476                                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_UNKNOWN_FILE, (LPCTSTR)m_sAddress );
00477                                         Close();
00478                                         return FALSE;
00479                                 }
00480                         }
00481                 }
00482         }
00483         
00484         ASSERT( m_pUpload == NULL );
00485         m_pUpload = new CUploadTransferBT( this, m_pDownload );
00486         
00487         m_bOnline = TRUE;
00488         
00489         DetermineUserAgent();
00490         if ( m_bExtended ) m_sUserAgent = _T("Shareaza");
00491         
00492         return OnOnline();
00493 }
00494 /*
00495 BOOL CBTClient::OnNoHandshake2()
00496 {       // If the other client didn't send a peer ID
00497         ZeroMemory( m_pGUID.b, 20 );
00498         
00499         ASSERT( m_pDownload != NULL );
00500         
00501         if ( m_bInitiated )
00502         {
00503                 ASSERT( m_pDownloadTransfer != NULL );
00504                 CopyMemory( &m_pDownloadTransfer->m_pSource->m_pGUID, &m_pGUID, 16 );
00505         }
00506         else if ( ! m_pDownload->IsMoving() && ! m_pDownload->IsPaused() )
00507         {
00508                 ASSERT( m_pDownloadTransfer == NULL );
00509                 
00510                 m_pDownloadTransfer = m_pDownload->CreateTorrentTransfer( this );
00511                 //This seems to be set to null sometimes... DownloadwithTorrent: if ( pSource->m_pTransfer != NULL )
00512                 if ( m_pDownloadTransfer == NULL )
00513                 {
00514                         m_pDownload = NULL;
00515                         theApp.Message( MSG_ERROR, IDS_BT_CLIENT_UNKNOWN_FILE, (LPCTSTR)m_sAddress );
00516                         Close();
00517                         return FALSE;
00518                 }
00519         }
00520         
00521         ASSERT( m_pUpload == NULL );
00522         m_pUpload = new CUploadTransferBT( this, m_pDownload );
00523         
00524         m_bOnline = TRUE;
00525         
00526         if ( ! m_bInitiated ) SendHandshake( FALSE, TRUE );
00527         
00528         return OnOnline();
00529 }
00530 */
00532 // CBTClient online handler
00533 
00534 void CBTClient::DetermineUserAgent()
00535 {
00536         int nNickStart = 0, nNickEnd = 13;
00537         CString strVer, strNick;
00538 
00539         if ( m_pGUID.b[0] == '-' && m_pGUID.b[7] == '-' )       
00540         {       // Azerus style
00541                 if ( m_pGUID.b[1] == 'A' && m_pGUID.b[2] == 'R' )
00542                 {
00543                         m_sUserAgent = _T("Arctic");
00544                 }
00545                 else if ( m_pGUID.b[1] == 'A' && m_pGUID.b[2] == 'Z' )
00546                 {
00547                         m_sUserAgent = _T("Azureus");
00548                 }
00549                 else if ( m_pGUID.b[1] == 'B' && m_pGUID.b[2] == 'B' )
00550                 {
00551                         m_sUserAgent = _T("BitBuddy");
00552                 }
00553                 else if ( m_pGUID.b[1] == 'B' && m_pGUID.b[2] == 'C' )
00554                 {
00555                         m_sUserAgent = _T("BitComet");
00556                 }
00557                 else if ( m_pGUID.b[1] == 'b' && m_pGUID.b[2] == 'k' )
00558                 {
00559                         m_sUserAgent = _T("BitKitten");
00560                 }
00561                 else if ( m_pGUID.b[1] == 'B' && m_pGUID.b[2] == 'O' )
00562                 {
00563                         // ?
00564                         m_sUserAgent = _T("BO");
00565                 }
00566                 else if ( m_pGUID.b[1] == 'B' && m_pGUID.b[2] == 'S' )
00567                 {
00568                         m_sUserAgent = _T("BTSlave");
00569                 }
00570                 else if ( m_pGUID.b[1] == 'B' && m_pGUID.b[2] == 'X' )
00571                 {
00572                         m_sUserAgent = _T("Bittorrent X");
00573                 }
00574                 else if ( m_pGUID.b[1] == 'C' && m_pGUID.b[2] == 'T' )
00575                 {
00576                         m_sUserAgent = _T("CTorrent");
00577                 }
00578                 else if ( ( m_pGUID.b[1] == 'L' && m_pGUID.b[2] == 'T' ) || ( m_pGUID.b[1] == 'l' && m_pGUID.b[2] == 't' ) )
00579                 {
00580                         m_sUserAgent = _T("libtorrent");
00581                 }
00582                 else if ( m_pGUID.b[1] == 'M' && m_pGUID.b[2] == 'P' )
00583                 {
00584                         m_sUserAgent = _T("MooPolice");
00585                 }
00586                 else if ( m_pGUID.b[1] == 'M' && m_pGUID.b[2] == 'T' )
00587                 {
00588                         m_sUserAgent = _T("MoonlightTorrent");
00589                 }
00590                 else if ( m_pGUID.b[1] == 'Q' && m_pGUID.b[2] == 'T' )
00591                 {
00592                         m_sUserAgent = _T("QT4");
00593                 }
00594                 else if ( m_pGUID.b[1] == 'S' && m_pGUID.b[2] == 'B' )
00595                 {
00596                         m_sUserAgent = _T("Swiftbit");
00597                 }
00598                 else if ( m_pGUID.b[1] == 'S' && m_pGUID.b[2] == 'N' )
00599                 {
00600                         m_sUserAgent = _T("ShareNET");
00601                 }
00602                 else if ( m_pGUID.b[1] == 'S' && m_pGUID.b[2] == 'S' )
00603                 {
00604                         m_sUserAgent = _T("Swarmscope");
00605                 }
00606                 else if ( m_pGUID.b[1] == 'S' && m_pGUID.b[2] == '~' )
00607                 {       
00608                         m_sUserAgent = _T("Sbeta");
00609                 }
00610                 else if ( m_pGUID.b[1] == 'S' && m_pGUID.b[2] == 'Z' )
00611                 {       
00612                         //m_sUserAgent = _T("Shareaza");
00613                         // Shareaza versions don't always 'fit' into the BT numbering, so skip that
00614                         m_sUserAgent.Empty();   
00615                 }
00616                 else if ( m_pGUID.b[1] == 'T' && m_pGUID.b[2] == 'N' )
00617                 {
00618                         m_sUserAgent = _T("TorrentDOTnet");
00619                 }
00620                 else if ( m_pGUID.b[1] == 'T' && m_pGUID.b[2] == 'S' )
00621                 {
00622                         m_sUserAgent = _T("Torrentstorm");
00623                 }
00624                 else if ( m_pGUID.b[1] == 'X' && m_pGUID.b[2] == 'T' )
00625                 {
00626                         m_sUserAgent = _T("XanTorrent");
00627                 }
00628                 else if ( m_pGUID.b[1] == 'Z' && m_pGUID.b[2] == 'T' )
00629                 {
00630                         m_sUserAgent = _T("ZipTorrent");
00631                 }
00632                 else // Unknown client using this naming.
00633                 {
00634                         m_sUserAgent.Format( _T("%c%c"), m_pGUID.b[1], m_pGUID.b[2] );
00635                 }
00636                 
00637                 if ( m_sUserAgent.IsEmpty() ) 
00638                 {
00639                         // If we don't want the version, etc.
00640                         m_sUserAgent.Format( _T("BitTorrent (%c%c)"), m_pGUID.b[1], m_pGUID.b[2] );
00641                 }
00642                 else
00643                 {
00644                         // Add the version to the name
00645                         strVer.Format( _T(" %i.%i.%i.%i"),
00646                                 ( m_pGUID.b[3] - '0' ), ( m_pGUID.b[4] - '0' ),
00647                                 ( m_pGUID.b[5] - '0' ), ( m_pGUID.b[6] - '0' ) );
00648                         m_sUserAgent += strVer;
00649                 }
00650         }
00651         else if ( m_pGUID.b[4] == '-' && m_pGUID.b[5] == '-' && m_pGUID.b[6] == '-' && m_pGUID.b[7] == '-' )
00652         {       // Shadow style
00653                 switch ( m_pGUID.b[0] )
00654                 {
00655                 case 'A':
00656                         m_sUserAgent = _T("ABC");
00657                         break;
00658                 case 'O':
00659                         m_sUserAgent = _T("Osprey");
00660                         break;
00661                 case 'S':
00662                         m_sUserAgent = _T("Shadow");
00663                         break;
00664                 case 'T':
00665                         m_sUserAgent = _T("BitTornado");
00666                         break;
00667                 case 'U':
00668                         m_sUserAgent = _T("UPnP NAT BT");
00669                         break;
00670                 default: // Unknown client using this naming.
00671                         m_sUserAgent.Format(_T("%c"), m_pGUID.b[0]);
00672                 }
00673                 
00674                 strVer.Format( _T(" %i.%i.%i"),
00675                         ( m_pGUID.b[1] - '0' ), ( m_pGUID.b[2] - '0' ),
00676                         ( m_pGUID.b[3] - '0' ) );
00677                 m_sUserAgent += strVer;
00678         }
00679         else if  ( m_pGUID.b[0] == 'M' && m_pGUID.b[2] == '-' && m_pGUID.b[4] == '-' && m_pGUID.b[6] == '-' )
00680         {       // BitTorrent (Standard client, newer version)
00681                 m_sUserAgent.Format( _T("BitTorrent %i.%i.%i"), m_pGUID.b[1] - '0' , m_pGUID.b[3] - '0' , m_pGUID.b[5]- '0' );
00682         }
00683         else if  ( m_pGUID.b[0] == 'P' && m_pGUID.b[1] == 'l' && m_pGUID.b[2] == 'u' && m_pGUID.b[3] == 's' )
00684         {       // BitTorrent Plus
00685                 m_sUserAgent.Format( _T("BitTorrent Plus %i.%i%i"), m_pGUID.b[4] - '0', m_pGUID.b[5] - '0', m_pGUID.b[6] - '0' );
00686         }
00687         else if  ( m_pGUID.b[0] == 'e' && m_pGUID.b[1] == 'x' && m_pGUID.b[2] == 'b' && m_pGUID.b[3] == 'c' )
00688         {       
00689                 // BitLord
00690                 if  ( m_pGUID.b[6] == 'L' && m_pGUID.b[7] == 'O' && m_pGUID.b[8] == 'R' && m_pGUID.b[9] == 'D' )
00691                         m_sUserAgent.Format( _T("BitLord %i.%02i"), m_pGUID.b[4], m_pGUID.b[5] );
00692                 // Old BitComet
00693                 else 
00694                         m_sUserAgent.Format( _T("BitComet %i.%02i"), m_pGUID.b[4], m_pGUID.b[5] );
00695         }
00696         else if  ( ( m_pGUID.b[0] == 'B' && m_pGUID.b[1] == 'S' ) || ( m_pGUID.b[2] == 'B' && m_pGUID.b[3] == 'S' ) )
00697         {       // BitSpirit
00698                 m_sUserAgent.Format( _T("BitSpirit") );
00699         }
00700         else if  ( m_pGUID.b[0] == 'B' && m_pGUID.b[1] == 'T' && m_pGUID.b[2] == 'M' )
00701         {       // BTuga Revolution
00702                 m_sUserAgent.Format( _T("BTuga Rv %i.%i"), m_pGUID.b[3] - '0', m_pGUID.b[4] - '0' );
00703                 nNickStart = 5;
00704         }
00705         else if  ( ( m_pGUID.b[0] == 'b' && m_pGUID.b[1] == 't' && m_pGUID.b[2] == 'u' && m_pGUID.b[3] == 'g' && m_pGUID.b[4] == 'a' ) || ( m_pGUID.b[0] == 'o' && m_pGUID.b[1] == 'e' && m_pGUID.b[2] == 'r' && m_pGUID.b[3] == 'n' && m_pGUID.b[4] == 'u' ) )
00706         {       // BTugaXP
00707                 m_sUserAgent.Format( _T("BTugaXP") );
00708         }
00709         else if  ( m_pGUID.b[0] == 'M' && m_pGUID.b[1] == 'b' && m_pGUID.b[2] == 'r' && m_pGUID.b[3] == 's' && m_pGUID.b[4] == 't' )
00710         {       // Burst
00711                 m_sUserAgent.Format( _T("Burst %i.%i.%i"), m_pGUID.b[5] - '0', m_pGUID.b[7] - '0', m_pGUID.b[9] - '0' );
00712         }
00713         else if  ( m_pGUID.b[0] == 'e' && m_pGUID.b[1] == 'X' )
00714         {       // eXeem
00715                 m_sUserAgent.Format( _T("eXeem") );
00716                 nNickStart = 2;
00717         }
00718         else if  ( m_pGUID.b[0] == '-' && m_pGUID.b[1] == 'G' && m_pGUID.b[2] == '3' )
00719         {       // G3 Torrent
00720                 m_sUserAgent.Format( _T("G3 Torrent") );
00721                 nNickStart = 3;
00722                 nNickEnd = 11;
00723         }
00724         else if  ( m_pGUID.b[0] == '-' && m_pGUID.b[1] == 'M' && m_pGUID.b[2] == 'L' )
00725         {       // MLdonkey
00726                 m_sUserAgent.Format( _T("MLdonkey %i.%i.%i"), m_pGUID.b[3] - '0' , m_pGUID.b[5] - '0' , m_pGUID.b[7] - '0' );
00727         }
00728         else if  ( m_pGUID.b[0] == 'O' && m_pGUID.b[1] == 'P' )
00729         {       // Opera
00730                 m_sUserAgent.Format( _T("Opera %i%i%i%i"), m_pGUID.b[2] - '0', m_pGUID.b[3] - '0', m_pGUID.b[4] - '0', m_pGUID.b[5] - '0' );
00731         }
00732         else if  ( ( m_pGUID.b[0] == 'a' && m_pGUID.b[1] == '0' && m_pGUID.b[2] == '0' && m_pGUID.b[3] == '-' && m_pGUID.b[4] == '-' && m_pGUID.b[5] == '-' && m_pGUID.b[6] == '0' ) || ( m_pGUID.b[0] == 'a' && m_pGUID.b[1] == '0' && m_pGUID.b[2] == '2' && m_pGUID.b[3] == '-' && m_pGUID.b[4] == '-' && m_pGUID.b[5] == '-' && m_pGUID.b[6] == '0' ) )
00733         {       // Swarmy
00734                 m_sUserAgent.Format( _T("Swarmy") );
00735         }
00736         else if  ( m_pGUID.b[0] == 'X' && m_pGUID.b[1] == 'B' && m_pGUID.b[2] == 'T' )
00737         {       // XBT
00738                 m_sUserAgent.Format( _T("XBT %i.%i.%i"), m_pGUID.b[3] - '0', m_pGUID.b[4] - '0', m_pGUID.b[5] - '0' );
00739         }
00740         else if  ( !m_pGUID.b[0] && !m_pGUID.b[1] && !m_pGUID.b[2] && !m_pGUID.b[3] && !m_pGUID.b[4] && !m_pGUID.b[5] && !m_pGUID.b[6] && !m_pGUID.b[7] && m_pGUID.b[8] && m_pGUID.b[9] && m_pGUID.b[10] && m_pGUID.b[11] && m_pGUID.b[12] && m_pGUID.b[13] && m_pGUID.b[14] && m_pGUID.b[15] && m_pGUID.b[16] == 'U' && m_pGUID.b[17] == 'D' && m_pGUID.b[18] == 'P' && m_pGUID.b[19] == '0' )
00741         {       // BitSpirit    (Spoofed Client ID)     // GUID 0 - 7: 0        GUID 8 - 15: !0 GUID 16 -19: UDP0       // ToDO: Check that other clients don't use this method
00742                 m_sUserAgent.Format( _T("BitSpirit") );
00743         }
00744         else
00745         {       // Unknown peer ID string
00746                 m_sUserAgent = _T("BitTorrent");
00747         }
00748 
00749         if ( nNickStart > 0 )
00750                 for ( int i = nNickStart; i <= nNickEnd; i++ )  // Extract nick from m_pGUID.b
00751                 {
00752                         if ( m_pGUID.b[i] == NULL ) break;
00753 
00754                         strNick.AppendFormat( _T("%c"), m_pGUID.b[i] );
00755                 }
00756 
00757         if ( m_pDownloadTransfer != NULL )
00758         {
00759                 m_pDownloadTransfer->m_sUserAgent = m_sUserAgent;
00760                 if ( m_pDownloadTransfer->m_pSource != NULL )
00761                 {
00762                         m_pDownloadTransfer->m_pSource->m_sServer = m_sUserAgent;
00763                         if ( strNick.GetLength() ) m_pDownloadTransfer->m_pSource->m_sNick = strNick;
00764                         m_pDownloadTransfer->m_pSource->m_bClientExtended = ( m_bExtended && ! m_pDownloadTransfer->m_pSource->m_bPushOnly);
00765                 }
00766         }
00767 
00768         if ( m_pUpload != NULL )
00769         {
00770                 m_pUpload->m_sUserAgent = m_sUserAgent;
00771                 if ( strNick.GetLength() ) m_pUpload->m_sNick = strNick;
00772                 m_pUpload->m_bClientExtended = m_bExtended;
00773         }
00774 }
00775 
00777 // CBTClient online handler
00778 
00779 BOOL CBTClient::OnOnline()
00780 {
00781         ASSERT( m_bOnline );
00782         ASSERT( m_pDownload != NULL );
00783         ASSERT( m_pUpload != NULL );
00784         
00785         theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_ONLINE, (LPCTSTR)m_sAddress,
00786                 (LPCTSTR)m_pDownload->GetDisplayName() );
00787         
00788         if ( m_bExtended ) SendBeHandshake();
00789         
00790         if ( CBTPacket* pBitfield = m_pDownload->CreateBitfieldPacket() )
00791                 Send( pBitfield );
00792         
00793         if ( m_pDownloadTransfer != NULL && ! m_pDownloadTransfer->OnConnected() ) return FALSE;
00794         if ( ! m_pUpload->OnConnected() ) return FALSE;
00795         
00796         return TRUE;
00797 }
00798 
00800 // CBTClient packet switch
00801 
00802 BOOL CBTClient::OnPacket(CBTPacket* pPacket)
00803 {
00804         switch ( pPacket->m_nType )
00805         {
00806         case BT_PACKET_KEEPALIVE:
00807                 break;
00808         case BT_PACKET_CHOKE:
00809                 if ( m_pDownloadTransfer != NULL && ! m_pDownloadTransfer->OnChoked( pPacket ) ) return FALSE;
00810                 m_pDownload->ChokeTorrent();
00811                 break;
00812         case BT_PACKET_UNCHOKE:
00813                 if ( m_pDownloadTransfer != NULL && ! m_pDownloadTransfer->OnUnchoked( pPacket ) ) return FALSE;
00814                 m_pDownload->ChokeTorrent();
00815                 break;
00816         case BT_PACKET_INTERESTED:
00817                 if ( ! m_pUpload->OnInterested( pPacket ) ) return FALSE;
00818                 m_pDownload->ChokeTorrent();
00819                 break;
00820         case BT_PACKET_NOT_INTERESTED:
00821                 if ( ! m_pUpload->OnUninterested( pPacket ) ) return FALSE;
00822                 m_pDownload->ChokeTorrent();
00823                 break;
00824         case BT_PACKET_HAVE:
00825                 return m_pDownloadTransfer == NULL || m_pDownloadTransfer->OnHave( pPacket );
00826         case BT_PACKET_BITFIELD:
00827                 return m_pDownloadTransfer == NULL || m_pDownloadTransfer->OnBitfield( pPacket );
00828         case BT_PACKET_REQUEST:
00829                 return m_pUpload->OnRequest( pPacket );
00830         case BT_PACKET_PIECE:
00831                 return m_pDownloadTransfer == NULL || m_pDownloadTransfer->OnPiece( pPacket );
00832         case BT_PACKET_CANCEL:
00833                 return m_pUpload->OnCancel( pPacket );
00834         
00835         case BT_PACKET_HANDSHAKE:
00836                 if ( ! m_bExtended ) break;
00837                 return OnBeHandshake( pPacket );
00838         case BT_PACKET_SOURCE_REQUEST:
00839                 if ( ! m_bExchange ) break;
00840                 return OnSourceRequest( pPacket );
00841         case BT_PACKET_SOURCE_RESPONSE:
00842                 if ( ! m_bExchange ) break;
00843                 return m_pDownloadTransfer == NULL || m_pDownloadTransfer->OnSourceResponse( pPacket );
00844         }
00845         
00846         return TRUE;
00847 }
00848 
00850 // CBTClient advanced handshake
00851 
00852 void CBTClient::SendBeHandshake()
00853 {       // Send extended handshake (for G2 capable clients)
00854         CBENode pRoot;
00855         
00856         CString strNick = MyProfile.GetNick().Left( 255 ); // Truncate to 255 characters
00857         if ( strNick.GetLength() ) pRoot.Add( "nickname" )->SetString( strNick );
00858 
00859         
00860         pRoot.Add( "source-exchange" )->SetInt( 2 );
00861         pRoot.Add( "user-agent" )->SetString( Settings.SmartAgent() );
00862         
00863         CBuffer pOutput;
00864         pRoot.Encode( &pOutput );
00865         
00866         CBTPacket* pPacket = CBTPacket::New( BT_PACKET_HANDSHAKE );
00867         pPacket->Write( pOutput.m_pBuffer, pOutput.m_nLength );
00868         Send( pPacket );
00869 }
00870 
00871 BOOL CBTClient::OnBeHandshake(CBTPacket* pPacket)
00872 {       // On extended handshake (for G2 capable clients)
00873         if ( pPacket->GetRemaining() > 1024 ) return TRUE;
00874         
00875         CBuffer pInput;
00876         pInput.Add( pPacket->m_pBuffer, pPacket->GetRemaining() );
00877         
00878         CBENode* pRoot = CBENode::Decode( &pInput );
00879         if ( pRoot == NULL ) return TRUE;
00880         
00881         CBENode* pAgent = pRoot->GetNode( "user-agent" );
00882         
00883         if ( pAgent->IsType( CBENode::beString ) )
00884         {
00885                 m_sUserAgent = pAgent->GetString();
00886                 
00887                 if ( m_pDownloadTransfer != NULL )
00888                 {
00889                         m_pDownloadTransfer->m_sUserAgent = m_sUserAgent;
00890                         if ( m_pDownloadTransfer->m_pSource != NULL )
00891                         {
00892                                 m_pDownloadTransfer->m_pSource->m_sServer = m_sUserAgent;
00893                                 m_pDownloadTransfer->m_pSource->m_bClientExtended = TRUE;
00894                         }
00895                 }
00896                 
00897                 if ( m_pUpload != NULL ) 
00898                 {
00899                         m_pUpload->m_sUserAgent = m_sUserAgent;
00900                         m_pUpload->m_bClientExtended = TRUE;
00901                 }
00902         }
00903         
00904         CBENode* pNick = pRoot->GetNode( "nickname" );
00905         
00906         if ( pNick->IsType( CBENode::beString ) )
00907         {
00908                 if ( m_pDownloadTransfer != NULL )
00909                 {
00910                         m_pDownloadTransfer->m_pSource->m_sNick = pNick->GetString();
00911                 }
00912         }
00913         
00914         if ( CBENode* pExchange = pRoot->GetNode( "source-exchange" ) )
00915         {
00916                 if ( pExchange->GetInt() >= 2 )
00917                 {
00918                         m_bExchange = TRUE;
00919                         
00920                         if ( m_pDownloadTransfer != NULL )
00921                                 Send( CBTPacket::New( BT_PACKET_SOURCE_REQUEST ) );
00922                 }
00923         }
00924         
00925         delete pRoot;
00926         
00927         theApp.Message( MSG_DEFAULT, IDS_BT_CLIENT_EXTENDED, (LPCTSTR)m_sAddress, (LPCTSTR)m_sUserAgent );
00928         
00929         return TRUE;
00930 }
00931 
00933 // CBTClient source request
00934 
00935 BOOL CBTClient::OnSourceRequest(CBTPacket* pPacket)
00936 {
00937         if ( m_pDownload == NULL ) return TRUE;
00938         
00939         CBENode pRoot;
00940         CBENode* pPeers = pRoot.Add( "peers" );
00941         
00942         for ( CDownloadSource* pSource = m_pDownload->GetFirstSource() ; pSource ; pSource = pSource->m_pNext )
00943         {
00944                 if ( pSource->m_pTransfer == NULL ) continue;
00945                 if ( pSource->m_pTransfer->m_nState < dtsRequesting ) continue;
00946                 
00947                 if ( pSource->m_nProtocol == PROTOCOL_BT )
00948                 {
00949                         CBENode* pPeer = pPeers->Add();
00950                         CSourceURL pURL;
00951                         
00952                         if ( pURL.Parse( pSource->m_sURL ) && pURL.m_bBTC )
00953                         {
00954                                 pPeer->Add( "peer id" )->SetString( &pURL.m_pBTC, sizeof(SHA1) );
00955                         }
00956                         
00957                         pPeer->Add( "ip" )->SetString( CString( inet_ntoa( pSource->m_pAddress ) ) );
00958                         pPeer->Add( "port" )->SetInt( pSource->m_nPort );
00959                 }
00960                 else if (       pSource->m_nProtocol == PROTOCOL_HTTP &&
00961                                         pSource->m_bReadContent == TRUE &&
00962                                         pSource->m_bPushOnly == FALSE )
00963                 {
00964                         CBENode* pPeer = pPeers->Add();
00965                         pPeer->Add( "url" )->SetString( pSource->m_sURL );
00966                 }
00967         }
00968         
00969         if ( pPeers->GetCount() == 0 ) return TRUE;
00970         
00971         CBuffer pOutput;
00972         pRoot.Encode( &pOutput );
00973         
00974         CBTPacket* pResponse = CBTPacket::New( BT_PACKET_SOURCE_RESPONSE );
00975         pResponse->Write( pOutput.m_pBuffer, pOutput.m_nLength );
00976         Send( pResponse );
00977         
00978         return TRUE;
00979 }

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