void CEDClients::OnRun() { DWORD tNow = GetTickCount(); // Delay to limit the rate of ed2k packets being sent. // Keep ed2k transfers under 10 KB/s per source if ( tNow < m_tLastRun + Settings.eDonkey.PacketThrottle ) return; CSingleLock oCEDClientsLock( &m_pSection ); if ( ! oCEDClientsLock.Lock( 250 ) ) return; CSingleLock oCTransfersLock( &Transfers.m_pSection ); if ( ! oCTransfersLock.Lock( 250 ) ) return; tNow = GetTickCount(); // Update if ( Settings.eDonkey.ServerWalk && Network.IsConnected() && Settings.eDonkey.Enabled ) RunGlobalStatsRequests( tNow ); for ( CEDClient* pClient = m_pFirst ; pClient ; ) { CEDClient* pNext = pClient->m_pEdNext; pClient->OnRunEx( tNow ); pClient = pNext; } m_tLastRun = tNow; }
CEDClient* CEDClients::Connect(DWORD nClientID, WORD nClientPort, IN_ADDR* pServerAddress, WORD nServerPort, GGUID* pGUID) { if ( pGUID != NULL ) { if ( CEDClient* pClient = GetByGUID( pGUID ) ) return pClient; } if ( IsFull() ) return NULL; CEDClient* pClient = NULL; if ( CEDPacket::IsLowID( nClientID ) ) { if ( pServerAddress == NULL || nServerPort == 0 ) return NULL; pClient = GetByID( nClientID, pServerAddress, pGUID ); } else { if ( Security.IsDenied( (IN_ADDR*)&nClientID ) ) return NULL; pClient = GetByID( nClientID, NULL, pGUID ); } if ( pClient == NULL ) { pClient = new CEDClient(); pClient->ConnectTo( nClientID, nClientPort, pServerAddress, nServerPort, pGUID ); } return pClient; }
bool CEDClients::IsFull(const CEDClient* pCheckThis) { CQuickLock oLock( m_pSection ); // Count the number of connected clients DWORD nCount = 0; for ( CEDClient* pClient = m_pFirst ; pClient ; pClient = pClient->m_pEdNext ) { if ( pClient->IsValid() ) ++nCount; } // Get current time const DWORD tNow = GetTickCount(); // If there are more clients current connected than there should be, set full timer if ( nCount >= Settings.eDonkey.MaxLinks ) m_tLastMaxClients = tNow; // If we have not been full in the past 2 seconds, then we're okay to start new connections if ( tNow - m_tLastMaxClients > 2ul * 1000ul ) return false; // If we're checking a client that's already connected, say we aren't full. (don't drop it) if ( pCheckThis && pCheckThis->IsValid() ) return false; // We're too full to start new connections return true; }
void CEDClients::OnRun() { DWORD tNow = GetTickCount(); // Delay to limit the rate of ed2k packets being sent. // keep ed2k transfers under 10 KB/s per source if ( tNow - m_tLastRun < Settings.eDonkey.PacketThrottle ) return; CSingleLock oCTranfersLock( &Transfers.m_pSection ); if ( ! oCTranfersLock.Lock( 250 ) ) return; CSingleLock oCEDClientsLock( &m_pSection ); if ( ! oCEDClientsLock.Lock( 250 ) ) return; for ( CEDClient* pClient = m_pFirst ; pClient ; ) { CEDClient* pNext = pClient->m_pEdNext; pClient->OnRunEx( tNow ); pClient = pNext; } m_tLastRun = tNow; }
void CEDClients::Clear() { for ( CEDClient* pClient = m_pFirst ; pClient ; ) { CEDClient* pNext = pClient->m_pEdNext; pClient->Remove(); pClient = pNext; } ASSERT( m_pFirst == NULL ); ASSERT( m_pLast == NULL ); ASSERT( m_nCount == 0 ); }
BOOL CEDClients::IsOverloaded() const { CQuickLock oLock( m_pSection ); DWORD nCount = 0; for ( CEDClient* pClient = m_pFirst ; pClient ; pClient = pClient->m_pEdNext ) { if ( pClient->IsValid() ) nCount++; } return ( nCount >= ( Settings.eDonkey.MaxLinks + 25 ) ); }
BOOL CEDClients::Merge(CEDClient* pClient) { ASSERT( pClient != NULL ); for ( CEDClient* pOther = m_pFirst ; pOther ; pOther = pOther->m_pEdNext ) { if ( pOther != pClient && pOther->Equals( pClient ) ) { pClient->Merge( pOther ); pOther->Remove(); return TRUE; } } return FALSE; }
CEDClient* CEDClients::Connect(DWORD nClientID, WORD nClientPort, IN_ADDR* pServerAddress, WORD nServerPort, const Hashes::Guid& oGUID) { CEDClient* pClient = NULL; { CQuickLock oLock( m_pSection ); if ( oGUID ) { pClient = GetByGUID( oGUID ); if ( pClient ) return pClient; } if ( IsFull() ) return NULL; if ( CEDPacket::IsLowID( nClientID ) ) { if ( pServerAddress == NULL || nServerPort == 0 ) return NULL; pClient = GetByID( nClientID, pServerAddress, oGUID ); } else { if ( Security.IsDenied( (IN_ADDR*)&nClientID ) ) return NULL; pClient = GetByID( nClientID, NULL, oGUID ); } } if ( pClient == NULL ) { pClient = new CEDClient(); pClient->ConnectTo( nClientID, nClientPort, pServerAddress, nServerPort, oGUID ); } return pClient; }
void CEDClients::OnRun() { // Delay to limit the rate of ed2k packets being sent. // keep ed2k transfers under 10 KB/s per source DWORD tNow = GetTickCount(); if ( tNow - m_tLastRun < Settings.eDonkey.PacketThrottle ) return; m_tLastRun = tNow; if ( Settings.eDonkey.ServerWalk && Settings.eDonkey.EnableToday ) { RunGlobalStatsRequests( tNow ); } for ( CEDClient* pClient = m_pFirst ; pClient ; ) { CEDClient* pNext = pClient->m_pEdNext; pClient->OnRunEx( tNow ); pClient = pNext; } }
BOOL CEDClients::OnAccept(CConnection* pConnection) { ASSERT( pConnection != NULL ); if ( Settings.Connection.RequireForTransfers && ! Settings.eDonkey.EnableToday ) { theApp.Message( MSG_ERROR, IDS_ED2K_CLIENT_DISABLED, (LPCTSTR)pConnection->m_sAddress ); return FALSE; } CSingleLock pLock( &Transfers.m_pSection ); if ( ! pLock.Lock( 250 ) ) return FALSE; if ( IsFull() ) { // Even if we're full, we still need to accept connections from clients we have queued, etc if ( ( GetByIP( &pConnection->m_pHost.sin_addr ) == NULL ) || ( IsOverloaded() ) ) { theApp.Message( MSG_DEBUG, _T("Rejecting ed2k connection from %s, max client connections reached."), (LPCTSTR)pConnection->m_sAddress ); return FALSE; } else { theApp.Message( MSG_DEBUG, _T("Accepting ed2k connection from %s despite client connection limit."), (LPCTSTR)pConnection->m_sAddress ); } } CEDClient* pClient = new CEDClient(); pClient->AttachTo( pConnection ); return TRUE; }
CPrivateChatFrame* CChatWindows::OpenPrivate(GGUID* pGUID, SOCKADDR_IN* pHost, BOOL bMustPush, PROTOCOLID nProtocol, SOCKADDR_IN* pServer) { CPrivateChatFrame* pFrame = NULL; ASSERT ( pHost != NULL ); if ( ( nProtocol == PROTOCOL_BT ) || ( nProtocol == PROTOCOL_FTP ) ) return NULL; if ( ! MyProfile.IsValid() ) { CString strMessage; LoadString( strMessage, IDS_CHAT_NEED_PROFILE ); if ( AfxMessageBox( strMessage, MB_YESNO|MB_ICONQUESTION ) == IDYES ) AfxGetMainWnd()->PostMessage( WM_COMMAND, ID_TOOLS_PROFILE ); return NULL; } if ( nProtocol == PROTOCOL_ED2K ) { CEDClient* pClient; // First, check if it's a low ID user on another server. if ( bMustPush && pServer ) { // It's a firewalled user (Low ID). If they are using another server, we // can't (shouldn't) contact them. (It places a heavy load on the ed2k servers) CSingleLock pLock1( &Network.m_pSection ); if ( ! pLock1.Lock( 250 ) ) return NULL; if ( Neighbours.Get( &pServer->sin_addr ) == NULL ) return NULL; pLock1.Unlock(); } // ED2K chat is handled by the EDClient section. (Transfers) // We need to find (or create) an EDClient to handle this chat session, since everything // on ed2k shares a TCP link. // First, lock the section to prevent a problem with other threads CSingleLock pLock( &Transfers.m_pSection ); if ( ! pLock.Lock( 250 ) ) return NULL; // We need to connect to them, so either find or create an EDClient if ( pServer ) pClient = EDClients.Connect(pHost->sin_addr.S_un.S_addr, pHost->sin_port, &pServer->sin_addr, pServer->sin_port, pGUID ); else pClient = EDClients.Connect(pHost->sin_addr.S_un.S_addr, pHost->sin_port, NULL, 0, pGUID ); // If we weren't able to create a client (Low-id and no server), then exit. if ( ! pClient ) return NULL; // Have it connect (if it isn't) if ( ! pClient->m_bConnected ) pClient->Connect(); // Tell it to start a chat session as soon as it's able pClient->OpenChat(); pLock.Unlock(); // Check for / make active any existing window pFrame = FindPrivate( &pHost->sin_addr ); // Check for an empty frame if ( pFrame == NULL ) { if ( bMustPush ) pFrame = FindED2KFrame( pHost->sin_addr.S_un.S_addr, pServer ); else pFrame = FindED2KFrame( pHost ); } if ( pFrame != NULL ) { // Open window if we found one CWnd* pParent = pFrame->GetParent(); if ( pParent->IsIconic() ) pParent->ShowWindow( SW_SHOWNORMAL ); pParent->BringWindowToTop(); pParent->SetForegroundWindow(); // And exit return pFrame; } // Open an empty (blank) chat frame. This is totally unnecessary- The EDClient will open // one as required, but it looks better to open one here. pFrame = new CPrivateChatFrame(); // Set name (Also used to match incoming connection) if ( bMustPush && pServer ) // Firewalled user (Low ID) { pFrame->m_sNick.Format( _T("%lu@%s:%hu"), pHost->sin_addr.S_un.S_addr, (LPCTSTR)CString( inet_ntoa( pServer->sin_addr ) ), pServer->sin_port ); } else // Regular user (High ID) { pFrame->m_sNick.Format( _T("%s:%hu"), (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), pHost->sin_port ); } // Open window CWnd* pParent = pFrame->GetParent(); if ( pParent->IsIconic() ) pParent->ShowWindow( SW_SHOWNORMAL ); pParent->BringWindowToTop(); pParent->SetForegroundWindow(); // Put a 'connecting' message in the window CString strMessage, strConnecting; LoadString( strConnecting, IDS_CHAT_CONNECTING_TO ); strMessage.Format( strConnecting, pFrame->m_sNick ); pFrame->OnStatusMessage( 0, strMessage ); return pFrame; } if ( pGUID != NULL ) pFrame = FindPrivate( pGUID ); if ( pFrame == NULL ) pFrame = FindPrivate( &pHost->sin_addr ); if ( pFrame == NULL ) { pFrame = new CPrivateChatFrame(); pFrame->Initiate( pGUID, pHost, bMustPush ); } pFrame->PostMessage( WM_COMMAND, ID_CHAT_CONNECT ); CWnd* pParent = pFrame->GetParent(); if ( pParent->IsIconic() ) pParent->ShowWindow( SW_SHOWNORMAL ); pParent->BringWindowToTop(); pParent->SetForegroundWindow(); return pFrame; }
BOOL CHostBrowser::Browse() { CQuickLock oTransfersLock( Transfers.m_pSection ); m_sAddress = inet_ntoa( m_pAddress ); m_sServer = protocolAbbr[ ( ( m_nProtocol == PROTOCOL_ANY ) ? PROTOCOL_NULL : m_nProtocol ) ]; m_pVendor = VendorCache.Lookup( m_sServer ); switch ( m_nProtocol ) { case PROTOCOL_G2: Settings.Gnutella2.Enabled = true; break; case PROTOCOL_G1: Settings.Gnutella1.Enabled = true; break; case PROTOCOL_ED2K: Settings.eDonkey.Enabled = true; break; case PROTOCOL_DC: Settings.DC.Enabled = true; break; //default: } // ED2K Clients have their connection controlled by ED2KClient. // (One connection used for many things) if ( m_nProtocol == PROTOCOL_ED2K ) { // Lock this object until we are finished with it CQuickLock oCEDClientsLock( EDClients.m_pSection ); SOCKADDR_IN* pServer = NULL; // ToDo: Add push connections CEDClient* pClient = EDClients.Connect( m_pAddress.s_addr, m_nPort, ( pServer ? &pServer->sin_addr : NULL ), ( pServer ? pServer->sin_port : 0 ), m_oClientID ); if ( pClient && pClient->m_bConnected ) { // Send browse request if ( CEDPacket* pPacket = CEDPacket::New( ED2K_C2C_ASKSHAREDDIRS ) ) pClient->Send( pPacket ); } else if ( ! pClient || ! pClient->Connect() ) { theApp.Message( MSG_NOTICE, IDS_BROWSE_CANT_CONNECT_TO, (LPCTSTR)m_sAddress ); return FALSE; } } else if ( m_nProtocol == PROTOCOL_DC ) { CEnvyURL oURL; oURL.m_nProtocol = PROTOCOL_DC; oURL.m_nAction = CEnvyURL::uriDownload; oURL.m_pServerAddress = m_pAddress; oURL.m_nServerPort = m_nPort; oURL.m_sLogin = m_sNick; oURL.m_sName.Format( L"Files of %s.xml.bz2", (LPCTSTR)SafeFilename( m_sNick ) ); oURL.m_sURL.Format( L"dchub://%s@%s:%u/files.xml.bz2", (LPCTSTR)URLEncode( m_sNick ), (LPCTSTR)CString( inet_ntoa( m_pAddress ) ), m_nPort ); return ( Downloads.Add( oURL ) != NULL ); } else // G2/Gunetella { if ( IsValid() ) return FALSE; if ( m_bMustPush ) { if ( SendPush( FALSE ) ) { theApp.Message( MSG_INFO, IDS_BROWSE_PUSHED_TO, (LPCTSTR)m_sAddress ); } else { theApp.Message( MSG_NOTICE, IDS_BROWSE_CANT_PUSH_TO, (LPCTSTR)m_sAddress ); return FALSE; } } else { if ( ConnectTo( &m_pAddress, m_nPort ) ) { theApp.Message( MSG_INFO, IDS_BROWSE_CONNECTING_TO, (LPCTSTR)m_sAddress ); } else { theApp.Message( MSG_NOTICE, IDS_BROWSE_CANT_CONNECT_TO, (LPCTSTR)m_sAddress ); return FALSE; } } } m_nState = hbsConnecting; m_nHits = 0; delete m_pProfile; m_pProfile = NULL; // Ensure window text is updated after state has been set to "connecting" m_pNotify->UpdateMessages(); return TRUE; }
CPrivateChatWnd* CChatWindows::OpenPrivateED2K(const Hashes::Guid& oGUID, const SOCKADDR_IN* pHost, BOOL bMustPush, SOCKADDR_IN* pServer) { // First, check if it's a low ID user on another server. if ( bMustPush && pServer ) { // It's a firewalled user (Low ID). If they are using another server, // we can't (shouldn't) contact them. (Places heavy load on ed2k servers) CSingleLock pLock1( &Network.m_pSection ); if ( ! pLock1.Lock( 250 ) ) return NULL; if ( Neighbours.Get( pServer->sin_addr ) == NULL ) return NULL; pLock1.Unlock(); } // ED2K chat is handled by the EDClient section. (Transfers) // We need to find (or create) an EDClient to handle this chat session, // since everything on ed2k shares a TCP link. // First, lock the section to prevent a problem with other threads CSingleLock pLock( &Transfers.m_pSection ); if ( ! pLock.Lock( 250 ) ) return NULL; // We need to connect to them, so either find or create an EDClient CEDClient* pClient; if ( pServer ) pClient = EDClients.Connect(pHost->sin_addr.s_addr, ntohs( pHost->sin_port ), &pServer->sin_addr, ntohs( pServer->sin_port ), oGUID ); else pClient = EDClients.Connect(pHost->sin_addr.s_addr, ntohs( pHost->sin_port ), NULL, 0, oGUID ); // If we weren't able to create a client (Low-id and no server), then exit. if ( ! pClient ) return NULL; // Have it connect (if it isn't) if ( ! pClient->m_bConnected ) pClient->Connect(); // Tell it to start a chat session as soon as it's able pClient->OpenChat(); pLock.Unlock(); // Check for / make active any existing window CPrivateChatWnd* pFrame = FindPrivate( pHost ); // Check for an empty frame if ( pFrame == NULL ) { if ( bMustPush ) pFrame = FindED2KFrame( pHost->sin_addr.s_addr, pServer ); else pFrame = FindED2KFrame( pHost ); } if ( pFrame != NULL ) { // Open window if we found one //CWnd* pParent = pFrame->GetParent(); //if ( pParent->IsIconic() ) pParent->ShowWindow( SW_SHOWNORMAL ); //pParent->BringWindowToTop(); //pParent->SetForegroundWindow(); pFrame->Open(); // And exit return pFrame; } // Set name (Also used to match incoming connection) CString strNick; if ( bMustPush && pServer ) // Firewalled user (Low ID) { strNick.Format( L"%lu@%s:%hu", pHost->sin_addr.S_un.S_addr, (LPCTSTR)CString( inet_ntoa( pServer->sin_addr ) ), ntohs( pServer->sin_port ) ); } else // Regular user (High ID) { strNick.Format( L"%s:%hu", (LPCTSTR)CString( inet_ntoa( pHost->sin_addr ) ), ntohs( pHost->sin_port ) ); } // Open an empty (blank) chat frame. This is totally unnecessary- The EDClient will open // one as required, but it looks better to open one here. pFrame = new CPrivateChatWnd(); pFrame->Setup( strNick ); // Obsolete: for reference & deletion // // Open window // CWnd* pParent = pFrame->GetParent(); // if ( pParent->IsIconic() ) pParent->ShowWindow( SW_SHOWNORMAL ); // pParent->BringWindowToTop(); // pParent->SetForegroundWindow(); // // Put a 'connecting' message in the window // CString strMessage; // strMessage.Format( LoadString( IDS_CHAT_CONNECTING_TO ), (LPCTSTR)pFrame->m_sNick ); // pFrame->OnStatusMessage( 0, strMessage ); // // if ( oGUID ) // pFrame = FindPrivate( oGUID ); // if ( pFrame == NULL ) // pFrame = FindPrivate( &pHost->sin_addr ); // if ( pFrame == NULL ) // { // pFrame = new CPrivateChatWnd(); // pFrame->Initiate( oGUID, pHost, bMustPush ); // } // // pFrame->PostMessage( WM_COMMAND, ID_CHAT_CONNECT ); // // CWnd* pParent = pFrame->GetParent(); // if ( pParent->IsIconic() ) pParent->ShowWindow( SW_SHOWNORMAL ); // pParent->BringWindowToTop(); // pParent->SetForegroundWindow(); return pFrame; }
BOOL CEDClients::PushTo(DWORD nClientID, WORD nClientPort) { CEDClient* pClient = Connect( nClientID, nClientPort, NULL, 0, NULL ); if ( pClient == NULL ) return FALSE; return pClient->Connect(); }