]> www.infradead.org Git - users/sagi/libnvme.git/commitdiff
util: Add ipaddrs_eq() to check whether two IP addresses are equal
authorMartin Belanger <martin.belanger@dell.com>
Fri, 19 May 2023 17:40:45 +0000 (13:40 -0400)
committerDaniel Wagner <wagi@monom.org>
Fri, 2 Jun 2023 11:37:46 +0000 (13:37 +0200)
Signed-off-by: Martin Belanger <martin.belanger@dell.com>
src/nvme/util.c
src/nvme/util.h
test/meson.build
test/test-util.c [new file with mode: 0644]

index e7cbc8a8328e5698905a1394ad2d0c08abe92657..a253954554e434ac552d1908d65604158e2d7e36 100644 (file)
@@ -8,6 +8,7 @@
  */
 
 #include <stdio.h>
+#include <stdbool.h>
 #include <string.h>
 #include <errno.h>
 
@@ -904,3 +905,61 @@ int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN])
 
        return 0;
 }
+
+bool ipaddrs_eq(const char *addr1, const char *addr2) {
+       bool result = false;
+       struct addrinfo *info1 = NULL, hint1 = { .ai_flags=AI_NUMERICHOST, .ai_family=AF_UNSPEC };
+       struct addrinfo *info2 = NULL, hint2 = { .ai_flags=AI_NUMERICHOST, .ai_family=AF_UNSPEC };
+
+       if (addr1 == addr2)
+               return true;
+
+       if (!addr1 || ! addr2)
+               return false;
+
+       if (getaddrinfo(addr1, 0, &hint1, &info1) || !info1)
+               goto ipaddrs_eq_fail;
+
+       if (getaddrinfo(addr2, 0, &hint2, &info2) || !info2)
+               goto ipaddrs_eq_fail;
+
+       if (info1->ai_family == AF_INET && info2->ai_family == AF_INET) {
+               struct sockaddr_in *sockaddr1 = (struct sockaddr_in *)(info1->ai_addr);
+               struct sockaddr_in *sockaddr2 = (struct sockaddr_in *)(info2->ai_addr);
+               result = sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr;
+       } else if (info1->ai_family == AF_INET6 && info2->ai_family == AF_INET6) {
+               struct sockaddr_in6 *sockaddr1 = (struct sockaddr_in6 *)(info1->ai_addr);
+               struct sockaddr_in6 *sockaddr2 = (struct sockaddr_in6 *)(info2->ai_addr);
+               result = !memcmp(&sockaddr1->sin6_addr, &sockaddr2->sin6_addr, sizeof(struct in6_addr));
+       } else {
+               struct sockaddr_in *sockaddr_v4;
+               struct sockaddr_in6 *sockaddr_v6;
+               switch (info1->ai_family) {
+               case AF_INET:
+                       sockaddr_v6 = (struct sockaddr_in6 *)(info2->ai_addr);
+                       if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
+                               sockaddr_v4 = (struct sockaddr_in *)(info1->ai_addr);
+                               result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
+                       }
+                       break;
+
+               case AF_INET6:
+                       sockaddr_v6 = (struct sockaddr_in6 *)(info1->ai_addr);
+                       if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
+                               sockaddr_v4 = (struct sockaddr_in *)(info2->ai_addr);
+                               result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
+                       }
+                       break;
+
+               default: ;
+               }
+       }
+
+ipaddrs_eq_fail:
+       if (info1)
+               freeaddrinfo(info1);
+       if (info2)
+               freeaddrinfo(info2);
+       return result;
+}
+
index 961da18bada3493435760e0f76130ed8be533fb1..18d0b66cee514436bea967a2f3531fb9873ae549 100644 (file)
@@ -626,4 +626,13 @@ int nvme_uuid_from_string(const char *str, unsigned char uuid[NVME_UUID_LEN]);
  */
 int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]);
 
+/**
+ * ipaddrs_eq - Check if 2 IP addresses are equal.
+ * @addr1: IP address (can be IPv4 or IPv6)
+ * @addr2: IP address (can be IPv4 or IPv6)
+ *
+ * Return: true if addr1 == addr2. false otherwise.
+ */
+bool ipaddrs_eq(const char *addr1, const char *addr2);
+
 #endif /* _LIBNVME_UTIL_H */
index ea1995d710db791a3e6e47da36e8a855b1d0e54f..fdb9ecfb77b84d78ae4e5a710d76469ee3232776 100644 (file)
@@ -75,4 +75,11 @@ tree = executable(
 
 test('tree', tree)
 
+test_util = executable(
+    'test-util',
+    ['test-util.c'],
+    include_directories: [incdir, internal_incdir]
+)
+test('Test util.c', test_util)
+
 subdir('nbft')
diff --git a/test/test-util.c b/test/test-util.c
new file mode 100644 (file)
index 0000000..08761cb
--- /dev/null
@@ -0,0 +1,118 @@
+/**
+ SPDX-License-Identifier: LGPL-2.1-or-later
+
+ This file is part of libnvme.
+ Copyright (c) 2023 Dell Inc.
+
+ Authors: Martin Belanger <Martin.Belanger@dell.com>
+*/
+
+/**
+ * In this file we test private functions found in
+ * "src/nvme/util.c". Note that the source files are included
+ * directly because the private functions are not available from
+ * the libnvme.so.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <netdb.h>
+#include <string.h>
+
+#include "nvme/cleanup.c"      /* to resolve cleanup_charp() */
+#include "nvme/log.c"          /* to resolve __nvme_msg() */
+#include "nvme/util.c"
+
+static size_t safe_strlen(const char *p) {
+       return p ? strlen(p) : strlen("null");
+}
+
+static bool test_nvme_get_version(enum nvme_version type, const char * exp_str) {
+       const char * str;
+       str = nvme_get_version(type);
+       return !strcmp(str, exp_str);
+}
+
+static bool test_ipaddrs_eq() {
+       int test_success = true;
+       static const char *x = "1.1.1.1";
+       struct {
+               const char *a;
+               const char *b;
+               bool  exp_result;
+       } addrs[] = {
+               {"192.168.56.101", "192.168.56.101", true},
+               {"2001:0db8:0000:0000:0000:ff00:0042:8329", "2001:0db8::ff00:0042:8329", true},
+               {NULL, NULL, true},
+               {x, x, true},
+               {"::ffff:192.168.56.101", "::ffff:192.168.56.101", true},
+               {"::ffff:192.168.56.101", "192.168.56.101", true},
+               {"::ffff:192.168.56.222", "192.168.56.101", false},
+               {"1.2.3.4", "192.168.56.101", false},
+               {"2001:0db8:0001:0000:0000:ff00:0042:8329", "2001:0db8::ff00:0042:8329", false},
+               {"2001:0db8:0001:0000:0000:ff00:0042:8329", NULL, false},
+       };
+
+       size_t i;
+       size_t n = sizeof(addrs) / sizeof(addrs[0]);
+       size_t longest_a = 0, longest_b = 0;
+
+       for (i = 0; i < n; i++) {
+               size_t l;
+               l = safe_strlen(addrs[i].a);
+               if (l > longest_a) longest_a = l;
+               l = safe_strlen(addrs[i].b);
+               if (l > longest_b) longest_b = l;
+       }
+
+       for (i = 0; i < n; i++) {
+               bool result = ipaddrs_eq(addrs[i].a, addrs[i].b);
+               bool pass = result == addrs[i].exp_result;
+               int pad_a = longest_a - safe_strlen(addrs[i].a);
+               int pad_b = longest_b - safe_strlen(addrs[i].b);
+               printf("%s %*.*s %s %*.*s  -> %-10s  %s\n",
+                      addrs[i].a ? addrs[i].a : "null",
+                      pad_a, pad_a, "",
+                      addrs[i].b ? addrs[i].b : "null",
+                      pad_b, pad_b, "",
+                      result ? "equal/same" : "different",
+                      pass ? "[PASS]" : "[FAIL]");
+
+               if (!pass)
+                       test_success = false;
+       }
+
+       return test_success;
+}
+
+int main(int argc, char *argv[]) {
+       int exit_val = EXIT_SUCCESS;
+       bool pass;
+
+       printf("\n------------------------------------------------------------------------------\n");
+       pass = test_nvme_get_version(NVME_VERSION_PROJECT, PROJECT_VERSION);
+       printf("nvme_get_version(NVME_VERSION_PROJECT) %s\n", pass ? "[PASS]" : "[FAIL]");
+       if (!pass)
+               exit_val = EXIT_FAILURE;
+
+       printf("\n------------------------------------------------------------------------------\n");
+       pass = test_nvme_get_version(NVME_VERSION_GIT, GIT_VERSION);
+       printf("nvme_get_version(NVME_VERSION_GIT) %s\n", pass ? "[PASS]" : "[FAIL]");
+       if (!pass)
+               exit_val = EXIT_FAILURE;
+
+       printf("\n------------------------------------------------------------------------------\n");
+       pass = test_nvme_get_version(-1, "n/a");
+       printf("nvme_get_version(-1) %s\n", pass ? "[PASS]" : "[FAIL]");
+       if (!pass)
+               exit_val = EXIT_FAILURE;
+
+       printf("\n------------------------------------------------------------------------------\n");
+       pass = test_ipaddrs_eq();
+       printf("ipaddrs_eq() %s", pass ? "[PASS]" : "[FAIL]");
+       if (!pass)
+               exit_val = EXIT_FAILURE;
+
+       exit(exit_val);
+}