ctdb-protocol: Add ctdb_sock_addr_from_string()
authorMartin Schwenke <martin@meltin.net>
Mon, 11 Sep 2017 06:39:38 +0000 (16:39 +1000)
committerMartin Schwenke <martins@samba.org>
Tue, 19 Sep 2017 11:30:26 +0000 (13:30 +0200)
This and the supporting functions duplicate functionality (parse_ip()
and parse_ip_port()) from common/system_util.c.  The old functions
will be removed at a later time.

Signed-off-by: Martin Schwenke <martin@meltin.net>
Reviewed-by: Amitay Isaacs <amitay@gmail.com>
ctdb/protocol/protocol_util.c
ctdb/protocol/protocol_util.h
ctdb/tests/src/protocol_util_test.c

index 26425d97a567e0a6e58009be4892644ca15df0d1..3c8c21a472a6c5108b0d92b35d48a84a40be3158 100644 (file)
@@ -174,6 +174,132 @@ const char *ctdb_sock_addr_to_string(TALLOC_CTX *mem_ctx,
        return cip;
 }
 
+static int ipv4_from_string(const char *str, struct sockaddr_in *ip)
+{
+       int ret;
+
+       *ip = (struct sockaddr_in) {
+               .sin_family = AF_INET,
+       };
+
+       ret = inet_pton(AF_INET, str, &ip->sin_addr);
+       if (ret != 1) {
+               return EINVAL;
+       }
+
+#ifdef HAVE_SOCK_SIN_LEN
+       ip->sin_len = sizeof(*ip);
+#endif
+       return 0;
+}
+
+static int ipv6_from_string(const char *str, struct sockaddr_in6 *ip6)
+{
+       int ret;
+
+       *ip6 = (struct sockaddr_in6) {
+               .sin6_family   = AF_INET6,
+       };
+
+       ret = inet_pton(AF_INET6, str, &ip6->sin6_addr);
+       if (ret != 1) {
+               return EINVAL;
+       }
+
+#ifdef HAVE_SOCK_SIN_LEN
+       ip6->sin6_len = sizeof(*ip6);
+#endif
+       return 0;
+}
+
+static int ip_from_string(const char *str, ctdb_sock_addr *addr)
+{
+       char *p;
+       int ret;
+
+       if (addr == NULL) {
+               return EINVAL;
+       }
+
+       ZERO_STRUCTP(addr); /* valgrind :-) */
+
+       /* IPv4 or IPv6 address?
+        *
+        * Use rindex() because we need the right-most ':' below for
+        * IPv4-mapped IPv6 addresses anyway...
+        */
+       p = rindex(str, ':');
+       if (p == NULL) {
+               ret = ipv4_from_string(str, &addr->ip);
+       } else {
+               uint8_t ipv4_mapped_prefix[12] = {
+                       0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff
+               };
+
+               ret = ipv6_from_string(str, &addr->ip6);
+               if (ret != 0) {
+                       return ret;
+               }
+
+               /*
+                * Check for IPv4-mapped IPv6 address
+                * (e.g. ::ffff:192.0.2.128) - reparse as IPv4 if
+                * necessary
+                */
+               if (memcmp(&addr->ip6.sin6_addr.s6_addr[0],
+                          ipv4_mapped_prefix,
+                          sizeof(ipv4_mapped_prefix)) == 0) {
+                       /* Reparse as IPv4 */
+                       ret = ipv4_from_string(p+1, &addr->ip);
+               }
+       }
+
+       return ret;
+}
+
+int ctdb_sock_addr_from_string(const char *str,
+                              ctdb_sock_addr *addr, bool with_port)
+{
+       char *p;
+       char s[64]; /* Much longer than INET6_ADDRSTRLEN */
+       unsigned port;
+       char *endp = NULL;
+       size_t len;
+       bool ret;
+
+       if (! with_port) {
+               ret = ip_from_string(str, addr);
+               return ret;
+       }
+
+       /* Parse out port number and then IP address */
+
+       len = strlen(str);
+       if (len >= sizeof(s)) {
+               return EINVAL;
+       }
+
+       strncpy(s, str, len+1);
+
+       p = rindex(s, ':');
+       if (p == NULL) {
+               return EINVAL;
+       }
+
+       port = strtoul(p+1, &endp, 10);
+       if (endp == p+1 || *endp != '\0') {
+               /* Empty string or trailing garbage */
+               return EINVAL;
+       }
+
+       *p = '\0';
+       ret = ip_from_string(s, addr);
+
+       ctdb_sock_addr_set_port(addr, port);
+
+       return ret;
+}
+
 unsigned int ctdb_sock_addr_port(ctdb_sock_addr *addr)
 {
        switch (addr->sa.sa_family) {
index b8c4f0aae4239ee1bd57363748f126499f894db4..88819366e5d09420d9bcee97d3a44fc854010583 100644 (file)
@@ -39,6 +39,8 @@ int ctdb_sock_addr_to_buf(char *buf, socklen_t buflen,
                          ctdb_sock_addr *addr, bool with_port);
 const char *ctdb_sock_addr_to_string(TALLOC_CTX *mem_ctx,
                                     ctdb_sock_addr *addr, bool with_port);
+int ctdb_sock_addr_from_string(const char *str,
+                              ctdb_sock_addr *addr, bool with_port);
 unsigned int ctdb_sock_addr_port(ctdb_sock_addr *addr);
 void ctdb_sock_addr_set_port(ctdb_sock_addr *addr, unsigned int port);
 int ctdb_sock_addr_cmp_ip(const ctdb_sock_addr *addr1,
index 1fcf1a0648d43bb49955e9127503c1ba71792641..8926de0197b7e68d0a9d0b7e28045e62d59731b4 100644 (file)
 #include "protocol/protocol_types.c"
 #include "protocol/protocol_util.c"
 
-#include "common/system_util.c"
+/*
+ * Test parsing of IPs, conversion to string
+ */
 
-/* Test parsing of IPs, conversion to string */
 static void test_sock_addr_to_string(const char *ip, bool with_port)
 {
        ctdb_sock_addr sa;
        const char *s;
-       bool status;
+       int ret;
 
-       if (with_port) {
-               status = parse_ip_port(ip, &sa);
-       } else {
-               status = parse_ip(ip, NULL, 0, &sa);
-       }
-       assert(status);
+       ret = ctdb_sock_addr_from_string(ip, &sa, with_port);
+       assert(ret == 0);
        s = ctdb_sock_addr_to_string(NULL, &sa, with_port);
        assert(strcmp(ip, s) == 0);
        talloc_free(discard_const(s));
 }
 
-static void test_sock_addr_cmp(const char *ip1, const char *ip2, int res)
+static void test_sock_addr_from_string_bad(const char *ip, bool with_port)
+{
+       ctdb_sock_addr sa;
+       int ret;
+
+       ret = ctdb_sock_addr_from_string(ip, &sa, with_port);
+       assert(ret != 0);
+}
+
+static void test_sock_addr_cmp(const char *ip1, const char *ip2,
+                              bool with_port, int res)
 {
        ctdb_sock_addr sa1, sa2;
        int ret;
 
-       assert(parse_ip(ip1, NULL, 0, &sa1));
-       assert(parse_ip(ip2, NULL, 0, &sa2));
+       ret = ctdb_sock_addr_from_string(ip1, &sa1, with_port);
+       assert(ret == 0);
+       ret = ctdb_sock_addr_from_string(ip2, &sa2, with_port);
+       assert(ret == 0);
        ret = ctdb_sock_addr_cmp(&sa1, &sa2);
        if (ret < 0) {
                ret = -1;
@@ -77,20 +86,29 @@ int main(int argc, char *argv[])
        test_sock_addr_to_string("192.168.2.1:123", true);
        test_sock_addr_to_string("fe80::6af7:28ff:fefa:d136:234", true);
 
-
-       test_sock_addr_cmp("127.0.0.1", "127.0.0.1" , 0);
-       test_sock_addr_cmp("127.0.0.1", "127.0.0.2" , -1);
-       test_sock_addr_cmp("127.0.0.2", "127.0.0.1" , 1);
-       test_sock_addr_cmp("127.0.1.2", "127.0.2.1" , -1);
-       test_sock_addr_cmp("127.0.2.1", "127.0.1.2" , 1);
-       test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136", "127.0.1.2" , 1);
+       test_sock_addr_from_string_bad("0.0.0", false);
+       test_sock_addr_from_string_bad("0.0.0:0", true);
+       test_sock_addr_from_string_bad("fe80::6af7:28ff:fefa:d136", true);
+       test_sock_addr_from_string_bad("junk", false);
+       test_sock_addr_from_string_bad("0.0.0.0:0 trailing junk", true);
+
+       test_sock_addr_cmp("127.0.0.1", "127.0.0.1" , false, 0);
+       test_sock_addr_cmp("127.0.0.1", "127.0.0.2" , false, -1);
+       test_sock_addr_cmp("127.0.0.2", "127.0.0.1" , false, 1);
+       test_sock_addr_cmp("127.0.1.2", "127.0.2.1" , false, -1);
+       test_sock_addr_cmp("127.0.2.1", "127.0.1.2" , false, 1);
+       test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136", "127.0.1.2" , false, 1);
        test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136",
-                          "fe80::6af7:28ff:fefa:d136" , 0);
+                          "fe80::6af7:28ff:fefa:d136" , false, 0);
        test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136",
-                          "fe80::6af7:28ff:fefa:d137" , -1);
+                          "fe80::6af7:28ff:fefa:d137" , false, -1);
        test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136",
-                          "fe80:0000:0000:0000:6af7:28ff:fefa:d136" , 0);
-       test_sock_addr_cmp("::ffff:192.0.2.128", "192.0.2.128", 0);
+                          "fe80:0000:0000:0000:6af7:28ff:fefa:d136" ,
+                          false, 0);
+       test_sock_addr_cmp("::ffff:192.0.2.128", "192.0.2.128", false, 0);
 
+       test_sock_addr_cmp("127.0.0.1:123", "127.0.0.1:124" , true, -1);
+       test_sock_addr_cmp("fe80::6af7:28ff:fefa:d136:123",
+                          "fe80::6af7:28ff:fefa:d136:122" , true, 1);
        return 0;
 }