Beispiel #1
0
void ONBinaryProtocol::parseBuffer()
{
    if (_buffer.length() < 1)
        return;

    const char *data = _buffer.constData();
    const char *bufferEnd = data + _buffer.length();

    do {
        auto header = reinterpret_cast<const BinaryPacketHeader *>(data);
        if (data + ntohl(header->MessageLength) > bufferEnd) {
            break;
        }
        // Increment data after break, since if we havent have enough data, we will need the header next time.
        data += sizeof(BinaryPacketHeader);

        _currentPacket.Message = static_cast<Protocol::Message>(ntohl(header->Message));
        _currentPacket.Arguments.clear();

        const char *dataEnd = data + ntohl(header->MessageLength);
        while (dataEnd > data) {
            if (data + sizeof(BinaryArgumentHeader) > dataEnd) {
                throw Exception("Message argument header is missing");
            }

            auto argHeader = reinterpret_cast<const BinaryArgumentHeader *>(data);
            data += sizeof(BinaryArgumentHeader);

            if (data + ntohl(argHeader->ArgumentLength) > dataEnd) {
                throw Exception("Message argument is too long");
            }

            _currentPacket.Arguments.insert(
                    static_cast<Protocol::MessageArgument>(ntohl(argHeader->Argument)),
                    QByteArray(data, ntohl(argHeader->ArgumentLength))
                );
            data += ntohl(argHeader->ArgumentLength);
        }

        emit PacketReceived(_currentPacket);
    } while (data < bufferEnd);

    _buffer.remove(0, data - _buffer.constData());
}
Beispiel #2
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);
    }
}
Beispiel #3
0
void SyncClient::on_data_received()
{
    qDebug() << "Got Data";

    QDataStream dataStream(mSocket);
    dataStream.setVersion(QDataStream::Qt_5_3);

    if(mNextPacketSize == 0)
    {
        if(mSocket->bytesAvailable() < static_cast<int>(sizeof(quint16)))
        {
            // We still don't know how much to read
            return;
        }

        // Read the size of the next packet
        dataStream >> mNextPacketSize;

        qDebug() << "Next Packet Size " << mNextPacketSize;
    }

    if(mSocket->bytesAvailable() < mNextPacketSize)
    {
        // Wait until we're able to read a full packet
        return;
    }

    // Reset the size
    mNextPacketSize = 0;

    eSyncPacketType packetType;
    dataStream >> (quint32&)packetType;

    switch(packetType)
    {
    case kSyncPacketType_Undefined:
    {
        break;
    }
    case kSyncPacketType_Handshake:
    {
        SyncPacket_Handshake* packet = new SyncPacket_Handshake();
        packet->Type = packetType;
        dataStream >> packet->Message;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_AddTrack:
    {
        SyncPacket_AddTrack* packet = new SyncPacket_AddTrack();
        packet->Type = packetType;
        dataStream >> packet->TrackName;
        dataStream >> (quint32&)packet->TrackType;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_RenameTrack:
    {
        SyncPacket_RenameTrack* packet = new SyncPacket_RenameTrack();
        packet->Type = packetType;
        dataStream >> packet->TrackName;
        dataStream >> packet->NewTrackName;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_RemoveTrack:
    {
        SyncPacket_RemoveTrack* packet = new SyncPacket_RemoveTrack();
        packet->Type = packetType;
        dataStream >> packet->TrackName;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_AddKey:
    {
        SyncPacket_AddKey* packet = new SyncPacket_AddKey();
        packet->Type = packetType;
        dataStream >> packet->TrackName;
        dataStream >> packet->Position;
        dataStream >> packet->Data;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_ModifyKey:
    {
        SyncPacket_ModifyKey* packet = new SyncPacket_ModifyKey();
        packet->Type = packetType;
        dataStream >> packet->TrackName;
        dataStream >> packet->Position;
        dataStream >> packet->Data;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_RemoveKey:
    {
        SyncPacket_RemoveKey* packet = new SyncPacket_RemoveKey();
        packet->Type = packetType;
        dataStream >> packet->TrackName;
        dataStream >> packet->Position;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_Seek:
    {
        SyncPacket_Seek* packet = new SyncPacket_Seek();
        packet->Type = packetType;
        dataStream >> packet->Position;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_Play:
    {
        SyncPacket_Play* packet = new SyncPacket_Play();
        packet->Type = packetType;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_Pause:
    {
        SyncPacket_Pause* packet = new SyncPacket_Pause();
        packet->Type = packetType;

        emit PacketReceived(packet);
        break;
    }
    case kSyncPacketType_Response:
    {
        SyncPacket_Response* packet = new SyncPacket_Response();
        packet->Type = packetType;
        dataStream >> packet->Result;

        emit PacketReceived(packet);
        break;
    }
    }
}
Beispiel #4
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);
	}	
}
Beispiel #5
0
void CEMSocket::OnReceive(int nErrorCode)
{
	if(nErrorCode) {
		uint32 error = LastError(); 
		if (error != wxSOCKET_WOULDBLOCK) {
			OnError(nErrorCode);
			return;
		}
	}
	
	// Check current connection state
	if (byConnected == ES_DISCONNECTED) {
		return;
	} else {	
		byConnected = ES_CONNECTED; // ES_DISCONNECTED, ES_NOTCONNECTED, ES_CONNECTED
	}

	uint32 ret;
	do {
		// CPU load improvement
		if (downloadLimitEnable && downloadLimit == 0){
			pendingOnReceive = true;
			return;
		}

		uint32 readMax;
		byte *buf;
		if (pendingHeaderSize < PACKET_HEADER_SIZE) {
			delete[] pendingPacket;
			pendingPacket = NULL;
			buf = pendingHeader + pendingHeaderSize;
			readMax = PACKET_HEADER_SIZE - pendingHeaderSize;
		} else if (pendingPacket == NULL) {
			pendingPacketSize = 0;
			readMax = CPacket::GetPacketSizeFromHeader(pendingHeader);
			if (readMax > MAX_PACKET_SIZE) {
				pendingHeaderSize = 0;
				OnError(ERR_TOOBIG);
				return;
			}
			pendingPacket = new byte[readMax + 1];
			buf = pendingPacket;
		} else {
			buf = pendingPacket + pendingPacketSize;
			readMax = CPacket::GetPacketSizeFromHeader(pendingHeader) - pendingPacketSize;
		}

		if (downloadLimitEnable && readMax > downloadLimit) {
			readMax = downloadLimit;
		}

		ret = 0;
		if (readMax) {
			wxMutexLocker lock(m_sendLocker);
			ret = Read(buf, readMax);
			if (Error() || (ret == 0)) {
				if (LastError() == wxSOCKET_WOULDBLOCK) {
					pendingOnReceive = true;
				}
				return;
			}
		}

		// Bandwidth control
		if (downloadLimitEnable) {
			// Update limit
			if (ret >= downloadLimit) {
				downloadLimit = 0;
			} else {
				downloadLimit -= ret;
			}
		}

		// CPU load improvement
		// Detect if the socket's buffer is empty (or the size did match...)
		pendingOnReceive = (ret == readMax);

		if (pendingHeaderSize >= PACKET_HEADER_SIZE) {
			pendingPacketSize += ret;
			if (pendingPacketSize >= CPacket::GetPacketSizeFromHeader(pendingHeader)) {
				CScopedPtr<CPacket> packet(new CPacket(pendingHeader, pendingPacket));
				pendingPacket = NULL;
				pendingPacketSize = 0;
				pendingHeaderSize = 0;

				// Bugfix We still need to check for a valid protocol
				// Remark: the default eMule v0.26b had removed this test......
				switch (packet->GetProtocol()){
					case OP_EDONKEYPROT:
					case OP_PACKEDPROT:
					case OP_EMULEPROT:
					case OP_ED2KV2HEADER:
					case OP_ED2KV2PACKEDPROT:
						break;
					default:
						OnError(ERR_WRONGHEADER);
						return;
				}

				// Process packet
				PacketReceived(packet.get());
			}
		} else {
			pendingHeaderSize += ret;
		}
	} while (ret && pendingHeaderSize >= PACKET_HEADER_SIZE);
}