// Called when a remote computer wants to connect to us // When WSAAccept accepted the connection, it created a new socket hSocket for it and wrote the remote IP in pHost void CConnection::AcceptFrom(SOCKET hSocket, SOCKADDR_IN* pHost) { // Make sure the newly accepted socket is valid ASSERT( ! IsValid() ); // Record the connection information here m_hSocket = hSocket; // Keep the socket here m_pHost = *pHost; // Copy the remote IP address into this object m_sAddress = inet_ntoa( m_pHost.sin_addr ); // Store it as a string also UpdateCountry(); // Make new input and output buffer objects ASSERT( m_pInput == NULL ); ASSERT( m_pOutput == NULL ); CreateBuffers(); // Facts about the connection m_bInitiated = FALSE; // We didn't initiate this connection m_bConnected = TRUE; // We're connected right now m_tConnected = GetTickCount(); // Record the time this happened // Choose asynchronous, non-blocking reading and writing on the new socket DWORD dwValue = 1; ioctlsocket( m_hSocket, FIONBIO, &dwValue ); // Record one more incoming connection in the statistics Statistics.Current.Connections.Incoming++; }
BOOL CDownloadTransferBT::Initiate() { ASSUME_LOCK( Transfers.m_pSection ); ASSERT( m_pClient == NULL ); ASSERT( m_nState == dtsNull ); theApp.Message( MSG_DEBUG, _T("Connecting to BitTorrent host %s..."), (LPCTSTR)CString( inet_ntoa( m_pSource->m_pAddress ) ) ); m_pClient = new CBTClient(); if ( ! m_pClient->Connect( this ) ) { delete m_pClient; m_pClient = NULL; Close( TRI_FALSE ); return FALSE; } SetState( dtsConnecting ); m_tConnected = GetTickCount(); m_pHost = m_pClient->m_pHost; m_sAddress = m_pClient->m_sAddress; UpdateCountry(); return TRUE; }
BOOL CDownloadTransferBT::OnConnected() { ASSUME_LOCK( Transfers.m_pSection ); ASSERT( m_pClient != NULL ); ASSERT( m_pSource != NULL ); SetState( dtsTorrent ); m_pHost = m_pClient->m_pHost; m_sAddress = m_pClient->m_sAddress; UpdateCountry(); // not deleting source for source exchange. if ( m_pDownload->IsCompleted() ) { // This source is only here to push start torrent uploads. (We don't want to download) m_bInterested = FALSE; theApp.Message( MSG_INFO, _T("Initiated push start for upload to %s"), (LPCTSTR)m_sAddress ); } else { // Regular download m_pClient->m_mInput.pLimit = &m_nBandwidth; theApp.Message( MSG_INFO, IDS_DOWNLOAD_CONNECTED, (LPCTSTR)m_sAddress ); if ( ! m_pDownload->PrepareFile() ) { Close( TRI_TRUE ); return FALSE; } m_pClient->m_mInput.pLimit = &m_nBandwidth; } m_pSource->SetLastSeen(); return TRUE; }
BOOL CDownloadTransferED2K::OnConnected() { ASSERT( m_pClient != NULL ); ASSERT( m_pSource != NULL ); m_pHost = m_pClient->m_pHost; m_sAddress = m_pClient->m_sAddress; UpdateCountry(); m_pSource->m_oGUID = m_pClient->m_oGUID; m_pSource->m_sNick = m_pClient->m_sNick; m_pSource->m_sServer = m_sUserAgent = m_pClient->m_sUserAgent; m_pSource->SetLastSeen(); theApp.Message( MSG_INFO, IDS_DOWNLOAD_CONNECTED, (LPCTSTR)m_sAddress ); return SendPrimaryRequest(); }
BOOL CDownloadTransferED2K::Initiate() { ASSERT( m_pClient == NULL ); ASSERT( m_nState == dtsNull ); if ( ! m_pDownload->m_oED2K || m_pDownload->m_nSize == SIZE_UNKNOWN ) { Close( TRI_FALSE ); return FALSE; } m_pClient = EDClients.Connect( m_pSource->m_pAddress.S_un.S_addr, m_pSource->m_nPort, m_pSource->m_nServerPort ? &m_pSource->m_pServerAddress : NULL, m_pSource->m_nServerPort, m_pSource->m_oGUID ); if ( m_pClient == NULL ) { Close( EDClients.IsFull() ? TRI_TRUE : TRI_FALSE ); return FALSE; } SetState( dtsConnecting ); m_tConnected = GetTickCount(); if ( ! m_pClient->AttachDownload( this ) ) { SetState( dtsNull ); m_pClient = NULL; Close( TRI_TRUE ); return FALSE; } m_pHost = m_pClient->m_pHost; m_sAddress = m_pClient->m_sAddress; if ( m_sAddress.IsEmpty() ) m_sAddress = inet_ntoa( m_pHost.sin_addr ); UpdateCountry(); m_pClient->m_mInput.pLimit = &m_nBandwidth; return TRUE; }
BOOL CUploadTransferDC::OnUpload(const std::string& strType, const std::string& strFilename, QWORD nOffset, QWORD nLength, const std::string& strOptions) { ASSERT( m_pClient ); if ( m_nState >= upsUploading ) { // Drop unsent data CLockedBuffer pOutput( m_pClient->GetOutput() ); pOutput->Clear(); m_nState = upsRequest; } ClearRequest(); m_sUserAgent = m_pClient->GetUserAgent(); m_pHost = m_pClient->m_pHost; m_sAddress = m_pClient->m_sAddress; UpdateCountry(); m_pClient->m_mInput.pLimit = &Settings.Bandwidth.Request; m_pClient->m_mOutput.pLimit = &m_nBandwidth; m_tRequest = GetTickCount(); BOOL bZip = ( strOptions.find("ZL1") != std::string::npos ); if ( strType == "tthl" ) { m_bGet = FALSE; if ( strFilename.substr( 0, 4 ) == "TTH/" ) { Hashes::TigerHash oTiger; if ( oTiger.fromString( CA2W( strFilename.substr( 4 ).c_str() ) ) ) { CSingleLock oLock( &Library.m_pSection ); if ( oLock.Lock( 1000 ) ) { if ( CLibraryFile* pFile = LibraryMaps.LookupFileByTiger( oTiger, TRUE, TRUE ) ) { if ( RequestTigerTree( pFile, nOffset, nLength ) ) return TRUE; } } } } } else if ( strType == "file" || strType =="get" ) { m_bGet = ( strType == "get" ); if ( strFilename == "files.xml" || strFilename == "files.xml.bz2" ) { if ( RequestFileList( TRUE, bZip, strFilename, nOffset, nLength ) ) return TRUE; } else if ( strFilename.substr( 0, 4 ) == "TTH/" ) { Hashes::TigerHash oTiger; if ( oTiger.fromString( CA2W( strFilename.substr( 4 ).c_str() ) ) ) { CSingleLock oLock( &Library.m_pSection ); if ( oLock.Lock( 1000 ) ) { if ( CLibraryFile* pFile = LibraryMaps.LookupFileByTiger( oTiger, TRUE, TRUE ) ) { if ( RequestFile( pFile, nOffset, nLength ) ) return TRUE; } } } } } else if ( strType == "list" ) { m_bGet = FALSE; if ( RequestFileList( FALSE, bZip, strFilename, nOffset, nLength ) ) return TRUE; } else if ( strType == "send" ) { if ( m_bGet ) { if ( m_pXML.GetCount() ) { // Send cached file list m_bGet = FALSE; StartSending( upsBrowse ); m_pClient->Write( &m_pXML ); m_pXML.Clear(); return TRUE; } else if ( SendFile() ) { // Send already requested file return TRUE; } } // else $Send without $Get } else { // Invalid request type theApp.Message( MSG_ERROR, _T("DC++ Invalid request type from %s"), (LPCTSTR)m_sAddress ); return FALSE; } theApp.Message( MSG_ERROR, IDS_UPLOAD_FILENOTFOUND, (LPCTSTR)m_sAddress, (LPCTSTR)CA2CT( strFilename.c_str() ) ); m_pClient->SendCommand( FILE_NOT_AVAILABLE ); return TRUE; }
// Connect this CConnection object to a remote computer on the Internet // Takes pAddress, a Windows Sockets structure that holds an IP address, and takes the port number seprately // Returns true if connected BOOL CConnection::ConnectTo(const IN_ADDR* pAddress, WORD nPort) { // Make sure the socket isn't already connected somehow if ( IsValid() ) return FALSE; // Make sure we have an address and a nonzero port number if ( pAddress == NULL || nPort == 0 ) return FALSE; // S_un.S_addr is the IP as a single unsigned 4-byte long if ( pAddress->S_un.S_addr == 0 ) return FALSE; // The IP address is in the security list of government and corporate addresses we want to avoid if ( Security.IsDenied( pAddress ) ) { // Report that we aren't connecting to this IP address and return false theApp.Message( MSG_ERROR, IDS_NETWORK_SECURITY_OUTGOING, (LPCTSTR)CString( inet_ntoa( *pAddress ) ) ); return FALSE; } // The IN_ADDR structure we just got passed isn't the same as the one already stored in this object if ( pAddress != &m_pHost.sin_addr ) { // Zero the memory of the entire SOCKADDR_IN structure m_pHost, and then copy in the sin_addr part ZeroMemory( &m_pHost, sizeof( m_pHost ) ); m_pHost.sin_addr = *pAddress; } // Fill in more parts of the m_pHost structure m_pHost.sin_family = AF_INET; // PF_INET means just normal IPv4, not IPv6 yet m_pHost.sin_port = htons( nPort ); // Copy the port number into the m_pHost structure m_sAddress = inet_ntoa( m_pHost.sin_addr ); // Save the IP address as a string of text UpdateCountry(); // Create a socket and store it in m_hSocket // Normal IPv4 not IPv6, and the two-way sequenced reliable byte streams of TCP, not the datagrams of UDP m_hSocket = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP ); // Choose asynchronous, non-blocking reading and writing on our new socket DWORD dwValue = 1; ioctlsocket( m_hSocket, FIONBIO, &dwValue ); // Call Windows Sockets ioctlsocket to control the input/output mode of our new socket // Give it our new socket // Select the option for blocking i/o, should the program wait on read and write calls, or keep going? // Nonzero, it should keep going // If the OutHost string in connection settings has an IP address written in it if ( Settings.Connection.OutHost.GetLength() ) { // Read the text and copy the IP address and port into a new local MFC SOCKADDR_IN structure called pOutgoing SOCKADDR_IN pOutgoing; Network.Resolve( Settings.Connection.OutHost, 0, &pOutgoing ); // S_addr is the IP address as a single long number, if it's not zero if ( pOutgoing.sin_addr.S_un.S_addr ) { // Call bind in Windows Sockets to associate the local address with the socket bind( m_hSocket, // Our socket (SOCKADDR*)&pOutgoing, // The IP address this computer appears to have on the Internet (do) sizeof( SOCKADDR_IN ) ); // Tell bind how many bytes it can read at the pointer } } DestroyBuffers(); // Try to connect to the remote computer if ( WSAConnect( m_hSocket, // Our socket (SOCKADDR*)&m_pHost, // The remote IP address and port number sizeof( SOCKADDR_IN ), // How many bytes the function can read NULL, NULL, NULL, NULL ) ) // No advanced features { // If no error occurs, WSAConnect returns 0, so if we're here an error happened int nError = WSAGetLastError(); // Get the last Windows Sockets error number // An error of "would block" is normal because connections can't be made instantly and this is a non-blocking socket if ( nError != WSAEWOULDBLOCK ) { CNetwork::CloseSocket( m_hSocket, true ); if ( nError != 0 ) Statistics.Current.Connections.Errors++; return FALSE; } } CreateBuffers(); // Record that we initiated this connection, and when it happened m_bInitiated = TRUE; m_tConnected = GetTickCount(); // Record one more outgoing connection in the statistics Statistics.Current.Connections.Outgoing++; // Connection successfully attempted return TRUE; }