blob: 40258277d01b0bbbc1d74cc3400c56711e507d4a [file] [log] [blame]
Gavin McDonald0b75e1a2010-10-28 02:12:01 +00001/*
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_TPROTOCOL_H_
21#define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1
22
23#include <transport/TTransport.h>
24#include <protocol/TProtocolException.h>
25
26#include <boost/shared_ptr.hpp>
27#include <boost/static_assert.hpp>
28
29#include <netinet/in.h>
30#include <sys/types.h>
31#include <string>
32#include <map>
33
34
35// Use this to get around strict aliasing rules.
36// For example, uint64_t i = bitwise_cast<uint64_t>(returns_double());
37// The most obvious implementation is to just cast a pointer,
38// but that doesn't work.
39// For a pretty in-depth explanation of the problem, see
40// http://www.cellperformance.com/mike_acton/2006/06/ (...)
41// understanding_strict_aliasing.html
42template <typename To, typename From>
43static inline To bitwise_cast(From from) {
44 BOOST_STATIC_ASSERT(sizeof(From) == sizeof(To));
45
46 // BAD!!! These are all broken with -O2.
47 //return *reinterpret_cast<To*>(&from); // BAD!!!
48 //return *static_cast<To*>(static_cast<void*>(&from)); // BAD!!!
49 //return *(To*)(void*)&from; // BAD!!!
50
51 // Super clean and paritally blessed by section 3.9 of the standard.
52 //unsigned char c[sizeof(from)];
53 //memcpy(c, &from, sizeof(from));
54 //To to;
55 //memcpy(&to, c, sizeof(c));
56 //return to;
57
58 // Slightly more questionable.
59 // Same code emitted by GCC.
60 //To to;
61 //memcpy(&to, &from, sizeof(from));
62 //return to;
63
64 // Technically undefined, but almost universally supported,
65 // and the most efficient implementation.
66 union {
67 From f;
68 To t;
69 } u;
70 u.f = from;
71 return u.t;
72}
73
74
75namespace apache { namespace thrift { namespace protocol {
76
77using apache::thrift::transport::TTransport;
78
79#ifdef HAVE_ENDIAN_H
80#include <endian.h>
81#endif
82
83#ifndef __BYTE_ORDER
84# if defined(BYTE_ORDER) && defined(LITTLE_ENDIAN) && defined(BIG_ENDIAN)
85# define __BYTE_ORDER BYTE_ORDER
86# define __LITTLE_ENDIAN LITTLE_ENDIAN
87# define __BIG_ENDIAN BIG_ENDIAN
88# else
89# error "Cannot determine endianness"
90# endif
91#endif
92
93#if __BYTE_ORDER == __BIG_ENDIAN
94# define ntohll(n) (n)
95# define htonll(n) (n)
96# if defined(__GNUC__) && defined(__GLIBC__)
97# include <byteswap.h>
98# define htolell(n) bswap_64(n)
99# define letohll(n) bswap_64(n)
100# else /* GNUC & GLIBC */
101# define bswap_64(n) \
102 ( (((n) & 0xff00000000000000ull) >> 56) \
103 | (((n) & 0x00ff000000000000ull) >> 40) \
104 | (((n) & 0x0000ff0000000000ull) >> 24) \
105 | (((n) & 0x000000ff00000000ull) >> 8) \
106 | (((n) & 0x00000000ff000000ull) << 8) \
107 | (((n) & 0x0000000000ff0000ull) << 24) \
108 | (((n) & 0x000000000000ff00ull) << 40) \
109 | (((n) & 0x00000000000000ffull) << 56) )
110# define ntolell(n) bswap_64(n)
111# define letonll(n) bswap_64(n)
112# endif /* GNUC & GLIBC */
113#elif __BYTE_ORDER == __LITTLE_ENDIAN
114# define htolell(n) (n)
115# define letohll(n) (n)
116# if defined(__GNUC__) && defined(__GLIBC__)
117# include <byteswap.h>
118# define ntohll(n) bswap_64(n)
119# define htonll(n) bswap_64(n)
120# else /* GNUC & GLIBC */
121# define ntohll(n) ( (((unsigned long long)ntohl(n)) << 32) + ntohl(n >> 32) )
122# define htonll(n) ( (((unsigned long long)htonl(n)) << 32) + htonl(n >> 32) )
123# endif /* GNUC & GLIBC */
124#else /* __BYTE_ORDER */
125# error "Can't define htonll or ntohll!"
126#endif
127
128/**
129 * Enumerated definition of the types that the Thrift protocol supports.
130 * Take special note of the T_END type which is used specifically to mark
131 * the end of a sequence of fields.
132 */
133enum TType {
134 T_STOP = 0,
135 T_VOID = 1,
136 T_BOOL = 2,
137 T_BYTE = 3,
138 T_I08 = 3,
139 T_I16 = 6,
140 T_I32 = 8,
141 T_U64 = 9,
142 T_I64 = 10,
143 T_DOUBLE = 4,
144 T_STRING = 11,
145 T_UTF7 = 11,
146 T_STRUCT = 12,
147 T_MAP = 13,
148 T_SET = 14,
149 T_LIST = 15,
150 T_UTF8 = 16,
151 T_UTF16 = 17
152};
153
154/**
155 * Enumerated definition of the message types that the Thrift protocol
156 * supports.
157 */
158enum TMessageType {
159 T_CALL = 1,
160 T_REPLY = 2,
161 T_EXCEPTION = 3,
162 T_ONEWAY = 4
163};
164
165/**
166 * Abstract class for a thrift protocol driver. These are all the methods that
167 * a protocol must implement. Essentially, there must be some way of reading
168 * and writing all the base types, plus a mechanism for writing out structs
169 * with indexed fields.
170 *
171 * TProtocol objects should not be shared across multiple encoding contexts,
172 * as they may need to maintain internal state in some protocols (i.e. XML).
173 * Note that is is acceptable for the TProtocol module to do its own internal
174 * buffered reads/writes to the underlying TTransport where appropriate (i.e.
175 * when parsing an input XML stream, reading should be batched rather than
176 * looking ahead character by character for a close tag).
177 *
178 */
179class TProtocol {
180 public:
181 virtual ~TProtocol() {}
182
183 /**
184 * Writing functions.
185 */
186
187 virtual uint32_t writeMessageBegin(const std::string& name,
188 const TMessageType messageType,
189 const int32_t seqid) = 0;
190
191 virtual uint32_t writeMessageEnd() = 0;
192
193
194 virtual uint32_t writeStructBegin(const char* name) = 0;
195
196 virtual uint32_t writeStructEnd() = 0;
197
198 virtual uint32_t writeFieldBegin(const char* name,
199 const TType fieldType,
200 const int16_t fieldId) = 0;
201
202 virtual uint32_t writeFieldEnd() = 0;
203
204 virtual uint32_t writeFieldStop() = 0;
205
206 virtual uint32_t writeMapBegin(const TType keyType,
207 const TType valType,
208 const uint32_t size) = 0;
209
210 virtual uint32_t writeMapEnd() = 0;
211
212 virtual uint32_t writeListBegin(const TType elemType,
213 const uint32_t size) = 0;
214
215 virtual uint32_t writeListEnd() = 0;
216
217 virtual uint32_t writeSetBegin(const TType elemType,
218 const uint32_t size) = 0;
219
220 virtual uint32_t writeSetEnd() = 0;
221
222 virtual uint32_t writeBool(const bool value) = 0;
223
224 virtual uint32_t writeByte(const int8_t byte) = 0;
225
226 virtual uint32_t writeI16(const int16_t i16) = 0;
227
228 virtual uint32_t writeI32(const int32_t i32) = 0;
229
230 virtual uint32_t writeI64(const int64_t i64) = 0;
231
232 virtual uint32_t writeDouble(const double dub) = 0;
233
234 virtual uint32_t writeString(const std::string& str) = 0;
235
236 virtual uint32_t writeBinary(const std::string& str) = 0;
237
238 /**
239 * Reading functions
240 */
241
242 virtual uint32_t readMessageBegin(std::string& name,
243 TMessageType& messageType,
244 int32_t& seqid) = 0;
245
246 virtual uint32_t readMessageEnd() = 0;
247
248 virtual uint32_t readStructBegin(std::string& name) = 0;
249
250 virtual uint32_t readStructEnd() = 0;
251
252 virtual uint32_t readFieldBegin(std::string& name,
253 TType& fieldType,
254 int16_t& fieldId) = 0;
255
256 virtual uint32_t readFieldEnd() = 0;
257
258 virtual uint32_t readMapBegin(TType& keyType,
259 TType& valType,
260 uint32_t& size) = 0;
261
262 virtual uint32_t readMapEnd() = 0;
263
264 virtual uint32_t readListBegin(TType& elemType,
265 uint32_t& size) = 0;
266
267 virtual uint32_t readListEnd() = 0;
268
269 virtual uint32_t readSetBegin(TType& elemType,
270 uint32_t& size) = 0;
271
272 virtual uint32_t readSetEnd() = 0;
273
274 virtual uint32_t readBool(bool& value) = 0;
275
276 virtual uint32_t readByte(int8_t& byte) = 0;
277
278 virtual uint32_t readI16(int16_t& i16) = 0;
279
280 virtual uint32_t readI32(int32_t& i32) = 0;
281
282 virtual uint32_t readI64(int64_t& i64) = 0;
283
284 virtual uint32_t readDouble(double& dub) = 0;
285
286 virtual uint32_t readString(std::string& str) = 0;
287
288 virtual uint32_t readBinary(std::string& str) = 0;
289
290 uint32_t readBool(std::vector<bool>::reference ref) {
291 bool value;
292 uint32_t rv = readBool(value);
293 ref = value;
294 return rv;
295 }
296
297 /**
298 * Method to arbitrarily skip over data.
299 */
300 uint32_t skip(TType type) {
301 switch (type) {
302 case T_BOOL:
303 {
304 bool boolv;
305 return readBool(boolv);
306 }
307 case T_BYTE:
308 {
309 int8_t bytev;
310 return readByte(bytev);
311 }
312 case T_I16:
313 {
314 int16_t i16;
315 return readI16(i16);
316 }
317 case T_I32:
318 {
319 int32_t i32;
320 return readI32(i32);
321 }
322 case T_I64:
323 {
324 int64_t i64;
325 return readI64(i64);
326 }
327 case T_DOUBLE:
328 {
329 double dub;
330 return readDouble(dub);
331 }
332 case T_STRING:
333 {
334 std::string str;
335 return readBinary(str);
336 }
337 case T_STRUCT:
338 {
339 uint32_t result = 0;
340 std::string name;
341 int16_t fid;
342 TType ftype;
343 result += readStructBegin(name);
344 while (true) {
345 result += readFieldBegin(name, ftype, fid);
346 if (ftype == T_STOP) {
347 break;
348 }
349 result += skip(ftype);
350 result += readFieldEnd();
351 }
352 result += readStructEnd();
353 return result;
354 }
355 case T_MAP:
356 {
357 uint32_t result = 0;
358 TType keyType;
359 TType valType;
360 uint32_t i, size;
361 result += readMapBegin(keyType, valType, size);
362 for (i = 0; i < size; i++) {
363 result += skip(keyType);
364 result += skip(valType);
365 }
366 result += readMapEnd();
367 return result;
368 }
369 case T_SET:
370 {
371 uint32_t result = 0;
372 TType elemType;
373 uint32_t i, size;
374 result += readSetBegin(elemType, size);
375 for (i = 0; i < size; i++) {
376 result += skip(elemType);
377 }
378 result += readSetEnd();
379 return result;
380 }
381 case T_LIST:
382 {
383 uint32_t result = 0;
384 TType elemType;
385 uint32_t i, size;
386 result += readListBegin(elemType, size);
387 for (i = 0; i < size; i++) {
388 result += skip(elemType);
389 }
390 result += readListEnd();
391 return result;
392 }
393 default:
394 return 0;
395 }
396 }
397
398 inline boost::shared_ptr<TTransport> getTransport() {
399 return ptrans_;
400 }
401
402 // TODO: remove these two calls, they are for backwards
403 // compatibility
404 inline boost::shared_ptr<TTransport> getInputTransport() {
405 return ptrans_;
406 }
407 inline boost::shared_ptr<TTransport> getOutputTransport() {
408 return ptrans_;
409 }
410
411 protected:
412 TProtocol(boost::shared_ptr<TTransport> ptrans):
413 ptrans_(ptrans) {
414 trans_ = ptrans.get();
415 }
416
417 boost::shared_ptr<TTransport> ptrans_;
418 TTransport* trans_;
419
420 private:
421 TProtocol() {}
422};
423
424/**
425 * Constructs input and output protocol objects given transports.
426 */
427class TProtocolFactory {
428 public:
429 TProtocolFactory() {}
430
431 virtual ~TProtocolFactory() {}
432
433 virtual boost::shared_ptr<TProtocol> getProtocol(boost::shared_ptr<TTransport> trans) = 0;
434};
435
436}}} // apache::thrift::protocol
437
438#endif // #define _THRIFT_PROTOCOL_TPROTOCOL_H_ 1