Exemple #1
0
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;
}
Exemple #2
0
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;
}
Exemple #3
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;
}
Exemple #4
0
CEMSocket::~CEMSocket()
{
	EMTrace("CEMSocket::~CEMSocket() on %d",(SOCKET)this);
	ClearQueues();
	RemoveAllLayers();
	AsyncSelect(0);
}
Exemple #5
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);
}
Exemple #6
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);
    }
}
Exemple #7
0
// 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;
}
Exemple #8
0
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);
	}	
}