create the getaddrinfo and getnameinfo library functions and friends
This commit is contained in:
parent
24964aa706
commit
a5a2073680
15 changed files with 1262 additions and 14 deletions
|
@ -386,7 +386,7 @@ static udpport_t portbyname(const char *name)
|
||||||
return se->s_port;
|
return se->s_port;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int send(network_t *np, void *data, size_t len)
|
static int sendpacket(network_t *np, void *data, size_t len)
|
||||||
{
|
{
|
||||||
/* Send out a packet using a filedescriptor that is probably in async mode,
|
/* Send out a packet using a filedescriptor that is probably in async mode,
|
||||||
* so first dup() a sync version, then write. Return true on success.
|
* so first dup() a sync version, then write. Return true on success.
|
||||||
|
@ -957,7 +957,8 @@ int main(int argc, char **argv)
|
||||||
if (!(np->flags & NF_BOUND)) {
|
if (!(np->flags & NF_BOUND)) {
|
||||||
/* Rebind over Ethernet. */
|
/* Rebind over Ethernet. */
|
||||||
udp2ether(bp, np);
|
udp2ether(bp, np);
|
||||||
if (send(np, bp->eth, sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
|
if (sendpacket(np, bp->eth,
|
||||||
|
sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
|
||||||
+ sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
|
+ sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
|
||||||
if (debug >= 1) {
|
if (debug >= 1) {
|
||||||
printf("%s: Broadcast DHCP %s\n",
|
printf("%s: Broadcast DHCP %s\n",
|
||||||
|
@ -967,7 +968,7 @@ int main(int argc, char **argv)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/* Renew over UDP. */
|
/* Renew over UDP. */
|
||||||
if (send(np, bp->udpio, sizeof(udp_io_hdr_t)
|
if (sendpacket(np, bp->udpio, sizeof(udp_io_hdr_t)
|
||||||
+ sizeof(dhcp_t))) {
|
+ sizeof(dhcp_t))) {
|
||||||
if (debug >= 1) {
|
if (debug >= 1) {
|
||||||
printf("%s: Sent DHCP %s to %s\n",
|
printf("%s: Sent DHCP %s to %s\n",
|
||||||
|
@ -1123,7 +1124,7 @@ int main(int argc, char **argv)
|
||||||
* is in use already.
|
* is in use already.
|
||||||
*/
|
*/
|
||||||
make_arp(bp, np);
|
make_arp(bp, np);
|
||||||
if (send(np, bp->eth, sizeof(arp46_t))) {
|
if (sendpacket(np, bp->eth, sizeof(arp46_t))) {
|
||||||
if (debug >= 2) {
|
if (debug >= 2) {
|
||||||
printf("Sent ARP for %s\n", inet_ntoa(np->ip));
|
printf("Sent ARP for %s\n", inet_ntoa(np->ip));
|
||||||
}
|
}
|
||||||
|
@ -1191,7 +1192,8 @@ int main(int argc, char **argv)
|
||||||
bp->udpio->uih_data_len= sizeof(dhcp_t);
|
bp->udpio->uih_data_len= sizeof(dhcp_t);
|
||||||
udp2ether(bp, np);
|
udp2ether(bp, np);
|
||||||
|
|
||||||
if (send(np, bp->eth, sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
|
if (sendpacket(np, bp->eth,
|
||||||
|
sizeof(eth_hdr_t) + sizeof(ip_hdr_t)
|
||||||
+ sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
|
+ sizeof(udp_hdr_t) + sizeof(dhcp_t))) {
|
||||||
if (debug >= 1) {
|
if (debug >= 1) {
|
||||||
printf("%s: Broadcast DHCP %s\n",
|
printf("%s: Broadcast DHCP %s\n",
|
||||||
|
@ -1255,7 +1257,7 @@ int main(int argc, char **argv)
|
||||||
* by DHCP to my own interface.
|
* by DHCP to my own interface.
|
||||||
*/
|
*/
|
||||||
icmp_advert(bp, np);
|
icmp_advert(bp, np);
|
||||||
if (send(np, bp->ip, sizeof(ip_hdr_t) + 16)) {
|
if (sendpacket(np, bp->ip, sizeof(ip_hdr_t) + 16)) {
|
||||||
if (debug >= 2) {
|
if (debug >= 2) {
|
||||||
printf("%s: Sent advert for %s to self\n",
|
printf("%s: Sent advert for %s to self\n",
|
||||||
np->fdp->device, inet_ntoa(np->gateway));
|
np->fdp->device, inet_ntoa(np->gateway));
|
||||||
|
@ -1267,7 +1269,7 @@ int main(int argc, char **argv)
|
||||||
if (np->sol_ct >= 0 && --np->sol_ct >= 0) {
|
if (np->sol_ct >= 0 && --np->sol_ct >= 0) {
|
||||||
/* Send a router solicitation. */
|
/* Send a router solicitation. */
|
||||||
icmp_solicit(bp);
|
icmp_solicit(bp);
|
||||||
if (send(np, bp->ip, sizeof(*bp->ip) + 8)) {
|
if (sendpacket(np, bp->ip, sizeof(*bp->ip) + 8)) {
|
||||||
if (debug >= 2) {
|
if (debug >= 2) {
|
||||||
printf("%s: Broadcast router solicitation\n",
|
printf("%s: Broadcast router solicitation\n",
|
||||||
np->fdp->device);
|
np->fdp->device);
|
||||||
|
@ -1365,7 +1367,7 @@ int main(int argc, char **argv)
|
||||||
/* Can we do something with this DHCP packet? */
|
/* Can we do something with this DHCP packet? */
|
||||||
if ((r= servdhcp(np, bp, r)) > 0) {
|
if ((r= servdhcp(np, bp, r)) > 0) {
|
||||||
/* Yes, we have something to send somewhere. */
|
/* Yes, we have something to send somewhere. */
|
||||||
if (send(np, bp->udpio, r)) {
|
if (sendpacket(np, bp->udpio, r)) {
|
||||||
if (debug >= 1) {
|
if (debug >= 1) {
|
||||||
printf("%s: Sent DHCP packet to %s\n",
|
printf("%s: Sent DHCP packet to %s\n",
|
||||||
np->fdp->device,
|
np->fdp->device,
|
||||||
|
|
|
@ -9,6 +9,7 @@ Created: June 1995 by Philip Homburg <philip@f-mnx.phicoh.com>
|
||||||
|
|
||||||
#include <inet/inet.h>
|
#include <inet/inet.h>
|
||||||
#undef printf
|
#undef printf
|
||||||
|
#undef send
|
||||||
|
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
|
@ -9,6 +9,7 @@ Created: March 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
|
||||||
|
|
||||||
#include <inet/inet.h>
|
#include <inet/inet.h>
|
||||||
#undef printf
|
#undef printf
|
||||||
|
#undef send
|
||||||
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
|
|
@ -1,4 +1,7 @@
|
||||||
/* net.h Copyright 2000 by Michael Temari All Rights Reserved */
|
/* net.h Copyright 2000 by Michael Temari All Rights Reserved */
|
||||||
/* 04/05/2000 Michael Temari <Michael@TemWare.Com> */
|
/* 04/05/2000 Michael Temari <Michael@TemWare.Com> */
|
||||||
|
|
||||||
|
/* avoid clash with POSIX connect */
|
||||||
|
#define connect _connect
|
||||||
_PROTOTYPE(int connect, (char *host, int port));
|
_PROTOTYPE(int connect, (char *host, int port));
|
||||||
|
|
||||||
|
|
|
@ -35,4 +35,9 @@ _PROTOTYPE( uint16_t ntohs, (uint16_t _netval) );
|
||||||
_PROTOTYPE( int inet_aton, (const char *_cp, struct in_addr *_pin) );
|
_PROTOTYPE( int inet_aton, (const char *_cp, struct in_addr *_pin) );
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
in_addr_t inet_addr(const char *cp);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* _ARPA__INET_H */
|
#endif /* _ARPA__INET_H */
|
||||||
|
|
||||||
|
|
|
@ -125,4 +125,74 @@ int servxcheck _ARGS((unsigned long _peer, const char *_service,
|
||||||
char *servxfile _ARGS((const char *_file));
|
char *servxfile _ARGS((const char *_file));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The definitions below are based on
|
||||||
|
* http://www.opengroup.org/onlinepubs/009695399/basedefs/netdb.h.html
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef _POSIX_SOURCE
|
||||||
|
|
||||||
|
/* headers exposed by netdb.h */
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
|
||||||
|
/* struct for use with getaddrinfo() */
|
||||||
|
struct addrinfo
|
||||||
|
{
|
||||||
|
int ai_flags; /* Input flags */
|
||||||
|
int ai_family; /* Address family of socket */
|
||||||
|
int ai_socktype; /* Socket type */
|
||||||
|
int ai_protocol; /* Protocol of socket */
|
||||||
|
socklen_t ai_addrlen; /* Length of socket address */
|
||||||
|
struct sockaddr *ai_addr; /* Socket address of socket */
|
||||||
|
char *ai_canonname; /* Canonical name of service location */
|
||||||
|
struct addrinfo *ai_next; /* Pointer to next in list */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* values for struct addrinfo.ai_flags */
|
||||||
|
#define AI_PASSIVE 0x00000001
|
||||||
|
#define AI_CANONNAME 0x00000002
|
||||||
|
#define AI_NUMERICHOST 0x00000004
|
||||||
|
#define AI_NUMERICSERV 0x00000008
|
||||||
|
/*
|
||||||
|
#define AI_V4MAPPED 0x00000010
|
||||||
|
#define AI_ALL 0x00000020
|
||||||
|
#define AI_ADDRCONFIG 0x00000040
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* flags for getnameinfo() */
|
||||||
|
/* #define NI_NOFQDN 0x00000001 */
|
||||||
|
#define NI_NUMERICHOST 0x00000002
|
||||||
|
#define NI_NAMEREQD 0x00000004
|
||||||
|
#define NI_NUMERICSERV 0x00000008
|
||||||
|
/* #define NI_NUMERICSCOPE 0x00000010 */
|
||||||
|
#define NI_DGRAM 0x00000020
|
||||||
|
|
||||||
|
/* error values for getaddrinfo() and getnameinfo() */
|
||||||
|
#define EAI_AGAIN 1
|
||||||
|
#define EAI_BADFLAGS 2
|
||||||
|
#define EAI_FAIL 3
|
||||||
|
#define EAI_FAMILY 4
|
||||||
|
#define EAI_MEMORY 5
|
||||||
|
#define EAI_NONAME 6
|
||||||
|
#define EAI_SERVICE 7
|
||||||
|
#define EAI_SOCKTYPE 8
|
||||||
|
#define EAI_SYSTEM 9
|
||||||
|
#define EAI_OVERFLOW 10
|
||||||
|
|
||||||
|
/* getaddrinfo() and friends */
|
||||||
|
void freeaddrinfo(struct addrinfo *ai);
|
||||||
|
int getaddrinfo(const char *nodename,
|
||||||
|
const char *servname,
|
||||||
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res);
|
||||||
|
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||||
|
char *node, socklen_t nodelen, char *service,
|
||||||
|
socklen_t servicelen, int flags);
|
||||||
|
const char *gai_strerror(int ecode);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* !_NETDB_H_ */
|
#endif /* !_NETDB_H_ */
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ LIBRARIES=libc
|
||||||
|
|
||||||
libc_FILES=" \
|
libc_FILES=" \
|
||||||
accept.c \
|
accept.c \
|
||||||
|
addrinfo.c \
|
||||||
bind.c \
|
bind.c \
|
||||||
connect.c \
|
connect.c \
|
||||||
dhcp_gettag.c \
|
dhcp_gettag.c \
|
||||||
|
@ -18,6 +19,7 @@ libc_FILES=" \
|
||||||
ethere2a.c \
|
ethere2a.c \
|
||||||
etherh2n.c \
|
etherh2n.c \
|
||||||
ethern2h.c \
|
ethern2h.c \
|
||||||
|
gai_strerror.c \
|
||||||
getdomain.c \
|
getdomain.c \
|
||||||
gethnmadr.c \
|
gethnmadr.c \
|
||||||
gethostent.c \
|
gethostent.c \
|
||||||
|
@ -41,6 +43,7 @@ libc_FILES=" \
|
||||||
inet_ntoa.c \
|
inet_ntoa.c \
|
||||||
listen.c \
|
listen.c \
|
||||||
memcspn.c \
|
memcspn.c \
|
||||||
|
nameinfo.c \
|
||||||
oneC_sum.c \
|
oneC_sum.c \
|
||||||
rcmd.c \
|
rcmd.c \
|
||||||
recv.c \
|
recv.c \
|
||||||
|
|
322
lib/ip/addrinfo.c
Executable file
322
lib/ip/addrinfo.c
Executable file
|
@ -0,0 +1,322 @@
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getaddrinfo and freeaddrinfo are based on
|
||||||
|
* http://www.opengroup.org/onlinepubs/009695399/functions/getaddrinfo.html
|
||||||
|
*/
|
||||||
|
void freeaddrinfo(struct addrinfo *ai)
|
||||||
|
{
|
||||||
|
struct addrinfo *next;
|
||||||
|
|
||||||
|
while (ai)
|
||||||
|
{
|
||||||
|
/* preserve next pointer */
|
||||||
|
next = ai->ai_next;
|
||||||
|
|
||||||
|
/* free each member of the struct and the struct itself */
|
||||||
|
if (ai->ai_addr) free(ai->ai_addr);
|
||||||
|
if (ai->ai_canonname) free(ai->ai_canonname);
|
||||||
|
free(ai);
|
||||||
|
|
||||||
|
/* continue to free the next element of the linked list */
|
||||||
|
ai = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getaddrinfo_parse_hints(
|
||||||
|
const struct addrinfo *hints,
|
||||||
|
int *flags,
|
||||||
|
int *socktype,
|
||||||
|
int *protocol)
|
||||||
|
{
|
||||||
|
assert(flags);
|
||||||
|
assert(socktype);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* if hints is not specified, no flags are specified and all
|
||||||
|
* socktypes must be returned
|
||||||
|
*/
|
||||||
|
if (!hints)
|
||||||
|
{
|
||||||
|
*flags = 0;
|
||||||
|
*socktype = 0;
|
||||||
|
*protocol = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check hints correctness */
|
||||||
|
if (hints->ai_addrlen || hints->ai_addr ||
|
||||||
|
hints->ai_canonname || hints->ai_next)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return EAI_SYSTEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check flags */
|
||||||
|
*flags = hints->ai_flags;
|
||||||
|
if (*flags & ~(AI_PASSIVE | AI_CANONNAME |
|
||||||
|
AI_NUMERICHOST | AI_NUMERICSERV))
|
||||||
|
return EAI_BADFLAGS;
|
||||||
|
|
||||||
|
/* only support IPv4 */
|
||||||
|
if (hints->ai_family != AF_UNSPEC && hints->ai_family != AF_INET)
|
||||||
|
return EAI_FAMILY;
|
||||||
|
|
||||||
|
/* only support SOCK_STREAM and SOCK_DGRAM */
|
||||||
|
*socktype = hints->ai_socktype;
|
||||||
|
switch (*socktype)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
case SOCK_STREAM:
|
||||||
|
case SOCK_DGRAM: break;
|
||||||
|
default: return EAI_SOCKTYPE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* get protocol */
|
||||||
|
*protocol = hints->ai_protocol;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getaddrinfo_resolve_hostname(
|
||||||
|
const char *nodename,
|
||||||
|
int flags,
|
||||||
|
char ***addr_list,
|
||||||
|
const char **canonname)
|
||||||
|
{
|
||||||
|
static struct in_addr addr;
|
||||||
|
static char *addr_array[2];
|
||||||
|
struct hostent *hostent;
|
||||||
|
|
||||||
|
assert(addr_list);
|
||||||
|
assert(canonname);
|
||||||
|
|
||||||
|
/* if no hostname is specified, use local address */
|
||||||
|
if (!nodename)
|
||||||
|
{
|
||||||
|
if ((flags & AI_PASSIVE) == AI_PASSIVE)
|
||||||
|
addr.s_addr = htonl(INADDR_ANY);
|
||||||
|
else
|
||||||
|
addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||||
|
|
||||||
|
addr_array[0] = (char *) &addr;
|
||||||
|
addr_array[1] = NULL;
|
||||||
|
*addr_list = addr_array;
|
||||||
|
*canonname = "localhost";
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*nodename)
|
||||||
|
return EAI_NONAME;
|
||||||
|
|
||||||
|
/* convert literal IP address */
|
||||||
|
addr.s_addr = inet_addr(nodename);
|
||||||
|
if (addr.s_addr != (in_addr_t) -1)
|
||||||
|
{
|
||||||
|
addr_array[0] = (char *) &addr;
|
||||||
|
addr_array[1] = NULL;
|
||||||
|
*addr_list = addr_array;
|
||||||
|
*canonname = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AI_NUMERICHOST avoids DNS lookup */
|
||||||
|
if ((flags & AI_NUMERICHOST) == AI_NUMERICHOST)
|
||||||
|
return EAI_NONAME;
|
||||||
|
|
||||||
|
/* attempt DNS lookup */
|
||||||
|
hostent = gethostbyname(nodename);
|
||||||
|
if (!hostent)
|
||||||
|
switch(h_errno)
|
||||||
|
{
|
||||||
|
case HOST_NOT_FOUND: return EAI_NONAME;
|
||||||
|
case NO_DATA: return EAI_FAIL;
|
||||||
|
case NO_RECOVERY: return EAI_FAIL;
|
||||||
|
case TRY_AGAIN: return EAI_AGAIN;
|
||||||
|
default: assert(0); return EAI_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* assumption: only IPv4 addresses returned */
|
||||||
|
assert(hostent->h_addrtype == AF_INET);
|
||||||
|
assert(hostent->h_length == sizeof(addr));
|
||||||
|
*addr_list = hostent->h_addr_list;
|
||||||
|
*canonname = hostent->h_name;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getaddrinfo_resolve_servname(
|
||||||
|
const char *servname,
|
||||||
|
int flags,
|
||||||
|
int socktype,
|
||||||
|
unsigned short *port,
|
||||||
|
int *protocol)
|
||||||
|
{
|
||||||
|
char *endptr;
|
||||||
|
long port_long;
|
||||||
|
struct protoent *protoent;
|
||||||
|
struct servent *servent;
|
||||||
|
|
||||||
|
assert(port);
|
||||||
|
assert(protocol);
|
||||||
|
|
||||||
|
/* if not specified, set port and protocol to zero */
|
||||||
|
if (!servname)
|
||||||
|
{
|
||||||
|
*port = 0;
|
||||||
|
*protocol = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!*servname)
|
||||||
|
return EAI_SERVICE;
|
||||||
|
|
||||||
|
/* try to parse port number */
|
||||||
|
port_long = strtol(servname, &endptr, 0);
|
||||||
|
if (!*endptr)
|
||||||
|
{
|
||||||
|
/* check whether port is within range */
|
||||||
|
if (port_long < 0 || port_long > (unsigned short) ~0)
|
||||||
|
return EAI_SERVICE;
|
||||||
|
|
||||||
|
*port = htons(port_long);
|
||||||
|
*protocol = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* AI_NUMERICSERV avoids lookup */
|
||||||
|
if ((flags & AI_NUMERICSERV) == AI_NUMERICSERV)
|
||||||
|
return EAI_SERVICE;
|
||||||
|
|
||||||
|
/* look up port number */
|
||||||
|
servent = getservbyname(servname,
|
||||||
|
(socktype == SOCK_STREAM) ? "tcp" : "udp");
|
||||||
|
if (!servent)
|
||||||
|
return EAI_SERVICE;
|
||||||
|
|
||||||
|
*port = servent->s_port;
|
||||||
|
|
||||||
|
/* determine protocol number */
|
||||||
|
protoent = getprotobyname(servent->s_proto);
|
||||||
|
*protocol = protoent ? protoent->p_proto : 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getaddrinfo(
|
||||||
|
const char *nodename,
|
||||||
|
const char *servname,
|
||||||
|
const struct addrinfo *hints,
|
||||||
|
struct addrinfo **res)
|
||||||
|
{
|
||||||
|
struct addrinfo *addrinfo, **addrinfo_p;
|
||||||
|
char **addr_list;
|
||||||
|
const char *canonname;
|
||||||
|
int flags, i, protocol, protocol_spec, r, result;
|
||||||
|
unsigned short port;
|
||||||
|
struct sockaddr_in *sockaddr;
|
||||||
|
int socktype, socktype_spec;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following flags are supported:
|
||||||
|
* - AI_CANONNAME
|
||||||
|
* - AI_PASSIVE
|
||||||
|
* - AI_NUMERICHOST
|
||||||
|
* - AI_NUMERICSERV
|
||||||
|
*
|
||||||
|
* The following flags not supported due to lack of IPv6 support:
|
||||||
|
* - AI_ADDRCONFIG
|
||||||
|
* - AI_ALL
|
||||||
|
* - AI_V4MAPPED
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* check arguments */
|
||||||
|
if ((!nodename && !servname) || !res)
|
||||||
|
return EAI_NONAME;
|
||||||
|
|
||||||
|
/* parse hints */
|
||||||
|
if ((r = getaddrinfo_parse_hints(hints, &flags, &socktype_spec, &protocol_spec)))
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* resolve hostname */
|
||||||
|
if ((r = getaddrinfo_resolve_hostname(nodename, flags, &addr_list, &canonname)))
|
||||||
|
return r;
|
||||||
|
|
||||||
|
/* return a result record for each address */
|
||||||
|
addrinfo_p = res;
|
||||||
|
*addrinfo_p = NULL;
|
||||||
|
result = EAI_NONAME;
|
||||||
|
while (*addr_list)
|
||||||
|
{
|
||||||
|
/* return a result record for each socktype */
|
||||||
|
for (i = 0; i < 2; i++)
|
||||||
|
{
|
||||||
|
/* should current socktype be selected? */
|
||||||
|
socktype = (i == 0) ? SOCK_STREAM : SOCK_DGRAM;
|
||||||
|
if (socktype_spec != 0 && socktype_spec != socktype)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* resolve port */
|
||||||
|
if ((r = getaddrinfo_resolve_servname(servname, flags, socktype, &port, &protocol)))
|
||||||
|
{
|
||||||
|
freeaddrinfo(*res);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enforce matching protocol */
|
||||||
|
if (!protocol)
|
||||||
|
protocol = protocol_spec;
|
||||||
|
else if (protocol_spec && protocol != protocol_spec)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* allocate result */
|
||||||
|
*addrinfo_p = addrinfo = (struct addrinfo *) calloc(1, sizeof(struct addrinfo));
|
||||||
|
if (!addrinfo)
|
||||||
|
{
|
||||||
|
freeaddrinfo(*res);
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
sockaddr = (struct sockaddr_in *) calloc(1, sizeof(struct sockaddr_in));
|
||||||
|
if (!sockaddr)
|
||||||
|
{
|
||||||
|
freeaddrinfo(*res);
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* provide information in result */
|
||||||
|
addrinfo->ai_family = AF_INET;
|
||||||
|
addrinfo->ai_socktype = socktype;
|
||||||
|
addrinfo->ai_protocol = protocol;
|
||||||
|
addrinfo->ai_addrlen = sizeof(*sockaddr);
|
||||||
|
addrinfo->ai_addr = (struct sockaddr *) sockaddr;
|
||||||
|
sockaddr->sin_family = AF_INET;
|
||||||
|
sockaddr->sin_port = port;
|
||||||
|
memcpy(&sockaddr->sin_addr, *addr_list, sizeof(sockaddr->sin_addr));
|
||||||
|
if (((flags & AI_CANONNAME) == AI_CANONNAME) && canonname)
|
||||||
|
{
|
||||||
|
addrinfo->ai_canonname = strdup(canonname);
|
||||||
|
if (!addrinfo->ai_canonname)
|
||||||
|
{
|
||||||
|
freeaddrinfo(*res);
|
||||||
|
return EAI_MEMORY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result = 0;
|
||||||
|
|
||||||
|
/* chain next result to the current one */
|
||||||
|
addrinfo_p = &addrinfo->ai_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* move on to next address */
|
||||||
|
addr_list++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* found anything meaningful? */
|
||||||
|
return result;
|
||||||
|
}
|
64
lib/ip/gai_strerror.c
Executable file
64
lib/ip/gai_strerror.c
Executable file
|
@ -0,0 +1,64 @@
|
||||||
|
#include <errno.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* gai_strerror is based on
|
||||||
|
* http://www.opengroup.org/onlinepubs/009695399/functions/gai_strerror.html
|
||||||
|
*/
|
||||||
|
const char *gai_strerror(int ecode)
|
||||||
|
{
|
||||||
|
static char buffer[256];
|
||||||
|
|
||||||
|
/* check for each known error code */
|
||||||
|
switch (ecode)
|
||||||
|
{
|
||||||
|
case EAI_AGAIN:
|
||||||
|
return "The name could not be resolved at this time";
|
||||||
|
|
||||||
|
case EAI_BADFLAGS:
|
||||||
|
return "The flags had an invalid value";
|
||||||
|
|
||||||
|
case EAI_FAIL:
|
||||||
|
return "A non-recoverable error occurred";
|
||||||
|
|
||||||
|
case EAI_FAMILY:
|
||||||
|
return "The address family was not recognized or the "
|
||||||
|
"address length was invalid for the specified "
|
||||||
|
"family";
|
||||||
|
|
||||||
|
case EAI_MEMORY:
|
||||||
|
return "There was a memory allocation failure";
|
||||||
|
|
||||||
|
case EAI_NONAME:
|
||||||
|
return "The name does not resolve for the supplied "
|
||||||
|
"parameters, NI_NAMEREQD is set and the host's "
|
||||||
|
"name cannot be located, or both nodename and "
|
||||||
|
"servname were null";
|
||||||
|
|
||||||
|
case EAI_SERVICE:
|
||||||
|
return "The service passed was not recognized for the "
|
||||||
|
"specified socket type";
|
||||||
|
|
||||||
|
case EAI_SOCKTYPE:
|
||||||
|
return "The intended socket type was not recognized";
|
||||||
|
|
||||||
|
case EAI_SYSTEM:
|
||||||
|
snprintf(buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"A system error occurred: %s",
|
||||||
|
strerror(errno));
|
||||||
|
return buffer;
|
||||||
|
|
||||||
|
case EAI_OVERFLOW:
|
||||||
|
return "An argument buffer overflowed";
|
||||||
|
}
|
||||||
|
|
||||||
|
/* unknown error code */
|
||||||
|
snprintf(buffer,
|
||||||
|
sizeof(buffer),
|
||||||
|
"An unknown error code was passed to gai_strerror: %d",
|
||||||
|
ecode);
|
||||||
|
return buffer;
|
||||||
|
}
|
|
@ -54,10 +54,6 @@ static char sccsid[] = "@(#)gethostnamadr.c 6.41 (Berkeley) 6/1/90";
|
||||||
static char *h_addr_ptrs[MAXADDRS + 1];
|
static char *h_addr_ptrs[MAXADDRS + 1];
|
||||||
|
|
||||||
#ifdef _MINIX
|
#ifdef _MINIX
|
||||||
struct in_addr
|
|
||||||
{
|
|
||||||
ipaddr_t s_addr;
|
|
||||||
};
|
|
||||||
union querybuf;
|
union querybuf;
|
||||||
|
|
||||||
extern int dn_skipname _ARGS(( const u_char *comp_dn, const u_char *eom ));
|
extern int dn_skipname _ARGS(( const u_char *comp_dn, const u_char *eom ));
|
||||||
|
|
148
lib/ip/nameinfo.c
Executable file
148
lib/ip/nameinfo.c
Executable file
|
@ -0,0 +1,148 @@
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
static size_t first_component_len(const char *s)
|
||||||
|
{
|
||||||
|
const char *first = s;
|
||||||
|
|
||||||
|
/* find the first dot or end of string */
|
||||||
|
while (*s && *s != '.')
|
||||||
|
s++;
|
||||||
|
|
||||||
|
/* return length */
|
||||||
|
return s - first;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getnameinfo_get_host(const struct sockaddr_in *sockaddr,
|
||||||
|
char *node, socklen_t nodelen, int flags)
|
||||||
|
{
|
||||||
|
struct hostent *hostent;
|
||||||
|
const char *ipaddr;
|
||||||
|
|
||||||
|
/* perform look-up */
|
||||||
|
if ((flags & NI_NUMERICHOST) != NI_NUMERICHOST)
|
||||||
|
{
|
||||||
|
hostent = gethostbyaddr(
|
||||||
|
(char *) &sockaddr->sin_addr,
|
||||||
|
sizeof(sockaddr->sin_addr),
|
||||||
|
AF_INET);
|
||||||
|
|
||||||
|
if (hostent && hostent->h_name)
|
||||||
|
{
|
||||||
|
/* return the hostname that was found */
|
||||||
|
if (nodelen <= strlen(hostent->h_name))
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
|
||||||
|
strcpy(node, hostent->h_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((flags & NI_NAMEREQD) == NI_NAMEREQD)
|
||||||
|
return EAI_NONAME;
|
||||||
|
|
||||||
|
/* basic implementation to provide numeric values */
|
||||||
|
ipaddr = inet_ntoa(sockaddr->sin_addr);
|
||||||
|
if (nodelen <= strlen(ipaddr))
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
|
||||||
|
strcpy(node, ipaddr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int getnameinfo_get_serv(const struct sockaddr_in *sockaddr,
|
||||||
|
char *service, socklen_t servicelen, int flags)
|
||||||
|
{
|
||||||
|
struct servent *servent;
|
||||||
|
unsigned short port;
|
||||||
|
|
||||||
|
/* perform look-up */
|
||||||
|
if ((flags & NI_NUMERICSERV) != NI_NUMERICSERV)
|
||||||
|
{
|
||||||
|
servent = getservbyport(sockaddr->sin_port,
|
||||||
|
((flags & NI_DGRAM) == NI_DGRAM) ? "udp" : "tcp");
|
||||||
|
if (servent && servent->s_name)
|
||||||
|
{
|
||||||
|
/* return the service name that was found */
|
||||||
|
if (strlen(servent->s_name) >= servicelen)
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
|
||||||
|
strcpy(service, servent->s_name);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* return port number */
|
||||||
|
port = ntohs(sockaddr->sin_port);
|
||||||
|
if (snprintf(service, servicelen, "%u", port) >= servicelen)
|
||||||
|
return EAI_OVERFLOW;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* getnameinfo is based on
|
||||||
|
* http://www.opengroup.org/onlinepubs/009695399/functions/getnameinfo.html
|
||||||
|
*/
|
||||||
|
int getnameinfo(const struct sockaddr *sa, socklen_t salen,
|
||||||
|
char *node, socklen_t nodelen, char *service,
|
||||||
|
socklen_t servicelen, int flags)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
const struct sockaddr_in *sockaddr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The following flags are really supported:
|
||||||
|
* - NI_NUMERICHOST
|
||||||
|
* - NI_NAMEREQD
|
||||||
|
* - NI_NUMERICSERV
|
||||||
|
* - NI_DGRAM
|
||||||
|
*
|
||||||
|
* The following flag is not supported:
|
||||||
|
* - NI_NUMERICSCOPE
|
||||||
|
*
|
||||||
|
* The following flags could have been supported but is not implemented:
|
||||||
|
* - NI_NOFQDN
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* check for invalid parameters; only support IPv4 */
|
||||||
|
if (sa == NULL)
|
||||||
|
{
|
||||||
|
errno = EINVAL;
|
||||||
|
return EAI_SYSTEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sa->sa_family != AF_INET || salen != sizeof(struct sockaddr_in))
|
||||||
|
return EAI_FAMILY;
|
||||||
|
|
||||||
|
if (flags & ~(NI_NUMERICHOST | NI_NAMEREQD | NI_NUMERICSERV | NI_DGRAM))
|
||||||
|
return EAI_BADFLAGS;
|
||||||
|
|
||||||
|
if ((!node || !nodelen) && (!service || !servicelen))
|
||||||
|
return EAI_NONAME;
|
||||||
|
|
||||||
|
/* look up host */
|
||||||
|
sockaddr = (const struct sockaddr_in *) sa;
|
||||||
|
if (node && nodelen > 0)
|
||||||
|
{
|
||||||
|
r = getnameinfo_get_host(sockaddr, node, nodelen, flags);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* look up service */
|
||||||
|
if (service && servicelen > 0)
|
||||||
|
{
|
||||||
|
r = getnameinfo_get_serv(sockaddr, service, servicelen, flags);
|
||||||
|
if (r)
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
66
man/man3/getaddrinfo.3
Executable file
66
man/man3/getaddrinfo.3
Executable file
|
@ -0,0 +1,66 @@
|
||||||
|
.TH GETADDRINFO 3 "January 19, 2010"
|
||||||
|
.UC 4
|
||||||
|
.SH NAME
|
||||||
|
getaddrinfo, freeaddrinfo, gai_strerror, getnameinfo \- address information
|
||||||
|
.SH SYNOPSIS
|
||||||
|
.nf
|
||||||
|
.ft B
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
void freeaddrinfo(struct addrinfo *\fIai\fP);
|
||||||
|
int getaddrinfo(const char *\fInodename\fP,
|
||||||
|
const char *\fIservname\fP,
|
||||||
|
const struct addrinfo *\fIhints\fP,
|
||||||
|
struct addrinfo **\fIres\fP);
|
||||||
|
int getnameinfo(const struct sockaddr *\fIsa\fP, socklen_t \fIsalen\fP,
|
||||||
|
char *\fInode\fP, socklen_t \fInodelen\fP, char *\fIservice\fP,
|
||||||
|
socklen_t \fIservicelen\fP, int \fIflags\fP);
|
||||||
|
const char *gai_strerror(int \fIecode\fP);
|
||||||
|
.fi
|
||||||
|
.SH DESCRIPTION
|
||||||
|
These functions provide to convert between host and service names on the one
|
||||||
|
hand and network addresses and ports on the other.
|
||||||
|
.PP
|
||||||
|
getaddrinfo converts the hostname specified in \fInodename\fP and/or the service
|
||||||
|
name in \fIservname\fP into a socket address that can be used to connect to that
|
||||||
|
service or listen for incoming connections. One of the parameters may be NULL.
|
||||||
|
If \fInodename\fP is NULL, an address for the local host is provided. If
|
||||||
|
\fIservname\fP is NULL, the network port is not filled in (and therefore set to
|
||||||
|
zero). Buffers are allocated to store the results and a pointer to the first
|
||||||
|
element of a linked list of addresses is stored in \fIai\fP. These buffers must
|
||||||
|
be freed by calling freeaddrinfo on the pointer returned in \fIai\fP.
|
||||||
|
.PP
|
||||||
|
getnameinfo converts the specified socket address into a hostname and/or service
|
||||||
|
name. These are stored in the buffers pointed to by \fInode\fP and \fIservice\fP
|
||||||
|
resepectively. \fInodelen\fP and \fIservicelen\fP specify the sizes of these
|
||||||
|
buffers. If the result string including null terminator does not fit in the
|
||||||
|
buffer, the function fails and EAI_OVERFLOW is returned.
|
||||||
|
.PP
|
||||||
|
For both functions, some flags may be specified to alter their behaviour. For
|
||||||
|
getaddrinfo these flags are specified in the ai_flags field of the optional
|
||||||
|
\fIhints\fP parameter. AI_PASSIVE indicates that an address suitable for the
|
||||||
|
bind function should be returned, otherwise an address suitable for connect is
|
||||||
|
provided. AI_CANONNAME requests that the canonical name of the host be retrieved
|
||||||
|
and stored in the ai_canonname field of the result. AI_NUMERICHOST and
|
||||||
|
AI_NUMERICSERV indicate respectively that \fInodename\fP is an IP address and
|
||||||
|
\fIservname\fP is a port number, avoiding a lookup. Search can be limited to a
|
||||||
|
specific socket type by setting \fIhints\fP\->ai_socktype to SOCK_STREAM or
|
||||||
|
SOCK_DGRAM. \fIhints\fP\->ai_family can be set to AF_UNSPEC or AF_INET but this
|
||||||
|
doesn't make a difference as MINIX supports only IPv4. Unused fields of
|
||||||
|
\fIhints\fP must be set to zero.
|
||||||
|
.PP
|
||||||
|
Flags for getnameinfo are specified in the \fIflags\fP parameter. NI_NUMERICHOST
|
||||||
|
and NI_NUMERICSERV respectively cause \fInode\fP to be set to an IP address
|
||||||
|
and \fIservice\fP to be set to a port number. NI_NAMEREQD causes the function
|
||||||
|
to fail with EAI_NONAME if a name is not found for the host (otherwise the IP
|
||||||
|
address is returned). NI_DGRAM indicates that a datagram service is specified,
|
||||||
|
the default being a stream service.
|
||||||
|
.SH "RETURN VALUE
|
||||||
|
If the functions succeed, they return 0. If they fail, one of the EAI_* values
|
||||||
|
defined in netdb.h is returned. This value can be converted into a string using
|
||||||
|
gai_strerror. The most important ones are EAI_NONAME (host name not found),
|
||||||
|
EAI_SERVICE (service name not found) and EAI_OVERFLOW (buffer too small, only
|
||||||
|
for getnameinfo).
|
||||||
|
.SH "KNOWN ISSUES
|
||||||
|
Since MINIX does not support IPv6, the related flags are not supported.
|
||||||
|
The NI_NOFQDN flag is also not (yet) supported.
|
|
@ -10,7 +10,7 @@ OBJ= test1 test2 test3 test4 test5 test6 test7 test8 test9 \
|
||||||
test21 test22 test23 test25 test26 test27 test28 test29 \
|
test21 test22 test23 test25 test26 test27 test28 test29 \
|
||||||
test30 test31 test32 test34 test35 test36 test37 test38 \
|
test30 test31 test32 test34 test35 test36 test37 test38 \
|
||||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
|
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
|
||||||
test42 test44 test45 test47
|
test42 test44 test45 test47 test48
|
||||||
|
|
||||||
BIGOBJ= test20 test24
|
BIGOBJ= test20 test24
|
||||||
ROOTOBJ= test11 test33 test43 test46
|
ROOTOBJ= test11 test33 test43 test46
|
||||||
|
@ -95,4 +95,5 @@ test45: test45.c test45.h
|
||||||
test45-gcc: test45.c test45.h
|
test45-gcc: test45.c test45.h
|
||||||
test46: test46.c
|
test46: test46.c
|
||||||
test47: test47.c
|
test47: test47.c
|
||||||
|
test48: test48.c
|
||||||
|
|
||||||
|
|
2
test/run
2
test/run
|
@ -19,7 +19,7 @@ echo " "
|
||||||
# Run all the tests, keeping track of who failed.
|
# Run all the tests, keeping track of who failed.
|
||||||
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
for i in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 \
|
||||||
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 \
|
||||||
41 42 43 44 45 45-gcc 46 47 sh1.sh sh2.sh
|
41 42 43 44 45 45-gcc 46 47 48 sh1.sh sh2.sh
|
||||||
do
|
do
|
||||||
if [ -x ./test$i ]
|
if [ -x ./test$i ]
|
||||||
then
|
then
|
||||||
|
|
566
test/test48.c
Executable file
566
test/test48.c
Executable file
|
@ -0,0 +1,566 @@
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#define MAX_ERRORS 8
|
||||||
|
|
||||||
|
static int errct;
|
||||||
|
|
||||||
|
static void quit(void)
|
||||||
|
{
|
||||||
|
if (errct > 0)
|
||||||
|
{
|
||||||
|
printf("%d errors\n", errct);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
printf("ok\n");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void err(void)
|
||||||
|
{
|
||||||
|
if (++errct >= MAX_ERRORS)
|
||||||
|
{
|
||||||
|
printf("aborted, too many errors\n");
|
||||||
|
quit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void printstr(const char *s)
|
||||||
|
{
|
||||||
|
if (s)
|
||||||
|
printf("\"%s\"", s);
|
||||||
|
else
|
||||||
|
printf("NULL");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getaddrinfo_err(
|
||||||
|
int n,
|
||||||
|
const char *nodename,
|
||||||
|
const char *servname,
|
||||||
|
int passhints,
|
||||||
|
int flags,
|
||||||
|
int family,
|
||||||
|
int socktype,
|
||||||
|
const char *exp_result,
|
||||||
|
const char *result)
|
||||||
|
{
|
||||||
|
printf("error %d: getaddrinfo(", n);
|
||||||
|
printstr(nodename);
|
||||||
|
printf(", ");
|
||||||
|
printstr(servname);
|
||||||
|
printf(", ");
|
||||||
|
if (passhints)
|
||||||
|
printf("{ 0x%x, %d, %d }", flags, family, socktype);
|
||||||
|
else
|
||||||
|
printf("NULL");
|
||||||
|
|
||||||
|
printf("); result: ");
|
||||||
|
printstr(result);
|
||||||
|
printf("; expected: ");
|
||||||
|
printstr(exp_result);
|
||||||
|
printf("\n");
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* yes, this is ugly, but not as ugly as repeating it all every time */
|
||||||
|
#define TEST_GETADDRINFO_ERR_PARAMS \
|
||||||
|
nodename, servname, passhints, flags, family, socktype
|
||||||
|
|
||||||
|
static void test_getaddrinfo_err_nr(
|
||||||
|
int n,
|
||||||
|
const char *nodename,
|
||||||
|
const char *servname,
|
||||||
|
int passhints,
|
||||||
|
int flags,
|
||||||
|
int family,
|
||||||
|
int socktype,
|
||||||
|
int exp_result,
|
||||||
|
int result)
|
||||||
|
{
|
||||||
|
char exp_result_s[23], result_s[23];
|
||||||
|
|
||||||
|
/* convert result to string */
|
||||||
|
snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x",
|
||||||
|
exp_result, exp_result);
|
||||||
|
snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result);
|
||||||
|
test_getaddrinfo_err(n, TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
exp_result_s, result_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getnameinfo_err(
|
||||||
|
int n,
|
||||||
|
unsigned long ipaddr,
|
||||||
|
unsigned short port,
|
||||||
|
socklen_t nodelen,
|
||||||
|
socklen_t servicelen,
|
||||||
|
int flags,
|
||||||
|
const char *exp_result,
|
||||||
|
const char *result)
|
||||||
|
{
|
||||||
|
printf("error %d: getnameinfo(0x%.8x, %d, %d, %d, 0x%x); result: ",
|
||||||
|
n, ntohl(ipaddr), ntohs(port), nodelen, servicelen, flags);
|
||||||
|
printstr(result);
|
||||||
|
printf("; expected: ");
|
||||||
|
printstr(exp_result);
|
||||||
|
printf("\n");
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
|
||||||
|
/* yes, this is ugly, but not as ugly as repeating it all every time */
|
||||||
|
#define TEST_GETNAMEINFO_ERR_PARAMS ipaddr, port, nodelen, servicelen, flags
|
||||||
|
|
||||||
|
static void test_getnameinfo_err_nr(
|
||||||
|
int n,
|
||||||
|
unsigned long ipaddr,
|
||||||
|
unsigned short port,
|
||||||
|
socklen_t nodelen,
|
||||||
|
socklen_t servicelen,
|
||||||
|
int flags,
|
||||||
|
int exp_result,
|
||||||
|
int result)
|
||||||
|
{
|
||||||
|
char exp_result_s[23], result_s[23];
|
||||||
|
|
||||||
|
/* convert result to string */
|
||||||
|
snprintf(exp_result_s, sizeof(exp_result_s), "%d/0x%x",
|
||||||
|
exp_result, exp_result);
|
||||||
|
snprintf(result_s, sizeof(result_s), "%d/0x%x", result, result);
|
||||||
|
test_getnameinfo_err(n, TEST_GETNAMEINFO_ERR_PARAMS,
|
||||||
|
exp_result_s, result_s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_getaddrinfo(
|
||||||
|
const char *nodename,
|
||||||
|
const char *servname,
|
||||||
|
int passhints,
|
||||||
|
int flags,
|
||||||
|
int family,
|
||||||
|
int socktype,
|
||||||
|
int exp_results,
|
||||||
|
unsigned long exp_ip,
|
||||||
|
int exp_canonname,
|
||||||
|
unsigned short exp_port)
|
||||||
|
{
|
||||||
|
struct addrinfo *ai, *ai_cur;
|
||||||
|
struct addrinfo hints;
|
||||||
|
struct sockaddr_in *sockaddr_in;
|
||||||
|
int ai_count_dgram, ai_count_stream, r;
|
||||||
|
|
||||||
|
/* some parameters are only meaningful with hints */
|
||||||
|
assert(passhints || !flags);
|
||||||
|
assert(passhints || family == AF_UNSPEC);
|
||||||
|
assert(passhints || !socktype);
|
||||||
|
|
||||||
|
/* initialize hints */
|
||||||
|
memset(&hints, 0, sizeof(hints));
|
||||||
|
hints.ai_flags = flags;
|
||||||
|
hints.ai_family = family;
|
||||||
|
hints.ai_socktype = socktype;
|
||||||
|
hints.ai_family = family;
|
||||||
|
|
||||||
|
/* perform query and test result */
|
||||||
|
ai = (struct addrinfo *) 0xDEADBEEF;
|
||||||
|
r = getaddrinfo(nodename, servname, passhints ? &hints : NULL, &ai);
|
||||||
|
if (r < 0 || r >= 32 || !((1 << r) & exp_results))
|
||||||
|
test_getaddrinfo_err_nr(1, TEST_GETADDRINFO_ERR_PARAMS, exp_results, r);
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* the function succeeded; do the results make sense? */
|
||||||
|
ai_cur = ai;
|
||||||
|
ai_count_dgram = 0;
|
||||||
|
ai_count_stream = 0;
|
||||||
|
while (ai_cur)
|
||||||
|
{
|
||||||
|
/* test result fields */
|
||||||
|
if (ai_cur->ai_family != AF_INET)
|
||||||
|
test_getaddrinfo_err_nr(2, TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
AF_INET, ai_cur->ai_family);
|
||||||
|
|
||||||
|
if (socktype && ai_cur->ai_socktype != socktype)
|
||||||
|
test_getaddrinfo_err_nr(3, TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
socktype, ai_cur->ai_socktype);
|
||||||
|
|
||||||
|
switch (ai_cur->ai_socktype)
|
||||||
|
{
|
||||||
|
case SOCK_DGRAM: ai_count_dgram++; break;
|
||||||
|
case SOCK_STREAM: ai_count_stream++; break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* do address and port match? */
|
||||||
|
if (ai_cur->ai_addrlen != sizeof(struct sockaddr_in))
|
||||||
|
test_getaddrinfo_err_nr(4, TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
sizeof(struct sockaddr_in),
|
||||||
|
ai_cur->ai_addrlen);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sockaddr_in = (struct sockaddr_in *) ai_cur->ai_addr;
|
||||||
|
if (sockaddr_in->sin_addr.s_addr != exp_ip)
|
||||||
|
test_getaddrinfo_err_nr(5,
|
||||||
|
TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
ntohl(exp_ip),
|
||||||
|
ntohl(sockaddr_in->sin_addr.s_addr));
|
||||||
|
|
||||||
|
if (sockaddr_in->sin_port != exp_port)
|
||||||
|
test_getaddrinfo_err_nr(6,
|
||||||
|
TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
ntohs(exp_port),
|
||||||
|
ntohs(sockaddr_in->sin_port));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* is canonical supplied? */
|
||||||
|
if (exp_canonname &&
|
||||||
|
(!ai_cur->ai_canonname || !*ai_cur->ai_canonname))
|
||||||
|
test_getaddrinfo_err(7,
|
||||||
|
TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
"(anything)", ai_cur->ai_canonname);
|
||||||
|
|
||||||
|
if (!exp_canonname && ai_cur->ai_canonname)
|
||||||
|
test_getaddrinfo_err(8,
|
||||||
|
TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
NULL, ai_cur->ai_canonname);
|
||||||
|
|
||||||
|
/* move to next result */
|
||||||
|
ai_cur = ai_cur->ai_next;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* check number of results */
|
||||||
|
if (ai_count_dgram != ((socktype == SOCK_STREAM) ? 0 : 1))
|
||||||
|
test_getaddrinfo_err_nr(9, TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
(socktype == SOCK_STREAM) ? 0 : 1, ai_count_dgram);
|
||||||
|
|
||||||
|
if (ai_count_stream != ((socktype == SOCK_DGRAM) ? 0 : 1))
|
||||||
|
test_getaddrinfo_err_nr(10, TEST_GETADDRINFO_ERR_PARAMS,
|
||||||
|
(socktype == SOCK_DGRAM) ? 0 : 1, ai_count_stream);
|
||||||
|
|
||||||
|
/* clean up */
|
||||||
|
freeaddrinfo(ai);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void memsetl(void *s, unsigned long c, size_t n)
|
||||||
|
{
|
||||||
|
unsigned char *p = (unsigned char *) s;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < n; i++)
|
||||||
|
p[i] = c >> (8 * (i % sizeof(c)));
|
||||||
|
}
|
||||||
|
|
||||||
|
void test_getnameinfo(
|
||||||
|
unsigned long ipaddr,
|
||||||
|
unsigned short port,
|
||||||
|
const char *exp_node,
|
||||||
|
socklen_t nodelen,
|
||||||
|
const char *exp_service,
|
||||||
|
socklen_t servicelen,
|
||||||
|
int flags,
|
||||||
|
int exp_results)
|
||||||
|
{
|
||||||
|
struct sockaddr_in sockaddr;
|
||||||
|
char node[256], service[256];
|
||||||
|
int r;
|
||||||
|
|
||||||
|
/* avoid buffer overflows */
|
||||||
|
assert(nodelen <= sizeof(node));
|
||||||
|
assert(servicelen <= sizeof(service));
|
||||||
|
|
||||||
|
/* perform query and test result */
|
||||||
|
sockaddr.sin_family = AF_INET;
|
||||||
|
sockaddr.sin_addr.s_addr = ipaddr;
|
||||||
|
sockaddr.sin_port = port;
|
||||||
|
memsetl(node, 0xDEADBEEF, nodelen);
|
||||||
|
memsetl(service, 0xDEADBEEF, servicelen);
|
||||||
|
r = getnameinfo((struct sockaddr *) &sockaddr, sizeof(sockaddr),
|
||||||
|
node, nodelen, service, servicelen, flags);
|
||||||
|
|
||||||
|
if (r < 0 || r >= 32 || !((1 << r) & exp_results))
|
||||||
|
test_getnameinfo_err_nr(1, TEST_GETNAMEINFO_ERR_PARAMS,
|
||||||
|
exp_results, r);
|
||||||
|
|
||||||
|
if (r)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* check results */
|
||||||
|
if (nodelen && strcmp(exp_node, node) != 0)
|
||||||
|
test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS,
|
||||||
|
exp_node, node);
|
||||||
|
|
||||||
|
if (servicelen && strcmp(exp_service, service) != 0)
|
||||||
|
test_getnameinfo_err(2, TEST_GETNAMEINFO_ERR_PARAMS,
|
||||||
|
exp_service, service);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
const char *nodename;
|
||||||
|
unsigned long ipaddr;
|
||||||
|
int numeric;
|
||||||
|
int canonname;
|
||||||
|
int need_network;
|
||||||
|
int exp_result;
|
||||||
|
} hosts[] = {
|
||||||
|
{ NULL, 0x7f000001, 1, 1, 0, 0 },
|
||||||
|
{ "0.0.0.0", 0x00000000, 1, 0, 0, 0, },
|
||||||
|
{ "0.0.0.255", 0x000000ff, 1, 0, 0, 0, },
|
||||||
|
{ "0.0.255.0", 0x0000ff00, 1, 0, 0, 0, },
|
||||||
|
{ "0.255.0.0", 0x00ff0000, 1, 0, 0, 0, },
|
||||||
|
{ "255.0.0.0", 0xff000000, 1, 0, 0, 0, },
|
||||||
|
{ "127.0.0.1", 0x7f000001, 1, 0, 0, 0, },
|
||||||
|
{ "localhost", 0x7f000001, 0, 1, 0, 0, },
|
||||||
|
{ "minix3.org", 0x82251414, 0, 1, 1, 0, },
|
||||||
|
{ "", 0x00000000, 1, 0, 0, (1 << EAI_NONAME) },
|
||||||
|
{ "256.256.256.256", 0x00000000, 1, 0, 0, (1 << EAI_NONAME) },
|
||||||
|
{ "minix3.xxx", 0x00000000, 0, 0, 1, (1 << EAI_NONAME) }};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
const char *servname;
|
||||||
|
unsigned short port;
|
||||||
|
int numeric;
|
||||||
|
int socktype;
|
||||||
|
int exp_result;
|
||||||
|
} services[] = {
|
||||||
|
{ NULL, 0, 1, 0, 0 },
|
||||||
|
{ "0", 0, 1, 0, 0 },
|
||||||
|
{ "1", 1, 1, 0, 0 },
|
||||||
|
{ "32767", 32767, 1, 0, 0 },
|
||||||
|
{ "32768", 32768, 1, 0, 0 },
|
||||||
|
{ "65535", 65535, 1, 0, 0 },
|
||||||
|
{ "echo", 7, 0, 0, 0 },
|
||||||
|
{ "ftp", 21, 0, SOCK_STREAM, 0 },
|
||||||
|
{ "tftp", 69, 0, SOCK_DGRAM , 0 },
|
||||||
|
{ "-1", 0, 1, 0, (1 << EAI_SERVICE) },
|
||||||
|
{ "", 0, 1, 0, (1 << EAI_SERVICE) },
|
||||||
|
{ "65537", 0, 1, 0, (1 << EAI_SERVICE) },
|
||||||
|
{ "XXX", 0, 0, 0, (1 << EAI_SERVICE) }};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
int exp_result;
|
||||||
|
} families[] = {
|
||||||
|
{ AF_UNSPEC, 0 },
|
||||||
|
{ AF_INET, 0 },
|
||||||
|
{ AF_UNSPEC + AF_INET + 1, (1 << EAI_FAMILY) }};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
int value;
|
||||||
|
int exp_result;
|
||||||
|
} socktypes[] = {
|
||||||
|
{ 0, 0 },
|
||||||
|
{ SOCK_STREAM, 0 },
|
||||||
|
{ SOCK_DGRAM, 0 },
|
||||||
|
{ SOCK_STREAM + SOCK_DGRAM + 1, (1 << EAI_SOCKTYPE) }};
|
||||||
|
|
||||||
|
#define LENGTH(a) (sizeof((a)) / sizeof((a)[0]))
|
||||||
|
|
||||||
|
static void test_getaddrinfo_all(int use_network)
|
||||||
|
{
|
||||||
|
int flag_PASSIVE, flag_CANONNAME, flag_NUMERICHOST, flag_NUMERICSERV;
|
||||||
|
int exp_results, flags, i, j, k, l, needhints, passhints;
|
||||||
|
unsigned long ipaddr;
|
||||||
|
|
||||||
|
/* loop through various parameter values */
|
||||||
|
for (i = 0; i < LENGTH(hosts); i++)
|
||||||
|
for (j = 0; j < LENGTH(services); j++)
|
||||||
|
for (k = 0; k < LENGTH(families); k++)
|
||||||
|
for (l = 0; l < LENGTH(socktypes); l++)
|
||||||
|
for (flag_PASSIVE = 0; flag_PASSIVE < 2; flag_PASSIVE++)
|
||||||
|
for (flag_CANONNAME = 0; flag_CANONNAME < 2; flag_CANONNAME++)
|
||||||
|
for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++)
|
||||||
|
for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++)
|
||||||
|
{
|
||||||
|
/* skip tests that need but cannot use network */
|
||||||
|
if (!use_network && hosts[i].need_network)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* determine flags */
|
||||||
|
flags = (flag_PASSIVE ? AI_PASSIVE : 0) |
|
||||||
|
(flag_CANONNAME ? AI_CANONNAME : 0) |
|
||||||
|
(flag_NUMERICHOST ? AI_NUMERICHOST : 0) |
|
||||||
|
(flag_NUMERICSERV ? AI_NUMERICSERV : 0);
|
||||||
|
|
||||||
|
/* flags may influence IP address */
|
||||||
|
ipaddr = hosts[i].ipaddr;
|
||||||
|
if (!hosts[i].nodename && flag_PASSIVE)
|
||||||
|
ipaddr = INADDR_ANY;
|
||||||
|
|
||||||
|
/* determine expected result */
|
||||||
|
exp_results =
|
||||||
|
hosts[i].exp_result |
|
||||||
|
services[j].exp_result |
|
||||||
|
families[k].exp_result |
|
||||||
|
socktypes[l].exp_result;
|
||||||
|
if (!hosts[i].nodename && !services[j].servname)
|
||||||
|
exp_results |= (1 << EAI_NONAME);
|
||||||
|
|
||||||
|
if (flag_NUMERICHOST && !hosts[i].numeric)
|
||||||
|
exp_results |= (1 << EAI_NONAME);
|
||||||
|
|
||||||
|
if (flag_NUMERICSERV && !services[j].numeric)
|
||||||
|
exp_results |= (1 << EAI_SERVICE);
|
||||||
|
|
||||||
|
if (services[j].socktype && socktypes[l].value != services[j].socktype)
|
||||||
|
exp_results |= (1 << EAI_SERVICE);
|
||||||
|
|
||||||
|
/* with no reason for failure, we demand success */
|
||||||
|
if (!exp_results)
|
||||||
|
exp_results |= (1 << 0);
|
||||||
|
|
||||||
|
/* some options require hints */
|
||||||
|
needhints = (families[k].value != AF_UNSPEC ||
|
||||||
|
socktypes[l].value != 0 || flags) ? 1 : 0;
|
||||||
|
for (passhints = needhints; passhints < 2; passhints++)
|
||||||
|
{
|
||||||
|
/* test getaddrinfo function */
|
||||||
|
test_getaddrinfo(
|
||||||
|
hosts[i].nodename,
|
||||||
|
services[j].servname,
|
||||||
|
passhints,
|
||||||
|
flags,
|
||||||
|
families[k].value,
|
||||||
|
socktypes[l].value,
|
||||||
|
exp_results,
|
||||||
|
htonl(ipaddr),
|
||||||
|
flag_CANONNAME && hosts[i].canonname,
|
||||||
|
htons(services[j].port));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
const char *nodename;
|
||||||
|
const char *nodenum;
|
||||||
|
unsigned long ipaddr;
|
||||||
|
int havename;
|
||||||
|
} ipaddrs[] = {
|
||||||
|
{ "0.0.0.0", "0.0.0.0", 0x00000000, 0 },
|
||||||
|
{ "0.0.0.255", "0.0.0.255", 0x000000ff, 0 },
|
||||||
|
{ "0.0.255.0", "0.0.255.0", 0x0000ff00, 0 },
|
||||||
|
{ "0.255.0.0", "0.255.0.0", 0x00ff0000, 0 },
|
||||||
|
{ "255.0.0.0", "255.0.0.0", 0xff000000, 0 },
|
||||||
|
{ "localhost", "127.0.0.1", 0x7f000001, 1 },
|
||||||
|
/* no reverse DNS unfortunately */
|
||||||
|
/* { "minix3.org", "130.37.20.20", 0x82251414, 1 } */};
|
||||||
|
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
const char *servname;
|
||||||
|
const char *servnum;
|
||||||
|
unsigned short port;
|
||||||
|
int socktype;
|
||||||
|
} ports[] = {
|
||||||
|
{ "0", "0", 0, 0 },
|
||||||
|
{ "tcpmux", "1", 1, SOCK_STREAM },
|
||||||
|
{ "32767", "32767", 32767, 0 },
|
||||||
|
{ "32768", "32768", 32768, 0 },
|
||||||
|
{ "65535", "65535", 65535, 0 },
|
||||||
|
{ "echo", "7", 7, 0 },
|
||||||
|
{ "ftp", "21", 21, SOCK_STREAM },
|
||||||
|
{ "tftp", "69", 69, SOCK_DGRAM }};
|
||||||
|
|
||||||
|
static int buflens[] = { 0, 1, 2, 3, 4, 5, 6, 9, 10, 11, 255 };
|
||||||
|
|
||||||
|
static void test_getnameinfo_all(void)
|
||||||
|
{
|
||||||
|
int flag_NUMERICHOST, flag_NAMEREQD, flag_NUMERICSERV, flag_DGRAM;
|
||||||
|
int exp_results, flags, i, j, k, l, socktypemismatch;
|
||||||
|
const char *nodename, *servname;
|
||||||
|
|
||||||
|
/* loop through various parameter values */
|
||||||
|
for (i = 0; i < LENGTH(ipaddrs); i++)
|
||||||
|
for (j = 0; j < LENGTH(ports); j++)
|
||||||
|
for (k = 0; k < LENGTH(buflens); k++)
|
||||||
|
for (l = 0; l < LENGTH(buflens); l++)
|
||||||
|
for (flag_NUMERICHOST = 0; flag_NUMERICHOST < 2; flag_NUMERICHOST++)
|
||||||
|
for (flag_NAMEREQD = 0; flag_NAMEREQD < 2; flag_NAMEREQD++)
|
||||||
|
for (flag_NUMERICSERV = 0; flag_NUMERICSERV < 2; flag_NUMERICSERV++)
|
||||||
|
for (flag_DGRAM = 0; flag_DGRAM < 2; flag_DGRAM++)
|
||||||
|
{
|
||||||
|
/* determine flags */
|
||||||
|
flags = (flag_NUMERICHOST ? NI_NUMERICHOST : 0) |
|
||||||
|
(flag_NAMEREQD ? NI_NAMEREQD : 0) |
|
||||||
|
(flag_NUMERICSERV ? NI_NUMERICSERV : 0) |
|
||||||
|
(flag_DGRAM ? NI_DGRAM : 0);
|
||||||
|
|
||||||
|
/* determine expected result */
|
||||||
|
exp_results = 0;
|
||||||
|
if (!buflens[k] && !buflens[l])
|
||||||
|
exp_results |= (1 << EAI_NONAME);
|
||||||
|
|
||||||
|
nodename = flag_NUMERICHOST ? ipaddrs[i].nodenum : ipaddrs[i].nodename;
|
||||||
|
if (buflens[k] > 0 && buflens[k] <= strlen(nodename))
|
||||||
|
exp_results |= (1 << EAI_OVERFLOW);
|
||||||
|
|
||||||
|
socktypemismatch =
|
||||||
|
(flag_DGRAM && ports[j].socktype == SOCK_STREAM) ||
|
||||||
|
(!flag_DGRAM && ports[j].socktype == SOCK_DGRAM);
|
||||||
|
servname = (flag_NUMERICSERV || socktypemismatch) ?
|
||||||
|
ports[j].servnum : ports[j].servname;
|
||||||
|
if (buflens[l] > 0 && buflens[l] <= strlen(servname))
|
||||||
|
exp_results |= (1 << EAI_OVERFLOW);
|
||||||
|
|
||||||
|
if (flag_NAMEREQD && (!ipaddrs[i].havename | flag_NUMERICHOST) && buflens[k])
|
||||||
|
exp_results |= (1 << EAI_NONAME);
|
||||||
|
|
||||||
|
/* with no reason for failure, we demand success */
|
||||||
|
if (!exp_results)
|
||||||
|
exp_results |= (1 << 0);
|
||||||
|
|
||||||
|
/* perform the test */
|
||||||
|
test_getnameinfo(
|
||||||
|
htonl(ipaddrs[i].ipaddr),
|
||||||
|
htons(ports[j].port),
|
||||||
|
nodename,
|
||||||
|
buflens[k],
|
||||||
|
servname,
|
||||||
|
buflens[l],
|
||||||
|
flags,
|
||||||
|
exp_results);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int can_use_network(void)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
/* try to ping minix3.org */
|
||||||
|
status = system("ping www.minix3.org > /dev/nul 2>&1");
|
||||||
|
if (status == 127)
|
||||||
|
{
|
||||||
|
printf("cannot execute ping\n");
|
||||||
|
err();
|
||||||
|
}
|
||||||
|
|
||||||
|
return status == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int use_network;
|
||||||
|
|
||||||
|
printf("Test 48 ");
|
||||||
|
fflush(stdout);
|
||||||
|
|
||||||
|
use_network = can_use_network();
|
||||||
|
if (!use_network)
|
||||||
|
printf("Warning: no network\n");
|
||||||
|
|
||||||
|
test_getaddrinfo_all(use_network);
|
||||||
|
test_getnameinfo_all();
|
||||||
|
|
||||||
|
quit();
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue