From f34b5ec45f70109f4d3d321ea17f996ff4b1c14d Mon Sep 17 00:00:00 2001 From: Simon Josefsson Date: Wed, 10 Nov 2004 14:53:00 +0000 Subject: [PATCH] Add getaddrinfo. --- ChangeLog | 7 ++ MODULES.html.sh | 1 + lib/ChangeLog | 4 + lib/gai_strerror.c | 72 ++++++++++++++++ lib/getaddrinfo.c | 195 ++++++++++++++++++++++++++++++++++++++++++++ lib/getaddrinfo.h | 90 ++++++++++++++++++++ m4/ChangeLog | 4 + m4/getaddrinfo.m4 | 20 +++++ modules/getaddrinfo | 26 ++++++ 9 files changed, 419 insertions(+) create mode 100644 lib/gai_strerror.c create mode 100644 lib/getaddrinfo.c create mode 100644 lib/getaddrinfo.h create mode 100644 m4/getaddrinfo.m4 create mode 100644 modules/getaddrinfo diff --git a/ChangeLog b/ChangeLog index ed622eefec..dcef61a3e7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2004-11-08 Simon Josefsson + + * MODULES.html.sh (Support for systems lacking POSIX:2001): Add + getaddrinfo. + + * modules/getaddrinfo: New file. + 2004-11-10 Jim Meyering * modules/closeout (Depends-on): Remove fpending. diff --git a/MODULES.html.sh b/MODULES.html.sh index 9f56391f4d..9f8092154a 100755 --- a/MODULES.html.sh +++ b/MODULES.html.sh @@ -1730,6 +1730,7 @@ func_all_modules () func_module chown func_module dup2 func_module ftruncate + func_module getaddrinfo func_module getcwd func_module getgroups func_module gethostname diff --git a/lib/ChangeLog b/lib/ChangeLog index 97431d2607..91a9bf085d 100644 --- a/lib/ChangeLog +++ b/lib/ChangeLog @@ -1,3 +1,7 @@ +2004-11-08 Simon Josefsson + + * getaddrinfo.h, getaddrinfo.c: New file. + 2004-11-10 Jim Meyering Ensure that no close failure goes unreported. diff --git a/lib/gai_strerror.c b/lib/gai_strerror.c new file mode 100644 index 0000000000..953f1360f6 --- /dev/null +++ b/lib/gai_strerror.c @@ -0,0 +1,72 @@ +/* Copyright (C) 1997, 2001, 2002, 2004 Free Software Foundation, Inc. + This file is part of the GNU C Library. + Contributed by Philip Blundell , 1997. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + The GNU C Library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ + +#include +#include + +#ifdef _LIBC +# include +#else +# include "getaddrinfo.h" +# include "gettext.h" +# define _(String) gettext (String) +# define N_(String) String +#endif + +static struct + { + int code; + const char *msg; + } +values[] = + { + { EAI_ADDRFAMILY, N_("Address family for hostname not supported") }, + { EAI_AGAIN, N_("Temporary failure in name resolution") }, + { EAI_BADFLAGS, N_("Bad value for ai_flags") }, + { EAI_FAIL, N_("Non-recoverable failure in name resolution") }, + { EAI_FAMILY, N_("ai_family not supported") }, + { EAI_MEMORY, N_("Memory allocation failure") }, + { EAI_NODATA, N_("No address associated with hostname") }, + { EAI_NONAME, N_("Name or service not known") }, + { EAI_SERVICE, N_("Servname not supported for ai_socktype") }, + { EAI_SOCKTYPE, N_("ai_socktype not supported") }, + { EAI_SYSTEM, N_("System error") }, +#ifdef __USE_GNU + { EAI_INPROGRESS, N_("Processing request in progress") }, + { EAI_CANCELED, N_("Request canceled") }, + { EAI_NOTCANCELED, N_("Request not canceled") }, + { EAI_ALLDONE, N_("All requests done") }, + { EAI_INTR, N_("Interrupted by a signal") }, + { EAI_IDN_ENCODE, N_("Parameter string not correctly encoded") } +#endif + }; + +const char * +gai_strerror (int code) +{ + size_t i; + for (i = 0; i < sizeof (values) / sizeof (values[0]); ++i) + if (values[i].code == code) + return _(values[i].msg); + + return _("Unknown error"); +} +#ifdef _LIBC +libc_hidden_def (gai_strerror) +#endif diff --git a/lib/getaddrinfo.c b/lib/getaddrinfo.c new file mode 100644 index 0000000000..145eac519b --- /dev/null +++ b/lib/getaddrinfo.c @@ -0,0 +1,195 @@ +/* Get address information (partial implementation). + Copyright (C) 1997, 2001, 2002, 2004 Free Software Foundation, Inc. + Contributed by Simon Josefsson . + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#if HAVE_CONFIG_H +# include +#endif + +/* Get calloc. */ +#include + +/* Get memcpy. */ +#include + +/* Get struct hostent. */ +#include + +#include + +#include "gettext.h" +#define _(String) gettext (String) +#define N_(String) String + +#include "getaddrinfo.h" + +static inline bool +validate_family (int family) +{ + /* FIXME: Support more families. */ +#if HAVE_IPV4 + if (family == PF_INET) + return true; +#endif +#if HAVE_IPV6 + if (family == PF_INET6) + return true; +#endif + if (family == PF_UNSPEC) + return true; + return false; +} + +/* Translate name of a service location and/or a service name to set of + socket addresses. */ +int +getaddrinfo (const char *restrict nodename, + const char *restrict servname, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res) +{ + struct addrinfo *tmp; + struct servent *se; + struct hostent *he; + size_t sinlen; + + if (hints && hints->ai_flags) + /* FIXME: Support more flags. */ + return EAI_BADFLAGS; + + if (hints && !validate_family (hints->ai_family)) + return EAI_FAMILY; + + if (hints && hints->ai_socktype) + /* FIXME: Support more socket types. */ + return EAI_SOCKTYPE; + + if (hints && + hints->ai_protocol != SOCK_STREAM && hints->ai_protocol != SOCK_DGRAM) + /* FIXME: Support other protocols. */ + return EAI_SERVICE; /* FIXME: Better return code? */ + + if (!nodename) + /* FIXME: Support server bind mode. */ + return EAI_NONAME; + + if (servname) + { + const char *proto = + (hints && hints->ai_protocol == SOCK_DGRAM) ? "udp" : "tcp"; + + /* FIXME: Use getservbyname_r if available. */ + se = getservbyname (servname, proto); + + if (!se) + return EAI_SERVICE; + } + + /* FIXME: Use gethostbyname_r if available. */ + he = gethostbyname (nodename); + if (!he || he->h_addr_list[0] == NULL) + return EAI_NONAME; + + switch (he->h_addrtype) + { +#if HAVE_IPV6 + case PF_INET6: + sinlen = sizeof (struct sockaddr_in6); + break; +#endif + +#if HAVE_IPV4 + case PF_INET: + sinlen = sizeof (struct sockaddr_in); + break; +#endif + + default: + return EAI_NODATA; + } + + tmp = calloc (1, sizeof (*tmp) + sinlen); + if (!tmp) + return EAI_MEMORY; + + switch (he->h_addrtype) + { +#if HAVE_IPV6 + case PF_INET6: + { + struct sockaddr_in6 *sinp = (void *) tmp + sizeof (*tmp); + + if (se) + sinp->sin6_port = se->s_port; + + if (he->h_length != sizeof (sinp->sin6_addr)) + return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ + + memcpy (&sinp->sin6_addr, he->h_addr_list[0], he->h_length); + + tmp->ai_addr = (struct sockaddr *) sinp; + tmp->ai_addrlen = sinlen; + } + break; +#endif + +#if HAVE_IPV4 + case PF_INET: + { + struct sockaddr_in *sinp = (void *) tmp + sizeof (*tmp); + + if (se) + sinp->sin_port = se->s_port; + + if (he->h_length != sizeof (sinp->sin_addr)) + return EAI_SYSTEM; /* FIXME: Better return code? Set errno? */ + + memcpy (&sinp->sin_addr, he->h_addr_list[0], he->h_length); + + tmp->ai_addr = (struct sockaddr *) sinp; + tmp->ai_addrlen = sinlen; + } + break; +#endif + + default: + free (tmp); + return EAI_NODATA; + } + + tmp->ai_addr->sa_family = he->h_addrtype; + + /* FIXME: If more than one address, create linked list of addrinfo's. */ + + *res = tmp; + + return 0; +} + +/* Free `addrinfo' structure AI including associated storage. */ +void +freeaddrinfo (struct addrinfo *ai) +{ + while (ai) + { + struct addrinfo *cur; + + cur = ai; + ai = ai->ai_next; + free (cur); + } +} diff --git a/lib/getaddrinfo.h b/lib/getaddrinfo.h new file mode 100644 index 0000000000..59553234e9 --- /dev/null +++ b/lib/getaddrinfo.h @@ -0,0 +1,90 @@ +/* Get address information. + Copyright (C) 1996-2002, 2003, 2004 Free Software Foundation, Inc. + Contributed by Simon Josefsson . + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2, or (at your option) + any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ + +#ifndef GETADDRINFO_H +# define GETADDRINFO_H + +/* Get getaddrinfo declarations, if available. */ +# include +# include + +# if defined HAVE_GETADDRINFO && !HAVE_GETADDRINFO + +/* Get socklen_t, struct sockaddr. */ +# include + +/* Structure to contain information about address of a service provider. */ +struct addrinfo +{ + int ai_flags; /* Input flags. */ + int ai_family; /* Protocol family for socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol for socket. */ + socklen_t ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address for socket. */ + char *ai_canonname; /* Canonical name for service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; + +/* Possible values for `ai_flags' field in `addrinfo' structure. */ +# define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */ +# define AI_CANONNAME 0x0002 /* Request for canonical name. */ +# define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */ +# define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */ +# define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */ +# define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose + returned address type.. */ + +/* Error values for `getaddrinfo' function. */ +# define EAI_BADFLAGS -1 /* Invalid value for `ai_flags' field. */ +# define EAI_NONAME -2 /* NAME or SERVICE is unknown. */ +# define EAI_AGAIN -3 /* Temporary failure in name resolution. */ +# define EAI_FAIL -4 /* Non-recoverable failure in name res. */ +# define EAI_NODATA -5 /* No address associated with NAME. */ +# define EAI_FAMILY -6 /* `ai_family' not supported. */ +# define EAI_SOCKTYPE -7 /* `ai_socktype' not supported. */ +# define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype'. */ +# define EAI_ADDRFAMILY -9 /* Address family for NAME not supported. */ +# define EAI_MEMORY -10 /* Memory allocation failure. */ +# define EAI_SYSTEM -11 /* System error returned in `errno'. */ +# define EAI_OVERFLOW -12 /* Argument buffer overflow. */ +# ifdef __USE_GNU +# define EAI_INPROGRESS -100 /* Processing request in progress. */ +# define EAI_CANCELED -101 /* Request canceled. */ +# define EAI_NOTCANCELED -102 /* Request not canceled. */ +# define EAI_ALLDONE -103 /* All requests done. */ +# define EAI_INTR -104 /* Interrupted by a signal. */ +# define EAI_IDN_ENCODE -105 /* IDN encoding failed. */ +# endif + +/* Translate name of a service location and/or a service name to set of + socket addresses. */ +extern int getaddrinfo (const char *restrict nodename, + const char *restrict servname, + const struct addrinfo *restrict hints, + struct addrinfo **restrict res); + +/* Free `addrinfo' structure AI including associated storage. */ +extern void freeaddrinfo (struct addrinfo *ai); + +/* Convert error return from getaddrinfo() to a string. */ +extern const char *gai_strerror (int ecode); + +# endif + +#endif /* GETADDRINFO_H */ diff --git a/m4/ChangeLog b/m4/ChangeLog index 8c5a7d27e3..f7bc10b2cf 100644 --- a/m4/ChangeLog +++ b/m4/ChangeLog @@ -1,3 +1,7 @@ +2004-11-08 Simon Josefsson + + * getaddrinfo.m4: New file. + 2004-11-09 Paul Eggert * strftime.m4 (_gl_STRFTIME_PREREQS): Remove. Move its body to diff --git a/m4/getaddrinfo.m4 b/m4/getaddrinfo.m4 new file mode 100644 index 0000000000..10de9d67ed --- /dev/null +++ b/m4/getaddrinfo.m4 @@ -0,0 +1,20 @@ +# getaddrinfo.m4 serial 1 +dnl Copyright (C) 2004 Free Software Foundation, Inc. +dnl This file is free software, distributed under the terms of the GNU +dnl General Public License. As a special exception to the GNU General +dnl Public License, this file may be distributed as part of a program +dnl that contains a configuration script generated by Autoconf, under +dnl the same distribution terms as the rest of that program. + +AC_DEFUN([gl_GETADDRINFO], +[ + AC_REPLACE_FUNCS(getaddrinfo) + gl_PREREQ_GETADDRINFO +]) + +# Prerequisites of lib/getaddrinfo.h and lib/getaddrinfo.c. +AC_DEFUN([gl_PREREQ_GETADDRINFO], [ + AC_REQUIRE([gl_C_RESTRICT]) + AC_REQUIRE([gl_SOCKET_FAMILIES]) + AC_REQUIRE([AC_C_INLINE]) +]) diff --git a/modules/getaddrinfo b/modules/getaddrinfo new file mode 100644 index 0000000000..67c5952f43 --- /dev/null +++ b/modules/getaddrinfo @@ -0,0 +1,26 @@ +Description: +Get address information. + +Files: +lib/getaddrinfo.h +lib/getaddrinfo.c +lib/gai_strerror.c +m4/getaddrinfo.m4 +m4/sockpfaf.m4 + +Depends-on: +restrict +gettext +stdbool + +configure.ac: +gl_GETADDRINFO + +Makefile.am: +lib_SOURCES += getaddrinfo.h + +Include: +"getaddrinfo.h" + +Maintainer: +Simon Josefsson -- 2.30.2