BOOL CEMSocket::AsyncSelect(long lEvent){ #ifdef EMSOCKET_DEBUG if (lEvent&FD_READ) EMTrace(" FD_READ"); if (lEvent&FD_CLOSE) EMTrace(" FD_CLOSE"); if (lEvent&FD_WRITE) EMTrace(" FD_WRITE"); #endif // deadlake changed to AsyncSocketEx PROXYSUPPORT if (m_SocketData.hSocket != INVALID_SOCKET) return CEncryptedStreamSocket::AsyncSelect(lEvent); return true; }
void CEMSocket::ClearQueues() { EMTrace("CEMSocket::ClearQueues on %d",(SOCKET)this); sendLocker.Lock(); for (POSITION pos = controlpacket_queue.GetHeadPosition(); pos != NULL; ) delete controlpacket_queue.GetNext(pos); controlpacket_queue.RemoveAll(); for (POSITION pos = standartpacket_queue.GetHeadPosition(); pos != NULL; ) delete standartpacket_queue.GetNext(pos).packet; standartpacket_queue.RemoveAll(); sendLocker.Unlock(); // Download (pseudo) rate control downloadLimit = 0; downloadLimitEnable = false; pendingOnReceive = false; // Download partial header pendingHeaderSize = 0; // Download partial packet delete pendingPacket; pendingPacket = NULL; pendingPacketSize = 0; // Upload control delete[] sendbuffer; sendbuffer = NULL; sendblen = 0; sent = 0; }
void CEMSocket::ClearQueues() { EMTrace("CEMSocket::ClearQueues on %d",(SOCKET)this); while(!m_controlPacketQueue.IsEmpty()) { delete m_controlPacketQueue.RemoveHead(); } while (!m_standardPacketQueue.IsEmpty()) { delete m_standardPacketQueue.RemoveHead(); } // Download (pseudo) rate control m_dwDownloadLimit = 0; m_bEnableDownloadLimit = false; m_bPendingOnReceive = false; // Download partial header m_dwPendingHeaderSize = 0; // Download partial packet delete m_pPendingPacket; m_pPendingPacket = NULL; m_dwPendingPacketSize = 0; // Upload control delete[] m_pcSendBuffer; m_pcSendBuffer = NULL; m_dwSendBufLen = 0; m_dwNumBytesSent = 0; m_bLinkedPackets = false; }
CEMSocket::~CEMSocket() { EMTrace("CEMSocket::~CEMSocket() on %d",(SOCKET)this); ClearQueues(); RemoveAllLayers(); AsyncSelect(0); }
CEMSocket::~CEMSocket(){ EMTrace("CEMSocket::~CEMSocket() on %d",(SOCKET)this); // need to be locked here to know that the other methods // won't be in the middle of things sendLocker.Lock(); byConnected = ES_DISCONNECTED; sendLocker.Unlock(); // now that we know no other method will keep adding to the queue // we can remove ourself from the queue theApp.uploadBandwidthThrottler->RemoveFromAllQueues(this); ClearQueues(); RemoveAllLayers(); // deadlake PROXYSUPPORT AsyncSelect(0); }
void CEMSocket::OnReceive(int nErrorCode) { // the 2 meg size was taken from another place static char GlobalReadBuffer[2000000]; // Check for an error code if (nErrorCode != 0) { OnError(nErrorCode); return; } // Check current connection state if (byConnected == ES_DISCONNECTED) { TRACE("->%s: the sock is disconnected\n",__FUNCTION__); return; } else { byConnected = ES_CONNECTED; // ES_DISCONNECTED, ES_NOTCONNECTED, ES_CONNECTED } // CPU load improvement if (downloadLimitEnable == true && downloadLimit == 0) { #ifdef _DEBUG_CPU TRACE("->%s: CPU load improvement\n",__FUNCTION__); #endif pendingOnReceive = true; //Receive(GlobalReadBuffer + pendingHeaderSize, 0); return; } // Remark: an overflow can not occur here uint32 readMax = sizeof(GlobalReadBuffer) - pendingHeaderSize; if (downloadLimitEnable == true && readMax > downloadLimit) { readMax = downloadLimit; } // We attempt to read up to 2 megs at a time (minus whatever is in our internal read buffer) uint32 ret = Receive(GlobalReadBuffer + pendingHeaderSize, readMax); GlobalReadBuffer[pendingHeaderSize+ret] = 0; if (ret == SOCKET_ERROR || byConnected == ES_DISCONNECTED) { return; } // Bandwidth control if (downloadLimitEnable == true) { // Update limit downloadLimit -= GetRealReceivedBytes(); } // CPU load improvement // Detect if the socket's buffer is empty (or the size did match...) pendingOnReceive = m_bFullReceive; if (ret == 0) return; // Copy back the partial header into the global read buffer for processing if (pendingHeaderSize > 0) { memcpy(GlobalReadBuffer, pendingHeader, pendingHeaderSize); ret += pendingHeaderSize; pendingHeaderSize = 0; } if (IsRawDataMode()) { DataReceived((BYTE*)GlobalReadBuffer, ret); return; } char *rptr = GlobalReadBuffer; // floating index initialized with begin of buffer const char *rend = GlobalReadBuffer + ret; // end of buffer // Loop, processing packets until we run out of them while ((rend - rptr >= PACKET_HEADER_SIZE) || ((pendingPacket != NULL) && (rend - rptr > 0))) { // Two possibilities here: // // 1. There is no pending incoming packet // 2. There is already a partial pending incoming packet // // It's important to remember that emule exchange two kinds of packet // - The control packet // - The data packet for the transport of the block // // The biggest part of the traffic is done with the data packets. // The default size of one block is 10240 bytes (or less if compressed), but the // maximal size for one packet on the network is 1300 bytes. It's the reason // why most of the Blocks are splitted before to be sent. // // Conclusion: When the download limit is disabled, this method can be at least // called 8 times (10240/1300) by the lower layer before a splitted packet is // rebuild and transferred to the above layer for processing. // // The purpose of this algorithm is to limit the amount of data exchanged between buffers if (pendingPacket == NULL) { pendingPacket = new Packet(rptr); // Create new packet container. rptr += 6; // Only the header is initialized so far // Bugfix We still need to check for a valid protocol // Remark: the default eMule v0.26b had removed this test...... switch (pendingPacket->prot) { case OP_EDONKEYPROT: case OP_PACKEDPROT: case OP_EMULEPROT: break; default: EMTrace("CEMSocket::OnReceive ERROR Wrong header"); delete pendingPacket; pendingPacket = NULL; OnError(ERR_WRONGHEADER); return; } // Security: Check for buffer overflow (2MB) if (pendingPacket->size > sizeof(GlobalReadBuffer)) { delete pendingPacket; pendingPacket = NULL; OnError(ERR_TOOBIG); return; } // Init data buffer pendingPacket->pBuffer = new char[pendingPacket->size + 1]; pendingPacketSize = 0; } // Bytes ready to be copied into packet's internal buffer ASSERT(rptr <= rend); uint32 toCopy = ((pendingPacket->size - pendingPacketSize) < (uint32)(rend - rptr)) ? (pendingPacket->size - pendingPacketSize) : (uint32)(rend - rptr); // Copy Bytes from Global buffer to packet's internal buffer memcpy(&pendingPacket->pBuffer[pendingPacketSize], rptr, toCopy); pendingPacketSize += toCopy; rptr += toCopy; // Check if packet is complet ASSERT(pendingPacket->size >= pendingPacketSize); if (pendingPacket->size == pendingPacketSize) { #ifdef EMSOCKET_DEBUG EMTrace("CEMSocket::PacketReceived on %d, opcode=%X, realSize=%d", (SOCKET)this, pendingPacket->opcode, pendingPacket->GetRealPacketSize()); #endif // Process packet bool bPacketResult = PacketReceived(pendingPacket); delete pendingPacket; pendingPacket = NULL; pendingPacketSize = 0; if (!bPacketResult) return; } } // Finally, if there is any data left over, save it for next time ASSERT(rptr <= rend); ASSERT(rend - rptr < PACKET_HEADER_SIZE); if (rptr != rend) { // Keep the partial head pendingHeaderSize = rend - rptr; memcpy(pendingHeader, rptr, pendingHeaderSize); } }
// pach2: // written this overriden Receive to handle transparently FIN notifications coming from calls to recv() // This was maybe(??) the cause of a lot of socket error, notably after a brutal close from peer // also added trace so that we can debug after the fact ... int CEMSocket::Receive(void* lpBuf, int nBufLen, int nFlags) { // EMTrace("CEMSocket::Receive on %d, maxSize=%d",(SOCKET)this,nBufLen); int recvRetCode = CEncryptedStreamSocket::Receive(lpBuf,nBufLen,nFlags); // deadlake PROXYSUPPORT - changed to AsyncSocketEx switch (recvRetCode) { case 0: if (GetRealReceivedBytes() > 0) // we received data but it was for the underlying encryption layer - all fine return 0; //EMTrace("CEMSocket::##Received FIN on %d, maxSize=%d",(SOCKET)this,nBufLen); // FIN received on socket // Connection is being closed by peer //ASSERT (false); if ( 0 == AsyncSelect(FD_CLOSE|FD_WRITE) ) { // no more READ notifications ... //int waserr = GetLastError(); // oups, AsyncSelect failed !!! ASSERT(false); } return 0; case SOCKET_ERROR: switch (GetLastError()) { case WSANOTINITIALISED: ASSERT(false); EMTrace("CEMSocket::OnReceive:A successful AfxSocketInit must occur before using this API."); break; case WSAENETDOWN: ASSERT(true); EMTrace("CEMSocket::OnReceive:The socket %d received a net down error",(SOCKET)this); break; case WSAENOTCONN: // The socket is not connected. EMTrace("CEMSocket::OnReceive:The socket %d is not connected",(SOCKET)this); break; case WSAEINPROGRESS: // A blocking Windows Sockets operation is in progress. EMTrace("CEMSocket::OnReceive:The socket %d is blocked",(SOCKET)this); break; case WSAEWOULDBLOCK: // The socket is marked as nonblocking and the Receive operation would block. EMTrace("CEMSocket::OnReceive:The socket %d would block",(SOCKET)this); break; case WSAENOTSOCK: // The descriptor is not a socket. EMTrace("CEMSocket::OnReceive:The descriptor %d is not a socket (may have been closed or never created)",(SOCKET)this); break; case WSAEOPNOTSUPP: // MSG_OOB was specified, but the socket is not of type SOCK_STREAM. break; case WSAESHUTDOWN: // The socket has been shut down; it is not possible to call Receive on a socket after ShutDown has been invoked with nHow set to 0 or 2. EMTrace("CEMSocket::OnReceive:The socket %d has been shut down",(SOCKET)this); break; case WSAEMSGSIZE: // The datagram was too large to fit into the specified buffer and was truncated. EMTrace("CEMSocket::OnReceive:The datagram was too large to fit and was truncated (socket %d)",(SOCKET)this); break; case WSAEINVAL: // The socket has not been bound with Bind. EMTrace("CEMSocket::OnReceive:The socket %d has not been bound",(SOCKET)this); break; case WSAECONNABORTED: // The virtual circuit was aborted due to timeout or other failure. EMTrace("CEMSocket::OnReceive:The socket %d has not been bound",(SOCKET)this); break; case WSAECONNRESET: // The virtual circuit was reset by the remote side. EMTrace("CEMSocket::OnReceive:The socket %d has not been bound",(SOCKET)this); break; default: EMTrace("CEMSocket::OnReceive:Unexpected socket error %x on socket %d",GetLastError(),(SOCKET)this); break; } break; default: // EMTrace("CEMSocket::OnReceive on %d, receivedSize=%d",(SOCKET)this,recvRetCode); return recvRetCode; } return SOCKET_ERROR; }
void CEMSocket::OnReceive(int iErrorCode) { // The 2 meg size was taken from another place // MOREVIT - Um, what?? static char g_arrcReadBuffer[2102400]; // 16*TCP window (16*131400) // Check for an error code if (iErrorCode != 0) { OnError(iErrorCode); return; } // Check current connection state if (m_eConnectionState == ES_DISCONNECTED) return; else m_eConnectionState = ES_CONNECTED; // ES_DISCONNECTED, ES_NOTCONNECTED, ES_CONNECTED // * CPU load improvement if (m_bEnableDownloadLimit && m_dwDownloadLimit == 0) { EMTrace("CEMSocket::OnReceive blocked by limit"); m_bPendingOnReceive = true; return; } // Determine the maximum amount of data we can read, allowing for the download limit (if any) // Remark: an overflow can not occur here uint32 dwReadMax = sizeof(g_arrcReadBuffer) - m_dwPendingHeaderSize; if (m_bEnableDownloadLimit && dwReadMax > m_dwDownloadLimit) dwReadMax = m_dwDownloadLimit; // We attempt to read up to 2 megs at a time (minus whatever is in our internal read buffer) uint32 dwNumBytesReceived = Receive(g_arrcReadBuffer + m_dwPendingHeaderSize, dwReadMax); if (dwNumBytesReceived == SOCKET_ERROR || dwNumBytesReceived == 0) { // TODO: Get error information from GetLastError()? return; } // * Bandwidth control if (m_bEnableDownloadLimit) { // Reduce the download limit by the number of bytes received. m_dwDownloadLimit -= dwNumBytesReceived; } // * CPU load improvement // Detect if the socket's buffer is empty (or the size did match...) m_bPendingOnReceive = (dwNumBytesReceived == dwReadMax); // Copy back the partial header into the global read buffer for processing if (m_dwPendingHeaderSize > 0) { memcpy(g_arrcReadBuffer, m_arrcPendingHeader, m_dwPendingHeaderSize); dwNumBytesReceived += m_dwPendingHeaderSize; m_dwPendingHeaderSize = 0; } char *pcReadBuffer = g_arrcReadBuffer; // floating index initialized with begin of buffer const char *pcReadBufferEnd = g_arrcReadBuffer + dwNumBytesReceived; // end of buffer // Loop, processing packets until we run out of them while ( (pcReadBufferEnd - pcReadBuffer >= PACKET_HEADER_SIZE) || ((m_pPendingPacket != NULL) && (pcReadBufferEnd - pcReadBuffer > 0)) ) { // Two possibilities here: // // 1. There is no pending incoming packet // 2. There is already a partial pending incoming packet // // It's important to remember that emule exchange two kinds of packet // - The control packet // - The data packet for the transport of the block // // The biggest part of the traffic is done with the data packets. // The default size of one block is 10240 bytes (or less if compressed), but the // maximal size for one packet on the network is 1300 bytes. It's the reason // why most of the Blocks are splitted before to be sent. // // Conclusion: When the download limit is disabled, this method can be at least // called 8 times (10240/1300) by the lower layer before a split packet is // rebuild and transferred to the above layer for processing. // // The purpose of this algorithm is to limit the amount of data exchanged between buffers if (m_pPendingPacket == NULL) { // Recheck current connection state as it can be changed after data reception if (m_eConnectionState == ES_DISCONNECTED) return; // Check the header data PacketHeader_Struct *pNewHeader = reinterpret_cast<PacketHeader_Struct*>(pcReadBuffer); // Bugfix: We still need to check for a valid protocol // Remark: the default eMule v0.26b had removed this test...... switch (pNewHeader->byteEDonkeyProtocol) { case OP_EDONKEYPROT: case OP_PACKEDPROT: case OP_EMULEPROT: break; default: EMTrace("%s: ERROR - Wrong protocol in packet header", __FUNCTION__); OnError(ERR_WRONGHEADER); return; } // Security: Check for buffer overflow (2MB) if ((pNewHeader->dwPacketLength - 1) > sizeof(g_arrcReadBuffer)) { OnError(ERR_TOOBIG); return; } // Create new packet container m_pPendingPacket = new Packet(pNewHeader); // Only the header is initialized so far. Advance past it pcReadBuffer += sizeof(PacketHeader_Struct); // Init data buffer m_pPendingPacket->m_pcBuffer = new char[m_pPendingPacket->m_dwSize + 1]; m_dwPendingPacketSize = 0; } // Bytes ready to be copied into packet's internal buffer ASSERT(pcReadBuffer <= pcReadBufferEnd); uint32 dwBytesToCopy = ((m_pPendingPacket->m_dwSize - m_dwPendingPacketSize) < static_cast<uint32>(pcReadBufferEnd - pcReadBuffer)) ? (m_pPendingPacket->m_dwSize - m_dwPendingPacketSize) : static_cast<uint32>(pcReadBufferEnd - pcReadBuffer); // Copy bytes from Global buffer to packet's internal buffer memcpy2(&m_pPendingPacket->m_pcBuffer[m_dwPendingPacketSize], pcReadBuffer, dwBytesToCopy); m_dwPendingPacketSize += dwBytesToCopy; pcReadBuffer += dwBytesToCopy; // Check if packet is complete ASSERT(m_pPendingPacket->m_dwSize >= m_dwPendingPacketSize); if (m_pPendingPacket->m_dwSize == m_dwPendingPacketSize) { #ifdef EMSOCKET_DEBUG EMTrace("CEMSocket::PacketReceived on %d, opcode=%X, realSize=%d", static_cast<SOCKET>(this), m_pPendingPacket->m_eOpcode, m_pPendingPacket->GetRealPacketSize()); #endif EMSOCKET_DEBUG // Process packet m_bInPacketReceived = true; PacketReceived(m_pPendingPacket); m_bInPacketReceived = false; delete m_pPendingPacket; m_pPendingPacket = NULL; m_dwPendingPacketSize = 0; } } // Finally, if there is any data left over, save it for next time ASSERT(pcReadBuffer <= pcReadBufferEnd); ASSERT(pcReadBufferEnd - pcReadBuffer < sizeof(PacketHeader_Struct)); if (pcReadBuffer != pcReadBufferEnd) { // Keep the partial head m_dwPendingHeaderSize = pcReadBufferEnd - pcReadBuffer; memcpy(m_arrcPendingHeader, pcReadBuffer, m_dwPendingHeaderSize); } }