glibc/sysdeps/posix/getaddrinfo.c
Ulrich Drepper 40a55d2054 Update.
1997-08-20 05:30  Ulrich Drepper  <drepper@cygnus.com>

	* catgets/catgets.c (catclose): Use __munmap instead of munmap.
	* catgets/gencat.c (read_input_file): Fix typo.

	* dirent/dirent.h: Make seekdir and telldir available for __USE_XOPEN.

	* elf/dl-load.c: Fix case of missing DT_RPATH in object which gets
	executed (e.g., when it is a static binary).

	* intl/bindtextdomain.c: Use strdup in glibc.  Correct comment.
	* intl/dcgettext.c: Likewise.
	* intl/dgettext.c: Likewise.
	* intl/explodename.c: Likewise.
	* intl/finddomain.c: Likewise.
	* intl/gettext.c: Likewise.
	* intl/gettext.h: Likewise.
	* intl/hash-string.h: Likewise.
	* intl/l10nflist.c: Likewise.
	* intl/libintl.h: Likewise.
	* intl/loadinfo.h: Likewise.
	* intl/loadmsgcat.c: Likewise.
	* intl/localealias.c: Likewise.
	* intl/textdomain.c: Likewise.

	Unify libio sources with code in libg++.
	* libio/fcloseall.c: Update and reformat copyright.  Protect use
	of weak_alias.  Use _IO_* thread macros instead of __libc_*.
	* libio/feof.c: Likewise.
	* libio/feof_u.c: Likewise.
	* libio/ferror.c: Likewise.
	* libio/ferror_u.c: Likewise.
	* libio/fgetc.c: Likewise.
	* libio/filedoalloc.c: Likewise.
	* libio/fileno.c: Likewise.
	* libio/fileops.c: Likewise.
	* libio/fputc.c: Likewise.
	* libio/fputc_u.c: Likewise.
	* libio/freopen.c: Likewise.
	* libio/fseek.c: Likewise.
	* libio/genops.c: Likewise.
	* libio/getc.c: Likewise.
	* libio/getc_u.c: Likewise.
	* libio/getchar.c: Likewise.
	* libio/getchar_u.c: Likewise.
	* libio/iofclose.c: Likewise.
	* libio/iofdopen.c: Likewise.
	* libio/iofflush.c: Likewise.
	* libio/iofflush_u.c: Likewise.
	* libio/iofgetpos.c: Likewise.
	* libio/iofgets.c: Likewise.
	* libio/iofopen.c: Likewise.
	* libio/iofopncook.c: Likewise.
	* libio/iofprintf.c: Likewise.
	* libio/iofputs.c: Likewise.
	* libio/iofread.c: Likewise.
	* libio/iofsetpos.c: Likewise.
	* libio/ioftell.c: Likewise.
	* libio/iofwrite.c: Likewise.
	* libio/iogetdelim.c: Likewise.
	* libio/iogetline.c: Likewise.
	* libio/iogets.c: Likewise.
	* libio/iopadn.c: Likewise.
	* libio/iopopen.c: Likewise.
	* libio/ioputs.c: Likewise.
	* libio/ioseekoff.c: Likewise.
	* libio/ioseekpos.c: Likewise.
	* libio/iosetbuffer.c: Likewise.
	* libio/iosetvbuf.c: Likewise.
	* libio/iosprintf.c: Likewise.
	* libio/ioungetc.c: Likewise.
	* libio/iovdprintf.c: Likewise.
	* libio/iovsprintf.c: Likewise.
	* libio/iovsscanf.c: Likewise.
	* libio/libio.h: Likewise.
	* libio/libioP.h: Likewise.
	* libio/obprintf.c: Likewise.
	* libio/pclose.c: Likewise.
	* libio/peekc.c: Likewise.
	* libio/putc.c: Likewise.
	* libio/putchar.c: Likewise.
	* libio/rewind.c: Likewise.
	* libio/setbuf.c: Likewise.
	* libio/setlinebuf.c: Likewise.
	* libio/stdfiles.c: Likewise.
	* libio/stdio.c: Likewise.
	* libio/strfile.h: Likewise.
	* libio/strops.c: Likewise.
	* libio/vasprintf.c: Likewise.
	* libio/vscanf.c: Likewise.
	* libio/vsnprintf.c: Likewise.

	* manual/libc.texinfo: Add menu entries for chapter on message
	translation.
	* manual/locale.texi: Correct next entry in @node for new chapter.
	* manual/search.texi: Likewise for previous link.
	* manual/message.texi: New file.
	* manual/startup.texi: Document LC_ALL, LC_MESSAGES, NLSPATH,
	setenv, unsetenv, and clearenv.
	* manual/string.texi: Fix typos.  Patch by Jim Meyering.

	* math/Makefile (test-longdouble-yes): Enable.  We want long double
	tests now.

	Crusade against strcat.
	* nis/nss_nisplus/nisplus-publickey.c: Remove uses of strcat.
	* stdlib/canonicalize.c: Likewise.

	* posix/glob.h: Define __const if necessary.  Use __const in all
	prototypes.

	* sysdeps/generic/stpcpy.c: Use K&R form to allow use in other
	GNU packages.

	* posix/wordexp.c: Completely reworked buffer handling for much
	better performance.  Patch by Tim Waugh.

	* socket/sys/sochet.h (getpeername): Fix type of LEN parameter,
	it must be socklen_t.

	* sysdeps/libm-i387/e_remainder.S: Pretty print.
	* sysdeps/libm-i387/e_remainderf.S: Likewise.
	* sysdeps/libm-i387/e_remainderl.S: Pop extra value for FPU stack.
	* sysdeps/libm-i387/s_cexp.S: Little optimization.
	* sysdeps/libm-i387/s_cexpl.S: Likewise.
	* sysdep/libm-ieee754/s_csinhl.c: Include <fenv.h>.

1997-08-18 15:21  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/sysv/linux/if_index.c (if_nameindex): Fix memory leak
	in cleanup code.

1997-08-17  Paul Eggert  <eggert@twinsun.com>

	* tzset.c (__tzset_internal): Fix memory leak when the user
	specifies a TZ value that uses a default rule file.
	Do not assume US DST rules when the user specifies
	that there is no DST.

1997-08-10 19:17  Philip Blundell  <Philip.Blundell@pobox.com>

	* inet/getnameinfo.c: Tidy up.
	* sysdeps/posix/getaddrinfo.c: Likewise.

	* sysdeps/unix/sysv/linux/if_index.c (if_nametoindex): Return 0 if
	using stub code.
	(if_indextoname): Use SIOGIFNAME ioctl if the kernel supports it.
	(if_nameindex): Use alloca() rather than malloc(); use
	SIOCGIFCOUNT ioctl if the kernel supports it.

1997-08-16  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/sys/mount.h: Remove the IS_* macros,
	they operate on internal kernel structures and have no place in a
	user header.

1997-08-16  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* Makerules (lib%.so): Depend on $(+preinit) and $(+postinit).
	(build-shlib): Filter them out of $^.

1997-08-15  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* elf/dl-error.c (_dl_signal_error): Fix error message.

1997-08-16 04:06  Ulrich Drepper  <drepper@cygnus.com>

	* assert/assert.h [__USE_GNU]: Undefine assert_perror.
	Reported by Theodore C. Belding <Ted.Belding@umich.edu>.

1997-08-13  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* Makeconfig: Change object suffixes from *.[spgb]o to *.o[spgb]
	to avoid conflict with PO files.
	* Makerules: Likewise.
	* Rules: Likewise.
	* elf/Makefile: Likewise.
	* extra-lib.mk: Likewise.
	* gmon/Makefile: Likewise.
	* nis/Makefile: Likewise.
	* nss/Makefile: Likewise.
	* resolv/Makefile: Likewise.
	* rpm/Makefile: Likewise.
	* sunrpc/Makefile: Likewise.
	* sysdeps/sparc/elf/Makefile: Likewise.
	* sysdeps/sparc64/elf/Makefile: Likewise.
	* sysdeps/unix/sysv/linux/sparc/Makefile: Likewise.
	(ASFLAGS-.os): Renamed from as-FLAGS.os.
1997-08-20 03:53:21 +00:00

617 lines
15 KiB
C

/* The Inner Net License, Version 2.00
The author(s) grant permission for redistribution and use in source and
binary forms, with or without modification, of the software and documentation
provided that the following conditions are met:
0. If you receive a version of the software that is specifically labelled
as not being for redistribution (check the version message and/or README),
you are not permitted to redistribute that version of the software in any
way or form.
1. All terms of the all other applicable copyrights and licenses must be
followed.
2. Redistributions of source code must retain the authors' copyright
notice(s), this list of conditions, and the following disclaimer.
3. Redistributions in binary form must reproduce the authors' copyright
notice(s), this list of conditions, and the following disclaimer in the
documentation and/or other materials provided with the distribution.
4. All advertising materials mentioning features or use of this software
must display the following acknowledgement with the name(s) of the
authors as specified in the copyright notice(s) substituted where
indicated:
This product includes software developed by <name(s)>, The Inner
Net, and other contributors.
5. Neither the name(s) of the author(s) nor the names of its contributors
may be used to endorse or promote products derived from this software
without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY ITS AUTHORS AND CONTRIBUTORS ``AS IS'' AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
If these license terms cause you a real problem, contact the author. */
/* This software is Copyright 1996 by Craig Metz, All Rights Reserved. */
/* getaddrinfo() v1.13 */
#include <sys/types.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/socket.h>
#include <stdio.h>
#include <string.h>
#include <sys/utsname.h>
#include <sys/un.h>
#include <netinet/in.h>
#include <netdb.h>
#include <errno.h>
#include <arpa/inet.h>
#define GAIH_OKIFUNSPEC 0x0100
#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
#ifndef UNIX_PATH_MAX
#define UNIX_PATH_MAX 108
#endif
struct gaih_service
{
const char *name;
int num;
};
struct gaih_servtuple
{
struct gaih_servtuple *next;
int socktype;
int protocol;
int port;
};
static struct gaih_servtuple nullserv = { NULL, 0, 0, 0 };
struct gaih_addrtuple
{
struct gaih_addrtuple *next;
int family;
char addr[16];
};
struct gaih_typeproto
{
int socktype;
int protocol;
char *name;
};
static struct gaih_typeproto gaih_inet_typeproto[] =
{
{ 0, 0, NULL },
{ SOCK_STREAM, IPPROTO_TCP, (char *) "tcp" },
{ SOCK_DGRAM, IPPROTO_UDP, (char *) "udp" },
{ 0, 0, NULL }
};
struct gaih
{
int family;
int (*gaih)(const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai);
};
static struct addrinfo default_hints =
{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
static int
gaih_local (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai)
{
struct utsname utsname;
if ((name != NULL) || (req->ai_flags & AI_CANONNAME))
if (uname(&utsname))
return -EAI_SYSTEM;
if (name != NULL)
{
if (strcmp(name, "localhost") &&
strcmp(name, "local") &&
strcmp(name, "unix") &&
strcmp(name, utsname.nodename))
return GAIH_OKIFUNSPEC | -EAI_NONAME;
}
*pai = malloc (sizeof(struct addrinfo) + sizeof(struct sockaddr_un)
+ ((req->ai_flags & AI_CANONNAME)
? (strlen(utsname.nodename) + 1): 0));
if (*pai == NULL)
return -EAI_MEMORY;
(*pai)->ai_next = NULL;
(*pai)->ai_flags = req->ai_flags;
(*pai)->ai_family = AF_LOCAL;
(*pai)->ai_socktype = req->ai_socktype ? req->ai_socktype : SOCK_STREAM;
(*pai)->ai_protocol = req->ai_protocol;
(*pai)->ai_addrlen = sizeof(struct sockaddr_un);
(*pai)->ai_addr = (void *)(*pai) + sizeof(struct addrinfo);
#if SALEN
((struct sockaddr_un *) (*pai)->ai_addr)->sun_len =
sizeof (struct sockaddr_un);
#endif /* SALEN */
((struct sockaddr_un *)(*pai)->ai_addr)->sun_family = AF_LOCAL;
memset(((struct sockaddr_un *)(*pai)->ai_addr)->sun_path, 0, UNIX_PATH_MAX);
if (service)
{
struct sockaddr_un *sunp = (struct sockaddr_un *) (*pai)->ai_addr;
if (strchr (service->name, '/') != NULL)
{
if (strlen (service->name) >= sizeof (sunp->sun_path))
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
strcpy (sunp->sun_path, service->name);
}
else
{
if (strlen (P_tmpdir "/") + 1 + strlen (service->name) >=
sizeof (sunp->sun_path))
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
__stpcpy (__stpcpy (sunp->sun_path, P_tmpdir "/"), service->name);
}
}
else
{
if (tmpnam (((struct sockaddr_un *) (*pai)->ai_addr)->sun_path) == NULL)
return -EAI_SYSTEM;
}
if (req->ai_flags & AI_CANONNAME)
strcpy ((*pai)->ai_canonname = (char *)(*pai) + sizeof(struct addrinfo) +
sizeof(struct sockaddr_un), utsname.nodename);
else
(*pai)->ai_canonname = NULL;
return 0;
}
static int
gaih_inet_serv (const char *servicename, struct gaih_typeproto *tp,
struct gaih_servtuple **st)
{
struct servent *s;
size_t tmpbuflen = 1024;
struct servent ts;
char *tmpbuf;
int r;
do
{
tmpbuf = __alloca (tmpbuflen);
if (tmpbuf == NULL)
return -EAI_MEMORY;
r = __getservbyname_r (servicename, tp->name, &ts, tmpbuf, tmpbuflen,
&s);
if (r)
{
if (errno == ERANGE)
tmpbuflen *= 2;
else
return GAIH_OKIFUNSPEC | -EAI_SERVICE;
}
}
while (r);
*st = malloc (sizeof (struct gaih_servtuple));
if (*st == NULL)
return -EAI_MEMORY;
(*st)->next = NULL;
(*st)->socktype = tp->socktype;
(*st)->protocol = tp->protocol;
(*st)->port = s->s_port;
return 0;
}
#define gethosts(_family, _type) \
{ \
int i, herrno; \
size_t tmpbuflen; \
struct hostent th; \
char *tmpbuf; \
tmpbuflen = 512; \
do { \
tmpbuflen *= 2; \
tmpbuf = __alloca (tmpbuflen); \
if (tmpbuf == NULL) \
return -EAI_MEMORY; \
rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \
tmpbuflen, &h, &herrno); \
} while ((rc != 0) && \
(herrno == NETDB_INTERNAL) && (errno == ERANGE)); \
if ((rc != 0) && (herrno == NETDB_INTERNAL)) \
{ \
__set_h_errno (herrno); \
return -EAI_SYSTEM; \
} \
if (h != NULL) \
{ \
for (i = 0; h->h_addr_list[i]; i++) \
{ \
if (*pat == NULL) \
{ \
*pat = __alloca (sizeof(struct gaih_addrtuple)); \
if (*pat == NULL) \
return -EAI_MEMORY; \
} \
(*pat)->next = NULL; \
(*pat)->family = _family; \
memcpy ((*pat)->addr, h->h_addr_list[i], \
sizeof(_type)); \
pat = &((*pat)->next); \
} \
} \
}
static int
gaih_inet (const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai)
{
struct gaih_typeproto *tp = gaih_inet_typeproto;
struct gaih_servtuple *st = &nullserv;
struct gaih_addrtuple *at = NULL;
int rc;
if (req->ai_protocol || req->ai_socktype)
{
for (tp++; tp->name &&
((req->ai_socktype != tp->socktype) || !req->ai_socktype) &&
((req->ai_protocol != tp->protocol) || !req->ai_protocol); tp++);
if (tp->name == NULL)
if (req->ai_socktype)
return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
else
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
}
if (service != NULL)
{
if (service->num < 0)
{
if (tp->name != NULL)
{
if (rc = gaih_inet_serv (service->name, tp, &st))
return rc;
}
else
{
struct gaih_servtuple **pst = &st;
for (tp++; tp->name; tp++)
{
if (rc = gaih_inet_serv (service->name, tp, pst))
{
if (rc & GAIH_OKIFUNSPEC)
continue;
return rc;
}
pst = &((*pst)->next);
}
if (st == &nullserv)
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
}
}
else
{
st = __alloca (sizeof(struct gaih_servtuple));
if (st == NULL)
return -EAI_MEMORY;
st->next = NULL;
st->socktype = tp->socktype;
st->protocol = tp->protocol;
st->port = htons (service->num);
}
}
if (name != NULL)
{
at = __alloca (sizeof(struct gaih_addrtuple));
if (at == NULL)
return -EAI_MEMORY;
at->family = 0;
at->next = NULL;
if (at->family || !req->ai_family || (req->ai_family == AF_INET))
if (inet_pton (AF_INET, name, at->addr) > 0)
at->family = AF_INET;
if (!at->family && (!req->ai_family || (req->ai_family == AF_INET6)))
if (inet_pton (AF_INET6, name, at->addr) > 0)
at->family = AF_INET6;
if (at->family == AF_UNSPEC)
{
struct hostent *h;
struct gaih_addrtuple **pat = &at;
if ((req->ai_family == AF_UNSPEC) || (req->ai_family == AF_INET6))
gethosts (AF_INET6, struct in6_addr);
if ((req->ai_family == AF_UNSPEC) || (req->ai_family == AF_INET))
gethosts (AF_INET, struct in_addr);
}
if (at->family == AF_UNSPEC)
return (GAIH_OKIFUNSPEC | -EAI_NONAME);
}
else
{
at = __alloca (sizeof(struct gaih_addrtuple));
if (at == NULL)
return -EAI_MEMORY;
memset (at, 0, sizeof(struct gaih_addrtuple));
at->next = __alloca (sizeof(struct gaih_addrtuple));
if (at->next == NULL)
return -EAI_MEMORY;
at->family = AF_INET6;
memset (at->next, 0, sizeof(struct gaih_addrtuple));
at->next->family = AF_INET;
}
if (pai == NULL)
return 0;
{
const char *c = NULL;
struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
size_t socklen, namelen;
/*
buffer is the size of an unformatted IPv6 address in printable format.
*/
char buffer[sizeof "ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255"];
while (at2 != NULL)
{
if (req->ai_flags & AI_CANONNAME)
{
struct hostent *h = NULL;
int herrno;
struct hostent th;
size_t tmpbuflen = 512;
char *tmpbuf;
do
{
tmpbuflen *= 2;
tmpbuf = __alloca (tmpbuflen);
if (tmpbuf == NULL)
return -EAI_MEMORY;
rc = __gethostbyaddr_r (at2->addr,
((at2->family == AF_INET6)
? sizeof(struct in6_addr)
: sizeof(struct in_addr)),
at2->family, &th, tmpbuf, tmpbuflen,
&h, &herrno);
}
while ((rc != 0) && (herrno == NETDB_INTERNAL)
&& (errno == ERANGE));
if ((rc != 0) && (herrno == NETDB_INTERNAL))
{
__set_h_errno (herrno);
return -EAI_SYSTEM;
}
if (h == NULL)
c = inet_ntop (at2->family, at2->addr, buffer, sizeof(buffer));
else
c = h->h_name;
if (c == NULL)
return GAIH_OKIFUNSPEC | -EAI_NONAME;
namelen = strlen (c) + 1;
}
else
namelen = 0;
if (at2->family == AF_INET6)
socklen = sizeof (struct sockaddr_in6);
else
socklen = sizeof (struct sockaddr_in);
for (st2 = st; st2 != NULL; st2 = st2->next)
{
*pai = malloc (sizeof (struct addrinfo) + socklen + namelen);
if (*pai == NULL)
return -EAI_MEMORY;
(*pai)->ai_flags = req->ai_flags;
(*pai)->ai_family = at2->family;
(*pai)->ai_socktype = st2->socktype;
(*pai)->ai_protocol = st2->protocol;
(*pai)->ai_addrlen = socklen;
(*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo);
#if SALEN
((struct sockaddr_in *) (*pai)->ai_addr)->sin_len = i;
#endif /* SALEN */
((struct sockaddr_in *) (*pai)->ai_addr)->sin_family = at2->family;
((struct sockaddr_in *) (*pai)->ai_addr)->sin_port = st2->port;
if (at2->family == AF_INET6)
{
struct sockaddr_in6 *sin6p =
(struct sockaddr_in6 *) (*pai)->ai_addr;
sin6p->sin6_flowinfo = 0;
memcpy (&sin6p->sin6_addr,
at2->addr, sizeof (struct in6_addr));
}
else
{
struct sockaddr_in *sinp =
(struct sockaddr_in *) (*pai)->ai_addr;
memcpy (&sinp->sin_addr,
at2->addr, sizeof (struct in_addr));
memset (sinp->sin_zero, '\0', sizeof (sinp->sin_zero));
}
if (c)
{
(*pai)->ai_canonname = ((void *) (*pai) +
sizeof (struct addrinfo) + socklen);
strcpy ((*pai)->ai_canonname, c);
}
else
(*pai)->ai_canonname = NULL;
(*pai)->ai_next = NULL;
pai = &((*pai)->ai_next);
}
at2 = at2->next;
}
}
return 0;
}
static struct gaih gaih[] =
{
{ PF_INET6, gaih_inet },
{ PF_INET, gaih_inet },
{ PF_LOCAL, gaih_local },
{ PF_UNSPEC, NULL }
};
int
getaddrinfo (const char *name, const char *service,
const struct addrinfo *hints, struct addrinfo **pai)
{
int i = 0, j = 0;
struct addrinfo *p = NULL, **end;
struct gaih *g = gaih, *pg = NULL;
struct gaih_service gaih_service, *pservice;
if (name != NULL && name[0] == '*' && name[1] == 0)
name = NULL;
if (service != NULL && service[0] == '*' && service[1] == 0)
service = NULL;
if (name == NULL && service == NULL)
return EAI_NONAME;
if (hints == NULL)
hints = &default_hints;
if (hints->ai_flags & ~3)
return EAI_BADFLAGS;
if ((hints->ai_flags & AI_CANONNAME) && name == NULL)
return EAI_BADFLAGS;
if (service && service[0])
{
char *c;
gaih_service.name = service;
gaih_service.num = strtoul (gaih_service.name, &c, 10);
if (*c)
gaih_service.num = -1;
else
/* Can't specify a numerical socket unless a protocol family was
given. */
if (hints->ai_socktype == 0)
return EAI_SERVICE;
pservice = &gaih_service;
}
else
pservice = NULL;
if (pai)
end = &p;
else
end = NULL;
while (g->gaih)
{
if ((hints->ai_family == g->family) || (hints->ai_family == AF_UNSPEC))
{
j++;
if ((pg == NULL) || (pg->gaih != g->gaih))
{
pg = g;
if (i = g->gaih (name, pservice, hints, end))
{
if ((hints->ai_family == AF_UNSPEC) && (i & GAIH_OKIFUNSPEC))
continue;
if (p)
freeaddrinfo (p);
return (i)?-(i & GAIH_EAI):EAI_NONAME;
}
if (end)
while(*end) end = &((*end)->ai_next);
}
}
++g;
}
if (j == 0)
return EAI_FAMILY;
if (p)
{
*pai = p;
return 0;
}
if (pai == NULL && i == 0)
return 0;
if (p)
freeaddrinfo (p);
return i ? -(i & GAIH_EAI) : EAI_NONAME;
}
void
freeaddrinfo (struct addrinfo *ai)
{
struct addrinfo *p;
while (ai != NULL)
{
p = ai;
ai = ai->ai_next;
free (p);
}
}