/* vim:ts=8:sts=8:sw=4:noai:noexpandtab * * unit tests for network interface declaration parsing. * * CAUTION: Assumes host is IPv4 by default for AF_UNSPEC * * Copyright (c) 2009-2010 Miru Limited. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* IFF_UP */ #ifndef _BSD_SOURCE # define _BSD_SOURCE 1 #endif #include #include #include #include #include #include #include #include #include #include #include #include #include /* mock state */ struct mock_host_t { struct sockaddr_storage address; char* canonical_hostname; char* alias; }; struct mock_network_t { char* name; struct sockaddr_storage number; char** aliases; }; struct mock_interface_t { unsigned int index; char* name; unsigned int flags; struct sockaddr_storage addr; struct sockaddr_storage netmask; }; static GList *mock_hosts = NULL, *mock_networks = NULL, *mock_interfaces = NULL; #define MOCK_HOSTNAME "kiku" #define MOCK_HOSTNAME6 "ip6-kiku" /* ping6 doesn't work on fe80:: */ #define MOCK_NETWORK "private" /* /etc/networks */ #define MOCK_NETWORK6 "ip6-private" #define MOCK_PGM_NETWORK "pgm-private" #define MOCK_PGM_NETWORK6 "pgm-ip6-private" #define MOCK_INTERFACE "eth0" #define MOCK_INTERFACE_INDEX 2 #define MOCK_ADDRESS "10.6.28.33" #define MOCK_GROUP ((in_addr_t) 0xefc00001) /* 239.192.0.1 */ #define MOCK_GROUP6_INIT { { { 0xff,8,0,0,0,0,0,0,0,0,0,0,0,0,0,1 } } } /* ff08::1 */ static const struct in6_addr mock_group6_addr = MOCK_GROUP6_INIT; #define MOCK_ADDRESS6 "2002:dce8:d28e::33" #define MOCK_ADDRESS6_INIT { { { 0x20,2,0xdc,0xe8,0xd2,0x8e,0,0,0,0,0,0,0,0,0,0x33 } } } static const struct in6_addr mock_address6_addr = MOCK_ADDRESS6_INIT; static int mock_family = 0; static char* mock_kiku = MOCK_HOSTNAME; static char* mock_localhost = "localhost"; static char* mock_invalid = "invalid.invalid"; /* RFC 2606 */ static char* mock_toolong = "abcdefghijabcdefghijabcdefghijabcdefghijabcdefghijabcdefghij12345"; /* 65 */ static char* mock_hostname = NULL; struct pgm_ifaddrs_t; struct pgm_error_t; bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); unsigned mock_pgm_if_nametoindex (const sa_family_t, const char*); char* mock_if_indextoname (unsigned int, char*); int mock_getnameinfo (const struct sockaddr*, socklen_t, char*, size_t, char*, size_t, int); int mock_getaddrinfo (const char*, const char*, const struct addrinfo*, struct addrinfo**); void mock_freeaddrinfo (struct addrinfo*); int mock_gethostname (char*, size_t); struct netent* mock_getnetbyname (const char*); bool mock_pgm_if_getnodeaddr (const sa_family_t, struct sockaddr*, const socklen_t, struct pgm_error_t**); #define pgm_getifaddrs mock_pgm_getifaddrs #define pgm_freeifaddrs mock_pgm_freeifaddrs #define pgm_if_nametoindex mock_pgm_if_nametoindex #define if_indextoname mock_if_indextoname #define getnameinfo mock_getnameinfo #define getaddrinfo mock_getaddrinfo #define freeaddrinfo mock_freeaddrinfo #define gethostname mock_gethostname #define getnetbyname mock_getnetbyname #define pgm_if_getnodeaddr mock_pgm_if_getnodeaddr #define IF_DEBUG #include "if.c" static gpointer create_host ( const char* address, const char* canonical_hostname, const char* alias ) { struct mock_host_t* new_host; g_assert (address); g_assert (canonical_hostname); new_host = g_slice_alloc0 (sizeof(struct mock_host_t)); g_assert (pgm_sockaddr_pton (address, (struct sockaddr*)&new_host->address)); new_host->canonical_hostname = g_strdup (canonical_hostname); new_host->alias = alias ? g_strdup (alias) : NULL; return new_host; } static gpointer create_network ( const char* name, const char* number ) { struct mock_network_t* new_network; g_assert (name); g_assert (number); new_network = g_slice_alloc0 (sizeof(struct mock_network_t)); new_network->name = g_strdup (name); g_assert (pgm_sockaddr_pton (number, (struct sockaddr*)&new_network->number)); return new_network; } static gpointer create_interface ( const unsigned index, const char* name, const char* flags ) { struct mock_interface_t* new_interface; g_assert (name); g_assert (flags); new_interface = g_slice_alloc0 (sizeof(struct mock_interface_t)); new_interface->index = index; new_interface->name = g_strdup (name); struct sockaddr_in* sin = (gpointer)&new_interface->addr; struct sockaddr_in6* sin6 = (gpointer)&new_interface->addr; gchar** tokens = g_strsplit (flags, ",", 0); for (guint i = 0; tokens[i]; i++) { if (strcmp (tokens[i], "up") == 0) new_interface->flags |= IFF_UP; else if (strcmp (tokens[i], "down") == 0) new_interface->flags |= 0; else if (strcmp (tokens[i], "loop") == 0) new_interface->flags |= IFF_LOOPBACK; else if (strcmp (tokens[i], "broadcast") == 0) new_interface->flags |= IFF_BROADCAST; else if (strcmp (tokens[i], "multicast") == 0) new_interface->flags |= IFF_MULTICAST; else if (strncmp (tokens[i], "ip=", strlen("ip=")) == 0) { const char* addr = tokens[i] + strlen("ip="); g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->addr)); } else if (strncmp (tokens[i], "netmask=", strlen("netmask=")) == 0) { const char* addr = tokens[i] + strlen("netmask="); g_assert (pgm_sockaddr_pton (addr, (struct sockaddr*)&new_interface->netmask)); } else if (strncmp (tokens[i], "scope=", strlen("scope=")) == 0) { const char* scope = tokens[i] + strlen("scope="); g_assert (AF_INET6 == ((struct sockaddr*)&new_interface->addr)->sa_family); ((struct sockaddr_in6*)&new_interface->addr)->sin6_scope_id = atoi (scope); } else g_error ("parsing failed for flag %s%s%s", tokens[i] ? "\"" : "", tokens[i] ? tokens[i] : "(null)", tokens[i] ? "\"" : ""); } g_strfreev (tokens); return new_interface; } #define APPEND_HOST2(a,b,c) \ do { \ gpointer data = create_host ((a), (b), (c)); \ g_assert (data); \ mock_hosts = g_list_append (mock_hosts, data); \ g_assert (mock_hosts); g_assert (mock_hosts->data); \ } while (0) #define APPEND_HOST(a,b) APPEND_HOST2((a),(b),NULL) #define APPEND_NETWORK(a,b) \ do { \ gpointer data = create_network ((a), (b)); \ g_assert (data); \ mock_networks = g_list_append (mock_networks, data); \ g_assert (mock_networks); g_assert (mock_networks->data); \ } while (0) #define APPEND_INTERFACE(a,b,c) \ do { \ gpointer data = create_interface ((a), (b), (c)); \ g_assert (data); \ mock_interfaces = g_list_append (mock_interfaces, data); \ g_assert (mock_interfaces); g_assert (mock_interfaces->data); \ } while (0) static void mock_setup_net (void) { mock_hostname = mock_kiku; APPEND_HOST ( "127.0.0.1", "localhost"); APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); APPEND_HOST2( "2002:dce8:d28e::33", "ip6-kiku", "kiku"); APPEND_HOST2( "172.12.90.1", "mi-hee.ko.miru.hk", "mi-hee"); APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); APPEND_HOST ( "239.192.0.1", "PGM.MCAST.NET"); APPEND_HOST ( "ff08::1", "IP6-PGM.MCAST.NET"); APPEND_NETWORK( "loopback", "127.0.0.0"); APPEND_NETWORK( "private", "10.6.28.0"); APPEND_NETWORK( "private2", "172.16.90.0"); APPEND_NETWORK( "pgm-private", "239.192.0.1"); #ifdef CONFIG_HAVE_IP6_NETWORKS APPEND_NETWORK( "ip6-private", "2002:dce8:d28e:0:0:0"); APPEND_NETWORK( "ip6-pgm-private","ff08::1"); #endif APPEND_INTERFACE( 1, "lo", "up,loop"); APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast"); APPEND_INTERFACE( 3, "eth1", "down,broadcast,multicast"); APPEND_INTERFACE( 1, "lo", "up,loop,ip=127.0.0.1,netmask=255.0.0.0"); APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=10.6.28.33,netmask=255.255.255.0"); APPEND_INTERFACE( 1, "lo", "up,loop,ip=::1,netmask=ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff,scope=0"); APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=2002:dce8:d28e::33,netmask=ffff:ffff:ffff:ffff::0,scope=0"); APPEND_INTERFACE( 2, "eth0", "up,broadcast,multicast,ip=fe80::214:5eff:febd:6dda,netmask=ffff:ffff:ffff:ffff::0,scope=2"); } static void mock_teardown_net (void) { GList* list; list = mock_hosts; while (list) { struct mock_host_t* host = list->data; g_free (host->canonical_hostname); if (host->alias) g_free (host->alias); g_slice_free1 (sizeof(struct mock_host_t), host); list = list->next; } g_list_free (mock_hosts); list = mock_networks; while (list) { struct mock_network_t* network = list->data; g_free (network->name); g_slice_free1 (sizeof(struct mock_network_t), network); list = list->next; } g_list_free (mock_networks); list = mock_interfaces; while (list) { struct mock_interface_t* interface = list->data; g_free (interface->name); g_slice_free1 (sizeof(struct mock_interface_t), interface); list = list->next; } g_list_free (mock_interfaces); } /* mock functions for external references */ size_t pgm_transport_pkt_offset2 ( const bool can_fragment, const bool use_pgmcc ) { return 0; } bool mock_pgm_getifaddrs ( struct pgm_ifaddrs_t** ifap, pgm_error_t** err ) { if (NULL == ifap) { return -1; } g_debug ("mock_getifaddrs (ifap:%p err:%p)", (gpointer)ifap, (gpointer)err); GList* list = mock_interfaces; int n = g_list_length (list); struct pgm_ifaddrs_t* ifa = calloc (n, sizeof(struct pgm_ifaddrs_t)); struct pgm_ifaddrs_t* ift = ifa; while (list) { struct mock_interface_t* interface = list->data; ift->ifa_addr = (gpointer)&interface->addr; ift->ifa_name = interface->name; ift->ifa_flags = interface->flags; ift->ifa_netmask = (gpointer)&interface->netmask; list = list->next; if (list) { ift->ifa_next = ift + 1; ift = ift->ifa_next; } } *ifap = ifa; return TRUE; } void mock_pgm_freeifaddrs ( struct pgm_ifaddrs_t* ifa ) { free (ifa); } unsigned mock_pgm_if_nametoindex ( const sa_family_t iffamily, const char* ifname ) { GList* list = mock_interfaces; while (list) { const struct mock_interface_t* interface = list->data; if (0 == strcmp (ifname, interface->name)) return interface->index; list = list->next; } return 0; } char* mock_if_indextoname ( unsigned ifindex, char* ifname ) { GList* list = mock_interfaces; while (list) { const struct mock_interface_t* interface = list->data; if (interface->index == ifindex) { strcpy (ifname, interface->name); return ifname; } list = list->next; } errno = ENXIO; return NULL; } int mock_getnameinfo ( const struct sockaddr* sa, socklen_t salen, char* host, size_t hostlen, char* serv, size_t servlen, int flags ) { if ((0 == hostlen && 0 == servlen) || (NULL == host && NULL == serv)) return EAI_NONAME; if (flags & NI_NUMERICHOST && flags & NI_NAMEREQD) return EAI_BADFLAGS; /* pre-conditions */ g_assert (NULL != host); g_assert (hostlen > 0); g_assert (NULL == serv); g_assert (0 == servlen); const int sa_family = sa->sa_family; if (AF_INET == sa_family) g_assert (sizeof(struct sockaddr_in) == salen); else { g_assert (AF_INET6 == sa_family); g_assert (sizeof(struct sockaddr_in6) == salen); } if (!(flags & NI_NUMERICHOST)) { GList* list = mock_hosts; while (list) { const struct mock_host_t* _host = list->data; const int host_family = ((struct sockaddr*)&_host->address)->sa_family; const size_t host_len = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); if (host_family == sa_family && host_len == salen && 0 == memcmp (sa, &_host->address, salen)) { if (hostlen < (1 + strlen(_host->canonical_hostname))) return EAI_OVERFLOW; strncpy (host, _host->canonical_hostname, hostlen); return 0; } list = list->next; } if (flags & NI_NAMEREQD) return EAI_NONAME; } if (AF_INET == sa_family) pgm_inet_ntop (sa_family, &((const struct sockaddr_in*)sa)->sin_addr, host, hostlen); else { const unsigned scope = ((const struct sockaddr_in6*)sa)->sin6_scope_id; pgm_inet_ntop (sa_family, &((const struct sockaddr_in6*)sa)->sin6_addr, host, hostlen); if (scope) { char buffer[1+IF_NAMESIZE]; strcat (host, "%"); strcat (host, mock_if_indextoname (scope, buffer)); } } return 0; } int mock_getaddrinfo ( const char* node, const char* service, const struct addrinfo* hints, struct addrinfo** res ) { const int ai_flags = hints ? hints->ai_flags : (AI_V4MAPPED | AI_ADDRCONFIG); const int ai_family = hints ? hints->ai_family : AF_UNSPEC; GList* list; struct sockaddr_storage addr; if (NULL == node && NULL == service) return EAI_NONAME; /* pre-conditions */ g_assert (NULL != node); g_assert (NULL == service); g_assert (!(ai_flags & AI_CANONNAME)); g_assert (!(ai_flags & AI_NUMERICSERV)); g_assert (!(ai_flags & AI_V4MAPPED)); g_message ("mock_getaddrinfo (node:%s%s%s service:%s%s%s hints:%p res:%p)", node ? "\"" : "", node ? node : "(null)", node ? "\"" : "", service ? "\"" : "", service ? service : "(null)", service ? "\"" : "", (gpointer)hints, (gpointer)res); gboolean has_ip4_config; gboolean has_ip6_config; if (hints && hints->ai_flags & AI_ADDRCONFIG) { has_ip4_config = has_ip6_config = FALSE; list = mock_interfaces; while (list) { const struct mock_interface_t* interface = list->data; if (AF_INET == ((struct sockaddr*)&interface->addr)->sa_family) has_ip4_config = TRUE; else if (AF_INET6 == ((struct sockaddr*)&interface->addr)->sa_family) has_ip6_config = TRUE; if (has_ip4_config && has_ip6_config) break; list = list->next; } } else { has_ip4_config = has_ip6_config = TRUE; } if (ai_flags & AI_NUMERICHOST) { pgm_sockaddr_pton (node, (struct sockaddr*)&addr); } list = mock_hosts; while (list) { struct mock_host_t* host = list->data; const int host_family = ((struct sockaddr*)&host->address)->sa_family; if (((strcmp (host->canonical_hostname, node) == 0) || (host->alias && strcmp (host->alias, node) == 0) || (ai_flags & AI_NUMERICHOST && 0 == pgm_sockaddr_cmp ((struct sockaddr*)&addr, (struct sockaddr*)&host->address))) && (host_family == ai_family || AF_UNSPEC == ai_family) && ((AF_INET == host_family && has_ip4_config) || (AF_INET6 == host_family && has_ip6_config))) { struct addrinfo* ai = malloc (sizeof(struct addrinfo)); memset (ai, 0, sizeof(struct addrinfo)); ai->ai_family = host_family; ai->ai_addrlen = AF_INET == host_family ? sizeof(struct sockaddr_in) : sizeof(struct sockaddr_in6); ai->ai_addr = (gpointer)&host->address; *res = ai; return 0; } list = list->next; } return EAI_NONAME; } void mock_freeaddrinfo ( struct addrinfo* res ) { free (res); } int mock_gethostname ( char* name, size_t len ) { if (NULL == name) { errno = EFAULT; return -1; } if (len < 0) { errno = EINVAL; return -1; } if (len < (1 + strlen (mock_hostname))) { errno = ENAMETOOLONG; return -1; } /* force an error */ if (mock_hostname == mock_toolong) { errno = ENAMETOOLONG; return -1; } strncpy (name, mock_hostname, len); if (len > 0) name[len - 1] = '\0'; return 0; } struct netent* mock_getnetbyname ( const char* name ) { static struct netent ne; GList* list = mock_networks; if (NULL == name) return NULL; while (list) { const struct mock_network_t* network = list->data; if (strcmp (network->name, name) == 0) { ne.n_name = network->name; ne.n_aliases = network->aliases; ne.n_addrtype = AF_INET; ne.n_net = g_ntohl (((struct sockaddr_in*)&network->number)->sin_addr.s_addr); return ≠ } list = list->next; } return NULL; } PGM_GNUC_INTERNAL bool mock_pgm_if_getnodeaddr ( const sa_family_t family, struct sockaddr* addr, const socklen_t cnt, pgm_error_t** error ) { switch (family) { case AF_UNSPEC: case AF_INET: ((struct sockaddr*)addr)->sa_family = AF_INET; ((struct sockaddr_in*)addr)->sin_addr.s_addr = inet_addr(MOCK_ADDRESS); break; case AF_INET6: ((struct sockaddr*)addr)->sa_family = AF_INET6; ((struct sockaddr_in6*)addr)->sin6_addr = mock_address6_addr; break; default: g_assert_not_reached(); } return TRUE; } /* following tests will use AF_UNSPEC address family */ static void mock_setup_unspec (void) { mock_family = AF_UNSPEC; } /* following tests will use AF_INET address family */ static void mock_setup_ip4 (void) { mock_family = AF_INET; } /* following tests will use AF_INET6 address family */ static void mock_setup_ip6 (void) { mock_family = AF_INET6; } /* return 0 if gsr multicast group does not match the default PGM group for * the address family, return -1 on no match. */ static gboolean match_default_group ( const int ai_family, const struct group_source_req* gsr ) { const struct sockaddr_in sa_default = { .sin_family = AF_INET, .sin_addr.s_addr = g_htonl (MOCK_GROUP) }; const struct sockaddr_in6 sa6_default = { .sin6_family = AF_INET6, .sin6_addr = MOCK_GROUP6_INIT }; gboolean is_match = FALSE; switch (ai_family) { case AF_UNSPEC: case AF_INET: is_match = (0 == pgm_sockaddr_cmp ((struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&sa_default)); if (!is_match) { char addr1[INET6_ADDRSTRLEN], addr2[INET6_ADDRSTRLEN]; pgm_sockaddr_ntop ((struct sockaddr*)&gsr->gsr_group, addr1, sizeof(addr1)); pgm_sockaddr_ntop ((struct sockaddr*)&sa_default, addr2, sizeof(addr2)); g_message ("FALSE == cmp(%s%s%s, default-group %s%s%s)", addr1 ? "\"" : "", addr1 ? addr1 : "(null)", addr1 ? "\"" : "", addr2 ? "\"" : "", addr2 ? addr2 : "(null)", addr2 ? "\"" : ""); } break; case AF_INET6: is_match = (0 == pgm_sockaddr_cmp ((struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&sa6_default)); if (!is_match) { char addr1[INET6_ADDRSTRLEN], addr2[INET6_ADDRSTRLEN]; pgm_sockaddr_ntop ((struct sockaddr*)&gsr->gsr_group, addr1, sizeof(addr1)); pgm_sockaddr_ntop ((struct sockaddr*)&sa6_default, addr2, sizeof(addr2)); g_message ("FALSE == cmp(%s%s%s, default-group %s%s%s)", addr1 ? "\"" : "", addr1 ? addr1 : "(null)", addr1 ? "\"" : "", addr2 ? "\"" : "", addr2 ? addr2 : "(null)", addr2 ? "\"" : ""); } default: break; } return is_match; } /* return 0 if gsr source inteface does not match the INADDR_ANY reserved * address, return -1 on no match. */ static int match_default_source ( const int ai_family, const struct group_source_req* gsr ) { if (0 != gsr->gsr_interface) return FALSE; /* ASM: source == group */ return (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&gsr->gsr_source)); } /* return 0 if gsr source interface does not match the hosts default interface, * return -1 on mismatch */ static int match_default_interface ( const int ai_family, const struct group_source_req* gsr ) { if (MOCK_INTERFACE_INDEX != gsr->gsr_interface) return FALSE; /* ASM: source == group */ return (0 == pgm_sockaddr_cmp ((const struct sockaddr*)&gsr->gsr_group, (const struct sockaddr*)&gsr->gsr_source)); } /* target: * bool * pgm_getaddrinfo ( * const char* s, * const struct pgm_addrinfo_t* const hints, * struct pgm_addrinfo_t** res, * pgm_error_t** err * ) */ struct test_case_t { const char* ip4; const char* ip6; }; #define IP4_AND_IP6(x) x, x static const struct test_case_t cases_001[] = { { IP4_AND_IP6("") }, { IP4_AND_IP6(";") }, { IP4_AND_IP6(";;") }, { "239.192.0.1", "ff08::1" }, { "239.192.0.1", "[ff08::1]" }, { ";239.192.0.1", ";ff08::1" }, { ";239.192.0.1", ";[ff08::1]" }, { ";239.192.0.1;239.192.0.1", ";ff08::1;ff08::1" }, { ";239.192.0.1;239.192.0.1", ";[ff08::1];[ff08::1]" }, { "PGM.MCAST.NET", "IP6-PGM.MCAST.NET" }, { ";PGM.MCAST.NET", ";IP6-PGM.MCAST.NET" }, { ";PGM.MCAST.NET;PGM.MCAST.NET", ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { ";239.192.0.1;PGM.MCAST.NET", ";ff08::1;IP6-PGM.MCAST.NET" }, { ";239.192.0.1;PGM.MCAST.NET", ";[ff08::1];IP6-PGM.MCAST.NET" }, { ";PGM.MCAST.NET;239.192.0.1", ";IP6-PGM.MCAST.NET;ff08::1" }, { ";PGM.MCAST.NET;239.192.0.1", ";IP6-PGM.MCAST.NET;[ff08::1]" }, { "pgm-private", /* ‡ */ "pgm-ip6-private" }, { ";pgm-private", /* ‡ */ ";pgm-ip6-private" }, { ";pgm-private;pgm-private", /* ‡ */ ";pgm-ip6-private;pgm-ip6-private" }, { ";PGM.MCAST.NET;pgm-private", /* ‡ */ ";IP6-PGM.MCAST.NET;pgm-ip6-private" }, { ";pgm-private;PGM.MCAST.NET", /* ‡ */ ";pgm-ip6-private;IP6-PGM.MCAST.NET" }, { ";239.192.0.1;pgm-private", /* ‡ */ ";ff08::1;pgm-ip6-private" }, { ";239.192.0.1;pgm-private", /* ‡ */ ";[ff08::1];pgm-ip6-private" }, { ";pgm-private;239.192.0.1", /* ‡ */ ";pgm-ip6-private;ff08::1" }, { ";pgm-private;239.192.0.1", /* ‡ */ ";pgm-ip6-private;[ff08::1]" }, }; START_TEST (test_parse_transport_pass_001) { fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); const char* s = (mock_family == AF_INET6) ? cases_001[_i].ip6 : cases_001[_i].ip4; struct pgm_addrinfo_t hints = { .ai_family = mock_family }, *res = NULL; pgm_error_t* err = NULL; g_message ("%i: test_parse_transport_001(%s, %s%s%s)", _i, (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); /* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and * pgm_if_parse_transport will fail. */ #ifndef CONFIG_HAVE_IP6_NETWORKS if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) { g_message ("IPv6 exception, /etc/networks not supported on this platform."); return; } #endif gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); if (!retval) { g_message ("pgm_getaddrinfo: %s", (err && err->message) ? err->message : "(null)"); } fail_unless (TRUE == retval, "pgm_getaddrinfo failed"); fail_if (NULL == res, "no result"); fail_unless (NULL == err, "error raised"); fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "receive address not match default source"); fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "send address not match default source"); } END_TEST /* interface name * * pre-condition: interface defined to match running host * ipv4 and ipv6 hostnames are different, otherwise "" tests might go unexpected. */ static const struct test_case_t cases_002[] = { { MOCK_INTERFACE, /* † */ MOCK_INTERFACE }, { MOCK_INTERFACE ";", /* † */ MOCK_INTERFACE ";" }, { MOCK_INTERFACE ";;", /* † */ MOCK_INTERFACE ";;" }, { MOCK_INTERFACE ";239.192.0.1", /* † */ MOCK_INTERFACE ";ff08::1" }, { MOCK_INTERFACE ";239.192.0.1", /* † */ MOCK_INTERFACE ";[ff08::1]" }, { MOCK_INTERFACE ";239.192.0.1;239.192.0.1", /* † */ MOCK_INTERFACE ";ff08::1;ff08::1" }, { MOCK_INTERFACE ";239.192.0.1;239.192.0.1", /* † */ MOCK_INTERFACE ";[ff08::1];[ff08::1]" }, { MOCK_INTERFACE ";PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET" }, { MOCK_INTERFACE ";PGM.MCAST.NET;PGM.MCAST.NET",/* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { MOCK_INTERFACE ";239.192.0.1;PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";ff08::1;IP6-PGM.MCAST.NET" }, { MOCK_INTERFACE ";239.192.0.1;PGM.MCAST.NET", /* † */ MOCK_INTERFACE ";[ff08::1];IP6-PGM.MCAST.NET" }, { MOCK_INTERFACE ";PGM.MCAST.NET;239.192.0.1", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;ff08::1" }, { MOCK_INTERFACE ";PGM.MCAST.NET;239.192.0.1", /* † */ MOCK_INTERFACE ";IP6-PGM.MCAST.NET;[ff08::1]" }, { MOCK_INTERFACE ";pgm-private", /* ‡ */ MOCK_INTERFACE ";pgm-ip6-private" }, { MOCK_INTERFACE ";pgm-private;pgm-private", /* ‡ */ MOCK_INTERFACE ";pgm-ip6-private;pgm-ip6-private" }, { MOCK_ADDRESS, MOCK_ADDRESS6 }, { MOCK_ADDRESS, "[" MOCK_ADDRESS6 "]" }, { MOCK_ADDRESS ";", MOCK_ADDRESS6 ";" }, { MOCK_ADDRESS ";", "[" MOCK_ADDRESS6 "];" }, { MOCK_ADDRESS ";;", MOCK_ADDRESS6 ";;" }, { MOCK_ADDRESS ";;", "[" MOCK_ADDRESS6 "];;" }, { MOCK_ADDRESS ";239.192.0.1", MOCK_ADDRESS6 ";ff08::1" }, { MOCK_ADDRESS ";239.192.0.1", "[" MOCK_ADDRESS6 "];[ff08::1]" }, { MOCK_ADDRESS ";239.192.0.1;239.192.0.1", MOCK_ADDRESS6 ";ff08::1;ff08::1" }, { MOCK_ADDRESS ";239.192.0.1;239.192.0.1", "[" MOCK_ADDRESS6 "];[ff08::1];[ff08::1]" }, { MOCK_ADDRESS ";PGM.MCAST.NET", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS ";PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS ";PGM.MCAST.NET;PGM.MCAST.NET", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS ";PGM.MCAST.NET;PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS ";239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 ";ff08::1;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS ";239.192.0.1;PGM.MCAST.NET", "[" MOCK_ADDRESS6 "];[ff08::1];IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS ";PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 ";IP6-PGM.MCAST.NET;ff08::1" }, { MOCK_ADDRESS ";PGM.MCAST.NET;239.192.0.1", "[" MOCK_ADDRESS6 "];IP6-PGM.MCAST.NET;[ff08::1]" }, { MOCK_ADDRESS ";pgm-private", MOCK_ADDRESS6 ";pgm-ip6-private" }, { MOCK_ADDRESS ";pgm-private", "[" MOCK_ADDRESS6 "];pgm-ip6-private" }, { MOCK_ADDRESS ";pgm-private;pgm-private", MOCK_ADDRESS6 ";pgm-ip6-private;pgm-ip6-private" }, { MOCK_ADDRESS ";pgm-private;pgm-private", "[" MOCK_ADDRESS6 "];pgm-ip6-private;pgm-ip6-private" }, { MOCK_NETWORK, /* ‡ */ MOCK_NETWORK6 }, { MOCK_NETWORK ";", /* ‡ */ MOCK_NETWORK6 ";" }, { MOCK_NETWORK ";;", /* ‡ */ MOCK_NETWORK6 ";;" }, { MOCK_NETWORK ";239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";ff08::1" }, { MOCK_NETWORK ";239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";[ff08::1]" }, { MOCK_NETWORK ";239.192.0.1;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";ff08::1;ff08::1" }, { MOCK_NETWORK ";239.192.0.1;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";[ff08::1];[ff08::1]" }, { MOCK_NETWORK ";PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET" }, { MOCK_NETWORK ";PGM.MCAST.NET;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { MOCK_NETWORK ";239.192.0.1;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";ff08::1;IP6-PGM.MCAST.NET" }, { MOCK_NETWORK ";239.192.0.1;PGM.MCAST.NET", /* ‡ */ MOCK_NETWORK6 ";[ff08::1];IP6-PGM.MCAST.NET" }, { MOCK_NETWORK ";PGM.MCAST.NET;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;ff08::1" }, { MOCK_NETWORK ";PGM.MCAST.NET;239.192.0.1", /* ‡ */ MOCK_NETWORK6 ";IP6-PGM.MCAST.NET;[ff08::1]" }, { MOCK_NETWORK ";pgm-private", /* ‡ */ MOCK_NETWORK6 ";pgm-ip6-private" }, { MOCK_NETWORK ";pgm-private;pgm-private", /* ‡ */ MOCK_NETWORK6 ";pgm-ip6-private;pgm-ip6-private" }, { MOCK_HOSTNAME, MOCK_HOSTNAME6 }, { MOCK_HOSTNAME ";", MOCK_HOSTNAME6 ";" }, { MOCK_HOSTNAME ";;", MOCK_HOSTNAME6 ";;" }, { MOCK_HOSTNAME ";239.192.0.1", MOCK_HOSTNAME6 ";ff08::1" }, { MOCK_HOSTNAME ";239.192.0.1", MOCK_HOSTNAME6 ";[ff08::1]" }, { MOCK_HOSTNAME ";239.192.0.1;239.192.0.1", MOCK_HOSTNAME6 ";ff08::1;ff08::1" }, { MOCK_HOSTNAME ";239.192.0.1;239.192.0.1", MOCK_HOSTNAME6 ";[ff08::1];[ff08::1]" }, { MOCK_HOSTNAME ";PGM.MCAST.NET", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET" }, { MOCK_HOSTNAME ";PGM.MCAST.NET;PGM.MCAST.NET", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { MOCK_HOSTNAME ";239.192.0.1;PGM.MCAST.NET", MOCK_HOSTNAME6 ";ff08::1;IP6-PGM.MCAST.NET" }, { MOCK_HOSTNAME ";239.192.0.1;PGM.MCAST.NET", MOCK_HOSTNAME6 ";[ff08::1];IP6-PGM.MCAST.NET" }, { MOCK_HOSTNAME ";PGM.MCAST.NET;239.192.0.1", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;ff08::1" }, { MOCK_HOSTNAME ";PGM.MCAST.NET;239.192.0.1", MOCK_HOSTNAME6 ";IP6-PGM.MCAST.NET;[ff08::1]" }, { MOCK_HOSTNAME ";pgm-private", MOCK_HOSTNAME6 ";pgm-ip6-private" }, { MOCK_HOSTNAME ";pgm-private;pgm-private", MOCK_HOSTNAME6 ";pgm-ip6-private;pgm-ip6-private" }, }; START_TEST (test_parse_transport_pass_002) { fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); const char* s = (mock_family == AF_INET6) ? cases_002[_i].ip6 : cases_002[_i].ip4; struct pgm_addrinfo_t hints = { .ai_family = mock_family }, *res = NULL; pgm_error_t* err = NULL; g_message ("%i: test_parse_transport_002(%s, %s%s%s)", _i, (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); /* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and * pgm_if_parse_transport will fail. */ #ifndef CONFIG_HAVE_IP6_NETWORKS if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) { g_message ("IPv6 exception, /etc/networks not supported on this platform."); return; } #endif /* † Multiple scoped IPv6 interfaces match a simple interface name network parameter and so * pgm-if_parse_transport will fail finding multiple matching interfaces */ if (AF_INET6 == mock_family && 0 == strncmp (s, MOCK_INTERFACE, strlen (MOCK_INTERFACE))) { g_message ("IPv6 exception, multiple scoped addresses on one interface"); fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); fail_if (NULL == err, "error not raised"); fail_unless (PGM_ERROR_NOTUNIQ == err->code, "interfaces not found unique"); return; } fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); fail_unless (match_default_interface (mock_family, &res->ai_recv_addrs[0]), "receive address not match default interface"); fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); fail_unless (match_default_interface (mock_family, &res->ai_send_addrs[0]), "send address not match default interface"); } END_TEST /* network to node address in bits, 8-32 * * e.g. 127.0.0.1/16 */ static const struct test_case_t cases_003[] = { { MOCK_ADDRESS "/24", MOCK_ADDRESS6 "/64" }, { MOCK_ADDRESS "/24;", MOCK_ADDRESS6 "/64;" }, { MOCK_ADDRESS "/24;;", MOCK_ADDRESS6 "/64;;" }, { MOCK_ADDRESS "/24;239.192.0.1", MOCK_ADDRESS6 "/64;ff08::1" }, { MOCK_ADDRESS "/24;239.192.0.1", MOCK_ADDRESS6 "/64;[ff08::1]" }, { MOCK_ADDRESS "/24;239.192.0.1;239.192.0.1", MOCK_ADDRESS6 "/64;ff08::1;ff08::1" }, { MOCK_ADDRESS "/24;239.192.0.1;239.192.0.1", MOCK_ADDRESS6 "/64;[ff08::1];[ff08::1]" }, { MOCK_ADDRESS "/24;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS "/24;PGM.MCAST.NET;PGM.MCAST.NET",MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS "/24;239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;ff08::1;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS "/24;239.192.0.1;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;[ff08::1];IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS "/24;PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;ff08::1" }, { MOCK_ADDRESS "/24;PGM.MCAST.NET;239.192.0.1", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;[ff08::1]" }, { MOCK_ADDRESS "/24;PGM.MCAST.NET", MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS "/24;PGM.MCAST.NET;PGM.MCAST.NET",MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;IP6-PGM.MCAST.NET" }, { MOCK_ADDRESS "/24;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private" }, { MOCK_ADDRESS "/24;pgm-private;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;pgm-ip6-private" }, { MOCK_ADDRESS "/24;239.192.0.1;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;ff08::1;pgm-ip6-private" }, { MOCK_ADDRESS "/24;239.192.0.1;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;[ff08::1];pgm-ip6-private" }, { MOCK_ADDRESS "/24;pgm-private;239.192.0.1", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;ff08::1" }, { MOCK_ADDRESS "/24;pgm-private;239.192.0.1", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;[ff08::1]" }, { MOCK_ADDRESS "/24;PGM.MCAST.NET;pgm-private", /* ‡ */ MOCK_ADDRESS6 "/64;IP6-PGM.MCAST.NET;pgm-ip6-private" }, { MOCK_ADDRESS "/24;pgm-private;PGM.MCAST.NET", /* ‡ */ MOCK_ADDRESS6 "/64;pgm-ip6-private;IP6-PGM.MCAST.NET" }, }; START_TEST (test_parse_transport_pass_003) { fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); const char* s = (mock_family == AF_INET6) ? cases_003[_i].ip6 : cases_003[_i].ip4; struct pgm_addrinfo_t hints = { .ai_family = mock_family }, *res = NULL; pgm_error_t* err = NULL; g_message ("%i: test_parse_transport_003(%s, %s%s%s)", _i, (mock_family == AF_INET6) ? "AF_INET6" : ( (mock_family == AF_INET) ? "AF_INET" : "AF_UNSPEC" ), s ? "\"" : "", s ? s : "(null)", s ? "\"" : ""); /* ‡ Linux does not support IPv6 /etc/networks so IPv6 entries appear as 255.255.255.255 and * pgm_if_parse_transport will fail. */ #ifndef CONFIG_HAVE_IP6_NETWORKS if (NULL != strstr (s, MOCK_NETWORK6) || NULL != strstr (s, MOCK_PGM_NETWORK6)) { g_message ("IPv6 exception, /etc/networks not supported on this platform."); return; } #endif gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); if (!retval) { g_message ("pgm_getaddrinfo: %s", (err && err->message) ? err->message : "(null)"); } fail_unless (TRUE == retval, "pgm_getaddrinfo failed"); fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); fail_unless (match_default_group (mock_family, &res->ai_recv_addrs[0]), "receive address not match default group"); fail_unless (match_default_interface (mock_family, &res->ai_recv_addrs[0]), "receive address not match default interface"); fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); fail_unless (match_default_group (mock_family, &res->ai_send_addrs[0]), "send address not match default group"); fail_unless (match_default_interface (mock_family, &res->ai_send_addrs[0]), "send address not match default interface"); } END_TEST /* asymmetric groups */ START_TEST (test_parse_transport_pass_004) { fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); const char* s = (mock_family == AF_INET6) ? ";ff08::1;ff08::2" /* AF_INET */: ";239.192.56.1;239.192.56.2"; struct pgm_addrinfo_t hints = { .ai_family = mock_family }, *res = NULL; pgm_error_t* err = NULL; struct sockaddr_storage addr; fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "get_transport_info failed"); fail_unless (1 == res->ai_recv_addrs_len, "not exactly one receive address"); fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); if (mock_family == AF_INET6) { inet_pton (AF_INET6, "ff08::1", &((struct sockaddr_in6*)&addr)->sin6_addr); ((struct sockaddr*)&addr)->sa_family = mock_family; ((struct sockaddr_in6*)&addr)->sin6_port = 0; ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); inet_pton (AF_INET6, "ff08::2", &((struct sockaddr_in6*)&addr)->sin6_addr); ((struct sockaddr*)&addr)->sa_family = mock_family; ((struct sockaddr_in6*)&addr)->sin6_port = 0; ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); } else { inet_pton (AF_INET, "239.192.56.1", &((struct sockaddr_in*)&addr)->sin_addr); ((struct sockaddr*)&addr)->sa_family = AF_INET; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); inet_pton (AF_INET, "239.192.56.2", &((struct sockaddr_in*)&addr)->sin_addr); ((struct sockaddr*)&addr)->sa_family = AF_INET; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); } fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "source not match"); fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "source not match"); } END_TEST /* multiple receive groups and asymmetric sending */ START_TEST (test_parse_transport_pass_005) { fail_unless (mock_family == AF_UNSPEC || mock_family == AF_INET || mock_family == AF_INET6, "invalid mock address family"); const char* s = (mock_family == AF_INET6) ? ";ff08::1,ff08::2;ff08::3" /* AF_INET */: ";239.192.56.1,239.192.56.2;239.192.56.3"; struct pgm_addrinfo_t hints = { .ai_family = mock_family }, *res = NULL; pgm_error_t* err = NULL; struct sockaddr_storage addr; fail_unless (TRUE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (2 == res->ai_recv_addrs_len, "not exactly one receive address"); fail_unless (1 == res->ai_send_addrs_len, "not exactly one send address"); if (mock_family == AF_INET6) { inet_pton (AF_INET6, "ff08::1", &((struct sockaddr_in6*)&addr)->sin6_addr); ((struct sockaddr*)&addr)->sa_family = mock_family; ((struct sockaddr_in6*)&addr)->sin6_port = 0; ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); inet_pton (AF_INET6, "ff08::2", &((struct sockaddr_in6*)&addr)->sin6_addr); ((struct sockaddr*)&addr)->sa_family = mock_family; ((struct sockaddr_in6*)&addr)->sin6_port = 0; ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[1].gsr_group, (struct sockaddr*)&addr), "group not match"); inet_pton (AF_INET6, "ff08::3", &((struct sockaddr_in6*)&addr)->sin6_addr); ((struct sockaddr*)&addr)->sa_family = mock_family; ((struct sockaddr_in6*)&addr)->sin6_port = 0; ((struct sockaddr_in6*)&addr)->sin6_flowinfo = 0; ((struct sockaddr_in6*)&addr)->sin6_scope_id = 0; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); } else { inet_pton (AF_INET, "239.192.56.1", &((struct sockaddr_in*)&addr)->sin_addr); ((struct sockaddr*)&addr)->sa_family = AF_INET; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); inet_pton (AF_INET, "239.192.56.2", &((struct sockaddr_in*)&addr)->sin_addr); ((struct sockaddr*)&addr)->sa_family = AF_INET; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_recv_addrs[1].gsr_group, (struct sockaddr*)&addr), "group not match"); inet_pton (AF_INET, "239.192.56.3", &((struct sockaddr_in*)&addr)->sin_addr); ((struct sockaddr*)&addr)->sa_family = AF_INET; fail_unless (0 == pgm_sockaddr_cmp ((struct sockaddr*)&res->ai_send_addrs[0].gsr_group, (struct sockaddr*)&addr), "group not match"); } fail_unless (match_default_source (mock_family, &res->ai_recv_addrs[0]), "source not match"); fail_unless (match_default_source (mock_family, &res->ai_send_addrs[0]), "source not match"); } END_TEST /* too many interfaces */ START_TEST (test_parse_transport_fail_001) { const char* s = "eth0,lo;;;"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* invalid characters, or simply just bogus */ START_TEST (test_parse_transport_fail_002) { const char* s = "!@#$%^&*()"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* too many groups */ START_TEST (test_parse_transport_fail_003) { const char* s = ";239.192.0.1,239.192.0.2,239.192.0.3,239.192.0.4,239.192.0.5,239.192.0.6,239.192.0.7,239.192.0.8,239.192.0.9,239.192.0.10,239.192.0.11,239.192.0.12,239.192.0.13,239.192.0.14,239.192.0.15,239.192.0.16,239.192.0.17,239.192.0.18,239.192.0.19,239.192.0.20;239.192.0.21"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* too many receiver groups in asymmetric pairing */ START_TEST (test_parse_transport_fail_004) { const char* s = ";239.192.0.1,239.192.0.2,239.192.0.3,239.192.0.4,239.192.0.5,239.192.0.6,239.192.0.7,239.192.0.8,239.192.0.9,239.192.0.10,239.192.0.11,239.192.0.12,239.192.0.13,239.192.0.14,239.192.0.15,239.192.0.16,239.192.0.17,239.192.0.18,239.192.0.19,239.192.0.20,239.192.0.21;239.192.0.22"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* null string */ START_TEST (test_parse_transport_fail_005) { const char* s = NULL; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* invalid address family */ START_TEST (test_parse_transport_fail_006) { const char* s = ";"; struct pgm_addrinfo_t hints = { .ai_family = AF_IPX }, *res = NULL; pgm_error_t* err = NULL; fail_unless (FALSE == pgm_getaddrinfo (s, &hints, &res, &err), "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* invalid transport info pointer */ START_TEST (test_parse_transport_fail_007) { const char* s = ";"; pgm_error_t* err = NULL; fail_unless (FALSE == pgm_getaddrinfo (s, NULL, NULL, &err), "pgm_getaddrinfo failed"); } END_TEST /* invalid interface */ START_TEST (test_parse_transport_fail_008) { const char* s = "qe0;"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); if (!retval) { g_message ("pgm_getaddrinfo: %s", err ? err->message : "(null)"); } fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* non-existing interface IP address */ START_TEST (test_parse_transport_fail_009) { const char* s = "172.16.90.1;"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); if (!retval) { g_message ("pgm_getaddrinfo: %s", (err && err->message) ? err->message : "(null)"); } fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* non-existing network name address */ START_TEST (test_parse_transport_fail_010) { const char* s = "private2;"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); if (!retval) { g_message ("pgm_getaddrinfo: %s", (err && err->message) ? err->message : "(null)"); } fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* non-existing host name interface */ START_TEST (test_parse_transport_fail_011) { const char* s = "mi-hee.ko.miru.hk;"; struct pgm_addrinfo_t hints = { .ai_family = AF_UNSPEC }, *res = NULL; pgm_error_t* err = NULL; gboolean retval = pgm_getaddrinfo (s, &hints, &res, &err); if (!retval) { g_message ("pgm_getaddrinfo: %s", (err && err->message) ? err->message : "(null)"); } fail_unless (FALSE == retval, "pgm_getaddrinfo failed"); fail_unless (NULL == res, "unexpected result"); } END_TEST /* target: * pgm_if_print_all (void) */ START_TEST (test_print_all_pass_001) { pgm_if_print_all (); } END_TEST /* target: * bool * is_in_net ( * const struct in_addr* addr, -- in host byte order * const struct in_addr* netaddr, * const struct in_addr* netmask * ) */ struct test_case_net_t { const char* addr; const char* netaddr; const char* netmask; const gboolean answer; }; static const struct test_case_net_t cases_004[] = { { "127.0.0.1", "127.0.0.1", "255.0.0.0", TRUE }, { "127.0.0.1", "127.0.0.1", "255.255.0.0", TRUE }, { "127.0.0.1", "127.0.0.1", "255.255.255.0", TRUE }, { "127.0.0.1", "127.0.0.1", "255.255.255.255", TRUE }, { "127.0.0.1", "127.0.0.0", "255.0.0.0", TRUE }, { "127.0.0.1", "127.0.0.0", "255.255.0.0", TRUE }, { "127.0.0.1", "127.0.0.0", "255.255.255.0", TRUE }, { "127.0.0.1", "127.0.0.0", "255.255.255.255", FALSE }, { "172.15.1.1", "172.16.0.0", "255.240.0.0", FALSE }, { "172.16.1.1", "172.16.0.0", "255.240.0.0", TRUE }, { "172.18.1.1", "172.16.0.0", "255.240.0.0", TRUE }, { "172.31.1.1", "172.16.0.0", "255.240.0.0", TRUE }, { "172.32.1.1", "172.16.0.0", "255.240.0.0", FALSE }, }; START_TEST (test_is_in_net_pass_001) { struct in_addr addr, netaddr, netmask; fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].addr, &addr)); fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].netaddr, &netaddr)); fail_unless (pgm_inet_pton (AF_INET, cases_004[_i].netmask, &netmask)); const gboolean answer = cases_004[_i].answer; addr.s_addr = g_ntohl (addr.s_addr); netaddr.s_addr = g_ntohl (netaddr.s_addr); netmask.s_addr = g_ntohl (netmask.s_addr); gboolean result = is_in_net (&addr, &netaddr, &netmask); g_message ("result %s (%s)", result ? "TRUE" : "FALSE", answer ? "TRUE" : "FALSE"); fail_unless (answer == result); } END_TEST static const struct test_case_net_t cases_005[] = { { "::1", "::1", "ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff", TRUE }, { "fe80::203:baff:fe4e:6cc8", "fe80::", "ffff:0000:0000:0000:0000:0000:0000:0000", TRUE }, { "2002:dec8:d28e::36", "2002:dec8:d28e::", "ffff:ffff:ffff:0000:0000:0000:0000:0000", TRUE }, { "2002:dec8:d28e::36", "2002:dafa:939:0::", "ffff:ffff:ffff:ffff:0000:0000:0000:0000", FALSE }, }; START_TEST (test_is_in_net6_pass_001) { struct in6_addr addr, netaddr, netmask; fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].addr, &addr)); fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].netaddr, &netaddr)); fail_unless (pgm_inet_pton (AF_INET6, cases_005[_i].netmask, &netmask)); const gboolean answer = cases_005[_i].answer; gboolean result = is_in_net6 (&addr, &netaddr, &netmask); g_message ("result %s (%s)", result ? "TRUE" : "FALSE", answer ? "TRUE" : "FALSE"); fail_unless (answer == result); } END_TEST static Suite* make_test_suite (void) { Suite* s; s = suite_create (__FILE__); TCase* tc_is_in_net = tcase_create ("is_in_net"); suite_add_tcase (s, tc_is_in_net); tcase_add_checked_fixture (tc_is_in_net, mock_setup_net, mock_teardown_net); tcase_add_checked_fixture (tc_is_in_net, mock_setup_unspec, NULL); tcase_add_loop_test (tc_is_in_net, test_is_in_net_pass_001, 0, G_N_ELEMENTS(cases_004)); TCase* tc_is_in_net6 = tcase_create ("is_in_net6"); suite_add_tcase (s, tc_is_in_net6); tcase_add_checked_fixture (tc_is_in_net6, mock_setup_net, mock_teardown_net); tcase_add_checked_fixture (tc_is_in_net6, mock_setup_unspec, NULL); tcase_add_loop_test (tc_is_in_net6, test_is_in_net6_pass_001, 0, G_N_ELEMENTS(cases_005)); /* three variations of all parse-transport tests, one for each valid * address family value: AF_UNSPEC, AF_INET, AF_INET6. */ /* unspecified address family, ai_family == AF_UNSPEC */ TCase* tc_parse_transport_unspec = tcase_create ("parse_transport/unspec"); suite_add_tcase (s, tc_parse_transport_unspec); tcase_add_checked_fixture (tc_parse_transport_unspec, mock_setup_net, mock_teardown_net); tcase_add_checked_fixture (tc_parse_transport_unspec, mock_setup_unspec, NULL); tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); tcase_add_loop_test (tc_parse_transport_unspec, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_pass_004); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_pass_005); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_001); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_002); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_003); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_004); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_005); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_006); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_007); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_008); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_009); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_010); tcase_add_test (tc_parse_transport_unspec, test_parse_transport_fail_011); /* IP version 4, ai_family = AF_INET */ TCase* tc_parse_transport_ip4 = tcase_create ("parse_transport/af_inet"); suite_add_tcase (s, tc_parse_transport_ip4); tcase_add_checked_fixture (tc_parse_transport_ip4, mock_setup_net, mock_teardown_net); tcase_add_checked_fixture (tc_parse_transport_ip4, mock_setup_ip4, NULL); tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); tcase_add_loop_test (tc_parse_transport_ip4, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); tcase_add_test (tc_parse_transport_ip4, test_parse_transport_pass_004); tcase_add_test (tc_parse_transport_ip4, test_parse_transport_pass_005); /* IP version 6, ai_family = AF_INET6 */ TCase* tc_parse_transport_ip6 = tcase_create ("parse_transport/af_inet6"); suite_add_tcase (s, tc_parse_transport_ip6); tcase_add_checked_fixture (tc_parse_transport_ip6, mock_setup_net, mock_teardown_net); tcase_add_checked_fixture (tc_parse_transport_ip6, mock_setup_ip6, NULL); tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_001, 0, G_N_ELEMENTS(cases_001)); tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_002, 0, G_N_ELEMENTS(cases_002)); tcase_add_loop_test (tc_parse_transport_ip6, test_parse_transport_pass_003, 0, G_N_ELEMENTS(cases_003)); tcase_add_test (tc_parse_transport_ip6, test_parse_transport_pass_004); tcase_add_test (tc_parse_transport_ip6, test_parse_transport_pass_005); TCase* tc_print_all = tcase_create ("print-all"); tcase_add_checked_fixture (tc_print_all, mock_setup_net, mock_teardown_net); suite_add_tcase (s, tc_print_all); tcase_add_test (tc_print_all, test_print_all_pass_001); return s; } static Suite* make_master_suite (void) { Suite* s = suite_create ("Master"); return s; } int main (void) { SRunner* sr = srunner_create (make_master_suite ()); srunner_add_suite (sr, make_test_suite ()); srunner_run_all (sr, CK_ENV); int number_failed = srunner_ntests_failed (sr); srunner_free (sr); return (number_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; } /* eof */