| /* |
| Copyright (c) 2014 DataStax |
| |
| Licensed under the Apache License, Version 2.0 (the "License"); |
| you may not use this file except in compliance with the License. |
| You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| */ |
| |
| #include "response.hpp" |
| #include "error_response.hpp" |
| #include "ready_response.hpp" |
| #include "result_response.hpp" |
| #include "supported_response.hpp" |
| #include "serialization.hpp" |
| |
| namespace cass { |
| |
| bool ResponseMessage::allocate_body(int8_t opcode) { |
| response_body_.reset(); |
| switch (opcode) { |
| case CQL_OPCODE_RESULT: |
| response_body_.reset(new ResultResponse()); |
| return true; |
| |
| case CQL_OPCODE_ERROR: |
| response_body_.reset(new ErrorResponse()); |
| return true; |
| |
| case CQL_OPCODE_SUPPORTED: |
| response_body_.reset(new SupportedResponse()); |
| return true; |
| |
| case CQL_OPCODE_READY: |
| response_body_.reset(new ReadyResponse()); |
| return true; |
| |
| default: |
| return false; |
| } |
| } |
| |
| int ResponseMessage::decode(int version, char* input, size_t size) { |
| char* input_pos = input; |
| |
| received_ += size; |
| |
| if (!is_header_received_) { |
| if (received_ >= CASS_HEADER_SIZE_V1_AND_V2) { |
| // We may have received more data then we need, only copy what we need |
| size_t overage = received_ - CASS_HEADER_SIZE_V1_AND_V2; |
| size_t needed = size - overage; |
| |
| memcpy(header_buffer_pos_, input_pos, needed); |
| header_buffer_pos_ += needed; |
| input_pos += needed; |
| assert(header_buffer_pos_ == header_buffer_ + CASS_HEADER_SIZE_V1_AND_V2); |
| |
| char* buffer = header_buffer_; |
| version_ = *(buffer++); |
| flags_ = *(buffer++); |
| stream_ = *(buffer++); |
| opcode_ = *(buffer++); |
| |
| decode_int32(buffer, length_); |
| |
| is_header_received_ = true; |
| |
| if (!allocate_body(opcode_) || !response_body_) { |
| return -1; |
| } |
| |
| response_body_->set_buffer(new char[length_]); |
| body_buffer_pos_ = response_body_->buffer(); |
| } else { |
| // We haven't received all the data for the header. We consume the |
| // entire buffer. |
| memcpy(header_buffer_pos_, input_pos, size); |
| header_buffer_pos_ += size; |
| return size; |
| } |
| } |
| |
| const size_t remaining = size - (input_pos - input); |
| const size_t frame_size = CASS_HEADER_SIZE_V1_AND_V2 + length_; |
| |
| if (received_ >= frame_size) { |
| // We may have received more data then we need, only copy what we need |
| size_t overage = received_ - frame_size; |
| size_t needed = remaining - overage; |
| |
| memcpy(body_buffer_pos_, input_pos, needed); |
| body_buffer_pos_ += needed; |
| input_pos += needed; |
| assert(body_buffer_pos_ == response_body_->buffer() + length_); |
| |
| if (!response_body_->decode(version, response_body_->buffer(), length_)) { |
| is_body_error_ = true; |
| } |
| is_body_ready_ = true; |
| } else { |
| // We haven't received all the data for the frame. We consume the entire |
| // buffer. |
| memcpy(body_buffer_pos_, input_pos, remaining); |
| body_buffer_pos_ += remaining; |
| return size; |
| } |
| |
| return input_pos - input; |
| } |
| |
| } // namespace cass |
| |