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()); }
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); } }
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; } } }
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); } }
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); }