1 /* Copyright (c) 2014, 2021, Oracle and/or its affiliates.
2 
3    This program is free software; you can redistribute it and/or modify
4    it under the terms of the GNU General Public License, version 2.0,
5    as published by the Free Software Foundation.
6 
7    This program is also distributed with certain software (including
8    but not limited to OpenSSL) that is licensed under separate terms,
9    as designated in a particular file or component or in included license
10    documentation.  The authors of MySQL hereby grant you an additional
11    permission to link the program and your derivative works with the
12    separately licensed software that they have included with MySQL.
13 
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License, version 2.0, for more details.
18 
19    You should have received a copy of the GNU General Public License
20    along with this program; if not, write to the Free Software
21    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
22 
23 #ifndef GCS_GCS_MESSAGE_INCLUDED
24 #define GCS_GCS_MESSAGE_INCLUDED
25 
26 #include "gcs_group_identifier.h"
27 #include "gcs_member_identifier.h"
28 #include "gcs_types.h"
29 
30 #include <stdint.h>
31 #include <vector>
32 #include <cstring>
33 
34 #define WIRE_PAYLOAD_LEN_SIZE 8
35 #define WIRE_HEADER_LEN_SIZE 4
36 
37 /**
38  @class Gcs_message_data
39 
40  This class serves as data container for information flowing in the GCS
41  ecosystem. It has been isolated in order to be used in place where a
42  full-blown Gcs_message does not make sense.
43 
44  For a full usage example, check the Gcs_message documentation.
45  */
46 class Gcs_message_data
47 {
48 public:
49   /**
50     Constructor of Gcs_message_data which pre-allocates space to store
51     the header and payload and should be used when creating messages to
52     send information to remote peers.
53 
54     @param  header_capacity Determines the header's size.
55     @param  header_capacity Determines the payload's size.
56   */
57   explicit Gcs_message_data(const uint32_t header_capacity,
58                             const uint64_t payload_capacity);
59 
60   /**
61     Constructor of Gcs_message_data which pre-allocates space to store
62     a message received from a remote peer.
63 
64     @param  data_len Data's length.
65   */
66   explicit Gcs_message_data(const uint64_t data_len);
67 
68 
69   virtual ~Gcs_message_data();
70 
71 
72   /**
73     Appends data to the header of the message. The data MUST have been
74     previously encoded in little endian format.
75 
76     If the data to be appended exceeds the pre-allocated buffer capacity
77     an error is returned.
78 
79     @param[in] to_append the data to append
80     @param[in] to_append_len the length of the data to append
81 
82     @return true on error, false otherwise.
83   */
84 
85   bool append_to_header(const uchar *to_append, uint32_t to_append_len);
86 
87 
88   /**
89     Appends data to the payload of the message. The data MUST have been
90     previously encoded in little endian format.
91 
92     If the data to be appended exceeds the pre-allocated buffer capacity
93     an error is returned.
94 
95     @param[in] to_append the data to append
96     @param[in] to_append_len the length of the data to append
97 
98     @return true on error, false otherwise.
99   */
100 
101   bool append_to_payload(const uchar *to_append, uint64_t to_append_len);
102 
103 
104   /**
105    Release the buffer's owership which means that this object will not
106    be responsible for deallocating its internal buffer. The caller should
107    do so.
108 
109    This method should be used along with the following method:
110    encode(**buffer, *buffer_len).
111   **/
112 
113   void release_ownership();
114 
115   /**
116    Encodes the header and payload into an internal buffer. If NULL pointer
117    is provided or the data was not already appended to the buffer, an error
118    is returned.
119 
120    The meta data is formated in little endian format, and is structured
121    on the wire as depicted below:
122 
123    -----------------------------------------------
124    | header len | payload len | header | payload |
125    -----------------------------------------------
126 
127    @param[in/out] Variable that will hold a pointer to the buffer
128    @param[in/out] Variable that will hold the buffer's size.
129 
130    @return true on error, false otherwise.
131   */
132 
133   bool encode(uchar **buffer, uint64_t *buffer_len);
134 
135 
136   /**
137    Encodes the header and payload into a buffer provided by the caller.
138    If the buffer is not large enough to store the encoded data or is a
139    NULL pointer, an error is returned.
140 
141    @param buffer[in/out] Buffer to store the encoded data in the message.
142    @param length[in/out] The length of the buffer where the data is to be stored.
143    It contains the length of the data dumped into the buffer once the function
144    succeeds.
145 
146    @return true on error, false otherwise.
147    */
148 
149   bool encode(uchar *buffer, uint64_t *buffer_len);
150 
151 
152   /**
153     Decodes data received via GCS and that belongs to a message. After
154     decoding, all the fields will be filled. The data MUST be in little endian
155     format.
156 
157     If the buffer is not large enough to store the encoded data or is a
158     NULL pointer, an error is returned.
159 
160     @param[in] data Data received via network
161     @param[in] data_len Data length received via network
162 
163     @return true on error, false otherwise.
164   */
165 
166   bool decode(const uchar *data, uint64_t data_len);
167 
168   /**
169     @return the message header in little endian format
170   */
171 
172   const uchar *get_header() const;
173 
174 
175   /**
176     @return the message header length
177   */
178 
179   uint32_t get_header_length() const;
180 
181 
182   /**
183     @return the message payload in little endian format
184   */
185 
186   const uchar *get_payload() const;
187 
188 
189   /**
190     @return the message payload_length
191   */
192 
193   uint64_t get_payload_length() const;
194 
195 
196   /**
197     @return the size of the encoded data when put on the wire.
198   */
199 
200   uint64_t get_encode_size() const;
201 
202 
203   /**
204     @return the size of the encoded payload when put on the wire.
205   */
206 
207   uint64_t get_encode_payload_size() const;
208 
209 
210   /**
211     @return the size of the encoded header when put on the wire.
212   */
213 
214   uint64_t get_encode_header_size() const;
215 
216 private:
217   /*
218     Pointer to the header's buffer.
219   */
220   uchar *m_header;
221 
222   /*
223     Pointer to the next empty position in the header's buffer.
224   */
225   uchar *m_header_slider;
226 
227   /*
228     Length of the header's buffer in use.
229   */
230   uint32_t m_header_len;
231 
232   /*
233     Capacity of the header's buffer.
234   */
235   uint32_t m_header_capacity;
236 
237   /*
238     Pointer to the payload's buffer.
239   */
240   uchar *m_payload;
241 
242   /*
243     Pointer to the next empty position in the payload's buffer.
244   */
245   uchar *m_payload_slider;
246 
247   /*
248     Length of the payload's buffer in use.
249   */
250   uint64_t m_payload_len;
251 
252   /*
253     Capacity of the header's buffer.
254   */
255   uint64_t m_payload_capacity;
256 
257   /*
258     Pointer to the begining of the buffer that contains both the
259     header and the payload.
260   */
261   uchar *m_buffer;
262 
263   /*
264     Length of the buffer that contains both the header, the
265     payload and metadata information.
266   */
267   uint64_t m_buffer_len;
268 
269   /*
270     Whether the current object owns the buffer and must free it
271     when deleted.
272   */
273   bool m_owner;
274 
275   /*
276     Disabling the copy constructor and assignment operator.
277   */
278   Gcs_message_data(Gcs_message_data const&);
279   Gcs_message_data& operator=(Gcs_message_data const&);
280 };
281 
282 
283 /**
284   @class Gcs_message
285 
286   Class that represents the data that is exchanged within a group. It is sent
287   by a member having the group as destination. It shall be received by all
288   members that pertain to the group in that moment.
289 
290   It is built using two major blocks: the header and the payload of the
291   message. A user of Gcs_message can freely add data to the header and to the
292   payload.
293 
294   Each binding implementation might use these two fields at its own
295   discretion but that data should be removed from the header/payload
296   before its delivery to the client layer.
297 
298   When the message is built, none of the data is passed unto it. One has to
299   use the append_* methods in order to append data. Calling encode() at the end
300   will provide a ready-to-send message.
301 
302   On the receiver side, one shall use decode() in order to have the header and
303   the payload restored in the original message fields.
304 
305   A typical use case of sending a message is:
306 
307   @code{.cpp}
308 
309   Gcs_control_interface       *gcs_ctrl_interface_instance;
310   Gcs_communication_interface *gcs_comm_interface_instance; // obtained
311                                                             // previously
312 
313   Gcs_member_identifier *myself=
314     gcs_ctrl_interface_instance->get_local_information();
315 
316   Gcs_group_identifier destination("the_group");
317 
318   Gcs_message *msg= new Gcs_message(&myself, new Gcs_message_data(0, 3));
319 
320   uchar[] some_data= {(uchar)0x12,
321                       (uchar)0x24,
322                       (uchar)0x00};
323 
324   msg->get_message_data()->append_to_payload(&some_data,
325                                              strlen(some_data));
326 
327   gcs_comm_interface_instance->send_message(msg);
328   @endcode
329 
330   A typical use case of receiving a message is:
331 
332   @code{.cpp}
333   class my_Gcs_communication_event_listener : Gcs_communication_event_listener
334   {
335     my_Gcs_communication_event_listener(my_Message_delegator *delegator)
336     {
337       this->delegator= delegator;
338     }
339 
340     void on_message_received(Gcs_message &message)
341     {
342       // Do something when message arrives...
343       delegator->process_gcs_message(message);
344     }
345 
346     private:
347       my_Message_delegator *delegator;
348   }
349   @endcode
350 */
351 class Gcs_message
352 {
353 public:
354   /**
355     Gcs_message 1st constructor. This is used to build full messages.
356 
357     Note that the Gcs_message will acquire ownership of the data, i.e.
358     Gcs_message_data, and will be responsible for deleting it.
359 
360     @param[in] origin The group member that sent the message
361     @param[in] destination The group in which this message belongs
362     @param[in] message_data External message data object.
363   */
364 
365   explicit Gcs_message(const Gcs_member_identifier &origin,
366                        const Gcs_group_identifier &destination,
367                        Gcs_message_data *message_data);
368 
369 
370   /**
371     Gcs_message 2nd constructor. This is used to send messages but with
372     an external Gcs_message_data object.
373 
374     Note that the Gcs_message will acquire ownership of the data, i.e.
375     Gcs_message_data, and will be responsible for deleting it.
376 
377     @param[in] origin The group member that sent the message
378     @param[in] message_data External message data object.
379   */
380 
381   explicit Gcs_message(const Gcs_member_identifier &origin,
382                        Gcs_message_data *message_data);
383 
384 
385   virtual ~Gcs_message();
386 
387 
388   /**
389     @return the origin of this message
390   */
391 
392   const Gcs_member_identifier &get_origin() const;
393 
394 
395   /**
396     @return the destination of this message. It might be NULL.
397   */
398 
399   const Gcs_group_identifier *get_destination() const;
400 
401 
402   /**
403     @return the message data to be filled.
404   */
405 
406   Gcs_message_data &get_message_data() const;
407 
408 
409 private:
410   void init(const Gcs_member_identifier *origin,
411             const Gcs_group_identifier *destination,
412             Gcs_message_data *message_data);
413 
414   Gcs_member_identifier *m_origin;
415   Gcs_group_identifier  *m_destination;
416   Gcs_message_data      *m_data;
417 
418   /*
419     Disabling the copy constructor and assignment operator.
420   */
421   Gcs_message(Gcs_message const&);
422   Gcs_message& operator=(Gcs_message const&);
423 };
424 
425 #endif // GCS_GCS_MESSAGE_INCLUDED
426