| 1 | /* |
| 2 | * Licensed to the Apache Software Foundation (ASF) under one |
| 3 | * or more contributor license agreements. See the NOTICE file |
| 4 | * distributed with this work for additional information |
| 5 | * regarding copyright ownership. The ASF licenses this file |
| 6 | * to you under the Apache License, Version 2.0 (the |
| 7 | * "License"); you may not use this file except in compliance |
| 8 | * with the License. You may obtain a copy of the License at |
| 9 | * |
| 10 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 11 | * |
| 12 | * Unless required by applicable law or agreed to in writing, |
| 13 | * software distributed under the License is distributed on an |
| 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 15 | * KIND, either express or implied. See the License for the |
| 16 | * specific language governing permissions and limitations |
| 17 | * under the License. |
| 18 | */ |
| 19 | |
| 20 | #include <cassert> |
| 21 | #include <algorithm> |
| 22 | #include <thrift/thrift_export.h> |
| 23 | |
| 24 | #include <thrift/transport/TBufferTransports.h> |
| 25 | |
| 26 | using std::string; |
| 27 | |
| 28 | namespace apache { |
| 29 | namespace thrift { |
| 30 | namespace transport { |
| 31 | |
| 32 | |
| 33 | |
| 34 | |
| 35 | void TMemoryBuffer::computeRead(uint32_t len, uint8_t** out_start, uint32_t* out_give) { |
| 36 | // Correct rBound_ so we can use the fast path in the future. |
| 37 | rBound_ = wBase_; |
| 38 | |
| 39 | // Decide how much to give. |
| 40 | uint32_t give = (std::min)(len, available_read()); |
| 41 | |
| 42 | *out_start = rBase_; |
| 43 | *out_give = give; |
| 44 | |
| 45 | // Preincrement rBase_ so the caller doesn't have to. |
| 46 | rBase_ += give; |
| 47 | } |
| 48 | |
| 49 | uint32_t TMemoryBuffer::readSlow(uint8_t* buf, uint32_t len) { |
| 50 | uint8_t* start; |
| 51 | uint32_t give; |
| 52 | computeRead(len, &start, &give); |
| 53 | |
| 54 | // Copy into the provided buffer. |
| 55 | memcpy(buf, start, give); |
| 56 | |
| 57 | return give; |
| 58 | } |
| 59 | |
| 60 | uint32_t TMemoryBuffer::readAppendToString(std::string& str, uint32_t len) { |
| 61 | // Don't get some stupid assertion failure. |
| 62 | if (buffer_ == nullptr) { |
| 63 | return 0; |
| 64 | } |
| 65 | |
| 66 | uint8_t* start; |
| 67 | uint32_t give; |
| 68 | computeRead(len, &start, &give); |
| 69 | |
| 70 | // Append to the provided string. |
| 71 | str.append((char*)start, give); |
| 72 | |
| 73 | return give; |
| 74 | } |
| 75 | |
| 76 | void TMemoryBuffer::ensureCanWrite(uint32_t len) { |
| 77 | // Check available space |
| 78 | uint32_t avail = available_write(); |
| 79 | if (len <= avail) { |
| 80 | return; |
| 81 | } |
| 82 | |
| 83 | if (!owner_) { |
| 84 | throw TTransportException("Insufficient space in external MemoryBuffer" ); |
| 85 | } |
| 86 | |
| 87 | // Grow the buffer as necessary. |
| 88 | uint64_t new_size = bufferSize_; |
| 89 | while (len > avail) { |
| 90 | new_size = new_size > 0 ? new_size * 2 : 1; |
| 91 | if (new_size > maxBufferSize_) { |
| 92 | throw TTransportException(TTransportException::BAD_ARGS, |
| 93 | "Internal buffer size overflow" ); |
| 94 | } |
| 95 | avail = available_write() + (static_cast<uint32_t>(new_size) - bufferSize_); |
| 96 | } |
| 97 | |
| 98 | // Allocate into a new pointer so we don't bork ours if it fails. |
| 99 | auto* new_buffer = static_cast<uint8_t*>(std::realloc(buffer_, new_size)); |
| 100 | if (new_buffer == nullptr) { |
| 101 | throw std::bad_alloc(); |
| 102 | } |
| 103 | |
| 104 | rBase_ = new_buffer + (rBase_ - buffer_); |
| 105 | rBound_ = new_buffer + (rBound_ - buffer_); |
| 106 | wBase_ = new_buffer + (wBase_ - buffer_); |
| 107 | wBound_ = new_buffer + new_size; |
| 108 | buffer_ = new_buffer; |
| 109 | bufferSize_ = static_cast<uint32_t>(new_size); |
| 110 | } |
| 111 | |
| 112 | void TMemoryBuffer::writeSlow(const uint8_t* buf, uint32_t len) { |
| 113 | ensureCanWrite(len); |
| 114 | |
| 115 | // Copy into the buffer and increment wBase_. |
| 116 | memcpy(wBase_, buf, len); |
| 117 | wBase_ += len; |
| 118 | } |
| 119 | |
| 120 | void TMemoryBuffer::wroteBytes(uint32_t len) { |
| 121 | uint32_t avail = available_write(); |
| 122 | if (len > avail) { |
| 123 | throw TTransportException("Client wrote more bytes than size of buffer." ); |
| 124 | } |
| 125 | wBase_ += len; |
| 126 | } |
| 127 | |
| 128 | const uint8_t* TMemoryBuffer::borrowSlow(uint8_t* buf, uint32_t* len) { |
| 129 | (void)buf; |
| 130 | rBound_ = wBase_; |
| 131 | if (available_read() >= *len) { |
| 132 | *len = available_read(); |
| 133 | return rBase_; |
| 134 | } |
| 135 | return nullptr; |
| 136 | } |
| 137 | } |
| 138 | } |
| 139 | } // apache::thrift::transport |
| 140 | |