Skip to content

Commit 5803563

Browse files
andy5995claude
andcommitted
test: Add CppUnit network tests for dual-stack connect/accept
Five tests in NetworkTest verify the dual-stack server implementation: - server binds and reports isPortBound() - IPv4 client connects and is accepted - accepted socket reports a plain IPv4 address (not ::ffff:...) - IPv6 client connects and is accepted (skipped if no IPv6 dual-stack) - accepted socket reports the IPv6 client address (skipped likewise) Also adds Socket::getSocketFamily() to query the address family in use, used by the tests to detect whether dual-stack is available. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2e19abc commit 5803563

2 files changed

Lines changed: 133 additions & 0 deletions

File tree

source/shared_lib/include/platform/posix/socket.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ class Socket {
204204

205205
virtual std::string getIpAddress();
206206
virtual void setIpAddress(std::string value) { ipAddress = value; }
207+
int getSocketFamily() const { return socketFamily; }
207208

208209
uint32 getConnectedIPAddress(string IP = "");
209210

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,132 @@
1+
// ==============================================================
2+
// This file is part of MegaGlest Unit Tests (www.megaglest.org)
3+
//
4+
// You can redistribute this code and/or modify it under
5+
// the terms of the GNU General Public License as published
6+
// by the Free Software Foundation; either version 2 of the
7+
// License, or (at your option) any later version
8+
// ==============================================================
9+
10+
#include <cppunit/extensions/HelperMacros.h>
11+
#include "socket.h"
12+
#include <unistd.h>
13+
14+
using namespace Shared::Platform;
15+
16+
// Base port for these tests; chosen to avoid well-known services.
17+
static const int TEST_PORT_BASE = 34527;
18+
19+
// Poll server.accept() for up to ~100 ms (50 × 2 ms sleeps).
20+
static Socket *pollAccept(ServerSocket &server, int tries = 50) {
21+
for (int i = 0; i < tries; ++i) {
22+
Socket *s = server.accept(false);
23+
if (s != nullptr) return s;
24+
usleep(2000);
25+
}
26+
return nullptr;
27+
}
28+
29+
// Returns true if this platform supports IPv6 dual-stack: an AF_INET6 socket
30+
// can be created and IPV6_V6ONLY can be cleared. ServerSocket::bind() already
31+
// does this probe and falls back to IPv4 silently, so we just check which
32+
// family was actually chosen.
33+
static bool platformHasIPv6DualStack() {
34+
ServerSocket probe;
35+
probe.bind(TEST_PORT_BASE + 9);
36+
return probe.getSocketFamily() == AF_INET6;
37+
}
38+
39+
class NetworkTest : public CppUnit::TestFixture {
40+
CPPUNIT_TEST_SUITE(NetworkTest);
41+
CPPUNIT_TEST(test_server_bind);
42+
CPPUNIT_TEST(test_ipv4_client_connect);
43+
CPPUNIT_TEST(test_ipv4_client_address_on_accept);
44+
CPPUNIT_TEST(test_ipv6_client_connect);
45+
CPPUNIT_TEST(test_ipv6_client_address_on_accept);
46+
CPPUNIT_TEST_SUITE_END();
47+
48+
public:
49+
// Server binds on a port and reports the port as bound
50+
void test_server_bind() {
51+
ServerSocket server;
52+
server.bind(TEST_PORT_BASE);
53+
server.listen(1);
54+
CPPUNIT_ASSERT(server.isPortBound());
55+
CPPUNIT_ASSERT(server.isSocketValid());
56+
}
57+
58+
// An IPv4 client can connect to the listening server
59+
void test_ipv4_client_connect() {
60+
ServerSocket server;
61+
server.bind(TEST_PORT_BASE + 1);
62+
server.listen(1);
63+
64+
ClientSocket client;
65+
client.connect(Ip("127.0.0.1"), TEST_PORT_BASE + 1);
66+
67+
Socket *accepted = pollAccept(server);
68+
CPPUNIT_ASSERT_MESSAGE("IPv4 connection was not accepted", accepted != nullptr);
69+
CPPUNIT_ASSERT(accepted->isSocketValid());
70+
delete accepted;
71+
}
72+
73+
// When an IPv4 client connects to a dual-stack server the accepted socket's
74+
// IP is a plain IPv4 string, not the mapped form "::ffff:127.0.0.1"
75+
void test_ipv4_client_address_on_accept() {
76+
ServerSocket server;
77+
server.bind(TEST_PORT_BASE + 2);
78+
server.listen(1);
79+
80+
ClientSocket client;
81+
client.connect(Ip("127.0.0.1"), TEST_PORT_BASE + 2);
82+
83+
Socket *accepted = pollAccept(server);
84+
CPPUNIT_ASSERT_MESSAGE("IPv4 connection was not accepted", accepted != nullptr);
85+
CPPUNIT_ASSERT_EQUAL(std::string("127.0.0.1"), accepted->getIpAddress());
86+
delete accepted;
87+
}
88+
89+
// An IPv6 client can connect to the dual-stack server.
90+
// Skipped on platforms without IPv6 support.
91+
void test_ipv6_client_connect() {
92+
if (!platformHasIPv6DualStack()) {
93+
std::cout << " [skipped: no IPv6 dual-stack] ";
94+
return;
95+
}
96+
97+
ServerSocket server;
98+
server.bind(TEST_PORT_BASE + 3);
99+
server.listen(1);
100+
101+
ClientSocket client;
102+
client.connect(Ip("::1"), TEST_PORT_BASE + 3);
103+
104+
Socket *accepted = pollAccept(server);
105+
CPPUNIT_ASSERT_MESSAGE("IPv6 connection was not accepted", accepted != nullptr);
106+
CPPUNIT_ASSERT(accepted->isSocketValid());
107+
delete accepted;
108+
}
109+
110+
// When an IPv6 client connects, the accepted socket reports the IPv6
111+
// address of the client
112+
void test_ipv6_client_address_on_accept() {
113+
if (!platformHasIPv6DualStack()) {
114+
std::cout << " [skipped: no IPv6 dual-stack] ";
115+
return;
116+
}
117+
118+
ServerSocket server;
119+
server.bind(TEST_PORT_BASE + 4);
120+
server.listen(1);
121+
122+
ClientSocket client;
123+
client.connect(Ip("::1"), TEST_PORT_BASE + 4);
124+
125+
Socket *accepted = pollAccept(server);
126+
CPPUNIT_ASSERT_MESSAGE("IPv6 connection was not accepted", accepted != nullptr);
127+
CPPUNIT_ASSERT_EQUAL(std::string("::1"), accepted->getIpAddress());
128+
delete accepted;
129+
}
130+
};
131+
132+
CPPUNIT_TEST_SUITE_REGISTRATION(NetworkTest);

0 commit comments

Comments
 (0)