Skip to content

Commit 2745883

Browse files
Martin Belangerigaw
authored andcommitted
util: Add ipaddrs_eq() to check whether two IP addresses are equal
Signed-off-by: Martin Belanger <[email protected]>
1 parent c885f3b commit 2745883

4 files changed

Lines changed: 193 additions & 0 deletions

File tree

src/nvme/util.c

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
*/
99

1010
#include <stdio.h>
11+
#include <stdbool.h>
1112
#include <string.h>
1213
#include <errno.h>
1314

@@ -904,3 +905,61 @@ int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN])
904905

905906
return 0;
906907
}
908+
909+
bool ipaddrs_eq(const char *addr1, const char *addr2) {
910+
bool result = false;
911+
struct addrinfo *info1 = NULL, hint1 = { .ai_flags=AI_NUMERICHOST, .ai_family=AF_UNSPEC };
912+
struct addrinfo *info2 = NULL, hint2 = { .ai_flags=AI_NUMERICHOST, .ai_family=AF_UNSPEC };
913+
914+
if (addr1 == addr2)
915+
return true;
916+
917+
if (!addr1 || ! addr2)
918+
return false;
919+
920+
if (getaddrinfo(addr1, 0, &hint1, &info1) || !info1)
921+
goto ipaddrs_eq_fail;
922+
923+
if (getaddrinfo(addr2, 0, &hint2, &info2) || !info2)
924+
goto ipaddrs_eq_fail;
925+
926+
if (info1->ai_family == AF_INET && info2->ai_family == AF_INET) {
927+
struct sockaddr_in *sockaddr1 = (struct sockaddr_in *)(info1->ai_addr);
928+
struct sockaddr_in *sockaddr2 = (struct sockaddr_in *)(info2->ai_addr);
929+
result = sockaddr1->sin_addr.s_addr == sockaddr2->sin_addr.s_addr;
930+
} else if (info1->ai_family == AF_INET6 && info2->ai_family == AF_INET6) {
931+
struct sockaddr_in6 *sockaddr1 = (struct sockaddr_in6 *)(info1->ai_addr);
932+
struct sockaddr_in6 *sockaddr2 = (struct sockaddr_in6 *)(info2->ai_addr);
933+
result = !memcmp(&sockaddr1->sin6_addr, &sockaddr2->sin6_addr, sizeof(struct in6_addr));
934+
} else {
935+
struct sockaddr_in *sockaddr_v4;
936+
struct sockaddr_in6 *sockaddr_v6;
937+
switch (info1->ai_family) {
938+
case AF_INET:
939+
sockaddr_v6 = (struct sockaddr_in6 *)(info2->ai_addr);
940+
if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
941+
sockaddr_v4 = (struct sockaddr_in *)(info1->ai_addr);
942+
result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
943+
}
944+
break;
945+
946+
case AF_INET6:
947+
sockaddr_v6 = (struct sockaddr_in6 *)(info1->ai_addr);
948+
if (IN6_IS_ADDR_V4MAPPED(&sockaddr_v6->sin6_addr)) {
949+
sockaddr_v4 = (struct sockaddr_in *)(info2->ai_addr);
950+
result = sockaddr_v4->sin_addr.s_addr == sockaddr_v6->sin6_addr.s6_addr32[3];
951+
}
952+
break;
953+
954+
default: ;
955+
}
956+
}
957+
958+
ipaddrs_eq_fail:
959+
if (info1)
960+
freeaddrinfo(info1);
961+
if (info2)
962+
freeaddrinfo(info2);
963+
return result;
964+
}
965+

src/nvme/util.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -626,4 +626,13 @@ int nvme_uuid_from_string(const char *str, unsigned char uuid[NVME_UUID_LEN]);
626626
*/
627627
int nvme_uuid_random(unsigned char uuid[NVME_UUID_LEN]);
628628

629+
/**
630+
* ipaddrs_eq - Check if 2 IP addresses are equal.
631+
* @addr1: IP address (can be IPv4 or IPv6)
632+
* @addr2: IP address (can be IPv4 or IPv6)
633+
*
634+
* Return: true if addr1 == addr2. false otherwise.
635+
*/
636+
bool ipaddrs_eq(const char *addr1, const char *addr2);
637+
629638
#endif /* _LIBNVME_UTIL_H */

test/meson.build

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,11 @@ tree = executable(
7575

7676
test('tree', tree)
7777

78+
test_util = executable(
79+
'test-util',
80+
['test-util.c'],
81+
include_directories: [incdir, internal_incdir]
82+
)
83+
test('Test util.c', test_util)
84+
7885
subdir('nbft')

test/test-util.c

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/**
2+
SPDX-License-Identifier: LGPL-2.1-or-later
3+
4+
This file is part of libnvme.
5+
Copyright (c) 2023 Dell Inc.
6+
7+
Authors: Martin Belanger <[email protected]>
8+
*/
9+
10+
/**
11+
* In this file we test private functions found in
12+
* "src/nvme/util.c". Note that the source files are included
13+
* directly because the private functions are not available from
14+
* the libnvme.so.
15+
*/
16+
17+
#include <stdlib.h>
18+
#include <stdio.h>
19+
#include <stdbool.h>
20+
#include <netdb.h>
21+
#include <string.h>
22+
23+
#include "nvme/cleanup.c" /* to resolve cleanup_charp() */
24+
#include "nvme/log.c" /* to resolve __nvme_msg() */
25+
#include "nvme/util.c"
26+
27+
static size_t safe_strlen(const char *p) {
28+
return p ? strlen(p) : strlen("null");
29+
}
30+
31+
static bool test_nvme_get_version(enum nvme_version type, const char * exp_str) {
32+
const char * str;
33+
str = nvme_get_version(type);
34+
return !strcmp(str, exp_str);
35+
}
36+
37+
static bool test_ipaddrs_eq() {
38+
int test_success = true;
39+
static const char *x = "1.1.1.1";
40+
struct {
41+
const char *a;
42+
const char *b;
43+
bool exp_result;
44+
} addrs[] = {
45+
{"192.168.56.101", "192.168.56.101", true},
46+
{"2001:0db8:0000:0000:0000:ff00:0042:8329", "2001:0db8::ff00:0042:8329", true},
47+
{NULL, NULL, true},
48+
{x, x, true},
49+
{"::ffff:192.168.56.101", "::ffff:192.168.56.101", true},
50+
{"::ffff:192.168.56.101", "192.168.56.101", true},
51+
{"::ffff:192.168.56.222", "192.168.56.101", false},
52+
{"1.2.3.4", "192.168.56.101", false},
53+
{"2001:0db8:0001:0000:0000:ff00:0042:8329", "2001:0db8::ff00:0042:8329", false},
54+
{"2001:0db8:0001:0000:0000:ff00:0042:8329", NULL, false},
55+
};
56+
57+
size_t i;
58+
size_t n = sizeof(addrs) / sizeof(addrs[0]);
59+
size_t longest_a = 0, longest_b = 0;
60+
61+
for (i = 0; i < n; i++) {
62+
size_t l;
63+
l = safe_strlen(addrs[i].a);
64+
if (l > longest_a) longest_a = l;
65+
l = safe_strlen(addrs[i].b);
66+
if (l > longest_b) longest_b = l;
67+
}
68+
69+
for (i = 0; i < n; i++) {
70+
bool result = ipaddrs_eq(addrs[i].a, addrs[i].b);
71+
bool pass = result == addrs[i].exp_result;
72+
int pad_a = longest_a - safe_strlen(addrs[i].a);
73+
int pad_b = longest_b - safe_strlen(addrs[i].b);
74+
printf("%s %*.*s %s %*.*s -> %-10s %s\n",
75+
addrs[i].a ? addrs[i].a : "null",
76+
pad_a, pad_a, "",
77+
addrs[i].b ? addrs[i].b : "null",
78+
pad_b, pad_b, "",
79+
result ? "equal/same" : "different",
80+
pass ? "[PASS]" : "[FAIL]");
81+
82+
if (!pass)
83+
test_success = false;
84+
}
85+
86+
return test_success;
87+
}
88+
89+
int main(int argc, char *argv[]) {
90+
int exit_val = EXIT_SUCCESS;
91+
bool pass;
92+
93+
printf("\n------------------------------------------------------------------------------\n");
94+
pass = test_nvme_get_version(NVME_VERSION_PROJECT, PROJECT_VERSION);
95+
printf("nvme_get_version(NVME_VERSION_PROJECT) %s\n", pass ? "[PASS]" : "[FAIL]");
96+
if (!pass)
97+
exit_val = EXIT_FAILURE;
98+
99+
printf("\n------------------------------------------------------------------------------\n");
100+
pass = test_nvme_get_version(NVME_VERSION_GIT, GIT_VERSION);
101+
printf("nvme_get_version(NVME_VERSION_GIT) %s\n", pass ? "[PASS]" : "[FAIL]");
102+
if (!pass)
103+
exit_val = EXIT_FAILURE;
104+
105+
printf("\n------------------------------------------------------------------------------\n");
106+
pass = test_nvme_get_version(-1, "n/a");
107+
printf("nvme_get_version(-1) %s\n", pass ? "[PASS]" : "[FAIL]");
108+
if (!pass)
109+
exit_val = EXIT_FAILURE;
110+
111+
printf("\n------------------------------------------------------------------------------\n");
112+
pass = test_ipaddrs_eq();
113+
printf("ipaddrs_eq() %s", pass ? "[PASS]" : "[FAIL]");
114+
if (!pass)
115+
exit_val = EXIT_FAILURE;
116+
117+
exit(exit_val);
118+
}

0 commit comments

Comments
 (0)