Commit 91dbc8db authored by jehan's avatar jehan

add a function to sort result of bctbx_name_to_addrinfo.

parent ebc3ff55
......@@ -459,6 +459,14 @@ BCTBX_PUBLIC int bctbx_addrinfo_to_printable_ip_address(const struct addrinfo *a
BCTBX_PUBLIC int bctbx_sockaddr_to_ip_address(const struct sockaddr *sa, socklen_t salen, char *ip, size_t ip_size, int *port);
BCTBX_PUBLIC int bctbx_sockaddr_to_printable_ip_address(struct sockaddr *sa, socklen_t salen, char *printable_ip, size_t printable_ip_size);
/** Sort a list of addrinfo with the following rules:
-IPV6 including NAT64.
-V4 MAPPED IPV6.
-V4.
**/
BCTBX_PUBLIC struct addrinfo *bctbx_addrinfo_sort(struct addrinfo *ai);
/**
* Convert a numeric ip address and port into an addrinfo, whose family will be as specified in the first argument.
* If AF_INET6 is requested, the returned addrinfo will always be an IPv6 address, possibly V4MAPPED if the
......
......@@ -1216,6 +1216,48 @@ static void _bctbx_addrinfo_to_ip_address_error(int err, char *ip, size_t ip_siz
strncpy(ip, "<bug!!>", ip_size);
}
struct addrinfo* bctbx_addrinfo_sort(struct addrinfo *ais) {
bctbx_list_t* v6 = NULL;
bctbx_list_t* v4_mapped = NULL;
bctbx_list_t* v4 = NULL;
struct addrinfo* res0 = NULL;
struct addrinfo* res = NULL;
//sort by type
for (struct addrinfo* ai = ais; ai != NULL; ) {
struct addrinfo* next = ai->ai_next;
struct sockaddr_in6 *sock_in6 = (struct sockaddr_in6 *)ai->ai_addr;
if (ai->ai_family == AF_INET6) {
if (IN6_IS_ADDR_V4MAPPED(&sock_in6->sin6_addr)) {
v4_mapped = bctbx_list_prepend(v4_mapped, ai);
} else {
v6 = bctbx_list_prepend(v6, ai);
}
} else {
v4 = bctbx_list_prepend(v4, ai);
}
ai->ai_next = NULL ;
ai = next;
}
v6 = bctbx_list_concat(v6, v4_mapped);
v6 = bctbx_list_concat(v6, v4);
for (bctbx_list_t *it = v6; it != NULL; it = it->next) {
if (res0 == NULL) {
res0 = res = (struct addrinfo*)it->data;
} else {
res->ai_next = (struct addrinfo*)it->data;
res = res->ai_next;
}
}
if (res)
res->ai_next = NULL;
bctbx_list_free(v6);
return res0;
}
int bctbx_addrinfo_to_ip_address(const struct addrinfo *ai, char *ip, size_t ip_size, int *port){
char serv[16];
int err=bctbx_getnameinfo(ai->ai_addr,(socklen_t)ai->ai_addrlen,ip,(socklen_t)ip_size,serv,(socklen_t)sizeof(serv),NI_NUMERICHOST|NI_NUMERICSERV);
......@@ -1279,6 +1321,10 @@ static struct addrinfo * _bctbx_name_to_addrinfo(int family, int socktype, const
bctbx_error("%s(%s): getaddrinfo failed: %s",__FUNCTION__, ipaddress, gai_strerror(err));
return NULL;
}
//sort result
if (res)
res = bctbx_addrinfo_sort(res);
return res;
}
......
......@@ -133,9 +133,51 @@ static void time_functions(void) {
BC_ASSERT_EQUAL(bctbx_time_string_to_sec("15dM12h"), (15*24+12)*3600, uint32_t, "%d");
}
static void bctbx_addrinfo_sort_test(void) {
struct addrinfo * res1 = bctbx_name_to_addrinfo(AF_INET6, SOCK_DGRAM, "sip3.linphone.org", 27256);
struct addrinfo * res2 = bctbx_ip_address_to_addrinfo(AF_INET6, SOCK_DGRAM, "91.121.209.194", 27256);
struct addrinfo * res3 = bctbx_ip_address_to_addrinfo(AF_INET, SOCK_DGRAM, "91.121.209.194", 27256);
bool_t searching_for_v6=TRUE;
char printable_ip[256];
struct addrinfo * res = res3;
for (struct addrinfo * ai=res2 ; ai !=NULL; ai=ai->ai_next) {
if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)(ai->ai_addr))->sin6_addr)) {
res->ai_next=ai;
break;
}
}
res->ai_next->ai_next=res1;
res->ai_next->ai_next->ai_next=NULL;
//So now, res as ipv4 first, then v4 mapped, then v6
for (struct addrinfo * ai=res ; ai !=NULL; ai=ai->ai_next) {
bctbx_addrinfo_to_printable_ip_address(ai, printable_ip, sizeof(printable_ip));
bctbx_message("bctbx_getaddrinfo origin address:%s", printable_ip);
}
//now apply bctbx_addrinfo_sort
for (struct addrinfo * ai=bctbx_addrinfo_sort(res) ; ai !=NULL; ai=ai->ai_next) {
if (ai->ai_family == AF_INET6) {
if (!searching_for_v6) {
BC_ASSERT_FALSE(IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)(ai->ai_addr))->sin6_addr));
}
if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6*)(ai->ai_addr))->sin6_addr)) {
searching_for_v6 = FALSE; // stating from now, all subsequent IP shall be pure V6
}
}
bctbx_addrinfo_to_printable_ip_address(ai, printable_ip, sizeof(printable_ip));
bctbx_message("bctbx_getaddrinfo sorted address:%s", printable_ip);
}
bctbx_freeaddrinfo(res);
}
static test_t utils_tests[] = {
TEST_NO_TAG("Bytes to/from Hexa strings", bytes_to_from_hexa_strings),
TEST_NO_TAG("Time", time_functions)
TEST_NO_TAG("Time", time_functions),
TEST_NO_TAG("Addrinfo sort", bctbx_addrinfo_sort_test)
};
test_suite_t utils_test_suite = {"Utils", NULL, NULL, NULL, NULL,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment