RCFProto
 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 RCF_FEATURE_SF==1
42 #include <RCF/SerializationProtocol_SF.hpp>
43 #endif
44 
45 #if RCF_FEATURE_BOOST_SERIALIZATION==1
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  MemIstream& 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  case 5: mInProtocol5 >> t; break;
101 
102  default: RCF_ASSERT(0)(mProtocol);
103  }
104  }
105  catch(const RCF::Exception &e)
106  {
107  RCF_UNUSED_VARIABLE(e);
108  throw;
109  }
110  catch(const std::exception &e)
111  {
112  RCF::SerializationException se( _RcfError_Deserialization(
113  typeid(t).name(),
114  typeid(e).name(),
115  e.what()));
116 
117  RCF_THROW(se);
118  }
119  }
120 
121  int getRuntimeVersion();
122 
123  private:
124 
125  void bindProtocol();
126  void unbindProtocol();
127 
128  friend class ClientStub; // TODO
129  friend class RcfSession; // TODO
130 
131  int mProtocol;
132  ByteBuffer mByteBuffer;
133  MemIstream mIs;
134 
135  Protocol< boost::mpl::int_<1> >::In mInProtocol1;
136  Protocol< boost::mpl::int_<2> >::In mInProtocol2;
137  Protocol< boost::mpl::int_<3> >::In mInProtocol3;
138  Protocol< boost::mpl::int_<4> >::In mInProtocol4;
139  Protocol< boost::mpl::int_<5> >::In mInProtocol5;
140 
141  int mRuntimeVersion;
142  int mArchiveVersion;
143  };
144 
145  class RCF_EXPORT SerializationProtocolOut
146  {
147  public:
148  SerializationProtocolOut();
149 
150  MemOstream& getMemOstream() { return *mOsPtr; }
151 
152  void setSerializationProtocol(int protocol);
153  int getSerializationProtocol() const;
154  void clear();
155  void reset(
156  int protocol,
157  std::size_t margin,
158  ByteBuffer byteBuffer,
159  int runtimeVersion,
160  int archiveVersion,
161  bool enableSfPointerTracking);
162 
163  template<typename T>
164  void write(const T &t)
165  {
166  try
167  {
168  switch (mProtocol)
169  {
170  case 1: mOutProtocol1 << t; break;
171  case 2: mOutProtocol2 << t; break;
172  case 3: mOutProtocol3 << t; break;
173  case 4: mOutProtocol4 << t; break;
174  case 5: mOutProtocol5 << t; break;
175 
176  default: RCF_ASSERT(0)(mProtocol);
177  }
178  }
179  catch(const std::exception &e)
180  {
181  RCF::SerializationException se( _RcfError_Serialization(
182  typeid(t).name(),
183  typeid(e).name(),
184  e.what()));
185 
186  RCF_THROW(se);
187  }
188  }
189 
190  void insert(const ByteBuffer &byteBuffer);
191  void extractByteBuffers();
192  void extractByteBuffers(std::vector<ByteBuffer> &byteBuffers);
193 
194  int getRuntimeVersion();
195 
196  private:
197 
198  void bindProtocol();
199  void unbindProtocol();
200 
201 
202  friend class ClientStub; // TODO
203  friend class RcfSession; // TODO
204 
205  int mProtocol;
206  std::size_t mMargin;
207  boost::shared_ptr<MemOstream> mOsPtr;
208  std::vector<std::pair<std::size_t, ByteBuffer> > mByteBuffers;
209 
210  // these need to be below mOsPtr, for good order of destruction
211  Protocol< boost::mpl::int_<1> >::Out mOutProtocol1;
212  Protocol< boost::mpl::int_<2> >::Out mOutProtocol2;
213  Protocol< boost::mpl::int_<3> >::Out mOutProtocol3;
214  Protocol< boost::mpl::int_<4> >::Out mOutProtocol4;
215  Protocol< boost::mpl::int_<5> >::Out mOutProtocol5;
216 
217  int mRuntimeVersion;
218  int mArchiveVersion;
219  };
220 
221  inline void serialize(
222  SerializationProtocolOut &,
223  const Void *)
224  {
225  }
226 
227  inline void serialize(
228  SerializationProtocolOut &,
229  const Void &)
230  {
231  }
232 
233  inline void deserialize(
234  SerializationProtocolIn &,
235  Void *)
236  {
237  }
238 
239  inline void deserialize(
240  SerializationProtocolIn &,
241  Void &)
242  {
243  }
244 
245  template<typename T>
246  void serializeImpl(
247  SerializationProtocolOut &out,
248  const T &t,
249  long int)
250  {
251  out.write(t);
252  }
253 
254  template<typename T>
255  void deserializeImpl(
256  SerializationProtocolIn &in,
257  T &t,
258  long int)
259  {
260  in.read(t);
261  }
262 
263 #if RCF_FEATURE_PROTOBUF==1
264 
265  // Some compile-time gymnastics to detect Protobuf classes, so we don't
266  // pass them off to SF or Boost.Serialization.
267 
268  template<typename T>
269  void serializeProtobufOrNot(
270  SerializationProtocolOut &out,
271  const T &t,
272  RCF::FalseType *)
273  {
274  serializeImpl(out, t, 0);
275  }
276 
277  template<typename T>
278  void deserializeProtobufOrNot(
279  SerializationProtocolIn &in,
280  T &t,
281  RCF::FalseType *)
282  {
283  deserializeImpl(in, t, 0);
284  }
285 
286  template<typename T>
287  void serializeProtobufOrNot(
288  SerializationProtocolOut &out,
289  const T & t,
290  RCF::TrueType *)
291  {
292  MemOstream & os = out.getMemOstream();
293  os.write("XXXX", 4);
294  std::streamoff beginPos = os.tellp();
295 
296  if (!t.IsInitialized())
297  {
298  RCF_THROW(Exception(_RcfError_ProtobufWriteInit(typeid(t).name())));
299  }
300 
301  // Make room for the protobuf object.
302  // TODO: Less obtuse way of reserving space.
303  int byteSize = t.ByteSize();
304  RCF_ASSERT_GTEQ(byteSize , 0);
305  for (int i=0; i<byteSize; ++i)
306  {
307  os.write("%", 1);
308  }
309  std::streamoff endPos = os.tellp();
310 
311  // Write the protobuf object straight into the underlying buffer.
312  char * pch = os.str();
313  bool ok = t.SerializeToArray(pch + beginPos, static_cast<int>(endPos - beginPos));
314  RCF_VERIFY(ok, Exception(_RcfError_ProtobufWrite(typeid(t).name())))(typeid(t));
315 
316  // Write the prepended length field.
317  boost::uint32_t len = static_cast<boost::uint32_t>(endPos - beginPos);
318  char buffer[4] = {0};
319  memcpy(buffer, &len, 4);
320  RCF::machineToNetworkOrder(buffer, 4, 1);
321 
322  os.rdbuf()->pubseekoff(beginPos-4, std::ios::beg, std::ios::out);
323  os.write(buffer, 4);
324  os.rdbuf()->pubseekoff(endPos, std::ios::beg, std::ios::out);
325  }
326 
327  template<typename T>
328  void serializeProtobufOrNot(
329  SerializationProtocolOut &out,
330  const T * pt,
331  RCF::TrueType *)
332  {
333  serializeProtobufOrNot(out, *pt, (RCF::TrueType *) NULL);
334  }
335 
336  template<typename T>
337  void serializeProtobufOrNot(
338  SerializationProtocolOut &out,
339  T * pt,
340  RCF::TrueType *)
341  {
342  serializeProtobufOrNot(out, *pt, (RCF::TrueType *) NULL);
343  }
344 
345  template<typename T>
346  void deserializeProtobufOrNot(
347  SerializationProtocolIn &in,
348  T &t,
349  RCF::TrueType *)
350  {
351  MemIstream & is = in.getIstream();
352 
353  char buffer[4];
354  is.read(buffer, 4);
355  boost::uint32_t len = 0;
356  memcpy( &len, buffer, 4);
357  RCF::networkToMachineOrder(&len, 4, 1);
358 
359  ByteBuffer byteBuffer;
360  in.extractSlice(byteBuffer, len);
361  bool ok = t.ParseFromArray(byteBuffer.getPtr(), static_cast<int>(byteBuffer.getLength()));
362  RCF_VERIFY(ok, Exception(_RcfError_ProtobufRead(typeid(t).name())))(typeid(t));
363  }
364 
365  template<typename T>
366  void deserializeProtobufOrNot(
367  SerializationProtocolIn &in,
368  T * & pt,
369  RCF::TrueType *)
370  {
371  if (pt == NULL)
372  {
373  pt = new T();
374  }
375 
376  deserializeProtobufOrNot(in, *pt, (RCF::TrueType *) NULL);
377  }
378 
379  template<typename T>
380  void serialize(
381  SerializationProtocolOut &out,
382  const T * pt)
383  {
384  typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
385  serializeProtobufOrNot(out, pt, (type *) NULL);
386  }
387 
388  template<typename T>
389  void serialize(
390  SerializationProtocolOut &out,
391  T * pt)
392  {
393  typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
394  serializeProtobufOrNot(out, pt, (type *) NULL);
395  }
396 
397  template<typename T>
398  void serialize(
399  SerializationProtocolOut &out,
400  const T & t)
401  {
402  typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
403  serializeProtobufOrNot(out, t, (type *) NULL);
404  }
405 
406  template<typename T>
407  void deserialize(
408  SerializationProtocolIn &in,
409  T * & pt)
410  {
411  typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
412  deserializeProtobufOrNot(in, pt, (type *) NULL);
413  }
414 
415  template<typename T>
416  void deserialize(
417  SerializationProtocolIn &in,
418  T & t)
419  {
420  typedef typename boost::is_base_and_derived<google::protobuf::Message, T>::type type;
421  deserializeProtobufOrNot(in, t, (type *) NULL);
422  }
423 
424 #else
425 
426  // Whatever is passed to serialize() and deserialize(), is passed directly
427  // on to the selected serialization framework. We have to be careful with
428  // this, because Boost.Serialization is very picky about whether one
429  // serializes a pointer or a value.
430 
431  template<typename T>
432  void serialize(
433  SerializationProtocolOut &out,
434  const T & t)
435  {
436  serializeImpl(out, t, 0);
437  }
438 
439  template<typename T>
440  void deserialize(
441  SerializationProtocolIn &in,
442  T & t)
443  {
444  deserializeImpl(in, t, 0);
445  }
446 
447 #endif
448 
449 } // namespace RCF
450 
451 #endif // ! INCLUDE_RCF_SERIALIZATIONPROTOCOL_HPP