glibc/sysdeps/posix/getaddrinfo.c
Ulrich Drepper ba1ffaa1c6 update from main archive 961030
Thu Oct 31 00:01:39 1996  Ulrich Drepper  <drepper@cygnus.com>

	* signal/Makefile (routines): Add sigwait.
	* signal/signal.h: Add prototype for sigwait.
	* sysdeps/posix/sigwait.c: New file.  Implementation of sigwait
	function from POSIX.1c.
	* sysdeps/stub/sigwait.c: New file.  Stub version of sigwait.

Wed Oct 30 02:01:17 1996  Richard Henderson  <rth@tamu.edu>

	* sunrpc/xdr_float.c (xdr_float): Handle sizeof(float)!=sizeof(long),
	but don't bother going farther than sizeof(float)==sizeof(int).
	(xdr_double): Handle little-endian machines!  Handle sizeof(double)
	!= 2*sizeof(long), though again don't bother with more than int.

Thu Oct 29 16:09:42 1996  Craig Metz  <cmetz@inner.net>

	* sysdeps/posix/getaddrinfo.c: Use buffer limits for inet_ntop
	function.

Tue Oct 29 12:37:22 1996  Ulrich Drepper  <drepper@cygnus.com>

	* Makerules: Create symbolic links for linking in $(libdir).
	(make-link): Use absolute path for destination if this is not in
	the same directory.

	* elf/rtld.c (dl_main): When verifying don't check the name of
	the dynamic linker.

	* shlib-versions: Change entries for Hurd specific libs from
	*-*-gnu* to *-*-gnu?* so that i586-pc-linux-gnu does not match
	these entries.

	* assert/assert.h: Reformat copyright.
	Change reference to ANSI into reference to ISO C.
	* ctype/ctype.h: Likewise.
	* errno.h: Likewise.
	* limits.h: Likewise.
	* math/math.h: Likewise.
	* setjmp/setjmp.h: Likewise.
	* stdio/stdio.h: Likewise.
	* libio/stdio.h: Likewise.
	* stdlib/stdlib.h: Likewise.
	* string/string.h: Likewise.
	* time/time.h: Likewise.

	* string/argz.h: Use __const is definitions.

	* elf/dlfcn.h: Use __const and __P.  Reformat copyright.
	* misc/err.h: Likewise.

	* wctype/wctype.h (wctrans_t): Use __const instead of const.

	* Makeconfig ($(common-objpfx)soversions.mk): Generate list of
	sonames for versioned libraries.
	* Makefile: Remove code to generate libc-version.h.
	Generate gnu/lib-names.h with info from soversions.mk.
	* features.h: Define __GLIBC__ and __GLIBC_MINOR__.

	* dirent/tst-seekdir.c: Initialize save3.
	* grp/testgrp.c: Initialize my_group.

	* grp/fgetgrent_r.c: Change interface to follow POSIX.1c.
	* grp/grp.h: Likewise.
	* nss/getXXbyYY.c: Likewise.
	* nss/getXXbyYY_r.c: Likewise.
	* nss/getXXent.c: Likewise.
	* nss/getXXent_r.c: Likewise.
	* pwd/fgetpwent_r.c: Likewise.
	* pwd/pwd.h: Likewise.
	* shadow/fgetspent_r.c: Likewise.
	* shadow/sgetspent.c: Likewise.
	* shadow/sgetspent_r.c: Likewise.
	* grp/fgetgrent.c: Adapt for change in interface of fgetgrent_r.
	* pwd/fgetpwent.c: Likewise, for fgetpwent_r.c.
	* shadow/fgetspent.c: Likewise, for fgetpwent_r.c.
	* resolv/netdb.h: Adapt prototypes for reentrant functions to
	follow POSIX.1c.
	* sunrpc/rpc/netdb.h: Likewise,
	* shadow/shadow.h: Likewise.

	* inet/getnetgrent_r.c: Follow change in pwd/grp function interface.

	* sysdeps/unix/getlogin_r.c: Return ERANGE when buffer is too small.

	* inet/herrno.c: Don't define __h_errno.  Only h_errno otherwise the
	ELF aliasing creates strange situations.
	* sysdeps/unix/sysv/linux/errnos.H: Define __set_errno as inline
	function.
	* sysdeps/unix/sysv/linux/i386/sysdep.S: Don't define __errno.
	* sysdeps/unix/sysv/linux/m68k/sysdep.S: Likewise.

	* libio/libio.h: Don't declare _IO_flockfile and _IO_funlockfile
	weak.

	* locale/programs/charmap.c: Add casts to prevent warnings.
	* locale/programs/linereader.h: Likewise.
	* locale/programs/ld-collate.c: Likewise.
	* locale/programs/stringtrans.c: Likewise.
	Change types for various variables to prevent warnings.
	* locale/programs/ld-ctype.c: Likewise.
	* locale/programs/linereader.h (lr_ungetc): Likewise.
	* locale/programs/charset.h (struct charset): Use `unsigned int'
	as type for width_default.
	* posix/regex.c: Change type of `this_reg' variables.
	* stdio-common/Makefile: Use -Wno-format for tstdiomisc.c.
	* stdio-common/bug5.c: De-ANSI-fy.  Use correct types for
	variables.
	* stdio-common/printf_fp.c: Initialize to_shift.
	* stdio-common/test_rdwr.c: Add cast.
	* stdio-common/vfprintf.c: Add casts and use correct types to
	prevent warnings.
	* stdio-common/vfscanf.c: Initialize str and strptr.
	* sysdeps/libm-ieee754/e_jnf.c: Use correct types to prevent warnings.
	* sysdeps/libm-ieee754/e_pow.c: Likewise.
	* sysdeps/libm-ieee754/e_powf.c: Likewise.
	* sysdeps/libm-ieee754/e_rem_pio2f.c: Likewise.
	* time/test-tz.c: Likewise.

	* manual/creature.texi: Document _REENTRANT and _THREAD_SAFE.
	* manual/libc.texinfo: Prevent makeinfo failure by avoiding
	libc.cp index.  This must be fixed.
	* manual/nss.texi: Adapt for correct POSIX.1c interface of
	reentrant functions.
	* manual/users.texi: Document netgroup functions.

	* po/es.po: Updated.
	* po/fr.po: Updated.

	* posix/fnmatch.c: Change to match libit version.

	* posix/unistd.h: Change prototype for ttyname_r to match POSIX.1c.
	* sysdep/posix/ttyname_r.c: Likewise.

	* stdlib/atexit.h (__new_exitfn): Add internal locking.
	* stdlib/exit.c: De-ANSI-fy.  Handle new ef_us value for flavor.
	* stdlib/exit.h: De-ANSI-fy.  Define new ef_us value for flavor.
	* stdlib/random.c (__srandom): Add internal locking.
	(__initstate): Likewise.
	(__setstate): Likewise.
	(__random): Likewise.

Mon Oct 28 22:28:37 1996  NIIBE Yutaka  <gniibe@mri.co.jp>

	* sysdeps/generic/crypt-entry.c (crypt_r): Use __set_errno.
	(crypt): Likewise.
	* resolv/gethnamaddr.c (gethostbyname2): Likewise.
	* sysdeps/generic/uname.c: Likewise.
	* sysdeps/posix/rename.c: Likewise.
	* sysdeps/stub/setrlimit.c: Likewise.

	* nss/nss_db/db-netgrp.c (_nss_db_setnetgrent): Fix typo.

Sun Oct 27 11:12:50 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* locale/programs/ld-collate.c (collate_order_elem): Fix format
	string.
	(collate_element_to): Cast field width argument to `int' for
	format string.
	(collate_symbol): Likewise.
	(collate_order_elem): Likewise.
	(collate_weight_bsymbol): Likewise.
	(collate_simple_weight): Likewise.

	* locale/programs/ld-time.c (STRARR_ELEM): Fix format string.

	* locale/programs/ld-ctype.c (ctype_class_newP): Add missing
	argument for format string.
	(ctype_map_newP): Likewise.
	(set_class_defaults): Fix format string.

	* locale/programs/localedef.c (construct_output_path): Putting an
	explicit \0 into the format string does not work, use %c.

Sat Oct 26 20:38:36 1996  Richard Henderson  <rth@tamu.edu>

	* Makerules: Install all shared libraries in $(slibdir).

	* login/Makefile: Build libutil.so in others pass after
	libc.so is created.

	* misc/mntent.h: Include <paths.h> for _PATH_MNTTAB & _PATH_MOUNTED.

	* string/stratcliff.c: Allocate 3 pages instead of one, then use
	mprotect so that we know that the adjacent pages are inaccessible.

	* resource/sys/resource.h: Move all structures and enums to ...
	* sysdeps/generic/resourcebits.h: ... here ...
	* sysdeps/unix/bsd/sun/sunos4/resourcebits.h: ... and here.
	* sysdeps/unix/sysv/linux/alpha/resourcebits.h: Remove.
	* sysdeps/unix/sysv/linux/i386/resourcebits.h: Remove.
	* sysdeps/unix/sysv/linux/m68k/resourcebits.h: Remove.
	* sysdeps/unix/sysv/linux/mips/resourcebits.h: Remove.
	* sysdeps/unix/sysv/linux/resourcebits.h: New file.  Use kernel
	header for RLIMIT_* definitions.  The members of struct rlimit
	are longs.


Thu Oct 24 17:43:34 1996  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* MakeTAGS (sysdep-dirs): Fix typo.

Wed Oct 23 03:45:22 1996  Ulrich Drepper  <drepper@cygnus.com>

	* Makefile (headers): Don't mention libc-version.h.
	(install-others): ...but here.

	* time/strptime.c: Recognize %s, %u, %g, and %G format.
 	nothing is found.  This guarantees all subsequent calls behave
	* sysdeps/unix/sysv/linux/syscalls.list: Change function name for
	* io/getwd.c (getwd) [! PATH_MAX]: Don't assume that the user's
	buffer is any longer than the amount necessary to hold the
	filename; the Hurd getcwd uses the *entire* contents of the
	buffer, however long it is specified to be.
	* posix/getconf.c: De-ANSI-fy.  Recognize POSIX.2 constant names.
	since these do not depend on the platform.
1996-10-31 02:57:12 +00:00

493 lines
12 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. */
#include <sys/types.h>
#include <sys/socket.h>
#include <stdlib.h>
#include <netinet/in.h>
#ifdef INET6
#include <netinet6/in6.h>
#endif /* INET6 */
#include <netdb.h>
#include <arpa/inet.h>
#include <string.h>
#define GAIH_OKIFUNSPEC 0x0100
#define GAIH_EAI ~(GAIH_OKIFUNSPEC)
#ifdef HOSTTABLE
struct hostent *_hostname2addr_hosts(const char *name, int);
struct hostent *_addr2hostname_hosts(const char *name, int, int);
#endif /* HOSTTABLE */
static struct addrinfo nullreq =
{ 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL };
struct gaih_service {
char *name;
unsigned long 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];
};
static struct gaih_addrtuple nulladdr;
struct gaih_typeproto {
int socktype;
int protocol;
const char *name;
};
static struct gaih_typeproto gaih_inet_typeproto[] = {
{ 0, 0, NULL },
{ SOCK_STREAM, IPPROTO_TCP, "tcp" },
{ SOCK_DGRAM, IPPROTO_UDP, "udp" },
{ 0, 0, NULL }
};
static int gaih_inet_serv(char *servicename, struct gaih_typeproto *tp, struct gaih_servtuple **st)
{
struct servent *s;
if (!(s = getservbyname(servicename, tp->name)))
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
if (!(*st = malloc(sizeof(struct gaih_servtuple))))
return -EAI_MEMORY;
(*st)->next = NULL;
(*st)->socktype = tp->socktype;
(*st)->protocol = tp->protocol;
(*st)->port = s->s_port;
return 0;
}
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 = &nulladdr;
int i;
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)
if (req->ai_socktype)
return (GAIH_OKIFUNSPEC | -EAI_SOCKTYPE);
else
return (GAIH_OKIFUNSPEC | -EAI_SERVICE);
}
if (service) {
if (service->name) {
if (tp->name) {
if (i = gaih_inet_serv(service->name, tp, &st))
return i;
} else {
struct gaih_servtuple **pst = &st;
for (tp++; tp->name; tp++) {
if (i = gaih_inet_serv(service->name, tp, pst)) {
if (i & GAIH_OKIFUNSPEC)
continue;
goto ret;
}
pst = &((*pst)->next);
}
if (st == &nullserv) {
i = (GAIH_OKIFUNSPEC | -EAI_SERVICE);
goto ret;
}
}
} else {
if (!(st = malloc(sizeof(struct gaih_servtuple))))
return -EAI_MEMORY;
st->next = NULL;
st->socktype = tp->socktype;
st->protocol = tp->protocol;
st->port = htons(service->num);
}
}
if (name) {
if (!(at = malloc(sizeof(struct gaih_addrtuple)))) {
i = -EAI_MEMORY;
goto ret;
}
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;
#ifdef INET6
if (!at->family && (!req->ai_family || (req->ai_family == AF_INET6)))
if (inet_pton(AF_INET6, name, at->addr) > 0)
at->family = AF_INET6;
#endif /* INET6 */
#ifdef HOSTTABLE
if (!at->family) {
struct hostent *h;
struct gaih_addrtuple **pat = &at;
#ifdef INET6
if (!req->ai_family || (req->ai_family == AF_INET6))
if (h = _hostname2addr_hosts(name, AF_INET6)) {
for (i = 0; h->h_addr_list[i]; i++) {
if (!*pat) {
if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
i = -EAI_MEMORY;
goto ret;
}
}
(*pat)->next = NULL;
(*pat)->family = AF_INET6;
memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr));
pat = &((*pat)->next);
}
}
#endif /* INET6 */
if (!req->ai_family || (req->ai_family == AF_INET))
if (h = _hostname2addr_hosts(name, AF_INET)) {
for (i = 0; h->h_addr_list[i]; i++) {
if (!*pat) {
if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
i = -EAI_MEMORY;
goto ret;
}
}
(*pat)->next = NULL;
(*pat)->family = AF_INET;
memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr));
pat = &((*pat)->next);
}
}
}
#endif /* HOSTTABLE */
#ifdef RESOLVER
if (!at->family) {
struct hostent *h;
struct gaih_addrtuple **pat = &at;
#ifdef INET6
if (!req->ai_family || (req->ai_family == AF_INET6))
if (h = gethostbyname2(name, AF_INET6)) {
for (i = 0; h->h_addr_list[i]; i++) {
if (!*pat) {
if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
i = -EAI_MEMORY;
goto ret;
}
}
(*pat)->next = NULL;
(*pat)->family = AF_INET6;
memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in6_addr));
pat = &((*pat)->next);
}
}
#endif /* INET6 */
if (!req->ai_family || (req->ai_family == AF_INET))
if (h = gethostbyname2(name, AF_INET)) {
for (i = 0; h->h_addr_list[i]; i++) {
if (!*pat) {
if (!(*pat = malloc(sizeof(struct gaih_addrtuple)))) {
i = -EAI_MEMORY;
goto ret;
}
}
(*pat)->next = NULL;
(*pat)->family = AF_INET;
memcpy((*pat)->addr, h->h_addr_list[i], sizeof(struct in_addr));
pat = &((*pat)->next);
}
}
}
#endif /* RESOLVER */
if (!at->family)
return (GAIH_OKIFUNSPEC | -EAI_NONAME);
} else {
memset(&nulladdr, 0, sizeof(nulladdr));
#ifdef INET6
if (!req->ai_family || (req->ai_family == AF_INET6))
nulladdr.family = AF_INET6;
else
#endif /* INET6 */
nulladdr.family = AF_INET;
}
{
const char *c = NULL;
struct gaih_servtuple *st2;
struct gaih_addrtuple *at2 = at;
int j;
#ifndef MAXHOSTNAMELEN
# define MAXHOSTNAMELEN 128
#endif /* MAXHOSTNAMELEN */
char buffer[MAXHOSTNAMELEN];
while(at2) {
if (req->ai_flags & AI_CANONNAME) {
struct hostent *h = NULL;
#ifdef RESOLVER
h = gethostbyaddr(at2->addr,
#ifdef INET6
(at2->family == AF_INET6) ? sizeof(struct in6_addr) :
#endif /* INET6 */
sizeof(struct in_addr), at2->family);
#endif /* RESOLVER */
#ifdef HOSTTABLE
if (!h)
h = _addr2hostname_hosts(at2->addr,
#ifdef INET6
(at2->family == AF_INET6) ? sizeof(struct in6_addr) :
#endif /* INET6 */
sizeof(struct in_addr), at2->family);
#endif /* HOSTTABLE */
if (!h)
c = inet_ntop(at2->family, at2->addr, buffer, sizeof(buffer));
else
c = h->h_name;
if (!c) {
i = (GAIH_OKIFUNSPEC | -EAI_NONAME);
goto ret;
}
j = strlen(c) + 1;
} else
j = 0;
#ifdef INET6
if (at2->family == AF_INET6)
i = sizeof(struct sockaddr_in6);
else
#endif /* INET6 */
i = sizeof(struct sockaddr_in);
st2 = st;
while(st2) {
if (!(*pai = malloc(sizeof(struct addrinfo) + i + j))) {
i = -EAI_MEMORY;
goto ret;
}
(*pai)->ai_flags = req->ai_flags;
(*pai)->ai_family = at2->family;
(*pai)->ai_socktype = st2->socktype;
(*pai)->ai_protocol = st2->protocol;
(*pai)->ai_addrlen = i;
(*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;
#ifdef INET6
if (at2->family == AF_INET6) {
((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_flowinfo = 0;
memcpy(&((struct sockaddr_in6 *)(*pai)->ai_addr)->sin6_addr, at2->addr, sizeof(struct in6_addr));
} else
#endif /* INET6 */
{
memcpy(&((struct sockaddr_in *)(*pai)->ai_addr)->sin_addr, at2->addr, sizeof(struct in_addr));
memset(((struct sockaddr_in *)(*pai)->ai_addr)->sin_zero, 0, sizeof(((struct sockaddr_in *)(*pai)->ai_addr)->sin_zero));
}
if (c) {
(*pai)->ai_canonname = (void *)(*pai) + sizeof(struct addrinfo) + i;
strcpy((*pai)->ai_canonname, c);
} else
(*pai)->ai_canonname = NULL;
(*pai)->ai_next = NULL;
pai = &((*pai)->ai_next);
st2 = st2->next;
}
at2 = at2->next;
}
}
i = 0;
ret:
if (st != &nullserv) {
struct gaih_servtuple *st2 = st;
while(st) {
st2 = st->next;
free(st);
st = st2;
}
}
if (at != &nulladdr) {
struct gaih_addrtuple *at2 = at;
while(at) {
at2 = at->next;
free(at);
at = at2;
}
}
return i;
}
struct gaih {
int family;
int (*gaih)(const char *name, const struct gaih_service *service,
const struct addrinfo *req, struct addrinfo **pai);
};
static struct gaih gaih[] = {
#ifdef INET6
{ PF_INET6, gaih_inet },
#endif /* INET6 */
{ PF_INET, gaih_inet },
{ PF_UNSPEC, NULL }
};
int getaddrinfo(const char *name, const char *service,
const struct addrinfo *req, struct addrinfo **pai)
{
int i = 0;
int j = 0;
struct addrinfo *p = NULL, **end = &p;
struct gaih *g = gaih, *pg = NULL;
struct gaih_service gaih_service, *pservice;
if (!name && !service)
return EAI_NONAME;
if (!req)
req = &nullreq;
if (req->ai_flags & ~3)
return EAI_BADFLAGS;
if ((req->ai_flags & AI_CANONNAME) && !name)
return EAI_BADFLAGS;
if (service && *service) {
char *c;
gaih_service.num = strtoul(gaih_service.name = (void *)service, &c, 10);
if (!*c) {
if (!req->ai_socktype)
return EAI_SERVICE;
gaih_service.name = NULL;
}
pservice = &gaih_service;
} else
pservice = NULL;
while(g->gaih) {
if ((req->ai_family == g->family) || !req->ai_family) {
j++;
if (!((pg && (pg->gaih == g->gaih)))) {
pg = g;
if ((i = g->gaih(name, pservice, req, end))) {
if (!req->ai_family && (i & GAIH_OKIFUNSPEC))
continue;
goto gaih_err;
}
while(*end) end = &((*end)->ai_next);
}
}
g++;
}
if (!j)
return EAI_FAMILY;
if (p) {
*pai = p;
return 0;
}
gaih_err:
if (p)
freeaddrinfo(p);
if (i)
return -(i & GAIH_EAI);
return EAI_NONAME;
}
void freeaddrinfo(struct addrinfo *ai)
{
struct addrinfo *p;
while(ai) {
p = ai;
ai = ai->ai_next;
free((void *)p);
}
}