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