diff options
Diffstat (limited to 'src/components/protocol_handler/src/protocol_packet.cc')
-rw-r--r-- | src/components/protocol_handler/src/protocol_packet.cc | 335 |
1 files changed, 247 insertions, 88 deletions
diff --git a/src/components/protocol_handler/src/protocol_packet.cc b/src/components/protocol_handler/src/protocol_packet.cc index 19c73127c..a31678ec6 100644 --- a/src/components/protocol_handler/src/protocol_packet.cc +++ b/src/components/protocol_handler/src/protocol_packet.cc @@ -33,55 +33,220 @@ #include <stdint.h> #include <memory.h> #include <new> +#include <cstring> +#include <limits> + +#include "protocol/common.h" #include "protocol_handler/protocol_packet.h" #include "utils/macro.h" +#include "utils/byte_order.h" namespace protocol_handler { +ProtocolPacket::ProtocolData::ProtocolData() + : data(NULL), totalDataBytes(0u) { } + +ProtocolPacket::ProtocolData::~ProtocolData() { + delete[] data; +} + +ProtocolPacket::ProtocolHeader::ProtocolHeader() + : version(0x00), + protection_flag(PROTECTION_OFF), + frameType(0x00), + serviceType(0x00), + frameData(0x00), + sessionId(0x00), + dataSize(0x00), + messageId(0x00) { +} + +ProtocolPacket::ProtocolHeader::ProtocolHeader( + uint8_t version, bool protection, uint8_t frameType, uint8_t serviceType, + uint8_t frameData, uint8_t sessionID, uint32_t dataSize, uint32_t messageID) + : version(version), + protection_flag(protection), + frameType(frameType), + serviceType(serviceType), + frameData(frameData), + sessionId(sessionID), + dataSize(dataSize), + messageId(messageID) { +} + +inline uint32_t read_be_uint32(const uint8_t* const data) { + // Int value read byte per byte + // reintercast for non-4 byte address alignment lead to UB on arm platform + uint32_t value = data[3]; + value += (data[2] << 8); + value += (data[1] << 16); + value += (data[0] << 24); + return value; +} + +void ProtocolPacket::ProtocolHeader::deserialize( + const uint8_t* message, const size_t messageSize) { + if (messageSize < PROTOCOL_HEADER_V1_SIZE) { + return; + } + // first 4 bits + version = message[0] >> 4u; + // 5th bit + protection_flag = message[0] & 0x08u; + // 6-8 bits + frameType = message[0] & 0x07u; + + serviceType = message[1]; + frameData = message[2]; + sessionId = message[3]; + + // FIXME(EZamakhov): usage for FirstFrame message + dataSize = read_be_uint32(message + 4); + switch (version) { + case PROTOCOL_VERSION_2: + case PROTOCOL_VERSION_3: + case PROTOCOL_VERSION_4:{ + if (messageSize < PROTOCOL_HEADER_V2_SIZE) { + return; + } + messageId = read_be_uint32(message + 8); + } + break; + default: + messageId = 0; + break; + } +} + +ProtocolPacket::ProtocolHeaderValidator::ProtocolHeaderValidator() + : max_payload_size_(std::numeric_limits<size_t>::max()) { +} + +void ProtocolPacket::ProtocolHeaderValidator::set_max_payload_size( + const size_t max_payload_size) { + max_payload_size_ = max_payload_size; +} + +size_t ProtocolPacket::ProtocolHeaderValidator::max_payload_size() const { + return max_payload_size_; +} + +RESULT_CODE ProtocolPacket::ProtocolHeaderValidator::validate( + const ProtocolHeader& header) const { + // expected payload size will be calculated depending + // on used protocol version + size_t payload_size = MAXIMUM_FRAME_DATA_V2_SIZE; + // Protocol version shall be from 1 to 4 + switch (header.version) { + case PROTOCOL_VERSION_1: + case PROTOCOL_VERSION_2: + break; + case PROTOCOL_VERSION_3: + case PROTOCOL_VERSION_4: + payload_size = max_payload_size_ > MAXIMUM_FRAME_DATA_V2_SIZE ? + max_payload_size_ : MAXIMUM_FRAME_DATA_V2_SIZE; + break; + default: + return RESULT_FAIL; + } + // ServiceType shall be equal 0x0 (Control), 0x07 (RPC), 0x0A (PCM), 0x0B (Video), 0x0F (Bulk) + if (ServiceTypeFromByte(header.serviceType) == kInvalidServiceType) { + return RESULT_FAIL; + } + // Check frame info for each frame type + // Frame type shall be 0x00 (Control), 0x01 (Single), 0x02 (First), 0x03 (Consecutive) + // For Control frames Frame info value shall be from 0x00 to 0x06 or 0xFE(Data Ack), 0xFF(HB Ack) + // For Single and First frames Frame info value shall be equal 0x00 + switch (header.frameType) { + case FRAME_TYPE_CONTROL : { + switch (header.frameData) { + case FRAME_DATA_HEART_BEAT: + case FRAME_DATA_START_SERVICE: + case FRAME_DATA_START_SERVICE_ACK: + case FRAME_DATA_START_SERVICE_NACK: + case FRAME_DATA_END_SERVICE: + case FRAME_DATA_END_SERVICE_ACK: + case FRAME_DATA_END_SERVICE_NACK: + case FRAME_DATA_SERVICE_DATA_ACK: + case FRAME_DATA_HEART_BEAT_ACK: + break; + default: + return RESULT_FAIL; + } + break; + } + case FRAME_TYPE_SINGLE: + if (header.frameData != FRAME_DATA_SINGLE) { + return RESULT_FAIL; + } + break; + case FRAME_TYPE_FIRST: + if (header.frameData != FRAME_DATA_FIRST) { + return RESULT_FAIL; + } + break; + case FRAME_TYPE_CONSECUTIVE: + // Could have any FrameInfo value + break; + default: + // All other Frame type is invalid + return RESULT_FAIL; + } + // For Control frames Data Size value shall be less than MTU header + // For Single and Consecutive Data Size value shall be greater than 0x00 + // and shall be less than payload size + if (header.dataSize > payload_size) { + return RESULT_FAIL; + } + switch (header.frameType) { + case FRAME_TYPE_SINGLE: + case FRAME_TYPE_CONSECUTIVE: + if (header.dataSize <= 0) { + return RESULT_FAIL; + } + break; + default: + break; + } + // Message ID be equal or greater than 0x01 (not actual for 1 protocol version and Control frames) + if (FRAME_TYPE_CONTROL != header.frameType && PROTOCOL_VERSION_1 != header.version + && header.messageId <= 0) { + // Message ID shall be greater than 0x00, but not implemented in SPT + // TODO(EZamakhov): return on fix on mobile side - APPLINK-9990 + return RESULT_FAIL; + } + return RESULT_OK; +} + ProtocolPacket::ProtocolPacket() - : payload_size_(0), - packet_id_(0), - connection_id_(0) { + : payload_size_(0), connection_id_(0) { } -ProtocolPacket::ProtocolPacket(uint8_t connection_id, +ProtocolPacket::ProtocolPacket(ConnectionID connection_id, uint8_t version, bool protection, uint8_t frameType, uint8_t serviceType, uint8_t frameData, uint8_t sessionID, uint32_t dataSize, uint32_t messageID, - const uint8_t *data, - uint32_t packet_id) + const uint8_t *data) : packet_header_(version, protection, frameType, serviceType, frameData, sessionID, dataSize, messageID), + packet_data_(), payload_size_(0), - packet_id_(packet_id), connection_id_(connection_id) { set_data(data, dataSize); - DCHECK(MAXIMUM_FRAME_DATA_SIZE >= dataSize); } -ProtocolPacket::ProtocolPacket(uint8_t connection_id, uint8_t *data_param, - uint32_t data_size) - : payload_size_(0), - packet_id_(0), +ProtocolPacket::ProtocolPacket(ConnectionID connection_id) + : packet_header_(), + packet_data_(), + payload_size_(0), connection_id_(connection_id) { - RESULT_CODE result = deserializePacket(data_param, data_size); - if (result != RESULT_OK) { - //NOTREACHED(); - } -} - -ProtocolPacket::~ProtocolPacket() { - delete[] packet_data_.data; } // Serialization RawMessagePtr ProtocolPacket::serializePacket() const { - uint8_t *packet = new (std::nothrow) uint8_t[MAXIMUM_FRAME_DATA_SIZE]; - if (!packet) { - return RawMessagePtr(); - } + // TODO(EZamakhov): Move header serialization to ProtocolHeader // version is low byte const uint8_t version_byte = packet_header_.version << 4; // protection is first bit of second byte @@ -89,30 +254,35 @@ RawMessagePtr ProtocolPacket::serializePacket() const { // frame type is last 3 bits of second byte const uint8_t frame_type_byte = packet_header_.frameType & 0x07; + uint8_t header[PROTOCOL_HEADER_V2_SIZE]; uint8_t offset = 0; - packet[offset++] = version_byte | protection_byte | frame_type_byte; - packet[offset++] = packet_header_.serviceType; - packet[offset++] = packet_header_.frameData; - packet[offset++] = packet_header_.sessionId; + header[offset++] = version_byte | protection_byte | frame_type_byte; + header[offset++] = packet_header_.serviceType; + header[offset++] = packet_header_.frameData; + header[offset++] = packet_header_.sessionId; - packet[offset++] = packet_header_.dataSize >> 24; - packet[offset++] = packet_header_.dataSize >> 16; - packet[offset++] = packet_header_.dataSize >> 8; - packet[offset++] = packet_header_.dataSize; + header[offset++] = packet_header_.dataSize >> 24; + header[offset++] = packet_header_.dataSize >> 16; + header[offset++] = packet_header_.dataSize >> 8; + header[offset++] = packet_header_.dataSize; if (packet_header_.version != PROTOCOL_VERSION_1) { - packet[offset++] = packet_header_.messageId >> 24; - packet[offset++] = packet_header_.messageId >> 16; - packet[offset++] = packet_header_.messageId >> 8; - packet[offset++] = packet_header_.messageId; - } + header[offset++] = packet_header_.messageId >> 24; + header[offset++] = packet_header_.messageId >> 16; + header[offset++] = packet_header_.messageId >> 8; + header[offset++] = packet_header_.messageId; + }; + + size_t total_packet_size = offset + (packet_data_.data ? packet_data_.totalDataBytes : 0); - DCHECK((offset + packet_data_.totalDataBytes) <= MAXIMUM_FRAME_DATA_SIZE); + uint8_t *packet = new (std::nothrow) uint8_t[total_packet_size]; + if (!packet) { + return RawMessagePtr(); + } - size_t total_packet_size = offset; - if (packet_data_.data) { + memcpy(packet, header, offset); + if (packet_data_.data && packet_data_.totalDataBytes) { memcpy(packet + offset, packet_data_.data, packet_data_.totalDataBytes); - total_packet_size += packet_data_.totalDataBytes; } const RawMessagePtr out_message( @@ -124,14 +294,10 @@ RawMessagePtr ProtocolPacket::serializePacket() const { return out_message; } -uint32_t ProtocolPacket::packet_id() const { - return packet_id_; -} - RESULT_CODE ProtocolPacket::appendData(uint8_t *chunkData, uint32_t chunkDataSize) { if (payload_size_ + chunkDataSize <= packet_data_.totalDataBytes) { - if (chunkData) { + if (chunkData && chunkDataSize > 0) { if (packet_data_.data) { memcpy(packet_data_.data + payload_size_, chunkData, chunkDataSize); payload_size_ += chunkDataSize; @@ -147,39 +313,36 @@ size_t ProtocolPacket::packet_size() const { return packet_header_.dataSize; } -RESULT_CODE ProtocolPacket::deserializePacket(const uint8_t *message, - uint32_t messageSize) { - uint8_t offset = 0; - uint8_t firstByte = message[offset]; - offset++; - - packet_header_.version = firstByte >> 4u; - - if (firstByte & 0x08u) { - packet_header_.protection_flag = true; - } else { - packet_header_.protection_flag = false; +bool ProtocolPacket::operator==(const ProtocolPacket& other) const { + if (connection_id_ == other.connection_id_ && + packet_header_.version == other.packet_header_.version && + packet_header_.protection_flag == other.packet_header_.protection_flag && + packet_header_.frameType == other.packet_header_.frameType && + packet_header_.serviceType == other.packet_header_.serviceType && + packet_header_.frameData == other.packet_header_.frameData && + packet_header_.sessionId == other.packet_header_.sessionId && + packet_header_.dataSize == other.packet_header_.dataSize && + packet_header_.messageId == other.packet_header_.messageId && + packet_data_.totalDataBytes == other.packet_data_.totalDataBytes) { + if (other.packet_data_.totalDataBytes == 0) { + return true; + } + // Compare payload data + if (packet_data_.data && other.packet_data_.data && + 0 == memcmp(packet_data_.data, other.packet_data_.data, + packet_data_.totalDataBytes)) { + return true; + } } + return false; +} - packet_header_.frameType = firstByte & 0x07u; - - packet_header_.serviceType = message[offset++]; - packet_header_.frameData = message[offset++]; - packet_header_.sessionId = message[offset++]; - - packet_header_.dataSize = message[offset++] << 24u; - packet_header_.dataSize |= message[offset++] << 16u; - packet_header_.dataSize |= message[offset++] << 8u; - packet_header_.dataSize |= message[offset++]; - - if (packet_header_.version != PROTOCOL_VERSION_1) { - packet_header_.messageId = message[offset++] << 24u; - packet_header_.messageId |= message[offset++] << 16u; - packet_header_.messageId |= message[offset++] << 8u; - packet_header_.messageId |= message[offset++]; - } else { - packet_header_.messageId = 0u; - } +RESULT_CODE ProtocolPacket::deserializePacket( + const uint8_t *message, const size_t messageSize) { + packet_header_.deserialize(message, messageSize); + const uint8_t offset = + packet_header_.version == PROTOCOL_VERSION_1 ? PROTOCOL_HEADER_V1_SIZE + : PROTOCOL_HEADER_V2_SIZE; packet_data_.totalDataBytes = packet_header_.dataSize; @@ -189,15 +352,14 @@ RESULT_CODE ProtocolPacket::deserializePacket(const uint8_t *message, dataPayloadSize = messageSize - offset; } - uint8_t *data = 0; + uint8_t *data = NULL; if (dataPayloadSize) { data = new (std::nothrow) uint8_t[dataPayloadSize]; - if (data) { - memcpy(data, message + offset, dataPayloadSize); - payload_size_ = dataPayloadSize; - } else { + if (!data) { return RESULT_FAIL; } + memcpy(data, message + offset, dataPayloadSize); + payload_size_ = dataPayloadSize; } if (packet_header_.frameType == FRAME_TYPE_FIRST) { @@ -212,9 +374,7 @@ RESULT_CODE ProtocolPacket::deserializePacket(const uint8_t *message, return RESULT_FAIL; } } else { - if (packet_data_.data) { - delete[] packet_data_.data; - } + delete[] packet_data_.data; packet_data_.data = data; } @@ -265,8 +425,7 @@ void ProtocolPacket::set_total_data_bytes(size_t dataBytes) { if (dataBytes) { delete[] packet_data_.data; packet_data_.data = new (std::nothrow) uint8_t[dataBytes]; - packet_data_.totalDataBytes = - packet_data_.data ? dataBytes : 0; + packet_data_.totalDataBytes = packet_data_.data ? dataBytes : 0u; } } @@ -280,7 +439,7 @@ void ProtocolPacket::set_data( memcpy(packet_data_.data, new_data, packet_data_.totalDataBytes); } else { // TODO(EZamakhov): add log info about memory problem - packet_header_.dataSize = packet_data_.totalDataBytes = 0; + packet_header_.dataSize = packet_data_.totalDataBytes = 0u; } } } |