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