1 /* Copyright (c) 2015, 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_XCOM_UTILS_INCLUDED
24 #define GCS_XCOM_UTILS_INCLUDED
25 
26 #include "xplatform/my_xp_thread.h"
27 #include "xplatform/my_xp_mutex.h"
28 #include "xplatform/my_xp_cond.h"
29 #include "xplatform/my_xp_util.h"
30 
31 #include "gcs_member_identifier.h"
32 #include "gcs_group_identifier.h"
33 #include "gcs_types.h"
34 #include "gcs_xcom_group_member_information.h"
35 
36 #include "simset.h"
37 #include "xcom_vp.h"
38 #include "xcom_common.h"
39 #include "node_list.h"
40 #include "node_set.h"
41 #include "task.h"
42 #include "server_struct.h"
43 #include "xcom_detector.h"
44 #include "site_struct.h"
45 #include "site_def.h"
46 #include "xcom_transport.h"
47 #include "xcom_base.h"
48 #include "task_net.h"
49 #include "node_connection.h"
50 #include "node_no.h"
51 
52 #include <vector>
53 #include <string>
54 
55 #define XCOM_COMM_STATUS_UNDEFINED -1
56 
57 /**
58   @class gcs_xcom_utils
59 
60   Class where the common binding utilities reside as static methods.
61 */
62 class Gcs_xcom_utils
63 {
64 public:
65   /**
66     Create a xcom group identifier from a Group Identifier.
67 
68     @param[in] group_id A group identifier
69 
70     @return an hash of the group identifier string that will serve as input
71             for the group id in XCom
72   */
73   static u_long build_xcom_group_id(Gcs_group_identifier &group_id);
74 
75   /**
76     Processes a list of comma separated peer nodes.
77 
78     @param peer_nodes input string of comma separated peer nodes
79     @param[out] processed_peers the list of configured peers
80    */
81   static
82   void process_peer_nodes(const std::string *peer_nodes,
83                           std::vector<std::string> &processed_peers);
84 
85   /**
86     Validates peer nodes according with IP/Address rules enforced by
87     is_valid_hostname function
88 
89     @param [in,out] peers input list of peer nodes. It will be cleansed of
90                     invalid peers
91     @param [in,out] invalid_peers This list will contain all invalid peers.
92    */
93   static
94   void validate_peer_nodes(std::vector<std::string> &peers,
95                            std::vector<std::string> &invalid_peers);
96 
97   /**
98    Simple multiplicative hash.
99 
100    @param buf the data to create an hash from
101    @param length data length
102 
103    @return calculated hash
104    */
105   static uint32_t mhash(unsigned char *buf, size_t length);
106 
107   static int init_net();
108   static int deinit_net();
109 
110   virtual ~Gcs_xcom_utils();
111 };
112 
113 /**
114   @class gcs_xcom_control_proxy
115 
116   This class is an abstraction layer between xcom and the actual
117   implementation. The purpose of this is to allow Gcs_xcom_control_interface
118   to be unit testable by creating mock classes on top of it.
119 */
120 class Gcs_xcom_proxy
121 {
122 public:
123   const static int connection_attempts= 10;
124 
Gcs_xcom_proxy()125   explicit Gcs_xcom_proxy() {}
126 
127   /**
128     The destructor.
129   */
~Gcs_xcom_proxy()130   virtual ~Gcs_xcom_proxy() {};
131 
132 
133   /**
134     This is an utility member function that is used to call into XCom for
135     creating list with node's addresses and their associated UUIDs. Note
136     that callers must provide the UUID.
137 
138     @param n The number of elements in the list
139     @param names The names to be put on the list
140     @param uuids The UUIDs to be put on the list
141     @return a pointer to the list containing all the elements needed. The
142     caller is responsible to reclaim memory once he is done with this data
143     @c delete_node_address
144   */
145 
146   virtual node_address *new_node_address_uuid(unsigned int n, char *names[], blob uuids[])= 0;
147 
148 
149   /**
150     This function is responsible to delete the list of nodes that had been
151     previously created by @c new_node_address.
152 
153     @param n the length of the list
154     @param na the list to delete
155 
156     @return false on success, true otherwise. In case of an error, memory may
157     not have been completely freed.
158   */
159 
160   virtual void delete_node_address(unsigned int n, node_address *na)= 0;
161 
162 
163   /**
164     This member function is responsible to call into XCom consensus and add a
165     node to the group. The caller is responsible for ensuring that the session
166     has been opened before @c open_session and also that the node is not yet
167     in the configuration.
168 
169     The callee must have opened an xcom connection before calling this
170     function. @c xcom_client_open_connection.
171 
172     @param fd the file descriptor to the XCom connection established earlier
173     @param nl The node list containing the list of peers to add
174     @param group_id the identifier of the group to which the nodes should
175            be added
176 
177     @return false on success, true otherwise. There could be errors later in
178     the process of adding a node. Since this is basically an asynchronous
179     function, one needs to wait for the actual view change to validate that we
180     were added to the configuration.
181   */
182 
183   virtual int
184   xcom_client_add_node(connection_descriptor* fd, node_list *nl, uint32_t group_id)= 0;
185 
186 
187   /**
188     This member function is responsible for triggering the removal of a node
189     from the XCom configuration. This function is asynchronous, so you need to
190     wait for the view change to actually validate that the removal was
191     successful.
192 
193     The caller is responsible for making sure that the server to be removed is
194     in the group.
195 
196     This function MUST be called after opening the local xcom session
197     @c xcom_open_handlers.
198 
199     @param nl The list of nodes to remove from the group
200     @param group_id The identifier of the group from which the nodes will
201            be removed
202     @param to_remove the node to remove
203   */
204 
205   virtual int xcom_client_remove_node(node_list *nl, uint32_t group_id)= 0;
206 
207   /**
208     This member function is responsible for triggering the removal of a node
209     from the XCom configuration. This function is asynchronous, so you need to
210     wait for the view change to actually validate that the removal was
211     successful.
212 
213     The caller is responsible for making sure that the server to be removed is
214     in the group.
215 
216     This function MUST be called after opening the local xcom session
217     @c xcom_open_handlers.
218 
219     This method is to contact remote instances requesting for a node
220     to be removed. You can use the local version which is:
221     - int xcom_client_remove_node(node_list *nl, uint32_t group_id)
222 
223     @param fd the file descriptor to the XCom connection established earlier
224     @param nl The list of nodes to remove from the group
225     @param group_id The identifier of the group from which the nodes will
226            be removed
227     @param to_remove the node to remove
228   */
229   virtual int xcom_client_remove_node(connection_descriptor* fd, node_list* nl,
230                                       uint32_t group_id)= 0;
231 
232   /**
233     This member function is responsible for pushing data into consensus on
234     XCom. The caller is responsible to making sure that there is an open XCom
235     session @c xcom_open_handlers and also that the server is  part of the XCom
236     configuration before sending data to it.
237 
238     @param size the size of the payload
239     @param data the payload
240 
241     @return 0 on success, not 0 otherwise
242   */
243 
244   virtual int xcom_client_send_data(unsigned long long size, char *data)= 0;
245 
246 
247   /**
248     This member function initializes XCom. This function must be called before
249     anything else and from within the XCom thread. It will eventually call
250     the main loop inside XCom.
251 
252     @param listen_port the port that the local XCom is to be listening on.
253   */
254 
255   virtual int xcom_init(xcom_port listen_port)= 0;
256 
257 
258   /**
259     This member function finishes the XCom thread. This function must be
260     called when the XCOM thread was started but the node has not joined
261     a group.
262 
263     @@param xcom_handlers_open indicates whether the handlers for the
264                                xcom thread have already been opened.
265   */
266 
267   virtual int xcom_exit(bool xcom_handlers_open)= 0;
268 
269 
270   /*
271     Return the operation mode as an integer from an operation mode provided
272     as a string. Note that the string must be provided in upper case letters
273     and the possible values are: "DISABLED", "PREFERRED", "REQUIRED",
274     "VERIFY_CA" or "VERIFY_IDENTITY".
275 
276     If a different value is provide, INVALID_SSL_MODE (-1) is returned.
277   */
278 
279   virtual int xcom_get_ssl_mode(const char* mode)= 0;
280 
281 
282   /*
283     Set the operation mode which might be the following:
284 
285     . SSL_DISABLED (1): The SSL mode will be disabled and this is the default
286       value.
287 
288     . SSL_PREFERRED (2): The SSL mode will be always disabled if this value is
289       provided and is only allowed to keep the solution compatibility with
290       MySQL server.
291 
292     . SSL_REQUIRED (4): The SSL mode will be enabled but the verifications
293       described in the next modes are not performed.
294 
295     . SSL_VERIFY_CA (4) - Verify the server TLS certificate against the configured
296       Certificate Authority (CA) certificates. The connection attempt fails if no
297       valid matching CA certificates are found.
298 
299     . SSL_VERIFY_IDENTITY (5): Like VERIFY_CA, but additionally verify that the
300       server certificate matches the host to which the connection is attempted.
301 
302     If a different value is provide, INVALID_SSL_MODE (-1) is returned.
303   */
304 
305   virtual int xcom_set_ssl_mode(int mode)= 0;
306 
307 
308   /*
309     Initialize the SSL.
310     Return 0 if success 1 otherwise.
311   */
312 
313   virtual int xcom_init_ssl()= 0;
314 
315 
316   /*
317     Destroy the SSL Configuration freeing allocated memory.
318   */
319 
320   virtual void xcom_destroy_ssl()= 0;
321 
322 
323   /*
324     Return whether the SSL will be used to encrypt data or not.
325 
326     Return 1 if it is enabled 0 otherwise.
327   */
328 
329   virtual int xcom_use_ssl()= 0;
330 
331 
332   /*
333     Set the necessary SSL parameters before initialization.
334 
335     server_key_file  - Path of file that contains the server's X509 key in PEM
336                        format.
337     server_cert_file - Path of file that contains the server's X509 certificate in
338                        PEM format.
339     client_key_file  - Path of file that contains the client's X509 key in PEM
340                        format.
341     client_cert_file - Path of file that contains the client's X509 certificate in
342                        PEM format.
343     ca_file          - Path of file that contains list of trusted SSL CAs.
344     ca_path          - Path of directory that contains trusted SSL CA certificates
345                        in PEM format.
346     crl_file         - Path of file that contains certificate revocation lists.
347     crl_path         - Path of directory that contains certificate revocation list
348                        files.
349     cipher           - List of permitted ciphers to use for connection encryption.
350     tls_version      - Protocols permitted for secure connections.
351 
352     Note that only the server_key_file/server_cert_file and the client_key_file/
353     client_cert_file are required and the rest of the pointers can be NULL.
354     If the key is provided along with the certificate, either the key file or
355     the other can be ommited.
356 
357     The caller can free the parameters after the SSL is started
358     if this is necessary.
359   */
360   virtual void  xcom_set_ssl_parameters(const char *server_key_file,
361                                         const char *server_cert_file,
362                                         const char *client_key_file,
363                                         const char *client_cert_file,
364                                         const char *ca_file,
365                                         const char *ca_path,
366                                         const char *crl_file,
367                                         const char *crl_path,
368                                         const char *cipher,
369                                         const char *tls_version)= 0;
370 
371 
372   virtual site_def const *find_site_def(synode_no synode)= 0;
373 
374   /**
375     This member function boots XCom.
376 
377     @param nl List with a single member - the one that boots the group
378     @param group_id the Group identifier to which the member belongs to
379     @return false 0 on success, not 0 otherwise
380   */
381 
382   virtual int xcom_client_boot(node_list *nl, uint32_t group_id)= 0;
383 
384 
385   /**
386     This member function opens a connection to an XCom instance.
387 
388     @param addr The XCom instance address
389     @param port The XCom instance port
390     @return a valid file descriptor on success, -1 otherwise
391   */
392 
393   virtual connection_descriptor* xcom_client_open_connection(std::string addr, xcom_port port)= 0;
394 
395 
396   /**
397     This member function closes the connection to an XCom instance.
398 
399     @param fd The connection file descriptor
400     @return 0 on success, not 0 otherwise
401   */
402 
403   virtual int xcom_client_close_connection(connection_descriptor* fd)= 0;
404 
405 
406   /**
407     This member function opens all the local connections to XCom needed before
408     one can push data into it.
409 
410     Even though this is used to connect to a local XCom, it can be used to
411     connect to a standalone XCom.
412 
413     @param addr The XCom address
414     @param port The XCom port
415 
416     @return false on success, true otherwise. If there was an error, no
417     connection will have been created.
418   */
419 
420   virtual bool xcom_open_handlers(std::string saddr, xcom_port port)= 0;
421 
422 
423   /**
424     This member function closes all the local connections to XCom that had been
425     previously opened by open_session.
426 
427     @return false on success, true otherwise. If there was an error the state
428     of the connections is undefined.
429   */
430 
431   virtual bool xcom_close_handlers()= 0;
432 
433 
434   /**
435     Acquires one of the handlers opened through @c xcom_open_handlers and locks
436     it.
437 
438     The caller is responsible for releasing the handler once it is not needed
439     anymore.
440 
441     This function is mostly used by the locally connecting functions such as
442     @c xcom_client_send_data, @c xcom_client_add_node,
443     @c xcom_client_remove_node, @c xcom_client_boot.
444 
445     @return a valid handler to communicate with XCom
446   */
447 
448   virtual int xcom_acquire_handler()= 0;
449 
450 
451   /**
452     Releases the handler and unlocks it.
453 
454     @param fd The handler that was previously acquired
455   */
456 
457   virtual void xcom_release_handler(int index)= 0;
458 
459 
460   /**
461     This member waits for XCom to be initialized.
462   */
463 
464   virtual enum_gcs_error xcom_wait_ready()= 0;
465 
466   /*
467   This member retrieves the value of XCom initialized
468   */
469   virtual bool xcom_is_ready()= 0;
470 
471   /*
472    This member sets the value of XCom initialized
473    */
474   virtual void xcom_set_ready(bool value)= 0;
475 
476   /*
477    This member signals that XCom has initialized.
478    */
479   virtual void xcom_signal_ready()= 0;
480 
481   /**
482     @brief Call this method to wait for XCom communications to be initialized.
483 
484     Call this method to wait for XCom communications to be initialized. It will
485     block until XCom communications are either OK or error out. The value of
486     the status (XCOM_COMMS_OK or XCOM_COMMS_ERROR) is written into the status
487     out parameters.
488 
489     @param status[out] value of the XCom communication layer status.
490                        It can be either XCOM_COMMS_OK or XCOM_COMMS_ERROR
491    */
492   virtual void xcom_wait_for_xcom_comms_status_change(int& status)= 0;
493 
494   /*
495    This verifies if the communication status callback from XCom has been called
496    and if the internal cached status is different from XCOM_COMM_STATUS_UNDEFINED
497   */
498   virtual bool xcom_has_comms_status_changed()= 0;
499 
500   /*
501    This sets the status value of communication status callback from XCom.
502    Its main purpose is to reset the internal cached status to XCOM_COMM_STATUS_UNDEFINED
503 
504    @param status the new status value
505    */
506   virtual void xcom_set_comms_status(int status)= 0;
507 
508   /*
509    This modifies the internal cached status to whatever value is delivered
510    by the XCom communication status callback. Then, it signals all threads
511    that might be waiting on xcom_wait_for_xcom_comms_status_change.
512 
513    @param status the new status value
514   */
515   virtual void xcom_signal_comms_status_changed(int status)= 0;
516 
517 
518   /**
519     @brief Call this method to wait for XCom to exit.
520 
521     Call this method to wait for XCom to exit. It will block until XCom has
522     exit or an error occurs.
523 
524     @return GCS_OK if success, otherwise GCS_NOK.
525   */
526 
527   virtual enum_gcs_error xcom_wait_exit()= 0;
528 
529 
530   /**
531     This verifies if XCom has finished or not.
532   */
533 
534   virtual bool xcom_is_exit()= 0;
535 
536 
537   /**
538     This sets whether XCom has finished or not.
539   */
540 
541   virtual void xcom_set_exit(bool value)= 0;
542 
543 
544   /**
545     Clean up variables used to notify states in the XCOM's state
546     machine.
547   */
548   virtual void xcom_set_cleanup()= 0;
549 
550 
551   /**
552     This modifies the internal cached status and signals all threads
553    that might be waiting on xcom_wait_exit.
554   */
555 
556   virtual void xcom_signal_exit()= 0;
557 
558 
559   /**
560     This method forces XCom to inject a new configuration in the group,
561     even if it does not contain a majority of members.
562 
563     @param nl The list of nodes that will belong to this new configuration
564     @param group_id The identifier of the group from which the nodes will
565            belong
566 
567     @return
568    */
569   virtual int xcom_client_force_config(node_list *nl,
570                                        uint32_t group_id)= 0;
571 
572   /**
573     This method forces XCom to inject a new configuration in the group,
574     even if it does not contain a majority of members.
575 
576     @param fd the file descriptor to the XCom connection established earlier
577     @param nl The list of nodes that will belong to this new configuration
578     @param group_id The identifier of the group from which the nodes will
579            belong
580 
581     @return
582    */
583   virtual int xcom_client_force_config(connection_descriptor *fd, node_list *nl,
584                                        uint32_t group_id)= 0;
585 };
586 
587 
588 /**
589   @class gcs_xcom_control_proxy_impl
590 
591   Implementation of gcs_xcom_control_proxy to be used by whom
592   instantiates Gcs_xcom_control_interface to be used in a real
593   scenario.
594 */
595 class Gcs_xcom_proxy_impl : public Gcs_xcom_proxy
596 {
597 private:
598   class Xcom_handler
599   {
600   private:
601     My_xp_mutex_impl m_lock;
602     connection_descriptor* m_fd;
603   public:
604     explicit Xcom_handler();
605     virtual ~Xcom_handler();
606 
get_fd()607     connection_descriptor* get_fd() { return m_fd; }
set_fd(connection_descriptor * fd)608     void set_fd(connection_descriptor* fd) { m_fd= fd; }
lock()609     void lock() { m_lock.lock(); }
unlock()610     void unlock() { m_lock.unlock(); }
611   private:
612     /*
613       Disabling the copy constructor and assignment operator.
614     */
615     Xcom_handler(Xcom_handler const&);
616     Xcom_handler& operator=(Xcom_handler const&);
617   };
618 public:
619   explicit Gcs_xcom_proxy_impl();
620   Gcs_xcom_proxy_impl(int wt);
621   virtual ~Gcs_xcom_proxy_impl();
622 
623   node_address *new_node_address_uuid(unsigned int n, char *names[], blob uuids[]);
624   void delete_node_address(unsigned int n, node_address *na);
625   int xcom_client_add_node(connection_descriptor* fd, node_list *nl, uint32_t group_id);
626   int xcom_client_remove_node(connection_descriptor* fd, node_list* nl, uint32_t group_id);
627   int xcom_client_remove_node(node_list *nl, uint32_t group_id);
628   int xcom_client_boot(node_list *nl, uint32_t group_id);
629   connection_descriptor* xcom_client_open_connection(std::string, xcom_port port);
630   int xcom_client_close_connection(connection_descriptor* fd);
631   int xcom_client_send_data(unsigned long long size, char *data);
632   int xcom_init(xcom_port listen_port);
633   int xcom_exit(bool xcom_handlers_open);
634   int xcom_get_ssl_mode(const char* mode);
635   int xcom_set_ssl_mode(int mode);
636   int xcom_init_ssl();
637   void xcom_destroy_ssl();
638   int xcom_use_ssl();
639   void xcom_set_ssl_parameters(const char *server_key_file,
640                                const char *server_cert_file,
641                                const char *client_key_file,
642                                const char *client_cert_file,
643                                const char *ca_file, const char *ca_path,
644                                const char *crl_file, const char *crl_path,
645                                const char *cipher, const char *tls_version);
646   site_def const *find_site_def(synode_no synode);
647 
648   bool xcom_open_handlers(std::string saddr, xcom_port port);
649   bool xcom_close_handlers();
650   int xcom_acquire_handler();
651   void xcom_release_handler(int index);
652   enum_gcs_error xcom_wait_ready();
653   bool xcom_is_ready();
654   void xcom_set_ready(bool value);
655   void xcom_signal_ready();
656 
657   void xcom_wait_for_xcom_comms_status_change(int& status);
658   bool xcom_has_comms_status_changed();
659   void xcom_set_comms_status(int status);
660   void xcom_signal_comms_status_changed(int status);
661 
662   enum_gcs_error xcom_wait_exit();
663   bool xcom_is_exit();
664   void xcom_set_exit(bool value);
665   void xcom_signal_exit();
666 
667   void xcom_set_cleanup();
668 
669   int xcom_client_force_config(node_list *nl, uint32_t group_id);
670   int xcom_client_force_config(connection_descriptor *fd, node_list *nl,
671                                uint32_t group_id);
672 
673 private:
674 
675   /* A pointer to the next local XCom connection to use. */
676   int m_xcom_handlers_cursor;
677 
678   /* This lock protects the list of local XCom connections. */
679   My_xp_mutex_impl m_lock_xcom_cursor;
680 
681   /* The maximum number of local xcom connections. */
682   int m_xcom_handlers_size;
683 
684   /*
685     Maximum waiting time used by timed_waits in xcom_wait_ready and
686     xcom_wait_for_xcom_comms_status_change.
687   */
688   int m_wait_time;
689 
690   /* A list of local XCom connections. */
691   Xcom_handler **m_xcom_handlers;
692 
693   // For synchronization between XCom and MySQL GCS infrastructure at startup.
694   My_xp_mutex_impl m_lock_xcom_ready;
695   My_xp_cond_impl  m_cond_xcom_ready;
696   bool             m_is_xcom_ready;
697 
698   My_xp_mutex_impl m_lock_xcom_comms_status;
699   My_xp_cond_impl  m_cond_xcom_comms_status;
700   int              m_xcom_comms_status;
701 
702   My_xp_mutex_impl m_lock_xcom_exit;
703   My_xp_cond_impl  m_cond_xcom_exit;
704   bool             m_is_xcom_exit;
705 
706   My_xp_socket_util* m_socket_util;
707 
708   // Stores SSL parameters
709   const char *m_server_key_file;
710   const char *m_server_cert_file;
711   const char *m_client_key_file;
712   const char *m_client_cert_file;
713   const char *m_ca_file;
714   const char *m_ca_path;
715   const char *m_crl_file;
716   const char *m_crl_path;
717   const char *m_cipher;
718   const char *m_tls_version;
719 
720 
721   /*
722     Disabling the copy constructor and assignment operator.
723   */
724   Gcs_xcom_proxy_impl(Gcs_xcom_proxy_impl const&);
725   Gcs_xcom_proxy_impl& operator=(Gcs_xcom_proxy_impl const&);
726 };
727 
728 /**
729   A Gcs_xcom_interface needs to have an instance of this class
730   initialized before engaging XCom.
731  */
732 class Gcs_xcom_app_cfg
733 {
734 public:
Gcs_xcom_app_cfg()735   explicit Gcs_xcom_app_cfg() { }
736 
~Gcs_xcom_app_cfg()737   virtual ~Gcs_xcom_app_cfg() { }
738 
739   /**
740     Initializes the data structures to communicate with
741     XCom the application injected configuration options.
742    */
743   void init();
744 
745   /**
746     Configures how many loops to spin before blocking on
747     the poll system call.
748     @param loops the number of spins.
749    */
750   void set_poll_spin_loops(unsigned int loops);
751 
752   /**
753     Must be called when XCom is not engaged anymore.
754    */
755   void deinit();
756 };
757 
758 typedef struct st_gcs_xcom_thread_startup_parameters
759 {
760   Gcs_xcom_proxy *proxy;
761   unsigned int   port;
762 } Gcs_xcom_thread_startup_parameters;
763 
764 
765 /**
766   This class contains information on the configuration, i.e set of nodes
767   or simply site definition, used by XCOM to deliver a message or view.
768 */
769 class Gcs_xcom_nodes
770 {
771 public:
772   /**
773     Constructor that reads the site definition and whether a node
774     is considered dead or alive to build a list of addresses and
775     statuses.
776   */
777 
778   explicit Gcs_xcom_nodes(const site_def *site, node_set &nodes);
779 
780 
781   /**
782     Empty constructor.
783   */
784 
785   explicit Gcs_xcom_nodes();
786 
787 
788   /**
789     Return the index of the current node (i.e. member).
790   */
791 
792   unsigned int get_node_no() const;
793 
794 
795   /**
796     Return a reference to the addresses' vector.
797   */
798 
799   const std::vector<std::string> &get_addresses() const;
800 
801   /**
802     Return a reference to the member uuids' vector.
803   */
804   const std::vector<Gcs_uuid> &get_uuids() const;
805 
806   /**
807     Return a reference to the statuses' vector.
808   */
809 
810   const std::vector<bool> &get_statuses() const;
811 
812   /**
813     Return the GCS UUID associated to an address if there is one.
814     If the address is not found, NULL is returned.
815   */
816   const Gcs_uuid *get_uuid(const std::string &address) const;
817 
818 
819   /**
820     Return the number of nodes.
821   */
822 
823   unsigned int get_size() const;
824 
825 
826   /**
827     Return with the configuration is valid or not.
828   */
is_valid()829   inline bool is_valid() const
830   {
831     /*
832       Unfortunately a node may get notifications even when its configuration
833       inside XCOM is not properly established and this may trigger view
834       changes and may lead to problems because the node is not really ready.
835 
836       We detect this fact by checking the node identification is valid.
837     */
838     return m_node_no != VOID_NODE_NO;
839   }
840 
841 private:
842   /*
843     Number of the current node which is used as an index to
844     the other data structures.
845   */
846   unsigned int m_node_no;
847 
848   /*
849     List of addresses.
850   */
851   std::vector<std::string> m_addresses;
852 
853   /*
854     List of uuids.
855   */
856   std::vector<Gcs_uuid> m_uuids;
857 
858   /*
859     List that defines whether a node is alive or dead.
860   */
861   std::vector<bool> m_statuses;
862 
863   /*
864     The size of the lists.
865   */
866   unsigned int m_size;
867 };
868 
869 /*****************************************************
870  *****************************************************
871 
872  Auxiliary checking functions.
873 
874  *****************************************************
875  *****************************************************
876  */
877 
878 /**
879  Checks whether the given string is a number or not
880  @param s the string to check.
881  @return true if it is a number, false otherwise.
882  */
is_number(const std::string & s)883 inline bool is_number(const std::string &s)
884 {
885   return s.find_first_not_of("0123456789") == std::string::npos;
886 }
887 
888 /**
889  Parses the string "host:port" and checks if it is correct.
890 
891  @param the server hostname and port in the form hostname:port.
892  @return true if it is a valid URL, false otherwise.
893  */
894 bool is_valid_hostname(const std::string &server_and_port);
895 
896 /**
897  Does some transformations on the parameters. For instance, replaces
898  aliases with the correct ones
899  */
900 void
901 fix_parameters_syntax(Gcs_interface_parameters &params);
902 
903 /**
904  Checks that parameters are syntatically valid.
905 
906  @param params The parameters to validate syntatically.
907  @returns false if there is a syntax error, true otherwise.
908  */
909 bool is_parameters_syntax_correct(const Gcs_interface_parameters &params);
910 
911 #endif  /* GCS_XCOM_UTILS_INCLUDED */
912