summaryrefslogtreecommitdiff
path: root/sql/wsrep_utils.h
diff options
context:
space:
mode:
Diffstat (limited to 'sql/wsrep_utils.h')
-rw-r--r--sql/wsrep_utils.h144
1 files changed, 143 insertions, 1 deletions
diff --git a/sql/wsrep_utils.h b/sql/wsrep_utils.h
index 1cc65578202..32829c605fb 100644
--- a/sql/wsrep_utils.h
+++ b/sql/wsrep_utils.h
@@ -19,11 +19,153 @@
#include "wsrep_priv.h"
#include "wsrep_mysqld.h"
-unsigned int wsrep_check_ip (const char* addr);
+unsigned int wsrep_check_ip (const char* addr, bool *is_ipv6);
size_t wsrep_guess_ip (char* buf, size_t buf_len);
namespace wsp {
+class Address {
+public:
+ Address()
+ : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false)
+ {
+ memset(m_address, 0, sizeof(m_address));
+ }
+ Address(const char *addr_in)
+ : m_address_len(0), m_family(UNSPEC), m_port(0), m_valid(false)
+ {
+ memset(m_address, 0, sizeof(m_address));
+ parse_addr(addr_in);
+ }
+ bool is_valid() { return m_valid; }
+ bool is_ipv6() { return (m_family == INET6); }
+
+ const char* get_address() { return m_address; }
+ size_t get_address_len() { return m_address_len; }
+ int get_port() { return m_port; }
+
+private:
+ enum family {
+ UNSPEC= 0,
+ INET, /* IPv4 */
+ INET6, /* IPv6 */
+ };
+
+ char m_address[256];
+ size_t m_address_len;
+ family m_family;
+ int m_port;
+ bool m_valid;
+
+ void parse_addr(const char *addr_in) {
+ const char *start;
+ const char *end;
+ const char *port;
+ const char* open_bracket= strchr(const_cast<char *>(addr_in), '[');
+ const char* close_bracket= strchr(const_cast<char *>(addr_in), ']');
+ const char* colon= strchr(const_cast<char *>(addr_in), ':');
+ const char* dot= strchr(const_cast<char *>(addr_in), '.');
+
+ int cc= colon_count(addr_in);
+
+ if (open_bracket != NULL ||
+ dot == NULL ||
+ (colon != NULL && (dot == NULL || colon < dot)))
+ {
+ // This could be an IPv6 address or a hostname
+ if (open_bracket != NULL) {
+ /* Sanity check: Address with '[' must include ']' */
+ if (close_bracket == NULL &&
+ open_bracket < close_bracket) /* Error: malformed address */
+ {
+ m_valid= false;
+ return;
+ }
+
+ start= open_bracket + 1;
+ end= close_bracket;
+
+ /* Check for port */
+ port= strchr(close_bracket, ':');
+ if ((port != NULL) && parse_port(port + 1))
+ {
+ return; /* Error: invalid port */
+ }
+ m_family= INET6;
+ }
+ else
+ {
+ switch (cc) {
+ case 0:
+ /* Hostname with no port */
+ start= addr_in;
+ end= addr_in + strlen(addr_in);
+ break;
+ case 1:
+ /* Hostname with port (host:port) */
+ start= addr_in;
+ end= colon;
+ parse_port(colon + 1);
+ break;
+ default:
+ /* IPv6 address */
+ start= addr_in;
+ end= addr_in + strlen(addr_in);
+ m_family= INET6;
+ break;
+ }
+ }
+ } else { /* IPv4 address or hostname */
+ start= addr_in;
+ if (colon != NULL) { /* Port */
+ end= colon;
+ if (parse_port(colon + 1))
+ return; /* Error: invalid port */
+ } else {
+ end= addr_in + strlen(addr_in);
+ }
+ }
+
+ size_t len= end - start;
+
+ /* Safety */
+ if (len >= sizeof(m_address))
+ {
+ // The supplied address is too large to fit into the internal buffer.
+ m_valid= false;
+ return;
+ }
+
+ memcpy(m_address, start, len);
+ m_address[len]= '\0';
+ m_address_len= ++ len;
+ m_valid= true;
+ return;
+ }
+
+ int colon_count(const char *addr) {
+ int count= 0, i= 0;
+
+ while(addr[i] != '\0')
+ {
+ if (addr[i] == ':') ++count;
+ ++ i;
+ }
+ return count;
+ }
+
+ bool parse_port(const char *port) {
+ m_port= strtol(port, NULL, 10);
+ if (errno == EINVAL || errno == ERANGE)
+ {
+ m_port= 0; /* Error: invalid port */
+ m_valid= false;
+ return true;
+ }
+ return false;
+ }
+};
+
class Config_state
{
public: