RCFProto

- Main Page
- Classes
- Files

- File List

All Classes Functions Typedefs
SerializationProtocol.hpp
1
2 //******************************************************************************
3 // RCF - Remote Call Framework
4 //
5 // Copyright (c) 2005 - 2013, Delta V Software. All rights reserved.
6 // http://www.deltavsoft.com
7 //
8 // RCF is distributed under dual licenses - closed source or GPL.
9 // Consult your particular license for conditions of use.
10 //
11 // If you have not purchased a commercial license, you are using RCF
12 // under GPL terms.
13 //
14 // Version: 2.0
15 // Contact: support <at> deltavsoft.com
16 //
17 //******************************************************************************
18
19 #ifndef INCLUDE_RCF_SERIALIZATIONPROTOCOL_HPP
20 #define INCLUDE_RCF_SERIALIZATIONPROTOCOL_HPP
21
22 #include <map>
23 #include <string>
24
25 #include <boost/mpl/bool_fwd.hpp>
26
27 #include <RCF/ByteBuffer.hpp>
28 #include <RCF/ByteOrdering.hpp>
29 #include <RCF/MemStream.hpp>
30
31 #if RCF_FEATURE_PROTOBUF==1
32 #include <boost/type_traits/is_base_and_derived.hpp>
33 #include <RCF/GoogleProtobufs.hpp>
34 #endif
35
36 // Serialization protocols
37
38 #include <RCF/Config.hpp>
39 #include <RCF/SerializationProtocol_Base.hpp>
40
41 #if defined(RCF_USE_SF_SERIALIZATION)
42 #include <RCF/SerializationProtocol_SF.hpp>
43 #endif
44
45 #if defined(RCF_USE_BOOST_SERIALIZATION) || defined(RCF_USE_BOOST_XML_SERIALIZATION)
46 #include <RCF/SerializationProtocol_BS.hpp>
47 #endif
48
49 namespace RCF {
50
51 RCF_EXPORT bool isSerializationProtocolSupported(int protocol);
52
53 RCF_EXPORT std::string getSerializationProtocolName(int protocol);
54
55 class Token;
56 class MethodInvocationRequest;
57 class MethodInvocationResponse;
58
59 class RCF_EXPORT SerializationProtocolIn
60 {
61 public:
62 SerializationProtocolIn();
63 ~SerializationProtocolIn();
64
65 std::istream& getIstream() { return mIs; }
66
67 void setSerializationProtocol(int protocol);
68 int getSerializationProtocol() const;
69
70 void reset(
71 const ByteBuffer &data,
72 int protocol,
73 int runtimeVersion,
74 int archiveVersion,
75 bool enableSfPointerTracking);
76
77 void clearByteBuffer();
78 void clear();
79 void extractSlice(ByteBuffer &byteBuffer, std::size_t len);
80 std::size_t getArchiveLength();
81 std::size_t getRemainingArchiveLength();
82
83 template<typename T>
84 void read(const T *pt)
85 {
86 read(*pt);
87 }
88
89 template<typename T>
90 void read(T &t)
91 {
92 try
93 {
94 switch (mProtocol)
95 {
96 case 1: mInProtocol1 >> t; break;
97 case 2: mInProtocol2 >> t; break;
98 case 3: mInProtocol3 >> t; break;
99 case 4: mInProtocol4 >> t; break;
100
101 #ifdef RCF_USE_BOOST_XML_SERIALIZATION
102 case 5: mInProtocol5 >> boost::serialization::make_nvp("Dummy", t); break;
103 #else
104 case 5: mInProtocol5 >> t; break;
105 #endif
106
107 default: RCF_ASSERT(0)(mProtocol);
108 }
109 }
110 catch(const RCF::Exception &e)
111 {
112 RCF_UNUSED_VARIABLE(e);
113 throw;
114 }
115 catch(const std::exception &e)
116 {
117 RCF::SerializationException se( _RcfError_Deserialization(
118 typeid(t).name(),
119 typeid(e).name(),
120 e.what()));
121
122 RCF_THROW(se);
123 }
124 }
125
126 int getRuntimeVersion();
127
128 private:
129
130 void bindProtocol();
131 void unbindProtocol();
132
133 friend class ClientStub; // TODO
134 friend class RcfSession; // TODO
135
136 int mProtocol;
137 ByteBuffer mByteBuffer;
138 MemIstream mIs;
139
140 Protocol< boost::mpl::int_<1> >::In mInProtocol1;
141 Protocol< boost::mpl::int_<2> >::In mInProtocol2;
142 Protocol< boost::mpl::int_<3> >::In mInProtocol3;
143 Protocol< boost::mpl::int_<4> >::In mInProtocol4;
144 Protocol< boost::mpl::int_<5> >::In mInProtocol5;
145
146 int mRuntimeVersion;
147 int mArchiveVersion;
148 };
149
150 class RCF_EXPORT SerializationProtocolOut
151 {
152 public:
153 SerializationProtocolOut();
154
155 MemOstream& getMemOstream() { return *mOsPtr; }
156
157 void setSerializationProtocol(int protocol);
158 int getSerializationProtocol() const;
159 void clear();
160 void reset(
161 int protocol,
162 std::size_t margin,
163 ByteBuffer byteBuffer,
164 int runtimeVersion,
165 int archiveVersion,
166 bool enableSfPointerTracking);
167
168 template<typename T>
169 void write(const T &t)
170 {
171 try
172 {
173 switch (mProtocol)
174 {
175 case 1: mOutProtocol1 << t; break;
176 case 2: mOutProtocol2 << t; break;
177 case 3: mOutProtocol3 << t; break;
178 case 4: mOutProtocol4 << t; break;
179
180 #ifdef RCF_USE_BOOST_XML_SERIALIZATION
181 case 5: mOutProtocol5 << boost::serialization::make_nvp("Dummy", t); break;
182 #else
183 case 5: mOutProtocol5 << t; break;
184 #endif
185
186 default: RCF_ASSERT(0)(mProtocol);
187 }
188 }
189 catch(const std::exception &e)
190 {
191 RCF::SerializationException se( _RcfError_Serialization(
192 typeid(t).name(),
193 typeid(e).name(),
194 e.what()));
195
196 RCF_THROW(se);
197 }
198 }
199
200 void insert(const ByteBuffer &byteBuffer);
201 void extractByteBuffers();
202 void extractByteBuffers(std::vector<ByteBuffer> &byteBuffers);
203
204 int getRuntimeVersion();
205
206 private:
207
208 void bindProtocol();
209 void unbindProtocol();
210
211
212 friend class ClientStub; // TODO
213 friend class RcfSession; // TODO
214
215 int mProtocol;
216 std::size_t mMargin;
217 boost::shared_ptr<MemOstream> mOsPtr;
218 std::vector<std::pair<std::size_t, ByteBuffer> > mByteBuffers;
219
220 // these need to be below mOsPtr, for good order of destruction
221 Protocol< boost::mpl::int_<1> >::Out mOutProtocol1;
222 Protocol< boost::mpl::int_<2> >::Out mOutProtocol2;
223 Protocol< boost::mpl::int_<3> >::Out mOutProtocol3;
224 Protocol< boost::mpl::int_<4> >::Out mOutProtocol4;
225 Protocol< boost::mpl::int_<5> >::Out mOutProtocol5;
226
227 int mRuntimeVersion;
228 int mArchiveVersion;
229 };
230
231 inline void serialize(
232 SerializationProtocolOut &,
233 const Void *)
234 {
235 }
236
237 inline void serialize(
238 SerializationProtocolOut &,
239 const Void &)
240 {
241 }
242
243 inline void deserialize(
244 SerializationProtocolIn &,
245 Void *)
246 {
247 }
248
249 inline void deserialize(
250 SerializationProtocolIn &,
251 Void &)
252 {
253 }
254
255 template<typename T>
256 void serializeImpl(
257 SerializationProtocolOut &out,
258 const T &t,
259 long int)
260 {
261 out.write(t);
262 }
263
264 template<typename T>
265 void deserializeImpl(
266 SerializationProtocolIn &in,
267 T &t,
268 long int)
269 {
270 in.read(t);
271 }
272
273 #if RCF_FEATURE_PROTOBUF==1
274
275 // Some compile-time gymnastics to detect Protobuf classes, so we don't
276 // pass them off to SF or Boost.Serialization.
277
278 template<typename T>
279 void serializeProtobufOrNot(
280 SerializationProtocolOut &out,
281 const T &t,
282 boost::mpl::false_ *)
283 {
284 serializeImpl(out, t, 0);
285 }
286
287 template<typename T>
288 void deserializeProtobufOrNot(
289 SerializationProtocolIn &in,
290 T &t,
291 boost::mpl::false_ *)
292 {
293 deserializeImpl(in, t, 0);
294 }
295
296 template<typename T>
297 void serializeProtobufOrNot(
298 SerializationProtocolOut &out,
299 const T & t,
300 boost::mpl::true_ *)
301 {
302 MemOstream & os = out.getMemOstream();
303 os.write("XXXX", 4);
304 std::streamoff beginPos = os.tellp();
305
306 if (!t.IsInitialized())
307 {
308 RCF_THROW(Exception(_RcfError_ProtobufWriteInit(typeid(t).name())));
309 }
310
311 // Make room for the protobuf object.
312 // TODO: Less obtuse way of reserving space.
313 int byteSize = t.ByteSize();
314 RCF_ASSERT_GTEQ(byteSize , 0);
315 for (int i=0; i<byteSize; ++i)
316 {
317 os.write("%", 1);
318 }
319 std::streamoff endPos = os.tellp();
320
321 // Write the protobuf object straight into the underlying buffer.
322 char * pch = os.str();
323 bool ok = t.SerializeToArray(pch + beginPos, static_cast<int>(endPos - beginPos));
324 RCF_VERIFY(ok, Exception(_RcfError_ProtobufWrite(typeid(t).name())))(typeid(t));
325
326 // Write the prepended length field.
327 boost::uint32_t len = static_cast<boost::uint32_t>(endPos - beginPos);
328 char buffer[4] = {0};
329 memcpy(buffer, &len, 4);
330 RCF::machineToNetworkOrder(buffer, 4, 1);
331
332 os.rdbuf()->pubseekoff(beginPos-4, std::ios::beg, std::ios::out);
333 os.write(buffer, 4);
334 os.rdbuf()->pubseekoff(endPos, std::ios::beg, std::ios::out);
335 }
336
337 template<typename T>
338 void serializeProtobufOrNot(
339 SerializationProtocolOut &out,
340 const T * pt,
341 boost::mpl::true_ *)
342 {
343 serializeProtobufOrNot(out, *pt, (boost::mpl::true_ *) NULL);
344 }
345
346 template<typename T>
347 void serializeProtobufOrNot(
348 SerializationProtocolOut &out,
349 T * pt,
350 boost::mpl::true_ *)
351 {
352 serializeProtobufOrNot(out, *pt, (boost::mpl::true_ *) NULL);
353 }
354
355 template<typename T>
356 void deserializeProtobufOrNot(
357 SerializationProtocolIn &in,
358 T &t,
359 boost::mpl::true_ *)
360 {
361 std::istream & is = in.getIstream();
362
363 char buffer[4];
364 is.read(buffer, 4);
365 boost::uint32_t len = 0;
366 memcpy( &len, buffer, 4);
367 RCF::networkToMachineOrder(&len, 4, 1);
368
369 ByteBuffer byteBuffer;
370 in.extractSlice(byteBuffer, len);
371 bool ok = t.ParseFromArray(byteBuffer.getPtr(), byteBuffer.getLength());
372 RCF_VERIFY(ok, Exception(_RcfError_ProtobufRead(typeid(t).name())))(typeid(t));
373 }
374
375 template<typename T>
376 void deserializeProtobufOrNot(
377 SerializationProtocolIn &in,
378 T * & pt,
379 boost::mpl::true_ *)
380 {
381 if (pt == NULL)
382 {
383 pt = new T();
384 }
385
386 deserializeProtobufOrNot(in, *pt, (boost::mpl::true_ *) NULL);
387 }
388
389 template<typename T>
390 void serialize(
391 SerializationProtocolOut &out,
392 const T * pt)
393 {
394 typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
395 serializeProtobufOrNot(out, pt, (type *) NULL);
396 }
397
398 template<typename T>
399 void serialize(
400 SerializationProtocolOut &out,
401 T * pt)
402 {
403 typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
404 serializeProtobufOrNot(out, pt, (type *) NULL);
405 }
406
407 template<typename T>
408 void serialize(
409 SerializationProtocolOut &out,
410 const T & t)
411 {
412 typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
413 serializeProtobufOrNot(out, t, (type *) NULL);
414 }
415
416 template<typename T>
417 void deserialize(
418 SerializationProtocolIn &in,
419 T * & pt)
420 {
421 typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
422 deserializeProtobufOrNot(in, pt, (type *) NULL);
423 }
424
425 template<typename T>
426 void deserialize(
427 SerializationProtocolIn &in,
428 T & t)
429 {
430 typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
431 deserializeProtobufOrNot(in, t, (type *) NULL);
432 }
433
434 #else
435
436 // Whatever is passed to serialize() and deserialize(), is passed directly
437 // on to the selected serialization framework. We have to be careful with
438 // this, because Boost.Serialization is very picky about whether one
439 // serializes a pointer or a value.
440
441 template<typename T>
442 void serialize(
443 SerializationProtocolOut &out,
444 const T & t)
445 {
446 serializeImpl(out, t, 0);
447 }
448
449 template<typename T>
450 void deserialize(
451 SerializationProtocolIn &in,
452 T & t)
453 {
454 deserializeImpl(in, t, 0);
455 }
456
457 #endif
458
459 } // namespace RCF
460
461 #endif // ! INCLUDE_RCF_SERIALIZATIONPROTOCOL_HPP