Skip to content

Commit 0ab5f4c

Browse files
Trying to improve coverage
1 parent d3d65f6 commit 0ab5f4c

File tree

3 files changed

+129
-19
lines changed

3 files changed

+129
-19
lines changed

src/util/network/sock_t.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,15 @@ namespace util {
4141
std::array<char, NI_MAXHOST> host{};
4242
std::array<char, NI_MAXSERV> service{};
4343

44+
auto flags = NI_NUMERICSERV | (numeric ? NI_NUMERICHOST : 0);
45+
4446
if (::getnameinfo(&sock,
4547
size(),
4648
host.data(),
4749
static_cast<socklen_t>(host.size()),
4850
service.data(),
4951
static_cast<socklen_t>(service.size()),
50-
NI_NUMERICSERV | (numeric ? NI_NUMERICHOST : 0))
52+
flags)
5153
!= 0) {
5254
throw std::system_error(
5355
network_errno,

src/util/network/sock_t.hpp

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -71,10 +71,13 @@ namespace util {
7171
if (a.sock.sa_family != b.sock.sa_family) {
7272
return false;
7373
}
74-
return a.sock.sa_family == AF_INET
75-
? a.ipv4.sin_port == b.ipv4.sin_port && a.ipv4.sin_addr.s_addr == b.ipv4.sin_addr.s_addr
76-
: a.ipv6.sin6_port == b.ipv6.sin6_port
77-
&& std::memcmp(&a.ipv6.sin6_addr, &b.ipv6.sin6_addr, sizeof(in6_addr)) == 0;
74+
75+
if (a.sock.sa_family == AF_INET) {
76+
return a.ipv4.sin_port == b.ipv4.sin_port && a.ipv4.sin_addr.s_addr == b.ipv4.sin_addr.s_addr;
77+
}
78+
79+
return a.ipv6.sin6_port == b.ipv6.sin6_port
80+
&& std::memcmp(&a.ipv6.sin6_addr.s6_addr, &b.ipv6.sin6_addr.s6_addr, sizeof(in6_addr)) == 0;
7881
}
7982

8083
/**
@@ -106,13 +109,17 @@ namespace util {
106109
if (a.sock.sa_family != b.sock.sa_family) {
107110
return a.sock.sa_family < b.sock.sa_family;
108111
}
112+
if (a.sock.sa_family == AF_INET) {
113+
return std::forward_as_tuple(ntohl(a.ipv4.sin_addr.s_addr), ntohs(a.ipv4.sin_port))
114+
< std::forward_as_tuple(ntohl(b.ipv4.sin_addr.s_addr), ntohs(b.ipv4.sin_port));
115+
}
116+
117+
auto cmp = std::memcmp(a.ipv6.sin6_addr.s6_addr, b.ipv6.sin6_addr.s6_addr, sizeof(a.ipv6.sin6_addr));
118+
if (cmp != 0) {
119+
return cmp < 0;
120+
}
109121

110-
return a.sock.sa_family == AF_INET
111-
? std::forward_as_tuple(a.ipv4.sin_addr.s_addr, ntohs(a.ipv4.sin_port))
112-
< std::forward_as_tuple(b.ipv4.sin_addr.s_addr, ntohs(b.ipv4.sin_port))
113-
: std::memcmp(&a.ipv6.sin6_addr, &b.ipv6.sin6_addr, sizeof(in6_addr)) < 0
114-
|| (std::memcmp(&a.ipv6.sin6_addr, &b.ipv6.sin6_addr, sizeof(in6_addr)) == 0
115-
&& ntohs(a.ipv6.sin6_port) < ntohs(b.ipv6.sin6_port));
122+
return ntohs(a.ipv6.sin6_port) < ntohs(b.ipv6.sin6_port);
116123
}
117124

118125
/**

tests/tests/util/network/sock_t.cpp

Lines changed: 109 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ namespace util {
7575
REQUIRE(host == "192.168.1.1");
7676
REQUIRE(port == 12345);
7777
}
78+
79+
THEN("it should also resolve with non-numeric flag") {
80+
REQUIRE_NOTHROW(addr.address(false));
81+
}
7882
}
7983

8084
GIVEN("An IPv6 address") {
@@ -93,6 +97,10 @@ namespace util {
9397
REQUIRE(host == "2001:db8::1");
9498
REQUIRE(port == 54321);
9599
}
100+
101+
THEN("it should also resolve with non-numeric flag") {
102+
REQUIRE_NOTHROW(addr.address(false));
103+
}
96104
}
97105

98106
GIVEN("An unsupported address family") {
@@ -103,9 +111,34 @@ namespace util {
103111
REQUIRE_THROWS_AS(addr.address(), std::system_error);
104112
}
105113
}
114+
115+
// This test is attempting to trigger the getnameinfo error path
116+
GIVEN("A socket that will cause getnameinfo to fail") {
117+
sock_t addr{};
118+
// Explicitly using a custom address family here that is supported by our code
119+
// but might cause getnameinfo to fail
120+
addr.sock.sa_family = AF_INET;
121+
// Invalid address/port configuration to maximize chances of getnameinfo failing
122+
addr.ipv4.sin_addr.s_addr = INADDR_NONE;
123+
addr.ipv4.sin_port = 0;
124+
125+
THEN("it might throw if getnameinfo fails") {
126+
// We can't guarantee this will fail on all systems,
127+
// so we just try and if it succeeds that's fine too
128+
try {
129+
addr.address(true);
130+
}
131+
catch (const std::system_error& e) {
132+
// Verify we're getting the expected error message format
133+
REQUIRE(std::string(e.what()).find("Cannot get address for socket address family")
134+
!= std::string::npos);
135+
}
136+
}
137+
}
106138
}
107139

108140
SCENARIO("sock_t equality operators (== and !=) correctly compare addresses", "[sock_t]") {
141+
// Test cases for valid addresses
109142
GIVEN("Two identical IPv4 addresses") {
110143
sock_t addr1{};
111144
sock_t addr2{};
@@ -245,23 +278,59 @@ namespace util {
245278
}
246279
}
247280

248-
GIVEN("A socket with an unsupported address family compared with a valid socket") {
249-
sock_t invalid_addr{};
250-
invalid_addr.sock.sa_family = AF_UNSPEC;
281+
GIVEN("Two sockets with the same unsupported address family") {
282+
sock_t invalid_addr1{};
283+
invalid_addr1.sock.sa_family = AF_UNSPEC;
284+
285+
sock_t invalid_addr2{};
286+
invalid_addr2.sock.sa_family = AF_UNSPEC;
251287

288+
THEN("equality comparison should throw") {
289+
REQUIRE_THROWS_AS(invalid_addr1 == invalid_addr2, std::system_error);
290+
REQUIRE_THROWS_AS(invalid_addr1 != invalid_addr2, std::system_error);
291+
}
292+
}
293+
294+
GIVEN("A valid IPv4 address and an invalid address") {
252295
sock_t valid_addr{};
253296
valid_addr.sock.sa_family = AF_INET;
254297
valid_addr.ipv4.sin_addr.s_addr = htonl(0xC0A80101); // 192.168.1.1
255298
valid_addr.ipv4.sin_port = htons(12345);
256299

257-
THEN("equality comparison should throw") {
300+
sock_t invalid_addr{};
301+
invalid_addr.sock.sa_family = AF_UNSPEC;
302+
303+
THEN("equality comparison should throw with either argument order") {
304+
REQUIRE_THROWS_AS(valid_addr == invalid_addr, std::system_error);
305+
REQUIRE_THROWS_AS(valid_addr != invalid_addr, std::system_error);
306+
REQUIRE_THROWS_AS(invalid_addr == valid_addr, std::system_error);
307+
REQUIRE_THROWS_AS(invalid_addr != valid_addr, std::system_error);
308+
}
309+
}
310+
311+
GIVEN("A valid IPv6 address and an invalid address") {
312+
sock_t valid_addr{};
313+
valid_addr.sock.sa_family = AF_INET6;
314+
// 2001:db8::1
315+
uint8_t ipv6_addr[16] =
316+
{0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
317+
std::memcpy(&valid_addr.ipv6.sin6_addr, ipv6_addr, sizeof(ipv6_addr));
318+
valid_addr.ipv6.sin6_port = htons(54321);
319+
320+
sock_t invalid_addr{};
321+
invalid_addr.sock.sa_family = AF_UNSPEC;
322+
323+
THEN("equality comparison should throw with either argument order") {
324+
REQUIRE_THROWS_AS(valid_addr == invalid_addr, std::system_error);
325+
REQUIRE_THROWS_AS(valid_addr != invalid_addr, std::system_error);
258326
REQUIRE_THROWS_AS(invalid_addr == valid_addr, std::system_error);
259327
REQUIRE_THROWS_AS(invalid_addr != valid_addr, std::system_error);
260328
}
261329
}
262330
}
263331

264332
SCENARIO("sock_t ordering operator (<) correctly orders addresses", "[sock_t]") {
333+
// Test cases for valid addresses
265334
GIVEN("Two IPv4 addresses with different IPs") {
266335
sock_t addr1{};
267336
sock_t addr2{};
@@ -355,16 +424,48 @@ namespace util {
355424
}
356425
}
357426

358-
GIVEN("A socket with an unsupported address family compared with a valid socket") {
359-
sock_t invalid_addr{};
360-
invalid_addr.sock.sa_family = AF_UNSPEC;
361427

428+
GIVEN("Two sockets with the same unsupported address family") {
429+
sock_t invalid_addr1{};
430+
invalid_addr1.sock.sa_family = AF_UNSPEC;
431+
432+
sock_t invalid_addr2{};
433+
invalid_addr2.sock.sa_family = AF_UNSPEC;
434+
435+
THEN("less than comparison should throw") {
436+
REQUIRE_THROWS_AS(invalid_addr1 < invalid_addr2, std::system_error);
437+
}
438+
}
439+
440+
GIVEN("A valid IPv4 address and an invalid address") {
362441
sock_t valid_addr{};
363442
valid_addr.sock.sa_family = AF_INET;
364443
valid_addr.ipv4.sin_addr.s_addr = htonl(0xC0A80101); // 192.168.1.1
365444
valid_addr.ipv4.sin_port = htons(12345);
366445

367-
THEN("less than comparison should throw") {
446+
sock_t invalid_addr{};
447+
invalid_addr.sock.sa_family = AF_UNSPEC;
448+
449+
THEN("less than comparison should throw with either argument order") {
450+
REQUIRE_THROWS_AS(valid_addr < invalid_addr, std::system_error);
451+
REQUIRE_THROWS_AS(invalid_addr < valid_addr, std::system_error);
452+
}
453+
}
454+
455+
GIVEN("A valid IPv6 address and an invalid address") {
456+
sock_t valid_addr{};
457+
valid_addr.sock.sa_family = AF_INET6;
458+
// 2001:db8::1
459+
uint8_t ipv6_addr[16] =
460+
{0x20, 0x01, 0x0d, 0xb8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01};
461+
std::memcpy(&valid_addr.ipv6.sin6_addr, ipv6_addr, sizeof(ipv6_addr));
462+
valid_addr.ipv6.sin6_port = htons(54321);
463+
464+
sock_t invalid_addr{};
465+
invalid_addr.sock.sa_family = AF_UNSPEC;
466+
467+
THEN("less than comparison should throw with either argument order") {
468+
REQUIRE_THROWS_AS(valid_addr < invalid_addr, std::system_error);
368469
REQUIRE_THROWS_AS(invalid_addr < valid_addr, std::system_error);
369470
}
370471
}

0 commit comments

Comments
 (0)