GComm  0.2.3
gmcast_message.hpp
1 /*
2  * Copyright (C) 2009-2012 Codership Oy <info@codership.com>
3  */
4 
5 #ifndef GCOMM_GMCAST_MESSAGE_HPP
6 #define GCOMM_GMCAST_MESSAGE_HPP
7 
8 #include "gcomm/types.hpp"
9 #include "gcomm/uuid.hpp"
10 #include "gmcast_node.hpp"
11 #include "gcomm/map.hpp"
12 
13 namespace gcomm
14 {
15  namespace gmcast
16  {
17  class Message;
18  }
19 }
20 
21 
23 {
24 public:
25 
26  enum Flags {
27  F_GROUP_NAME = 1 << 0,
28  F_NODE_NAME = 1 << 1,
29  F_NODE_ADDRESS = 1 << 2,
30  F_NODE_LIST = 1 << 3,
31  F_HANDSHAKE_UUID = 1 << 4,
32  // relay message to all peers in the same segment (excluding source)
33  // and to all other segments except source segment
34  F_RELAY = 1 << 5,
35  // relay message to all peers in the same segment
36  F_SEGMENT_RELAY = 1 << 6
37  };
38 
39  enum Type
40  {
41  T_INVALID = 0,
42  T_HANDSHAKE = 1,
43  T_HANDSHAKE_RESPONSE = 2,
44  T_OK = 3,
45  T_FAIL = 4,
46  T_TOPOLOGY_CHANGE = 5,
47  T_KEEPALIVE = 6,
48  /* Leave room for future use */
49  T_USER_BASE = 8,
50  T_MAX = 255
51  };
52 
53  class NodeList : public Map<UUID, Node> { };
54 
55 private:
56 
57  gu::byte_t version_;
58  Type type_;
59  gu::byte_t flags_;
60  gu::byte_t segment_id_;
61  gcomm::UUID handshake_uuid_;
62  gcomm::UUID source_uuid_;
63  gcomm::String<64> node_address_;
64  gcomm::String<32> group_name_;
65 
66 
67  Message& operator=(const Message&);
68 
69  NodeList node_list_;
70 public:
71 
72  static const char* type_to_string (Type t)
73  {
74  static const char* str[T_MAX] =
75  {
76  "INVALID",
77  "HANDSHAKE",
78  "HANDSHAKE_RESPONSE",
79  "HANDSHAKE_OK",
80  "HANDSHAKE_FAIL",
81  "TOPOLOGY_CHANGE",
82  "KEEPALIVE",
83  "RESERVED_7",
84  "USER_BASE"
85  };
86 
87  if (T_MAX > t) return str[t];
88 
89  return "UNDEFINED PACKET TYPE";
90  }
91 
92  Message(const Message& msg) :
93  version_ (msg.version_),
94  type_ (msg.type_),
95  flags_ (msg.flags_),
96  segment_id_ (msg.segment_id_),
97  handshake_uuid_ (msg.handshake_uuid_),
98  source_uuid_ (msg.source_uuid_),
99  node_address_ (msg.node_address_),
100  group_name_ (msg.group_name_),
101  node_list_ (msg.node_list_)
102  { }
103 
104  /* Default ctor */
105  Message ()
106  :
107  version_ (0),
108  type_ (T_INVALID),
109  flags_ (0),
110  segment_id_ (0),
111  handshake_uuid_ (),
112  source_uuid_ (),
113  node_address_ (),
114  group_name_ (),
115  node_list_ ()
116  {}
117 
118  /* Ctor for handshake */
119  Message (int v,
120  const Type type,
121  const UUID& handshake_uuid,
122  const UUID& source_uuid,
123  uint8_t segment_id)
124  :
125  version_ (v),
126  type_ (type),
127  flags_ (F_HANDSHAKE_UUID),
128  segment_id_ (segment_id),
129  handshake_uuid_ (handshake_uuid),
130  source_uuid_ (source_uuid),
131  node_address_ (),
132  group_name_ (),
133  node_list_ ()
134  {
135  if (type_ != T_HANDSHAKE)
136  gu_throw_fatal << "Invalid message type " << type_to_string(type_)
137  << " in handshake constructor";
138  }
139 
140  /* ok, fail and keepalive */
141  Message (int v,
142  const Type type,
143  const UUID& source_uuid,
144  uint8_t segment_id)
145  :
146  version_ (v),
147  type_ (type),
148  flags_ (),
149  segment_id_ (segment_id),
150  handshake_uuid_ (),
151  source_uuid_ (source_uuid),
152  node_address_ (),
153  group_name_ (),
154  node_list_ ()
155  {
156  if (type_ != T_OK && type_ != T_FAIL && type_ != T_KEEPALIVE)
157  gu_throw_fatal << "Invalid message type " << type_to_string(type_)
158  << " in ok/fail/keepalive constructor";
159  }
160 
161 
162  /* Ctor for user message */
163  Message (int v,
164  const Type type,
165  const UUID& source_uuid,
166  const int ttl,
167  uint8_t segment)
168  :
169  version_ (v),
170  type_ (type),
171  flags_ (0),
172  segment_id_ (segment),
173  handshake_uuid_ (),
174  source_uuid_ (source_uuid),
175  node_address_ (),
176  group_name_ (),
177  node_list_ ()
178  {
179  if (type_ < T_USER_BASE)
180  gu_throw_fatal << "Invalid message type " << type_to_string(type_)
181  << " in user message constructor";
182  }
183 
184  /* Ctor for handshake response */
185  Message (int v,
186  const Type type,
187  const gcomm::UUID& handshake_uuid,
188  const gcomm::UUID& source_uuid,
189  const std::string& node_address,
190  const std::string& group_name,
191  uint8_t segment_id)
192  :
193  version_ (v),
194  type_ (type),
195  flags_ (F_GROUP_NAME | F_NODE_ADDRESS | F_HANDSHAKE_UUID),
196  segment_id_ (segment_id),
197  handshake_uuid_ (handshake_uuid),
198  source_uuid_ (source_uuid),
199  node_address_ (node_address),
200  group_name_ (group_name),
201  node_list_ ()
202 
203  {
204  if (type_ != T_HANDSHAKE_RESPONSE)
205  gu_throw_fatal << "Invalid message type " << type_to_string(type_)
206  << " in handshake response constructor";
207  }
208 
209  /* Ctor for topology change */
210  Message (int v,
211  const Type type,
212  const gcomm::UUID& source_uuid,
213  const std::string& group_name,
214  const NodeList& nodes)
215  :
216  version_ (v),
217  type_ (type),
218  flags_ (F_GROUP_NAME | F_NODE_LIST),
219  segment_id_ (0),
220  handshake_uuid_ (),
221  source_uuid_ (source_uuid),
222  node_address_ (),
223  group_name_ (group_name),
224  node_list_ (nodes)
225  {
226  if (type_ != T_TOPOLOGY_CHANGE)
227  gu_throw_fatal << "Invalid message type " << type_to_string(type_)
228  << " in topology change constructor";
229  }
230 
231  ~Message() { }
232 
233 
234  size_t serialize(gu::byte_t* buf, const size_t buflen,
235  const size_t offset) const
236  {
237  size_t off;
238 
239  gu_trace (off = gu::serialize1(version_, buf, buflen, offset));
240  gu_trace (off = gu::serialize1(static_cast<gu::byte_t>(type_),buf,buflen,off));
241  gu_trace (off = gu::serialize1(flags_, buf, buflen, off));
242  gu_trace (off = gu::serialize1(segment_id_, buf, buflen, off));
243  gu_trace (off = source_uuid_.serialize(buf, buflen, off));
244 
245  if (flags_ & F_HANDSHAKE_UUID)
246  {
247  gu_trace(off = handshake_uuid_.serialize(buf, buflen, off));
248  }
249 
250  if (flags_ & F_NODE_ADDRESS)
251  {
252  gu_trace (off = node_address_.serialize(buf, buflen, off));
253  }
254 
255  if (flags_ & F_GROUP_NAME)
256  {
257  gu_trace (off = group_name_.serialize(buf, buflen, off));
258  }
259 
260  if (flags_ & F_NODE_LIST)
261  {
262  gu_trace(off = node_list_.serialize(buf, buflen, off));
263  }
264  return off;
265  }
266 
267  size_t read_v0(const gu::byte_t* buf, const size_t buflen, const size_t offset)
268  {
269  size_t off;
270  gu::byte_t t;
271 
272  gu_trace (off = gu::unserialize1(buf, buflen, offset, t));
273  type_ = static_cast<Type>(t);
274  switch (type_)
275  {
276  case T_HANDSHAKE:
277  case T_HANDSHAKE_RESPONSE:
278  case T_OK:
279  case T_FAIL:
280  case T_TOPOLOGY_CHANGE:
281  case T_KEEPALIVE:
282  case T_USER_BASE:
283  break;
284  default:
285  gu_throw_error(EINVAL) << "invalid message type "
286  << static_cast<int>(type_);
287  }
288  gu_trace (off = gu::unserialize1(buf, buflen, off, flags_));
289  gu_trace (off = gu::unserialize1(buf, buflen, off, segment_id_));
290  gu_trace (off = source_uuid_.unserialize(buf, buflen, off));
291 
292  if (flags_ & F_HANDSHAKE_UUID)
293  {
294  gu_trace(off = handshake_uuid_.unserialize(buf, buflen, off));
295  }
296 
297  if (flags_ & F_NODE_ADDRESS)
298  {
299  gu_trace (off = node_address_.unserialize(buf, buflen, off));
300  }
301 
302  if (flags_ & F_GROUP_NAME)
303  {
304  gu_trace (off = group_name_.unserialize(buf, buflen, off));
305  }
306 
307  if (flags_ & F_NODE_LIST)
308  {
309  gu_trace(off = node_list_.unserialize(buf, buflen, off));
310  }
311 
312  return off;
313  }
314 
315  size_t unserialize(const gu::byte_t* buf, const size_t buflen, const size_t offset)
316  {
317  size_t off;
318 
319  gu_trace (off = gu::unserialize1(buf, buflen, offset, version_));
320 
321  switch (version_) {
322  case 0:
323  gu_trace (return read_v0(buf, buflen, off));
324  default:
325  gu_throw_error(EPROTONOSUPPORT) << "Unsupported/unrecognized gmcast protocol version: " << version_;
326  }
327  }
328 
329  size_t serial_size() const
330  {
331  return 4 /* Common header: version, type, flags, segment_id */
332  + source_uuid_.serial_size()
333  + (flags_ & F_HANDSHAKE_UUID ? handshake_uuid_.serial_size() : 0)
334  /* GMCast address if set */
335  + (flags_ & F_NODE_ADDRESS ? node_address_.serial_size() : 0)
336  /* Group name if set */
337  + (flags_ & F_GROUP_NAME ? group_name_.serial_size() : 0)
338  /* Node list if set */
339  + (flags_ & F_NODE_LIST ? node_list_.serial_size() : 0);
340  }
341 
342  int version() const { return version_; }
343 
344  Type type() const { return type_; }
345 
346  void set_flags(uint8_t f) { flags_ = f; }
347  uint8_t flags() const { return flags_; }
348  uint8_t segment_id() const { return segment_id_; }
349 
350  const UUID& handshake_uuid() const { return handshake_uuid_; }
351 
352  const UUID& source_uuid() const { return source_uuid_; }
353 
354  const std::string& node_address() const { return node_address_.to_string(); }
355 
356  const std::string& group_name() const { return group_name_.to_string(); }
357 
358  const NodeList& node_list() const { return node_list_; }
359 };
360 
361 #endif // GCOMM_GMCAST_MESSAGE_HPP
Definition: map.hpp:210
Definition: gmcast_message.hpp:53
Definition: gmcast_message.hpp:22
Definition: uuid.hpp:26