diff options
Diffstat (limited to '3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c')
-rw-r--r-- | 3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c | 573 |
1 files changed, 573 insertions, 0 deletions
diff --git a/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c new file mode 100644 index 0000000..a226931 --- /dev/null +++ b/3rdparty/openpgm-svn-r1135/pgm/getnodeaddr_unittest.c @@ -0,0 +1,573 @@ +/* vim:ts=8:sts=8:sw=4:noai:noexpandtab + * + * unit tests for portable function to return the nodes IP address. + * + * 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 */ +#define _BSD_SOURCE 1 + +#include <errno.h> +#include <signal.h> +#include <stdbool.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <unistd.h> + +#include <glib.h> +#include <check.h> + + +/* mock state */ + +struct addrinfo; + +struct mock_host_t { + struct sockaddr_storage address; + char* canonical_hostname; + char* alias; +}; + +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_interfaces = NULL; + +#define MOCK_HOSTNAME "kiku" +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; + +static bool mock_pgm_getifaddrs (struct pgm_ifaddrs_t**, struct pgm_error_t**); +static void mock_pgm_freeifaddrs (struct pgm_ifaddrs_t*); +static int mock_getaddrinfo (const char*, const char*, const struct addrinfo*, struct addrinfo**); +static void mock_freeaddrinfo (struct addrinfo*); +static int mock_gethostname (char*, size_t); +static struct hostent* mock_gethostbyname (const char*); + + +#define pgm_getifaddrs mock_pgm_getifaddrs +#define pgm_freeifaddrs mock_pgm_freeifaddrs +#define getaddrinfo mock_getaddrinfo +#define freeaddrinfo mock_freeaddrinfo +#define gethostname mock_gethostname +#define gethostbyname mock_gethostbyname + + +#define GETNODEADDR_DEBUG +#include "getnodeaddr.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_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_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( "::1", "ip6-localhost", "ip6-loopback"); + + 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"); +} + +/* with broken IPv6 hostname setup */ +static +void +mock_setup_net2 (void) +{ + mock_hostname = mock_kiku; + + APPEND_HOST ( "127.0.0.1", "localhost"); + APPEND_HOST2( "10.6.28.33", "kiku.hk.miru.hk", "kiku"); + APPEND_HOST( "2002:dce8:d28e::33", "ip6-kiku"); + APPEND_HOST2( "::1", "ip6-localhost", "ip6-loopback"); + + 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_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_pkt_offset ( + const bool can_fragment, + const sa_family_t pgmcc_family /* 0 = disable */ + ) +{ + return 0; +} + +static +bool +mock_pgm_getifaddrs ( + struct pgm_ifaddrs_t** ifap, + pgm_error_t** err + ) +{ + if (NULL == ifap) { + return FALSE; + } + + 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 = malloc (n * sizeof(struct pgm_ifaddrs_t)); + memset (ifa, 0, 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; +} + +static +void +mock_pgm_freeifaddrs ( + struct pgm_ifaddrs_t* ifa + ) +{ + g_debug ("mock_freeifaddrs (ifa:%p)", (gpointer)ifa); + free (ifa); +} + +static +struct hostent* +mock_gethostbyname ( + const char* name + ) +{ + static struct hostent he; + static char* aliases[2]; + static char* addr_list[2]; + +/* pre-conditions */ + g_assert (NULL != name); + + g_debug ("mock_gethostbyname (name:%s%s%s)", + name ? "\"" : "", name ? name : "(null)", name ? "\"" : ""); + + GList* 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, name) == 0) || + (host->alias && strcmp (host->alias, name) == 0))) + { + he.h_name = host->canonical_hostname; + aliases[0] = host->alias; + aliases[1] = NULL; + he.h_aliases = aliases; + he.h_addrtype = host_family; + switch (host->address.ss_family){ + case AF_INET: + he.h_length = sizeof (struct in_addr); + addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in, sin_addr); + break; + case AF_INET6: + he.h_length = sizeof (struct in6_addr); + addr_list[0] = (char*)&host->address + G_STRUCT_OFFSET(struct sockaddr_in6, sin6_addr); + break; + default: + g_assert_not_reached(); + } + addr_list[1] = NULL; + he.h_addr_list = addr_list; + return &he; + } + list = list->next; + } + h_errno = HOST_NOT_FOUND; + return NULL; +} + +static +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_debug ("mock_getaddrinfo (node:\"%s\" service:%s hints:%p res:%p)", + node ? node : "(null)", + service ? service : "(null)", + (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; +} + +static +void +mock_freeaddrinfo ( + struct addrinfo* res + ) +{ + g_assert (NULL != res); + g_debug ("mock_freeaddrinfo (res:%p)", (gpointer)res); + free (res); +} + +static +int +mock_gethostname ( + char* name, + size_t len + ) +{ + g_debug ("mock_gethostname (name:%p len:%d)", + (gpointer)name, 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; +} + + +/* target: + * bool + * pgm_if_getnodeaddr ( + * const sa_family_t family, + * struct sockaddr* addr, + * const socklen_t cnt, + * pgm_error_t** error + * ) + */ + +START_TEST (test_getnodeaddr_pass_001) +{ + struct sockaddr_storage addr; + char saddr[INET6_ADDRSTRLEN]; + pgm_error_t* err = NULL; + gboolean success = pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), &err); + if (!success && err) { + g_error ("Resolving node address with AF_UNSPEC: %s", (err && err->message) ? err->message : "(null)"); + } + fail_unless (TRUE == success, "getnodeaddr failed"); + fail_unless (NULL == err, "error raised"); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("AF_UNSPEC:%s", saddr ? saddr : "(null)"); + fail_unless (TRUE == pgm_if_getnodeaddr (AF_INET, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed"); + fail_unless (NULL == err, "error raised"); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("AF_INET:%s", saddr ? saddr : "(null)"); + fail_unless (TRUE == pgm_if_getnodeaddr (AF_INET6, (struct sockaddr*)&addr, sizeof(addr), &err), "getnodeaddr failed"); + fail_unless (NULL == err, "error raised"); + pgm_sockaddr_ntop ((struct sockaddr*)&addr, saddr, sizeof(saddr)); + g_message ("AF_INET6:%s", saddr ? saddr : "(null)"); +} +END_TEST + +START_TEST (test_getnodeaddr_fail_001) +{ + pgm_error_t* err = NULL; + fail_unless (FALSE == pgm_if_getnodeaddr (AF_UNSPEC, NULL, 0, &err), "getnodeaddr failed"); +} +END_TEST + + +static +Suite* +make_test_suite (void) +{ + Suite* s; + +{ + mock_setup_net(); + + struct sockaddr_storage addr; + char saddr[INET6_ADDRSTRLEN]; + pgm_error_t* err = NULL; + gboolean success = pgm_if_getnodeaddr (AF_UNSPEC, (struct sockaddr*)&addr, sizeof(addr), &err); + if (!success && err) { + g_error ("Resolving node address with AF_UNSPEC: %s", (err && err->message) ? err->message : "(null)"); + } +} + s = suite_create (__FILE__); + + TCase* tc_getnodeaddr = tcase_create ("getnodeaddr"); + suite_add_tcase (s, tc_getnodeaddr); + tcase_add_checked_fixture (tc_getnodeaddr, mock_setup_net, mock_teardown_net); + tcase_add_test (tc_getnodeaddr, test_getnodeaddr_pass_001); + tcase_add_test (tc_getnodeaddr, test_getnodeaddr_fail_001); + + TCase* tc_getnodeaddr2 = tcase_create ("getnodeaddr/2"); + suite_add_tcase (s, tc_getnodeaddr2); + tcase_add_checked_fixture (tc_getnodeaddr2, mock_setup_net2, mock_teardown_net); + tcase_add_test (tc_getnodeaddr2, test_getnodeaddr_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 */ |