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 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