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;
|
||||
}
|
||||
|
||||
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,
|
||||
* 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)) {
|
||||
/* Rebind over Ethernet. */
|
||||
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))) {
|
||||
if (debug >= 1) {
|
||||
printf("%s: Broadcast DHCP %s\n",
|
||||
|
@ -967,7 +968,7 @@ int main(int argc, char **argv)
|
|||
}
|
||||
} else {
|
||||
/* 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))) {
|
||||
if (debug >= 1) {
|
||||
printf("%s: Sent DHCP %s to %s\n",
|
||||
|
@ -1123,7 +1124,7 @@ int main(int argc, char **argv)
|
|||
* is in use already.
|
||||
*/
|
||||
make_arp(bp, np);
|
||||
if (send(np, bp->eth, sizeof(arp46_t))) {
|
||||
if (sendpacket(np, bp->eth, sizeof(arp46_t))) {
|
||||
if (debug >= 2) {
|
||||
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);
|
||||
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))) {
|
||||
if (debug >= 1) {
|
||||
printf("%s: Broadcast DHCP %s\n",
|
||||
|
@ -1255,7 +1257,7 @@ int main(int argc, char **argv)
|
|||
* by DHCP to my own interface.
|
||||
*/
|
||||
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) {
|
||||
printf("%s: Sent advert for %s to self\n",
|
||||
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) {
|
||||
/* Send a router solicitation. */
|
||||
icmp_solicit(bp);
|
||||
if (send(np, bp->ip, sizeof(*bp->ip) + 8)) {
|
||||
if (sendpacket(np, bp->ip, sizeof(*bp->ip) + 8)) {
|
||||
if (debug >= 2) {
|
||||
printf("%s: Broadcast router solicitation\n",
|
||||
np->fdp->device);
|
||||
|
@ -1365,7 +1367,7 @@ int main(int argc, char **argv)
|
|||
/* Can we do something with this DHCP packet? */
|
||||
if ((r= servdhcp(np, bp, r)) > 0) {
|
||||
/* Yes, we have something to send somewhere. */
|
||||
if (send(np, bp->udpio, r)) {
|
||||
if (sendpacket(np, bp->udpio, r)) {
|
||||
if (debug >= 1) {
|
||||
printf("%s: Sent DHCP packet to %s\n",
|
||||
np->fdp->device,
|
||||
|
|
|
@ -9,6 +9,7 @@ Created: June 1995 by Philip Homburg <philip@f-mnx.phicoh.com>
|
|||
|
||||
#include <inet/inet.h>
|
||||
#undef printf
|
||||
#undef send
|
||||
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
|
|
|
@ -9,6 +9,7 @@ Created: March 2001 by Philip Homburg <philip@f-mnx.phicoh.com>
|
|||
|
||||
#include <inet/inet.h>
|
||||
#undef printf
|
||||
#undef send
|
||||
|
||||
#include <assert.h>
|
||||
#include <fcntl.h>
|
||||
|
|
|
@ -1,4 +1,7 @@
|
|||
/* net.h Copyright 2000 by Michael Temari All Rights Reserved */
|
||||
/* 04/05/2000 Michael Temari <Michael@TemWare.Com> */
|
||||
|
||||
/* avoid clash with POSIX connect */
|
||||
#define connect _connect
|
||||
_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) );
|
||||
#endif
|
||||
|
||||
#ifdef _POSIX_SOURCE
|
||||
in_addr_t inet_addr(const char *cp);
|
||||
#endif
|
||||
|
||||
#endif /* _ARPA__INET_H */
|
||||
|
||||
|
|
|
@ -125,4 +125,74 @@ int servxcheck _ARGS((unsigned long _peer, const char *_service,
|
|||
char *servxfile _ARGS((const char *_file));
|
||||
#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_ */
|
||||
|
||||
|
|
|
@ -8,6 +8,7 @@ LIBRARIES=libc
|
|||
|
||||
libc_FILES=" \
|
||||
accept.c \
|
||||
addrinfo.c \
|
||||
bind.c \
|
||||
connect.c \
|
||||
dhcp_gettag.c \
|
||||
|
@ -18,6 +19,7 @@ libc_FILES=" \
|
|||
ethere2a.c \
|
||||
etherh2n.c \
|
||||
ethern2h.c \
|
||||
gai_strerror.c \
|
||||
getdomain.c \
|
||||
gethnmadr.c \
|
||||
gethostent.c \
|
||||
|
@ -41,6 +43,7 @@ libc_FILES=" \
|
|||
inet_ntoa.c \
|
||||
listen.c \
|
||||
memcspn.c \
|
||||
nameinfo.c \
|
||||
oneC_sum.c \
|
||||
rcmd.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];
|
||||
|
||||
#ifdef _MINIX
|
||||
struct in_addr
|
||||
{
|
||||
ipaddr_t s_addr;
|
||||
};
|
||||
union querybuf;
|
||||
|
||||
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 \
|
||||
test30 test31 test32 test34 test35 test36 test37 test38 \
|
||||
test39 t10a t11a t11b test40 t40a t40b t40c t40d t40e t40f test41 \
|
||||
test42 test44 test45 test47
|
||||
test42 test44 test45 test47 test48
|
||||
|
||||
BIGOBJ= test20 test24
|
||||
ROOTOBJ= test11 test33 test43 test46
|
||||
|
@ -95,4 +95,5 @@ test45: test45.c test45.h
|
|||
test45-gcc: test45.c test45.h
|
||||
test46: test46.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.
|
||||
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 \
|
||||
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
|
||||
if [ -x ./test$i ]
|
||||
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