1
/* vim:ts=8:sts=8:sw=4:noai:noexpandtab
3
* unit tests for portable function to return the nodes IP address.
5
* Copyright (c) 2009-2010 Miru Limited.
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Lesser General Public
9
* License as published by the Free Software Foundation; either
10
* version 2.1 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Lesser General Public License for more details.
17
* You should have received a copy of the GNU Lesser General Public
18
* License along with this library; if not, write to the Free Software
19
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
31
# include <sys/types.h>
32
# include <sys/socket.h>
34
# include <ws2tcpip.h>
48
struct sockaddr_storage address;
49
char* canonical_hostname;
53
struct mock_interface_t {
57
struct sockaddr_storage addr;
58
struct sockaddr_storage netmask;
61
static GList *mock_hosts = NULL, *mock_interfaces = NULL;
63
#define MOCK_HOSTNAME "kiku"
64
static char* mock_kiku = MOCK_HOSTNAME;
65
static char* mock_localhost = "localhost";
66
static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */
67
static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */
68
static char* mock_hostname = NULL;
73
static int mock_getaddrinfo (const char*, const char*, const struct addrinfo*, struct addrinfo**);
74
static void mock_freeaddrinfo (struct addrinfo*);
75
static int mock_gethostname (char*, size_t);
76
static struct hostent* mock_gethostbyname (const char*);
79
#define pgm_getifaddrs mock_pgm_getifaddrs
80
#define pgm_freeifaddrs mock_pgm_freeifaddrs
81
#define getaddrinfo mock_getaddrinfo
82
#define freeaddrinfo mock_freeaddrinfo
83
#define gethostname mock_gethostname
84
#define gethostbyname mock_gethostbyname
87
#define GETNODEADDR_DEBUG
88
#include "getnodeaddr.c"
95
const char* canonical_hostname,
99
struct mock_host_t* new_host;
102
g_assert (canonical_hostname);
104
new_host = g_slice_alloc0 (sizeof(struct mock_host_t));
105
g_assert (pgm_sockaddr_pton (address, (struct sockaddr*)&new_host->address));
106
new_host->canonical_hostname = g_strdup (canonical_hostname);
107
new_host->alias = alias ? g_strdup (alias) : NULL;
115
const unsigned index,
120
struct mock_interface_t* new_interface;
125
new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t));
126
new_interface->index = index;
127
new_interface->name = g_strdup (name);
129
struct sockaddr_in* sin = (gpointer)&new_interface->addr;
130
struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr;
132
gchar** tokens = g_strsplit (flags, ",", 0);
133
for (guint i = 0; tokens[i]; i++)
135
if (strcmp (tokens[i], "up") == 0)
136
new_interface->flags |= IFF_UP;
137
else if (strcmp (tokens[i], "down") == 0)
138
new_interface->flags |= 0;
139
else if (strcmp (tokens[i], "loop") == 0)
140
new_interface->flags |= IFF_LOOPBACK;
141
else if (strcmp (tokens[i], "broadcast") == 0)
142
new_interface->flags |= IFF_BROADCAST;
143
else if (strcmp (tokens[i], "multicast") == 0)
144
new_interface->flags |= IFF_MULTICAST;
145
else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) {
146
const char* addr = tokens[i] + strlen("ip=");
147
g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr));
149
else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) {
150
const char* addr = tokens[i] + strlen("netmask=");
151
g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask));
153
else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) {
154
const char* scope = tokens[i] + strlen("scope=");
155
g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family);
156
((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope);
159
g_error ("parsing failed for flag %s%s%s",
160
tokens[i] ? "\"" : "", tokens[i] ? tokens[i] : "(null)", tokens[i] ? "\"" : "");
164
return new_interface;
167
#define APPEND_HOST2(a,b,c) \
169
gpointer data = create_host ((a), (b), (c)); \
171
mock_hosts = g_list_append (mock_hosts, data); \
172
g_assert (mock_hosts); g_assert (mock_hosts->data); \
174
#define APPEND_HOST(a,b) APPEND_HOST2((a),(b),NULL)
175
#define APPEND_INTERFACE(a,b,c) \
177
gpointer data = create_interface ((a), (b), (c)); \
179
mock_interfaces = g_list_append (mock_interfaces, data); \
180
g_assert (mock_interfaces); g_assert (mock_interfaces->data); \
184
mock_setup_net (void)
186
mock_hostname = mock_kiku;
188
APPEND_HOST ( "127.0.0.1", "localhost");
189
APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku");
190
APPEND_HOST2( "2002:dce8:d28e::33", "ip6-kiku", "kiku");
191
APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback");
193
APPEND_INTERFACE( 1, "lo", "up,loop");
194
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast");
195
APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast");
196
APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0");
197
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0");
198
APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0");
199
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0");
200
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2");
203
/* with broken IPv6 hostname setup */
206
mock_setup_net2 (void)
208
mock_hostname = mock_kiku;
210
APPEND_HOST ( "127.0.0.1", "localhost");
211
APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku");
212
APPEND_HOST( "2002:dce8:d28e::33", "ip6-kiku");
213
APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback");
215
APPEND_INTERFACE( 1, "lo", "up,loop");
216
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast");
217
APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast");
218
APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0");
219
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0");
220
APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0");
221
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0");
222
APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2");
227
mock_teardown_net (void)
231
/* rollback APPEND_HOST */
234
struct mock_host_t* host = list->data;
235
g_free (host->canonical_hostname);
236
host->canonical_hostname = NULL;
238
g_free (host->alias);
241
g_slice_free1 (sizeof(struct mock_host_t), host);
245
g_list_free (mock_hosts);
248
/* rollback APPEND_INTERFACE */
249
list = mock_interfaces;
251
struct mock_interface_t* interface_ = list->data;
252
g_free (interface_->name);
253
interface_->name = NULL;
254
g_slice_free1 (sizeof(struct mock_interface_t), interface_);
258
g_list_free (mock_interfaces);
259
mock_interfaces = NULL;
261
mock_hostname = NULL;
265
/* mock functions for external references */
269
const bool can_fragment,
270
const sa_family_t pgmcc_family /* 0 = disable */
278
pgm_get_nprocs (void)
284
mock_pgm_getifaddrs (
285
struct pgm_ifaddrs_t** ifap,
293
g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err);
295
GList* list = mock_interfaces;
296
int n = g_list_length (list);
297
struct pgm_ifaddrs_t* ifa = malloc (n * sizeof(struct pgm_ifaddrs_t));
298
memset (ifa, 0, n * sizeof(struct pgm_ifaddrs_t));
299
struct pgm_ifaddrs_t* ift = ifa;
301
struct mock_interface_t* interface_ = list->data;
302
ift->ifa_addr = (gpointer)&interface_->addr;
303
ift->ifa_name = interface_->name;
304
ift->ifa_flags = interface_->flags;
305
ift->ifa_netmask = (gpointer)&interface_->netmask;
308
ift->ifa_next = ift + 1;
318
mock_pgm_freeifaddrs (
319
struct pgm_ifaddrs_t* ifa
322
g_debug ("mock_freeifaddrs (ifa:%p)", (gpointer)ifa);
332
static struct hostent he;
333
static char* aliases[2];
334
static char* addr_list[2];
337
g_assert (NULL != name);
339
g_debug ("mock_gethostbyname (name:%s%s%s)",
340
name ? "\"" : "", name ? name : "(null)", name ? "\"" : "");
342
GList* list = mock_hosts;
344
struct mock_host_t* host = list->data;
345
const int host_family = ((struct sockaddr*)&host->address)->sa_family;
346
if (((strcmp (host->canonical_hostname, name) == 0) ||
347
(host->alias && strcmp (host->alias, name) == 0)))
349
he.h_name = host->canonical_hostname;
350
aliases[0] = host->alias;
352
he.h_aliases = aliases;
353
he.h_addrtype = host_family;
354
switch (host->address.ss_family){
356
he.h_length = sizeof (struct in_addr);
357
addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in, sin_addr);
360
he.h_length = sizeof (struct in6_addr);
361
addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in6, sin6_addr);
364
g_assert_not_reached();
367
he.h_addr_list = addr_list;
373
h_errno = HOST_NOT_FOUND;
375
WSASetLastError (WSAHOST_NOT_FOUND);
385
const struct addrinfo* hints,
386
struct addrinfo** res
390
const int ai_flags = hints ? hints->ai_flags : (AI_V4MAPPED | AI_ADDRCONFIG);
392
const int ai_flags = hints ? hints->ai_flags : (AI_ADDRCONFIG);
394
const int ai_family = hints ? hints->ai_family : AF_UNSPEC;
396
struct sockaddr_storage addr;
398
if (NULL == node && NULL == service)
402
g_assert (NULL != node);
403
g_assert (NULL == service);
404
g_assert (!(ai_flags & AI_CANONNAME));
405
#ifdef AI_NUMERICSERV
406
g_assert (!(ai_flags & AI_NUMERICSERV));
409
g_assert (!(ai_flags & AI_V4MAPPED));
412
g_debug ("mock_getaddrinfo (node:\"%s\" service:%s hints:%p res:%p)",
413
node ? node : "(null)",
414
service ? service : "(null)",
418
gboolean has_ip4_config;
419
gboolean has_ip6_config;
421
if (hints && hints->ai_flags & AI_ADDRCONFIG)
423
has_ip4_config = has_ip6_config = FALSE;
424
list = mock_interfaces;
426
const struct mock_interface_t* interface_ = list->data;
427
if (AF_INET == ((struct sockaddr*)&interface_->addr)->sa_family)
428
has_ip4_config = TRUE;
429
else if (AF_INET6 == ((struct sockaddr*)&interface_->addr)->sa_family)
430
has_ip6_config = TRUE;
431
if (has_ip4_config && has_ip6_config)
436
has_ip4_config = has_ip6_config = TRUE;
439
if (ai_flags & AI_NUMERICHOST) {
440
pgm_sockaddr_pton (node, (struct sockaddr*)&addr);
444
struct mock_host_t* host = list->data;
445
const int host_family = ((struct sockaddr*)&host->address)->sa_family;
446
if (((strcmp (host->canonical_hostname, node) == 0) ||
447
(host->alias && strcmp (host->alias, node) == 0) ||
448
(ai_flags & AI_NUMERICHOST &&
449
0 == pgm_sockaddr_cmp ((struct sockaddr*)&addr, (struct sockaddr*)&host->address)))
451
(host_family == ai_family || AF_UNSPEC == ai_family) &&
452
((AF_INET == host_family && has_ip4_config) || (AF_INET6 == host_family && has_ip6_config)))
454
struct addrinfo* ai = malloc (sizeof(struct addrinfo));
455
memset (ai, 0, sizeof(struct addrinfo));
456
ai->ai_family = host_family;
457
ai->ai_addrlen = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6);
458
ai->ai_addr = (gpointer)&host->address;
473
g_assert (NULL != res);
474
g_debug ("mock_freeaddrinfo (res:%p)", (gpointer)res);
485
g_debug ("mock_gethostname (name:%p len:%d)",
486
(gpointer)name, len);
496
if (len < (1 + strlen (mock_hostname))) {
497
errno = ENAMETOOLONG;
501
if (mock_hostname == mock_toolong) {
502
errno = ENAMETOOLONG;
505
strncpy (name, mock_hostname, len);
507
name[len - 1] = '\0';
514
* pgm_get_multicast_enabled_node_addr (
515
* const sa_family_t family,
516
* struct sockaddr* addr,
517
* const socklen_t cnt,
518
* pgm_error_t** error
522
START_TEST (test_getnodeaddr_pass_001)
524
struct sockaddr_storage addr;
525
char saddr[INET6_ADDRSTRLEN];
526
pgm_error_t* err = NULL;
527
gboolean success = pgm_get_multicast_enabled_node_addr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), &err);
528
if (!success && err) {
529
g_error ("Resolving node address with AF_UNSPEC: %s", (err && err->message) ? err->message : "(null)");
531
fail_unless (TRUE == success, "getnodeaddr failed");
532
fail_unless (NULL == err, "error raised");
533
pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr));
534
g_message ("AF_UNSPEC:%s", saddr ? saddr : "(null)");
535
fail_unless (TRUE == pgm_get_multicast_enabled_node_addr (AF_INET, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed");
536
fail_unless (NULL == err, "error raised");
537
pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr));
538
g_message ("AF_INET:%s", saddr ? saddr : "(null)");
539
fail_unless (TRUE == pgm_get_multicast_enabled_node_addr (AF_INET6, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed");
540
fail_unless (NULL == err, "error raised");
541
pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr));
542
g_message ("AF_INET6:%s", saddr ? saddr : "(null)");
546
START_TEST (test_getnodeaddr_fail_001)
548
pgm_error_t* err = NULL;
549
fail_unless (FALSE == pgm_get_multicast_enabled_node_addr (AF_UNSPEC, NULL, 0, &err), "getnodeaddr failed");
556
make_test_suite (void)
560
s = suite_create (__FILE__);
561
TCase* tc_getnodeaddr = tcase_create ("getnodeaddr");
562
suite_add_tcase (s, tc_getnodeaddr);
563
tcase_add_checked_fixture (tc_getnodeaddr, mock_setup_net, mock_teardown_net);
564
tcase_add_test (tc_getnodeaddr, test_getnodeaddr_pass_001);
565
tcase_add_test (tc_getnodeaddr, test_getnodeaddr_fail_001);
567
TCase* tc_getnodeaddr2 = tcase_create ("getnodeaddr/2");
568
suite_add_tcase (s, tc_getnodeaddr2);
569
tcase_add_checked_fixture (tc_getnodeaddr2, mock_setup_net2, mock_teardown_net);
570
tcase_add_test (tc_getnodeaddr2, test_getnodeaddr_pass_001);
576
make_master_suite (void)
578
Suite* s = suite_create ("Master");
586
WORD wVersionRequested = MAKEWORD (2, 2);
588
g_assert (0 == WSAStartup (wVersionRequested, &wsaData));
589
g_assert (LOBYTE (wsaData.wVersion) == 2 && HIBYTE (wsaData.wVersion) == 2);
592
SRunner* sr = srunner_create (make_master_suite ());
593
srunner_add_suite (sr, make_test_suite ());
594
srunner_run_all (sr, CK_ENV);
595
int number_failed = srunner_ntests_failed (sr);
597
pgm_messages_shutdown();
601
return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;