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 #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
21 #define _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_ 1
22
23 #include <thrift/protocol/TBinaryProtocol.h>
24 #include <thrift/transport/TTransportException.h>
25
26 #include <limits>
27
28 #include <netinet/in.h>
29
30 namespace apache {
31 namespace thrift {
32 namespace protocol {
33
34 template <class Transport_, class ByteOrder_>
writeMessageBegin(const std::string & name,const TMessageType messageType,const int32_t seqid)35 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageBegin(const std::string& name,
36 const TMessageType messageType,
37 const int32_t seqid) {
38 if (this->strict_write_) {
39 int32_t version = (VERSION_1) | ((int32_t)messageType);
40 uint32_t wsize = 0;
41 wsize += writeI32(version);
42 wsize += writeString(name);
43 wsize += writeI32(seqid);
44 return wsize;
45 } else {
46 uint32_t wsize = 0;
47 wsize += writeString(name);
48 wsize += writeByte((int8_t)messageType);
49 wsize += writeI32(seqid);
50 return wsize;
51 }
52 }
53
54 template <class Transport_, class ByteOrder_>
writeMessageEnd()55 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMessageEnd() {
56 return 0;
57 }
58
59 template <class Transport_, class ByteOrder_>
writeStructBegin(const char * name)60 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructBegin(const char* name) {
61 (void)name;
62 return 0;
63 }
64
65 template <class Transport_, class ByteOrder_>
writeStructEnd()66 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeStructEnd() {
67 return 0;
68 }
69
70 template <class Transport_, class ByteOrder_>
writeFieldBegin(const char * name,const TType fieldType,const int16_t fieldId)71 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldBegin(const char* name,
72 const TType fieldType,
73 const int16_t fieldId) {
74 (void)name;
75 uint32_t wsize = 0;
76 wsize += writeByte((int8_t)fieldType);
77 wsize += writeI16(fieldId);
78 return wsize;
79 }
80
81 template <class Transport_, class ByteOrder_>
writeFieldEnd()82 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldEnd() {
83 return 0;
84 }
85
86 template <class Transport_, class ByteOrder_>
writeFieldStop()87 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeFieldStop() {
88 return writeByte((int8_t)T_STOP);
89 }
90
91 template <class Transport_, class ByteOrder_>
writeMapBegin(const TType keyType,const TType valType,const uint32_t size)92 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapBegin(const TType keyType,
93 const TType valType,
94 const uint32_t size) {
95 uint32_t wsize = 0;
96 wsize += writeByte((int8_t)keyType);
97 wsize += writeByte((int8_t)valType);
98 wsize += writeI32((int32_t)size);
99 return wsize;
100 }
101
102 template <class Transport_, class ByteOrder_>
writeMapEnd()103 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeMapEnd() {
104 return 0;
105 }
106
107 template <class Transport_, class ByteOrder_>
writeListBegin(const TType elemType,const uint32_t size)108 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListBegin(const TType elemType,
109 const uint32_t size) {
110 uint32_t wsize = 0;
111 wsize += writeByte((int8_t)elemType);
112 wsize += writeI32((int32_t)size);
113 return wsize;
114 }
115
116 template <class Transport_, class ByteOrder_>
writeListEnd()117 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeListEnd() {
118 return 0;
119 }
120
121 template <class Transport_, class ByteOrder_>
writeSetBegin(const TType elemType,const uint32_t size)122 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetBegin(const TType elemType,
123 const uint32_t size) {
124 uint32_t wsize = 0;
125 wsize += writeByte((int8_t)elemType);
126 wsize += writeI32((int32_t)size);
127 return wsize;
128 }
129
130 template <class Transport_, class ByteOrder_>
writeSetEnd()131 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeSetEnd() {
132 return 0;
133 }
134
135 template <class Transport_, class ByteOrder_>
writeBool(const bool value)136 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBool(const bool value) {
137 uint8_t tmp = value ? 1 : 0;
138 this->trans_->write(&tmp, 1);
139 return 1;
140 }
141
142 template <class Transport_, class ByteOrder_>
writeByte(const int8_t byte)143 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeByte(const int8_t byte) {
144 this->trans_->write((uint8_t*)&byte, 1);
145 return 1;
146 }
147
148 template <class Transport_, class ByteOrder_>
writeI16(const int16_t i16)149 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI16(const int16_t i16) {
150 auto net = (int16_t)ByteOrder_::toWire16(i16);
151 this->trans_->write((uint8_t*)&net, 2);
152 return 2;
153 }
154
155 template <class Transport_, class ByteOrder_>
writeI32(const int32_t i32)156 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI32(const int32_t i32) {
157 auto net = (int32_t)ByteOrder_::toWire32(i32);
158 this->trans_->write((uint8_t*)&net, 4);
159 return 4;
160 }
161
162 template <class Transport_, class ByteOrder_>
writeI64(const int64_t i64)163 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeI64(const int64_t i64) {
164 auto net = (int64_t)ByteOrder_::toWire64(i64);
165 this->trans_->write((uint8_t*)&net, 8);
166 return 8;
167 }
168
169 template <class Transport_, class ByteOrder_>
writeDouble(const double dub)170 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeDouble(const double dub) {
171 static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
172 static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
173
174 auto bits = bitwise_cast<uint64_t>(dub);
175 bits = ByteOrder_::toWire64(bits);
176 this->trans_->write((uint8_t*)&bits, 8);
177 return 8;
178 }
179
180 template <class Transport_, class ByteOrder_>
181 template <typename StrType>
writeString(const StrType & str)182 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeString(const StrType& str) {
183 if (str.size() > static_cast<size_t>((std::numeric_limits<int32_t>::max)()))
184 throw TProtocolException(TProtocolException::SIZE_LIMIT);
185 auto size = static_cast<uint32_t>(str.size());
186 uint32_t result = writeI32((int32_t)size);
187 if (size > 0) {
188 this->trans_->write((uint8_t*)str.data(), size);
189 }
190 return result + size;
191 }
192
193 template <class Transport_, class ByteOrder_>
writeBinary(const std::string & str)194 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::writeBinary(const std::string& str) {
195 return TBinaryProtocolT<Transport_, ByteOrder_>::writeString(str);
196 }
197
198 /**
199 * Reading functions
200 */
201
202 template <class Transport_, class ByteOrder_>
readMessageBegin(std::string & name,TMessageType & messageType,int32_t & seqid)203 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageBegin(std::string& name,
204 TMessageType& messageType,
205 int32_t& seqid) {
206 uint32_t result = 0;
207 int32_t sz;
208 result += readI32(sz);
209
210 if (sz < 0) {
211 // Check for correct version number
212 int32_t version = sz & VERSION_MASK;
213 if (version != VERSION_1) {
214 throw TProtocolException(TProtocolException::BAD_VERSION, "Bad version identifier");
215 }
216 messageType = (TMessageType)(sz & 0x000000ff);
217 result += readString(name);
218 result += readI32(seqid);
219 } else {
220 if (this->strict_read_) {
221 throw TProtocolException(TProtocolException::BAD_VERSION,
222 "No version identifier... old protocol client in strict mode?");
223 } else {
224 // Handle pre-versioned input
225 int8_t type;
226 result += readStringBody(name, sz);
227 result += readByte(type);
228 messageType = (TMessageType)type;
229 result += readI32(seqid);
230 }
231 }
232 return result;
233 }
234
235 template <class Transport_, class ByteOrder_>
readMessageEnd()236 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMessageEnd() {
237 return 0;
238 }
239
240 template <class Transport_, class ByteOrder_>
readStructBegin(std::string & name)241 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructBegin(std::string& name) {
242 name = "";
243 return 0;
244 }
245
246 template <class Transport_, class ByteOrder_>
readStructEnd()247 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStructEnd() {
248 return 0;
249 }
250
251 template <class Transport_, class ByteOrder_>
readFieldBegin(std::string & name,TType & fieldType,int16_t & fieldId)252 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldBegin(std::string& name,
253 TType& fieldType,
254 int16_t& fieldId) {
255 (void)name;
256 uint32_t result = 0;
257 int8_t type;
258 result += readByte(type);
259 fieldType = (TType)type;
260 if (fieldType == T_STOP) {
261 fieldId = 0;
262 return result;
263 }
264 result += readI16(fieldId);
265 return result;
266 }
267
268 template <class Transport_, class ByteOrder_>
readFieldEnd()269 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readFieldEnd() {
270 return 0;
271 }
272
273 template <class Transport_, class ByteOrder_>
readMapBegin(TType & keyType,TType & valType,uint32_t & size)274 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapBegin(TType& keyType,
275 TType& valType,
276 uint32_t& size) {
277 int8_t k, v;
278 uint32_t result = 0;
279 int32_t sizei;
280 result += readByte(k);
281 keyType = (TType)k;
282 result += readByte(v);
283 valType = (TType)v;
284 result += readI32(sizei);
285 if (sizei < 0) {
286 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
287 } else if (this->container_limit_ && sizei > this->container_limit_) {
288 throw TProtocolException(TProtocolException::SIZE_LIMIT);
289 }
290 size = (uint32_t)sizei;
291
292 TMap map(keyType, valType, size);
293 checkReadBytesAvailable(map);
294
295 return result;
296 }
297
298 template <class Transport_, class ByteOrder_>
readMapEnd()299 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readMapEnd() {
300 return 0;
301 }
302
303 template <class Transport_, class ByteOrder_>
readListBegin(TType & elemType,uint32_t & size)304 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListBegin(TType& elemType, uint32_t& size) {
305 int8_t e;
306 uint32_t result = 0;
307 int32_t sizei;
308 result += readByte(e);
309 elemType = (TType)e;
310 result += readI32(sizei);
311 if (sizei < 0) {
312 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
313 } else if (this->container_limit_ && sizei > this->container_limit_) {
314 throw TProtocolException(TProtocolException::SIZE_LIMIT);
315 }
316 size = (uint32_t)sizei;
317
318 TList list(elemType, size);
319 checkReadBytesAvailable(list);
320
321 return result;
322 }
323
324 template <class Transport_, class ByteOrder_>
readListEnd()325 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readListEnd() {
326 return 0;
327 }
328
329 template <class Transport_, class ByteOrder_>
readSetBegin(TType & elemType,uint32_t & size)330 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetBegin(TType& elemType, uint32_t& size) {
331 int8_t e;
332 uint32_t result = 0;
333 int32_t sizei;
334 result += readByte(e);
335 elemType = (TType)e;
336 result += readI32(sizei);
337 if (sizei < 0) {
338 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
339 } else if (this->container_limit_ && sizei > this->container_limit_) {
340 throw TProtocolException(TProtocolException::SIZE_LIMIT);
341 }
342 size = (uint32_t)sizei;
343
344 TSet set(elemType, size);
345 checkReadBytesAvailable(set);
346
347 return result;
348 }
349
350 template <class Transport_, class ByteOrder_>
readSetEnd()351 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readSetEnd() {
352 return 0;
353 }
354
355 template <class Transport_, class ByteOrder_>
readBool(bool & value)356 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBool(bool& value) {
357 uint8_t b[1];
358 this->trans_->readAll(b, 1);
359 value = *(int8_t*)b != 0;
360 return 1;
361 }
362
363 template <class Transport_, class ByteOrder_>
readByte(int8_t & byte)364 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readByte(int8_t& byte) {
365 uint8_t b[1];
366 this->trans_->readAll(b, 1);
367 byte = *(int8_t*)b;
368 return 1;
369 }
370
371 template <class Transport_, class ByteOrder_>
readI16(int16_t & i16)372 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI16(int16_t& i16) {
373 union bytes {
374 uint8_t b[2];
375 int16_t all;
376 } theBytes;
377 this->trans_->readAll(theBytes.b, 2);
378 i16 = (int16_t)ByteOrder_::fromWire16(theBytes.all);
379 return 2;
380 }
381
382 template <class Transport_, class ByteOrder_>
readI32(int32_t & i32)383 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI32(int32_t& i32) {
384 union bytes {
385 uint8_t b[4];
386 int32_t all;
387 } theBytes;
388 this->trans_->readAll(theBytes.b, 4);
389 i32 = (int32_t)ByteOrder_::fromWire32(theBytes.all);
390 return 4;
391 }
392
393 template <class Transport_, class ByteOrder_>
readI64(int64_t & i64)394 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readI64(int64_t& i64) {
395 union bytes {
396 uint8_t b[8];
397 int64_t all;
398 } theBytes;
399 this->trans_->readAll(theBytes.b, 8);
400 i64 = (int64_t)ByteOrder_::fromWire64(theBytes.all);
401 return 8;
402 }
403
404 template <class Transport_, class ByteOrder_>
readDouble(double & dub)405 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readDouble(double& dub) {
406 static_assert(sizeof(double) == sizeof(uint64_t), "sizeof(double) == sizeof(uint64_t)");
407 static_assert(std::numeric_limits<double>::is_iec559, "std::numeric_limits<double>::is_iec559");
408
409 union bytes {
410 uint8_t b[8];
411 uint64_t all;
412 } theBytes;
413 this->trans_->readAll(theBytes.b, 8);
414 theBytes.all = ByteOrder_::fromWire64(theBytes.all);
415 dub = bitwise_cast<double>(theBytes.all);
416 return 8;
417 }
418
419 template <class Transport_, class ByteOrder_>
420 template <typename StrType>
readString(StrType & str)421 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readString(StrType& str) {
422 uint32_t result;
423 int32_t size;
424 result = readI32(size);
425 return result + readStringBody(str, size);
426 }
427
428 template <class Transport_, class ByteOrder_>
readBinary(std::string & str)429 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readBinary(std::string& str) {
430 return TBinaryProtocolT<Transport_, ByteOrder_>::readString(str);
431 }
432
433 template <class Transport_, class ByteOrder_>
434 template <typename StrType>
readStringBody(StrType & str,int32_t size)435 uint32_t TBinaryProtocolT<Transport_, ByteOrder_>::readStringBody(StrType& str, int32_t size) {
436 uint32_t result = 0;
437
438 // Catch error cases
439 if (size < 0) {
440 throw TProtocolException(TProtocolException::NEGATIVE_SIZE);
441 }
442 if (this->string_limit_ > 0 && size > this->string_limit_) {
443 throw TProtocolException(TProtocolException::SIZE_LIMIT);
444 }
445
446 // Catch empty string case
447 if (size == 0) {
448 str.clear();
449 return result;
450 }
451
452 // Try to borrow first
453 const uint8_t* borrow_buf;
454 uint32_t got = size;
455 if ((borrow_buf = this->trans_->borrow(nullptr, &got))) {
456 str.assign((const char*)borrow_buf, size);
457 this->trans_->consume(size);
458 return size;
459 }
460
461 str.resize(size);
462 this->trans_->readAll(reinterpret_cast<uint8_t*>(&str[0]), size);
463 return (uint32_t)size;
464 }
465
466 // Return the minimum number of bytes a type will consume on the wire
467 template <class Transport_, class ByteOrder_>
getMinSerializedSize(TType type)468 int TBinaryProtocolT<Transport_, ByteOrder_>::getMinSerializedSize(TType type)
469 {
470 switch (type)
471 {
472 case T_STOP: return 0;
473 case T_VOID: return 0;
474 case T_BOOL: return sizeof(int8_t);
475 case T_BYTE: return sizeof(int8_t);
476 case T_DOUBLE: return sizeof(double);
477 case T_I16: return sizeof(short);
478 case T_I32: return sizeof(int);
479 case T_I64: return sizeof(long);
480 case T_STRING: return sizeof(int); // string length
481 case T_STRUCT: return 0; // empty struct
482 case T_MAP: return sizeof(int); // element count
483 case T_SET: return sizeof(int); // element count
484 case T_LIST: return sizeof(int); // element count
485 default: throw TProtocolException(TProtocolException::UNKNOWN, "unrecognized type code");
486 }
487 }
488
489 }
490 }
491 } // apache::thrift::protocol
492
493 #endif // #ifndef _THRIFT_PROTOCOL_TBINARYPROTOCOL_TCC_
494