GComm  0.2.3
datagram.hpp
1 /*
2  * Copyright (C) 2010-2013 Codership Oy <info@codership.com>
3  */
4 
5 #ifndef GCOMM_DATAGRAM_HPP
6 #define GCOMM_DATAGRAM_HPP
7 
8 #include "gu_buffer.hpp"
9 #include "gu_serialize.hpp"
10 #include "gu_utils.hpp"
11 
12 #include <limits>
13 
14 #include <cstring>
15 #include <stdint.h>
16 
17 namespace gcomm
18 {
19 
21  // @class NetHeader
22  //
23  // @brief Header for datagrams sent over network
24  //
25  // Header structure is the following (MSB first)
26  //
27  // | version(4) | reserved(2) | F_CRC(2) | len(24) |
28  // | CRC(32) |
29  //
30  class NetHeader
31  {
32  public:
33 
34  typedef enum checksum
35  {
36  CS_NONE = 0,
37  CS_CRC32,
38  CS_CRC32C
39  } checksum_t;
40 
41  static checksum_t checksum_type (int i);
42 
43  NetHeader()
44  :
45  len_(),
46  crc32_()
47  { }
48 
49  NetHeader(uint32_t len, int version)
50  :
51  len_(len),
52  crc32_(0)
53  {
54  if (len > len_mask_)
55  gu_throw_error(EINVAL) << "msg too long " << len_;
56  len_ |= (static_cast<uint32_t>(version) << version_shift_);
57  }
58 
59  uint32_t len() const { return (len_ & len_mask_); }
60 
61  void set_crc32(uint32_t crc32, checksum_t type)
62  {
63  assert (CS_CRC32 == type || CS_CRC32C == type);
64  crc32_ = crc32;
65  CS_CRC32 == type ? len_ |= F_CRC32 : len_ |= F_CRC32C;
66  }
67 
68  bool has_crc32() const { return (len_ & F_CRC32); }
69  bool has_crc32c() const { return (len_ & F_CRC32C); }
70 
71  uint32_t crc32() const { return crc32_; }
72 
73  int version() const
74  {
75  return ((len_ & version_mask_) >> version_shift_);
76  }
77 
78  friend size_t serialize(const NetHeader& hdr, gu::byte_t* buf,
79  size_t buflen, size_t offset);
80 
81  friend size_t unserialize(const gu::byte_t* buf, size_t buflen,
82  size_t offset, NetHeader& hdr);
83 
84  friend size_t serial_size(const NetHeader& hdr);
85 
86  static const size_t serial_size_ = 8;
87 
88  private:
89 
90  static const uint32_t len_mask_ = 0x00ffffff;
91  static const uint32_t flags_mask_ = 0x0f000000;
92  static const uint32_t flags_shift_ = 24;
93  static const uint32_t version_mask_ = 0xf0000000;
94  static const uint32_t version_shift_ = 28;
95 
96  enum
97  {
98  F_CRC32 = 1 << 24, /* backward compatible */
99  F_CRC32C = 1 << 25
100  };
101 
102  uint32_t len_;
103  uint32_t crc32_;
104  };
105 
106  inline size_t serialize(const NetHeader& hdr, gu::byte_t* buf,
107  size_t buflen, size_t offset)
108  {
109  offset = gu::serialize4(hdr.len_, buf, buflen, offset);
110  offset = gu::serialize4(hdr.crc32_, buf, buflen, offset);
111  return offset;
112  }
113 
114  inline size_t unserialize(const gu::byte_t* buf, size_t buflen,
115  size_t offset, NetHeader& hdr)
116  {
117  offset = gu::unserialize4(buf, buflen, offset, hdr.len_);
118  offset = gu::unserialize4(buf, buflen, offset, hdr.crc32_);
119 
120  switch (hdr.version())
121  {
122  case 0:
123  if ((hdr.len_ & NetHeader::flags_mask_) &
124  ~(NetHeader::F_CRC32 | NetHeader::F_CRC32C))
125  {
126  gu_throw_error(EPROTO)
127  << "invalid flags "
128  << ((hdr.len_ & NetHeader::flags_mask_) >>
129  NetHeader::flags_shift_);
130  }
131  break;
132  default:
133  gu_throw_error(EPROTO) << "invalid protocol version "
134  << hdr.version();
135  }
136 
137  return offset;
138  }
139 
140  inline size_t serial_size(const NetHeader& hdr)
141  {
142  return NetHeader::serial_size_;
143  }
144 
151  class Datagram
152  {
153  public:
154  Datagram()
155  :
156  header_ (),
157  header_offset_(header_size_),
158  payload_ (new gu::Buffer()),
159  offset_ (0)
160  { }
170  Datagram(const gu::Buffer& buf, size_t offset = 0)
171  :
172  header_ (),
173  header_offset_(header_size_),
174  payload_ (new gu::Buffer(buf)),
175  offset_ (offset)
176  {
177  assert(offset_ <= payload_->size());
178  }
179 
180  Datagram(const gu::SharedBuffer& buf, size_t offset = 0)
181  :
182  header_ (),
183  header_offset_(header_size_),
184  payload_ (buf),
185  offset_ (offset)
186  {
187  assert(offset_ <= payload_->size());
188  }
189 
199  Datagram(const Datagram& dgram,
200  size_t off = std::numeric_limits<size_t>::max()) :
201  // header_(dgram.header_),
202  header_offset_(dgram.header_offset_),
203  payload_(dgram.payload_),
204  offset_(off == std::numeric_limits<size_t>::max() ? dgram.offset_ : off)
205  {
206  assert(offset_ <= dgram.len());
207  memcpy(header_ + header_offset_,
208  dgram.header_ + dgram.header_offset(),
209  dgram.header_len());
210  }
211 
215  ~Datagram() { }
216 
217  void normalize()
218  {
219  const gu::SharedBuffer old_payload(payload_);
220  payload_ = gu::SharedBuffer(new gu::Buffer);
221  payload_->reserve(header_len() + old_payload->size() - offset_);
222 
223  if (header_len() > offset_)
224  {
225  payload_->insert(payload_->end(),
226  header_ + header_offset_ + offset_,
227  header_ + header_size_);
228  offset_ = 0;
229  }
230  else
231  {
232  offset_ -= header_len();
233  }
234  header_offset_ = header_size_;
235  payload_->insert(payload_->end(), old_payload->begin() + offset_,
236  old_payload->end());
237  offset_ = 0;
238  }
239 
240  gu::byte_t* header() { return header_; }
241  const gu::byte_t* header() const { return header_; }
242  size_t header_size() const { return header_size_; }
243  size_t header_len() const { return (header_size_ - header_offset_); }
244  size_t header_offset() const { return header_offset_; }
245 
246  void set_header_offset(const size_t off)
247  {
248  // assert(off <= header_size_);
249  if (off > header_size_) gu_throw_fatal << "out of hdrspace";
250  header_offset_ = off;
251  }
252 
253  const gu::Buffer& payload() const
254  {
255  assert(payload_ != 0);
256  return *payload_;
257  }
258 
259  gu::Buffer& payload()
260  {
261  assert(payload_ != 0);
262  return *payload_;
263  }
264 
265  size_t len() const
266  {
267  return (header_size_ - header_offset_ + payload_->size());
268  }
269 
270  size_t offset() const { return offset_; }
271 
272  private:
273 
274  friend uint16_t crc16(const Datagram&, size_t);
275  friend uint32_t crc32(NetHeader::checksum_t, const Datagram&, size_t);
276 
277  static const size_t header_size_ = 128;
278  gu::byte_t header_[header_size_];
279  size_t header_offset_;
280  gu::SharedBuffer payload_;
281  size_t offset_;
282  };
283 
284  uint16_t crc16(const Datagram& dg, size_t offset = 0);
285  uint32_t crc32(NetHeader::checksum_t type, const Datagram& dg,
286  size_t offset = 0);
287 
288  /* returns true if checksum fails */
289  inline bool check_cs (const NetHeader& hdr, const Datagram& dg)
290  {
291  if (hdr.has_crc32c())
292  return (crc32(NetHeader::CS_CRC32C, dg) != hdr.crc32());
293 
294  if (hdr.has_crc32())
295  return (crc32(NetHeader::CS_CRC32, dg) != hdr.crc32());
296 
297  return (hdr.crc32() != 0);
298  }
299 } /* namespace gcomm */
300 
301 #endif // GCOMM_DATAGRAM_HPP
~Datagram()
Destruct datagram.
Definition: datagram.hpp:215
Definition: datagram.hpp:30
Datagram(const gu::Buffer &buf, size_t offset=0)
Construct new datagram from byte buffer.
Definition: datagram.hpp:170
Datagram(const Datagram &dgram, size_t off=std::numeric_limits< size_t >::max())
Copy constructor.
Definition: datagram.hpp:199
Datagram container.
Definition: datagram.hpp:151