You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
978 lines
28 KiB
978 lines
28 KiB
/* |
|
* Copyright (c) 2015 Fujitsu Ltd. |
|
* Copyright (c) International Business Machines Corp., 2001 |
|
* |
|
* This program is free software: you can redistribute it and/or modify |
|
* it under the terms of the GNU General Public License as published by |
|
* the Free Software Foundation, either version 3 of the License, or |
|
* (at your option) any later version. |
|
* |
|
* This program 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 General Public License for more details. |
|
* |
|
* You should have received a copy of the GNU General Public License |
|
* along with this program. If not, see <http://www.gnu.org/licenses/>. |
|
* |
|
* Author: David L Stevens |
|
*/ |
|
|
|
#include <unistd.h> |
|
#include <errno.h> |
|
|
|
#include <sys/socket.h> |
|
#include <netdb.h> |
|
#include <arpa/inet.h> |
|
|
|
#include "test.h" |
|
|
|
#ifndef AI_V4MAPPED |
|
#define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */ |
|
#endif |
|
|
|
static void setup(void); |
|
static void gaiv4(void); |
|
static void gaiv6(void); |
|
|
|
char *TCID = "getaddrinfo_01"; |
|
int TST_TOTAL = 22; |
|
|
|
int main(int argc, char *argv[]) |
|
{ |
|
int lc; |
|
|
|
tst_parse_opts(argc, argv, NULL, NULL); |
|
|
|
setup(); |
|
|
|
for (lc = 0; TEST_LOOPING(lc); ++lc) { |
|
tst_count = 0; |
|
|
|
gaiv4(); |
|
gaiv6(); |
|
} |
|
|
|
tst_exit(); |
|
} |
|
|
|
static void setup(void) |
|
{ |
|
TEST_PAUSE; |
|
} |
|
|
|
/* getaddrinfo tests (v4) */ |
|
static void gaiv4(void) |
|
{ |
|
struct addrinfo *aires, hints, *pai; |
|
char hostname[MAXHOSTNAMELEN + 1]; |
|
char shortname[MAXHOSTNAMELEN + 1]; |
|
char service[NI_MAXSERV + 1]; |
|
int servnum; |
|
char *p; |
|
|
|
if (gethostname(hostname, sizeof(hostname)) < 0) |
|
tst_brkm(TBROK | TERRNO, NULL, "gethostname failed"); |
|
strncpy(shortname, hostname, MAXHOSTNAMELEN); |
|
shortname[MAXHOSTNAMELEN] = '\0'; |
|
p = strchr(shortname, '.'); |
|
if (p) |
|
*p = '\0'; |
|
|
|
/* test 1, IPv4 basic lookup */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
TEST(getaddrinfo(hostname, 0, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in *psin = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in); |
|
err |= pai->ai_addr == 0; |
|
psin = (struct sockaddr_in *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
err |= psin->sin_family != AF_INET; |
|
err |= psin->sin_port != 0; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 basic lookup: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin, |
|
psin ? psin->sin_family : 0, |
|
psin ? psin->sin_port : 0, |
|
psin ? htons(psin->sin_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 basic lookup"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 basic " |
|
"lookup (\"%s\") returns %ld (\"%s\")", hostname, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 2, IPv4 canonical name */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
hints.ai_flags = AI_CANONNAME; |
|
TEST(getaddrinfo(shortname, 0, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
for (pai = aires; pai; pai = pai->ai_next) |
|
if (pai->ai_canonname) |
|
break; |
|
if (!pai) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 canonical name: no " |
|
"entries with canonical name set"); |
|
freeaddrinfo(aires); |
|
return; |
|
} else if (strcasecmp(hostname, pai->ai_canonname)) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 canonical name " |
|
"(\"%s\") doesn't match hostname (\"%s\")", |
|
pai->ai_canonname, hostname); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 canonical name"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 " |
|
"canonical name (\"%s\") returns %ld (\"%s\")", |
|
shortname, TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 3, IPv4 host+service name */ |
|
memset(&hints, 0, sizeof(hints)); |
|
/* |
|
* These are hard-coded for echo/7 to avoid using getservbyname(), |
|
* since it isn't thread-safe and these tests may be re-used |
|
* multithreaded. Sigh. |
|
*/ |
|
strcpy(service, "echo"); |
|
servnum = 7; |
|
hints.ai_family = AF_INET; |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in *psin = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in); |
|
err |= pai->ai_addr == 0; |
|
psin = (struct sockaddr_in *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
err |= psin->sin_family != AF_INET; |
|
err |= psin->sin_port != htons(servnum); |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 host+service: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin, |
|
psin ? psin->sin_family : 0, |
|
psin ? psin->sin_port : 0, |
|
psin ? htons(psin->sin_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 host+service"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 host+" |
|
"service returns %ld (\"%s\")", TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 4, IPv4 hostname+service, AI_PASSIVE */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
hints.ai_flags = AI_PASSIVE; |
|
hints.ai_socktype = SOCK_STREAM; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in *psin = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in); |
|
err |= pai->ai_addr == 0; |
|
psin = (struct sockaddr_in *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
/* AI_PASSIVE is ignored if hostname is |
|
* non-null; address must be set |
|
*/ |
|
err |= psin->sin_addr.s_addr == 0; |
|
err |= psin->sin_family != AF_INET; |
|
err |= psin->sin_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 host+service, PASSIVE" |
|
": fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin, |
|
psin ? psin->sin_family : 0, |
|
psin ? psin->sin_port : 0, |
|
psin ? htons(psin->sin_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 host+service PASSIVE"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 host+" |
|
"service, PASSIVE (\"%s\", \"%s\") returns %ld (\"%s\")", |
|
hostname, service, TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 5, IPv4 host+service w/ AI_NUMERICHOST */ |
|
memset(&hints, 0, sizeof(hints)); |
|
strcpy(service, "echo"); |
|
servnum = 7; |
|
hints.ai_family = AF_INET; |
|
hints.ai_flags = AI_NUMERICHOST; |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (TEST_RETURN != EAI_NONAME) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 AI_NUMERICHOST w/ hostname: " |
|
"returns %ld expected %d (EAI_NONAME)", |
|
TEST_RETURN, EAI_NONAME); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 AI_NUMERICHOST w/ hostname"); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
|
|
/* test 6, IPv4 0+service, AI_PASSIVE */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
hints.ai_flags = AI_PASSIVE; |
|
hints.ai_socktype = SOCK_STREAM; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in *psin = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in); |
|
err |= pai->ai_addr == 0; |
|
psin = (struct sockaddr_in *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
|
|
/* AI_PASSIVE means addr must be INADDR_ANY */ |
|
err |= psin->sin_addr.s_addr != 0; |
|
err |= psin->sin_family != AF_INET; |
|
err |= psin->sin_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 0+service, PASSIVE:" |
|
" fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin, |
|
psin ? psin->sin_family : 0, |
|
psin ? psin->sin_port : 0, |
|
psin ? htons(psin->sin_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 0+service, PASSIVE"); |
|
freeaddrinfo(aires); |
|
} else { |
|
if (TEST_RETURN == EAI_BADFLAGS) { |
|
tst_resm(TPASS, "getaddrinfo IPv4 0+service," |
|
" PASSIVE (\"\", \"%s\") returns %ld (\"%s\")", |
|
service, TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 0+service," |
|
" PASSIVE (\"\", \"%s\") returns %ld (\"%s\")", |
|
service, TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
} |
|
|
|
/* test 7, IPv4 0+service */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
hints.ai_socktype = SOCK_STREAM; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in *psin = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in); |
|
err |= pai->ai_addr == 0; |
|
psin = (struct sockaddr_in *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
/* hostname not set; addr should be loopback */ |
|
err |= psin->sin_addr.s_addr != |
|
htonl(INADDR_LOOPBACK); |
|
err |= psin->sin_family != AF_INET; |
|
err |= psin->sin_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 0+service: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin, |
|
psin ? psin->sin_family : 0, |
|
psin ? psin->sin_port : 0, |
|
psin ? htons(psin->sin_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 0+service"); |
|
freeaddrinfo(aires); |
|
} else { |
|
if (TEST_RETURN == EAI_BADFLAGS) { |
|
tst_resm(TPASS, "getaddrinfo IPv4 " |
|
"0+service (\"\", \"%s\") returns %ld (\"%s\")", |
|
service, TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 " |
|
"0+service (\"\", \"%s\") returns %ld (\"%s\")", |
|
service, TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
} |
|
|
|
/* test 8, IPv4 host+service, AI_NUMERICSERV */ |
|
#ifndef AI_NUMERICSERV |
|
tst_resm(TCONF, "getaddrinfo IPv4 host+service, AI_NUMERICSERV: flag " |
|
"not implemented"); |
|
#else |
|
memset(&hints, 0, sizeof(hints)); |
|
strcpy(service, "echo"); |
|
servnum = 7; |
|
hints.ai_family = AF_INET; |
|
hints.ai_flags = AI_NUMERICSERV; |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (TEST_RETURN != EAI_NONAME) { |
|
tst_resm(TFAIL, |
|
"getaddrinfo IPv4 host+service, AI_NUMERICSERV: " |
|
"returns %ld (\"%s\") expected %d (EAI_NONAME)", |
|
TEST_RETURN, gai_strerror(TEST_RETURN), EAI_NONAME); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 host+service, AI_NUMERICSERV"); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
#endif /* AI_NUMERICSERV */ |
|
|
|
/* test 9, IPv4 SOCK_STREAM/IPPROTO_UDP hints */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
hints.ai_socktype = SOCK_STREAM; |
|
hints.ai_protocol = IPPROTO_UDP; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 SOCK_STREAM/IPPROTO_UDP " |
|
"hints"); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 SOCK_STREAM/IPPROTO_UDP hints"); |
|
|
|
/* test 10, IPv4 socktype 0, 513 */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
hints.ai_socktype = 0; |
|
strcpy(service, "513"); |
|
servnum = htons(513); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in *psin = 0; |
|
int got_tcp, got_udp; |
|
int err = 0; |
|
|
|
got_tcp = got_udp = 0; |
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in); |
|
err |= pai->ai_addr == 0; |
|
got_tcp |= pai->ai_socktype == SOCK_STREAM; |
|
got_udp |= pai->ai_socktype == SOCK_DGRAM; |
|
psin = (struct sockaddr_in *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
/* hostname not set; addr should be loopback */ |
|
err |= psin->sin_addr.s_addr != |
|
htonl(INADDR_LOOPBACK); |
|
err |= psin->sin_family != AF_INET; |
|
err |= psin->sin_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 socktype 0,513: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin, |
|
psin ? psin->sin_family : 0, |
|
psin ? psin->sin_port : 0, |
|
psin ? htons(psin->sin_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} else if (got_tcp && got_udp) { |
|
tst_resm(TPASS, "getaddrinfo IPv4 socktype 0,513"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 socktype 0,513 TCP %d" |
|
" UDP %d", got_tcp, got_udp); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
} else { |
|
if (TEST_RETURN == EAI_BADFLAGS) { |
|
tst_resm(TPASS, "getaddrinfo IPv4 socktype 0,513" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 socktype 0,513" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
} |
|
|
|
/* test 11, IPv4 AI_V4MAPPED */ |
|
/* AI_V4MAPPED should be ignored because family != AF_INET6 */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET; |
|
hints.ai_flags = AI_V4MAPPED; |
|
TEST(getaddrinfo(hostname, 0, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in *psin = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in); |
|
err |= pai->ai_addr == 0; |
|
psin = (struct sockaddr_in *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
err |= psin->sin_family != AF_INET; |
|
err |= psin->sin_port != 0; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 AI_V4MAPPED: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin, |
|
psin ? psin->sin_family : 0, |
|
psin ? psin->sin_port : 0, |
|
psin ? htons(psin->sin_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv4 AI_V4MAPPED"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv4 " |
|
"AI_V4MAPPED (\"%s\") returns %ld (\"%s\")", hostname, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
} |
|
|
|
/* getaddrinfo tests (v6) */ |
|
static void gaiv6(void) |
|
{ |
|
struct addrinfo *aires, hints, *pai; |
|
char hostname[MAXHOSTNAMELEN + 1]; |
|
char shortname[MAXHOSTNAMELEN + 1]; |
|
char service[NI_MAXSERV + 1]; |
|
int servnum; |
|
char *p; |
|
|
|
if (gethostname(hostname, sizeof(hostname)) < 0) |
|
tst_brkm(TBROK, NULL, "gethostname failed - %s", |
|
strerror(errno)); |
|
strncpy(shortname, hostname, MAXHOSTNAMELEN); |
|
shortname[MAXHOSTNAMELEN] = '\0'; |
|
p = strchr(shortname, '.'); |
|
if (p) |
|
*p = '\0'; |
|
|
|
/* test 12, IPv6 basic lookup */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
TEST(getaddrinfo(hostname, 0, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in6 *psin6 = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET6; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in6); |
|
err |= pai->ai_addr == 0; |
|
psin6 = (struct sockaddr_in6 *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
err |= psin6->sin6_family != AF_INET6; |
|
err |= psin6->sin6_port != 0; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 basic lookup: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin6, |
|
psin6 ? psin6->sin6_family : 0, |
|
psin6 ? psin6->sin6_port : 0, |
|
psin6 ? htons(psin6->sin6_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 basic lookup"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 basic " |
|
"lookup (\"%s\") returns %ld (\"%s\")", hostname, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 13, IPv6 canonical name */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
hints.ai_flags = AI_CANONNAME; |
|
TEST(getaddrinfo(shortname, 0, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
for (pai = aires; pai; pai = pai->ai_next) |
|
if (pai->ai_canonname) |
|
break; |
|
if (!pai) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 canonical name: no " |
|
"entries with canonical name set"); |
|
freeaddrinfo(aires); |
|
return; |
|
} else if (strcasecmp(hostname, pai->ai_canonname)) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 canonical name " |
|
"(\"%s\") doesn't match hostname (\"%s\")", |
|
pai->ai_canonname, hostname); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 canonical name"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 " |
|
"canonical name (\"%s\") returns %ld (\"%s\")", |
|
shortname, TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 14, IPv6 host+service name */ |
|
memset(&hints, 0, sizeof(hints)); |
|
/* |
|
* These are hard-coded for echo/7 to avoid using getservbyname(), |
|
* since it isn't thread-safe and these tests may be re-used |
|
* multithreaded. Sigh. |
|
*/ |
|
strcpy(service, "echo"); |
|
servnum = 7; |
|
hints.ai_family = AF_INET6; |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in6 *psin6 = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET6; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in6); |
|
err |= pai->ai_addr == 0; |
|
psin6 = (struct sockaddr_in6 *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
err |= psin6->sin6_family != AF_INET6; |
|
err |= psin6->sin6_port != htons(servnum); |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 host+service: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin6, |
|
psin6 ? psin6->sin6_family : 0, |
|
psin6 ? psin6->sin6_port : 0, |
|
psin6 ? htons(psin6->sin6_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 host+service"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 host+" |
|
"service returns %ld (\"%s\")", TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 15, IPv6 hostname+service, AI_PASSIVE */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
hints.ai_flags = AI_PASSIVE; |
|
hints.ai_socktype = SOCK_STREAM; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in6 *psin6 = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET6; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in6); |
|
err |= pai->ai_addr == 0; |
|
psin6 = (struct sockaddr_in6 *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
/* AI_PASSIVE is ignored if hostname is |
|
* non-null; address must be set |
|
*/ |
|
err |= memcmp(&psin6->sin6_addr, &in6addr_any, |
|
sizeof(struct in6_addr)) == 0; |
|
err |= psin6->sin6_family != AF_INET6; |
|
err |= psin6->sin6_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 host+service, PASSIVE" |
|
": fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin6, |
|
psin6 ? psin6->sin6_family : 0, |
|
psin6 ? psin6->sin6_port : 0, |
|
psin6 ? htons(psin6->sin6_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 host+service PASSIVE"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 host+" |
|
"service, PASSIVE (\"%s\", \"%s\") returns %ld (\"%s\")", |
|
hostname, service, TEST_RETURN, |
|
gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
|
|
/* test 16, IPv6 host+service w/ AI_NUMERICHOST */ |
|
memset(&hints, 0, sizeof(hints)); |
|
strcpy(service, "echo"); |
|
servnum = 7; |
|
hints.ai_family = AF_INET6; |
|
hints.ai_flags = AI_NUMERICHOST; |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (TEST_RETURN != EAI_NONAME) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 AI_NUMERICHOST w/ hostname: " |
|
"returns %ld expected %d (EAI_NONAME)", |
|
TEST_RETURN, EAI_NONAME); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 AI_NUMERICHOST w/ hostname"); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
|
|
/* test 17, IPv6 0+service, AI_PASSIVE */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
hints.ai_flags = AI_PASSIVE; |
|
hints.ai_socktype = SOCK_STREAM; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in6 *psin6 = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET6; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in6); |
|
err |= pai->ai_addr == 0; |
|
psin6 = (struct sockaddr_in6 *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
|
|
/* AI_PASSIVE means addr must be INADDR_ANY */ |
|
err |= memcmp(&psin6->sin6_addr, &in6addr_any, |
|
sizeof(struct in6_addr)) != 0; |
|
err |= psin6->sin6_family != AF_INET6; |
|
err |= psin6->sin6_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 0+service, PASSIVE:" |
|
" fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin6, |
|
psin6 ? psin6->sin6_family : 0, |
|
psin6 ? psin6->sin6_port : 0, |
|
psin6 ? htons(psin6->sin6_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 0+service, PASSIVE"); |
|
freeaddrinfo(aires); |
|
} else { |
|
if (TEST_RETURN == EAI_BADFLAGS) { |
|
tst_resm(TPASS, "getaddrinfo IPv6 0+service, PASSIVE" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 0+service, PASSIVE" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
} |
|
|
|
/* test 18, IPv6 0+service */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
hints.ai_socktype = SOCK_STREAM; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in6 *psin6 = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET6; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in6); |
|
err |= pai->ai_addr == 0; |
|
psin6 = (struct sockaddr_in6 *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
/* hostname not set; addr should be loopback */ |
|
err |= memcmp(&psin6->sin6_addr, |
|
&in6addr_loopback, |
|
sizeof(struct in6_addr)) != 0; |
|
err |= psin6->sin6_family != AF_INET6; |
|
err |= psin6->sin6_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 0+service: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin6, |
|
psin6 ? psin6->sin6_family : 0, |
|
psin6 ? psin6->sin6_port : 0, |
|
psin6 ? htons(psin6->sin6_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 0+service"); |
|
freeaddrinfo(aires); |
|
} else { |
|
if (TEST_RETURN == EAI_BADFLAGS) { |
|
tst_resm(TPASS, "getaddrinfo IPv6 0+service" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 0+service" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
} |
|
|
|
/* test 19, IPv6 host+service, AI_NUMERICSERV */ |
|
#ifndef AI_NUMERICSERV |
|
tst_resm(TCONF, "getaddrinfo IPv6 host+service, AI_NUMERICSERV: flag " |
|
"not implemented"); |
|
#else |
|
memset(&hints, 0, sizeof(hints)); |
|
strcpy(service, "echo"); |
|
servnum = 7; |
|
hints.ai_family = AF_INET6; |
|
hints.ai_flags = AI_NUMERICSERV; |
|
TEST(getaddrinfo(hostname, service, &hints, &aires)); |
|
if (TEST_RETURN != EAI_NONAME) { |
|
tst_resm(TFAIL, |
|
"getaddrinfo IPv6 host+service, AI_NUMERICSERV: " |
|
"returns %ld (\"%s\") expected %d (EAI_NONAME)", |
|
TEST_RETURN, gai_strerror(TEST_RETURN), EAI_NONAME); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 host+service, AI_NUMERICSERV"); |
|
if (!TEST_RETURN) |
|
freeaddrinfo(aires); |
|
#endif /* AI_NUMERICSERV */ |
|
|
|
/* test 20, IPv6 SOCK_STREAM/IPPROTO_UDP hints */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
hints.ai_socktype = SOCK_STREAM; |
|
hints.ai_protocol = IPPROTO_UDP; |
|
strcpy(service, "9462"); |
|
servnum = htons(9462); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 SOCK_STREAM/IPPROTO_UDP " |
|
"hints"); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 SOCK_STREAM/IPPROTO_UDP hints"); |
|
|
|
/* test 21, IPv6 socktype 0, 513 */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
hints.ai_socktype = 0; |
|
strcpy(service, "513"); |
|
servnum = htons(513); |
|
TEST(getaddrinfo(0, service, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in6 *psin6 = 0; |
|
int got_tcp, got_udp; |
|
int err = 0; |
|
|
|
got_tcp = got_udp = 0; |
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET6; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in6); |
|
err |= pai->ai_addr == 0; |
|
got_tcp |= pai->ai_socktype == SOCK_STREAM; |
|
got_udp |= pai->ai_socktype == SOCK_DGRAM; |
|
psin6 = (struct sockaddr_in6 *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
/* hostname not set; addr should be loopback */ |
|
err |= memcmp(&psin6->sin6_addr, |
|
&in6addr_loopback, |
|
sizeof(struct in6_addr)) != 0; |
|
err |= psin6->sin6_family != AF_INET6; |
|
err |= psin6->sin6_port != servnum; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 socktype 0,513: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin6, |
|
psin6 ? psin6->sin6_family : 0, |
|
psin6 ? psin6->sin6_port : 0, |
|
psin6 ? htons(psin6->sin6_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} else if (got_tcp && got_udp) { |
|
tst_resm(TPASS, "getaddrinfo IPv6 socktype 0,513"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 socktype 0,513 TCP %d" |
|
" UDP %d", got_tcp, got_udp); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
} else { |
|
if (TEST_RETURN == EAI_BADFLAGS) { |
|
tst_resm(TPASS, "getaddrinfo IPv6 socktype 0,513" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 socktype 0,513" |
|
" (\"\", \"%s\") returns %ld (\"%s\")", service, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
} |
|
|
|
/* test 22, IPv6 AI_V4MAPPED */ |
|
memset(&hints, 0, sizeof(hints)); |
|
hints.ai_family = AF_INET6; |
|
hints.ai_flags = AI_V4MAPPED; |
|
TEST(getaddrinfo(hostname, 0, &hints, &aires)); |
|
if (!TEST_RETURN) { |
|
struct sockaddr_in6 *psin6 = 0; |
|
int err = 0; |
|
|
|
for (pai = aires; pai; pai = pai->ai_next) { |
|
err |= pai->ai_family != AF_INET6; |
|
err |= pai->ai_addrlen != sizeof(struct sockaddr_in6); |
|
err |= pai->ai_addr == 0; |
|
psin6 = (struct sockaddr_in6 *)pai->ai_addr; |
|
if (pai->ai_addr) { |
|
err |= psin6->sin6_family != AF_INET6; |
|
err |= psin6->sin6_port != 0; |
|
} |
|
if (err) |
|
break; |
|
} |
|
if (err) { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 AI_V4MAPPED: " |
|
"fam %d alen %d addr 0x%p addr/fam %d " |
|
"addr/port %d H[%d]", |
|
pai->ai_family, pai->ai_addrlen, psin6, |
|
psin6 ? psin6->sin6_family : 0, |
|
psin6 ? psin6->sin6_port : 0, |
|
psin6 ? htons(psin6->sin6_port) : 0); |
|
freeaddrinfo(aires); |
|
return; |
|
} |
|
tst_resm(TPASS, "getaddrinfo IPv6 AI_V4MAPPED"); |
|
freeaddrinfo(aires); |
|
} else { |
|
tst_resm(TFAIL, "getaddrinfo IPv6 " |
|
"AI_V4MAPPED (\"%s\") returns %ld (\"%s\")", hostname, |
|
TEST_RETURN, gai_strerror(TEST_RETURN)); |
|
return; |
|
} |
|
}
|
|
|