blob: 3bad468a74e94d9219fd44d20d1dee31ef0d9d6b [file] [log] [blame]
David Garcia Quintas6a484052016-01-25 19:12:37 -08001/*
2 *
Craig Tiller6169d5f2016-03-31 07:46:18 -07003 * Copyright 2015, Google Inc.
David Garcia Quintas6a484052016-01-25 19:12:37 -08004 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met:
9 *
10 * * Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above
13 * copyright notice, this list of conditions and the following disclaimer
14 * in the documentation and/or other materials provided with the
15 * distribution.
16 * * Neither the name of Google Inc. nor the names of its
17 * contributors may be used to endorse or promote products derived from
18 * this software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 *
32 */
33
34#ifndef GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
35#define GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H
36
37#include <type_traits>
38
David Garcia Quintasb9426402016-03-08 16:25:11 -080039#include <grpc++/impl/codegen/config_protobuf.h>
40#include <grpc++/impl/codegen/core_codegen_interface.h>
41#include <grpc++/impl/codegen/serialization_traits.h>
42#include <grpc++/impl/codegen/status.h>
David Garcia Quintas6a484052016-01-25 19:12:37 -080043#include <grpc/impl/codegen/byte_buffer.h>
David Garcia Quintas1b2db632016-04-27 15:06:54 -070044#include <grpc/impl/codegen/byte_buffer_reader.h>
David Garcia Quintasf588aeb2016-03-02 20:33:28 -080045#include <grpc/impl/codegen/log.h>
David Garcia Quintas1b2db632016-04-27 15:06:54 -070046#include <grpc/impl/codegen/slice.h>
David Garcia Quintas6a484052016-01-25 19:12:37 -080047
48namespace grpc {
49
David Garcia Quintas6848c4e2016-03-07 17:10:57 -080050extern CoreCodegenInterface* g_core_codegen_interface;
David Garcia Quintasf588aeb2016-03-02 20:33:28 -080051
David Garcia Quintas0fde7132016-05-13 15:13:51 -070052namespace internal {
David Garcia Quintas1b2db632016-04-27 15:06:54 -070053
54const int kGrpcBufferWriterMaxBufferLength = 8192;
55
56class GrpcBufferWriter GRPC_FINAL
57 : public ::grpc::protobuf::io::ZeroCopyOutputStream {
58 public:
59 explicit GrpcBufferWriter(grpc_byte_buffer** bp, int block_size)
60 : block_size_(block_size), byte_count_(0), have_backup_(false) {
61 *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(NULL, 0);
62 slice_buffer_ = &(*bp)->data.raw.slice_buffer;
63 }
64
65 ~GrpcBufferWriter() GRPC_OVERRIDE {
66 if (have_backup_) {
67 g_core_codegen_interface->gpr_slice_unref(backup_slice_);
68 }
69 }
70
71 bool Next(void** data, int* size) GRPC_OVERRIDE {
72 if (have_backup_) {
73 slice_ = backup_slice_;
74 have_backup_ = false;
75 } else {
76 slice_ = g_core_codegen_interface->gpr_slice_malloc(block_size_);
77 }
78 *data = GPR_SLICE_START_PTR(slice_);
79 // On win x64, int is only 32bit
80 GPR_CODEGEN_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
81 byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
82 g_core_codegen_interface->gpr_slice_buffer_add(slice_buffer_, slice_);
83 return true;
84 }
85
86 void BackUp(int count) GRPC_OVERRIDE {
87 g_core_codegen_interface->gpr_slice_buffer_pop(slice_buffer_);
88 if (count == block_size_) {
89 backup_slice_ = slice_;
90 } else {
91 backup_slice_ = g_core_codegen_interface->gpr_slice_split_tail(
92 &slice_, GPR_SLICE_LENGTH(slice_) - count);
93 g_core_codegen_interface->gpr_slice_buffer_add(slice_buffer_, slice_);
94 }
95 have_backup_ = true;
96 byte_count_ -= count;
97 }
98
99 grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE { return byte_count_; }
100
101 private:
102 const int block_size_;
103 int64_t byte_count_;
104 gpr_slice_buffer* slice_buffer_;
105 bool have_backup_;
106 gpr_slice backup_slice_;
107 gpr_slice slice_;
108};
109
110class GrpcBufferReader GRPC_FINAL
111 : public ::grpc::protobuf::io::ZeroCopyInputStream {
112 public:
113 explicit GrpcBufferReader(grpc_byte_buffer* buffer)
114 : byte_count_(0), backup_count_(0) {
115 g_core_codegen_interface->grpc_byte_buffer_reader_init(&reader_, buffer);
116 }
117 ~GrpcBufferReader() GRPC_OVERRIDE {
118 g_core_codegen_interface->grpc_byte_buffer_reader_destroy(&reader_);
119 }
120
121 bool Next(const void** data, int* size) GRPC_OVERRIDE {
122 if (backup_count_ > 0) {
123 *data = GPR_SLICE_START_PTR(slice_) + GPR_SLICE_LENGTH(slice_) -
124 backup_count_;
125 GPR_CODEGEN_ASSERT(backup_count_ <= INT_MAX);
126 *size = (int)backup_count_;
127 backup_count_ = 0;
128 return true;
129 }
130 if (!g_core_codegen_interface->grpc_byte_buffer_reader_next(&reader_,
131 &slice_)) {
132 return false;
133 }
134 g_core_codegen_interface->gpr_slice_unref(slice_);
135 *data = GPR_SLICE_START_PTR(slice_);
136 // On win x64, int is only 32bit
137 GPR_CODEGEN_ASSERT(GPR_SLICE_LENGTH(slice_) <= INT_MAX);
138 byte_count_ += * size = (int)GPR_SLICE_LENGTH(slice_);
139 return true;
140 }
141
142 void BackUp(int count) GRPC_OVERRIDE { backup_count_ = count; }
143
144 bool Skip(int count) GRPC_OVERRIDE {
145 const void* data;
146 int size;
147 while (Next(&data, &size)) {
148 if (size >= count) {
149 BackUp(size - count);
150 return true;
151 }
152 // size < count;
153 count -= size;
154 }
155 // error or we have too large count;
156 return false;
157 }
158
159 grpc::protobuf::int64 ByteCount() const GRPC_OVERRIDE {
160 return byte_count_ - backup_count_;
161 }
162
163 private:
164 int64_t byte_count_;
165 int64_t backup_count_;
166 grpc_byte_buffer_reader reader_;
167 gpr_slice slice_;
168};
David Garcia Quintas0fde7132016-05-13 15:13:51 -0700169} // namespace internal
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700170
David Garcia Quintas6a484052016-01-25 19:12:37 -0800171template <class T>
172class SerializationTraits<T, typename std::enable_if<std::is_base_of<
173 grpc::protobuf::Message, T>::value>::type> {
174 public:
175 static Status Serialize(const grpc::protobuf::Message& msg,
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700176 grpc_byte_buffer** bp, bool* own_buffer) {
David Garcia Quintas6a484052016-01-25 19:12:37 -0800177 *own_buffer = true;
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700178 int byte_size = msg.ByteSize();
David Garcia Quintas0fde7132016-05-13 15:13:51 -0700179 if (byte_size <= internal::kGrpcBufferWriterMaxBufferLength) {
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700180 gpr_slice slice = g_core_codegen_interface->gpr_slice_malloc(byte_size);
181 GPR_CODEGEN_ASSERT(
182 GPR_SLICE_END_PTR(slice) ==
183 msg.SerializeWithCachedSizesToArray(GPR_SLICE_START_PTR(slice)));
184 *bp = g_core_codegen_interface->grpc_raw_byte_buffer_create(&slice, 1);
185 g_core_codegen_interface->gpr_slice_unref(slice);
186 return g_core_codegen_interface->ok();
187 } else {
David Garcia Quintas0fde7132016-05-13 15:13:51 -0700188 internal::GrpcBufferWriter writer(
189 bp, internal::kGrpcBufferWriterMaxBufferLength);
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700190 return msg.SerializeToZeroCopyStream(&writer)
191 ? g_core_codegen_interface->ok()
192 : Status(StatusCode::INTERNAL, "Failed to serialize message");
193 }
David Garcia Quintas6a484052016-01-25 19:12:37 -0800194 }
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700195
David Garcia Quintas6a484052016-01-25 19:12:37 -0800196 static Status Deserialize(grpc_byte_buffer* buffer,
197 grpc::protobuf::Message* msg,
198 int max_message_size) {
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700199 if (buffer == nullptr) {
200 return Status(StatusCode::INTERNAL, "No payload");
201 }
202 Status result = g_core_codegen_interface->ok();
203 {
David Garcia Quintas0fde7132016-05-13 15:13:51 -0700204 internal::GrpcBufferReader reader(buffer);
David Garcia Quintas1b2db632016-04-27 15:06:54 -0700205 ::grpc::protobuf::io::CodedInputStream decoder(&reader);
206 if (max_message_size > 0) {
207 decoder.SetTotalBytesLimit(max_message_size, max_message_size);
208 }
209 if (!msg->ParseFromCodedStream(&decoder)) {
210 result = Status(StatusCode::INTERNAL, msg->InitializationErrorString());
211 }
212 if (!decoder.ConsumedEntireMessage()) {
213 result = Status(StatusCode::INTERNAL, "Did not read entire message");
214 }
215 }
216 g_core_codegen_interface->grpc_byte_buffer_destroy(buffer);
217 return result;
David Garcia Quintas6a484052016-01-25 19:12:37 -0800218 }
219};
220
221} // namespace grpc
222
223#endif // GRPCXX_IMPL_CODEGEN_PROTO_UTILS_H