1 /* 2 * 3 * Copyright 2015 gRPC authors. 4 * 5 * Licensed under the Apache License, Version 2.0 (the "License"); 6 * you may not use this file except in compliance with the License. 7 * You may obtain a copy of the License at 8 * 9 * http://www.apache.org/licenses/LICENSE-2.0 10 * 11 * Unless required by applicable law or agreed to in writing, software 12 * distributed under the License is distributed on an "AS IS" BASIS, 13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 * See the License for the specific language governing permissions and 15 * limitations under the License. 16 * 17 */ 18 19 #ifndef GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_READER_H 20 #define GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_READER_H 21 22 #include <type_traits> 23 24 #include <grpc/impl/codegen/byte_buffer_reader.h> 25 #include <grpc/impl/codegen/grpc_types.h> 26 #include <grpc/impl/codegen/slice.h> 27 #include <grpcpp/impl/codegen/byte_buffer.h> 28 #include <grpcpp/impl/codegen/config_protobuf.h> 29 #include <grpcpp/impl/codegen/core_codegen_interface.h> 30 #include <grpcpp/impl/codegen/serialization_traits.h> 31 #include <grpcpp/impl/codegen/status.h> 32 33 /// This header provides an object that reads bytes directly from a 34 /// grpc::ByteBuffer, via the ZeroCopyInputStream interface 35 36 namespace grpc { 37 38 extern CoreCodegenInterface* g_core_codegen_interface; 39 40 /// This is a specialization of the protobuf class ZeroCopyInputStream 41 /// The principle is to get one chunk of data at a time from the proto layer, 42 /// with options to backup (re-see some bytes) or skip (forward past some bytes) 43 /// 44 /// Read more about ZeroCopyInputStream interface here: 45 /// https://developers.google.com/protocol-buffers/docs/reference/cpp/google.protobuf.io.zero_copy_stream#ZeroCopyInputStream 46 class ProtoBufferReader : public ::grpc::protobuf::io::ZeroCopyInputStream { 47 public: 48 /// Constructs buffer reader from \a buffer. Will set \a status() to non ok 49 /// if \a buffer is invalid (the internal buffer has not been initialized). ProtoBufferReader(ByteBuffer * buffer)50 explicit ProtoBufferReader(ByteBuffer* buffer) 51 : byte_count_(0), backup_count_(0), status_() { 52 /// Implemented through a grpc_byte_buffer_reader which iterates 53 /// over the slices that make up a byte buffer 54 if (!buffer->Valid() || 55 !g_core_codegen_interface->grpc_byte_buffer_reader_init( 56 &reader_, buffer->c_buffer())) { 57 status_ = Status(StatusCode::INTERNAL, 58 "Couldn't initialize byte buffer reader"); 59 } 60 } 61 ~ProtoBufferReader()62 ~ProtoBufferReader() { 63 if (status_.ok()) { 64 g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_); 65 } 66 } 67 68 /// Give the proto library a chunk of data from the stream. The caller 69 /// may safely read from data[0, size - 1]. Next(const void ** data,int * size)70 bool Next(const void** data, int* size) override { 71 if (!status_.ok()) { 72 return false; 73 } 74 /// If we have backed up previously, we need to return the backed-up slice 75 if (backup_count_ > 0) { 76 *data = GRPC_SLICE_START_PTR(slice_) + GRPC_SLICE_LENGTH(slice_) - 77 backup_count_; 78 GPR_CODEGEN_ASSERT(backup_count_ <= INT_MAX); 79 *size = (int)backup_count_; 80 backup_count_ = 0; 81 return true; 82 } 83 /// Otherwise get the next slice from the byte buffer reader 84 if (!g_core_codegen_interface->grpc_byte_buffer_reader_next(&reader_, 85 &slice_)) { 86 return false; 87 } 88 g_core_codegen_interface->grpc_slice_unref(slice_); 89 *data = GRPC_SLICE_START_PTR(slice_); 90 // On win x64, int is only 32bit 91 GPR_CODEGEN_ASSERT(GRPC_SLICE_LENGTH(slice_) <= INT_MAX); 92 byte_count_ += * size = (int)GRPC_SLICE_LENGTH(slice_); 93 return true; 94 } 95 96 /// Returns the status of the buffer reader. status()97 Status status() const { return status_; } 98 99 /// The proto library calls this to indicate that we should back up \a count 100 /// bytes that have already been returned by the last call of Next. 101 /// So do the backup and have that ready for a later Next. BackUp(int count)102 void BackUp(int count) override { 103 GPR_CODEGEN_ASSERT(count <= static_cast<int>(GRPC_SLICE_LENGTH(slice_))); 104 backup_count_ = count; 105 } 106 107 /// The proto library calls this to skip over \a count bytes. Implement this 108 /// using Next and BackUp combined. Skip(int count)109 bool Skip(int count) override { 110 const void* data; 111 int size; 112 while (Next(&data, &size)) { 113 if (size >= count) { 114 BackUp(size - count); 115 return true; 116 } 117 // size < count; 118 count -= size; 119 } 120 // error or we have too large count; 121 return false; 122 } 123 124 /// Returns the total number of bytes read since this object was created. ByteCount()125 grpc::protobuf::int64 ByteCount() const override { 126 return byte_count_ - backup_count_; 127 } 128 129 // These protected members are needed to support internal optimizations. 130 // they expose internal bits of grpc core that are NOT stable. If you have 131 // a use case needs to use one of these functions, please send an email to 132 // https://groups.google.com/forum/#!forum/grpc-io. 133 protected: set_byte_count(int64_t byte_count)134 void set_byte_count(int64_t byte_count) { byte_count_ = byte_count; } backup_count()135 int64_t backup_count() { return backup_count_; } set_backup_count(int64_t backup_count)136 void set_backup_count(int64_t backup_count) { backup_count_ = backup_count; } reader()137 grpc_byte_buffer_reader* reader() { return &reader_; } slice()138 grpc_slice* slice() { return &slice_; } 139 140 private: 141 int64_t byte_count_; ///< total bytes read since object creation 142 int64_t backup_count_; ///< how far backed up in the stream we are 143 grpc_byte_buffer_reader reader_; ///< internal object to read \a grpc_slice 144 ///< from the \a grpc_byte_buffer 145 grpc_slice slice_; ///< current slice passed back to the caller 146 Status status_; ///< status of the entire object 147 }; 148 149 } // namespace grpc 150 151 #endif // GRPCPP_IMPL_CODEGEN_PROTO_BUFFER_READER_H 152