From 925c3c5c71596c02f7e58a0ffcdcaae44eb065c1 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Thu, 24 Apr 2003 23:45:17 +0000 Subject: [PATCH] Update. 2003-04-24 Ulrich Drepper * include/ifaddrs.h: New file. * include/netdb.h: Move definitions of AI_V4MAPPED, AI_ALL, and AI_ADDRCONFIG... * resolv/netdb.h: ...here. * sysdeps/gnu/ifaddrs.c. Use libc_hidden_def where appropriate. * sysdeps/unix/sysv/linux/ifaddrs.c: Likewise. * sysdeps/posix/getaddrinfo.c: Implement AI_V4MAPPED, AI_ALL, and AI_ADDRCONFIG. --- ChangeLog | 11 + NEWS | 8 +- configure | 344 +++++++++++++++++++++++++++++- include/netdb.h | 8 +- resolv/netdb.h | 4 + sysdeps/gnu/ifaddrs.c | 6 +- sysdeps/posix/getaddrinfo.c | 304 ++++++++++++++++++-------- sysdeps/unix/sysv/linux/ifaddrs.c | 2 + 8 files changed, 582 insertions(+), 105 deletions(-) diff --git a/ChangeLog b/ChangeLog index 95fdc51b1a..16f95f9255 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,14 @@ +2003-04-24 Ulrich Drepper + + * include/ifaddrs.h: New file. + * include/netdb.h: Move definitions of AI_V4MAPPED, AI_ALL, and + AI_ADDRCONFIG... + * resolv/netdb.h: ...here. + * sysdeps/gnu/ifaddrs.c. Use libc_hidden_def where appropriate. + * sysdeps/unix/sysv/linux/ifaddrs.c: Likewise. + * sysdeps/posix/getaddrinfo.c: Implement AI_V4MAPPED, AI_ALL, and + AI_ADDRCONFIG. + 2003-04-24 Roland McGrath * elf/dl-reloc.c (_dl_allocate_static_tls): Add internal_function. diff --git a/NEWS b/NEWS index 9ac019c660..b10c6f0bdc 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,4 @@ -GNU C Library NEWS -- history of user-visible changes. 2003-3-15 +GNU C Library NEWS -- history of user-visible changes. 2003-4-24 Copyright (C) 1992-2002,2003 Free Software Foundation, Inc. See the end for copying conditions. @@ -12,6 +12,12 @@ Version 2.3.3 * ELF thread-local storage support (TLS) now works on PowerPC and PowerPC64; implemented by Paul Mackerras, Steven Munroe, and Roland McGrath. + +* getifaddrs new uses on Linux the netlink interface to get the information. + Implemented by Thorsten Kukuk. + +* getaddrinfo now implements AI_V4MAPPED, AI_ALL, and AI_ADDRCONF. + Implemented by Ulrich Drepper. Version 2.3.2 diff --git a/configure b/configure index 33584db941..7847773884 100755 --- a/configure +++ b/configure @@ -312,7 +312,7 @@ ac_includes_default="\ # include #endif" -ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi subdirs force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os base_machine sysnames INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF CCVERSION SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO OLD_DEBIAN_INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_initfinit_array libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_Bgroup libc_cv_z_combreloc libc_cv_have_initfini libc_cv_cpp_asm_debuginfo no_whole_archive exceptions LIBGD EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir use_ldconfig ldd_rewrite_script gnu_ld gnu_as elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES linux_doors mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS' +ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS with_fp with_cvs enable_check_abi oldest_abi subdirs force_install all_warnings build build_cpu build_vendor build_os host host_cpu host_vendor host_os base_machine sysnames INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA LN_S CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC OBJEXT BUILD_CC cross_compiling CPP CXX CXXFLAGS ac_ct_CXX AR OBJDUMP RANLIB ac_ct_RANLIB MIG AS LD PWD_P MAKE MSGFMT MAKEINFO SED AUTOCONF CCVERSION SYSINCLUDES libc_cv_gcc_static_libgcc BASH libc_cv_have_bash2 KSH libc_cv_have_ksh AWK PERL INSTALL_INFO OLD_DEBIAN_INSTALL_INFO BISON VERSIONING libc_cv_asm_protected_directive libc_cv_initfinit_array libc_cv_z_nodelete libc_cv_z_nodlopen libc_cv_z_initfirst libc_cv_Bgroup libc_cv_z_combreloc libc_cv_have_initfini libc_cv_cpp_asm_debuginfo no_whole_archive exceptions LIBGD EGREP sizeof_long_double libc_cv_gcc_unwind_find_fde uname_sysname uname_release uname_version old_glibc_headers libc_cv_slibdir libc_cv_localedir libc_cv_sysconfdir libc_cv_rootsbindir use_ldconfig ldd_rewrite_script gnu_ld gnu_as elf xcoff static shared pic_default profile omitfp bounded static_nss nopic_initfini DEFINES linux_doors mach_interface_list VERSION RELEASE LIBOBJS LTLIBOBJS' ac_subst_files='' # Initialize some variables set by options. @@ -773,6 +773,14 @@ ac_env_CPP_set=${CPP+set} ac_env_CPP_value=$CPP ac_cv_env_CPP_set=${CPP+set} ac_cv_env_CPP_value=$CPP +ac_env_CXX_set=${CXX+set} +ac_env_CXX_value=$CXX +ac_cv_env_CXX_set=${CXX+set} +ac_cv_env_CXX_value=$CXX +ac_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_env_CXXFLAGS_value=$CXXFLAGS +ac_cv_env_CXXFLAGS_set=${CXXFLAGS+set} +ac_cv_env_CXXFLAGS_value=$CXXFLAGS # # Report the --help message. @@ -901,6 +909,8 @@ Some influential environment variables: CPPFLAGS C/C++ preprocessor flags, e.g. -I if you have headers in a nonstandard directory CPP C preprocessor + CXX C++ compiler command + CXXFLAGS C++ compiler flags Use these variables to override the choices made by `configure' or to help it to find libraries and programs with nonstandard names/locations. @@ -3200,6 +3210,327 @@ ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' ac_compiler_gnu=$ac_cv_c_compiler_gnu +# We need the C++ compiler only for testing. +ac_ext=cc +ac_cpp='$CXXCPP $CPPFLAGS' +ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_cxx_compiler_gnu +if test -n "$ac_tool_prefix"; then + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC + do + # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args. +set dummy $ac_tool_prefix$ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$CXX"; then + ac_cv_prog_CXX="$CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_CXX="$ac_tool_prefix$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +CXX=$ac_cv_prog_CXX +if test -n "$CXX"; then + echo "$as_me:$LINENO: result: $CXX" >&5 +echo "${ECHO_T}$CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$CXX" && break + done +fi +if test -z "$CXX"; then + ac_ct_CXX=$CXX + for ac_prog in $CCC g++ c++ gpp aCC CC cxx cc++ cl FCC KCC RCC xlC_r xlC +do + # Extract the first word of "$ac_prog", so it can be a program name with args. +set dummy $ac_prog; ac_word=$2 +echo "$as_me:$LINENO: checking for $ac_word" >&5 +echo $ECHO_N "checking for $ac_word... $ECHO_C" >&6 +if test "${ac_cv_prog_ac_ct_CXX+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + if test -n "$ac_ct_CXX"; then + ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test. +else +as_save_IFS=$IFS; IFS=$PATH_SEPARATOR +for as_dir in $PATH +do + IFS=$as_save_IFS + test -z "$as_dir" && as_dir=. + for ac_exec_ext in '' $ac_executable_extensions; do + if $as_executable_p "$as_dir/$ac_word$ac_exec_ext"; then + ac_cv_prog_ac_ct_CXX="$ac_prog" + echo "$as_me:$LINENO: found $as_dir/$ac_word$ac_exec_ext" >&5 + break 2 + fi +done +done + +fi +fi +ac_ct_CXX=$ac_cv_prog_ac_ct_CXX +if test -n "$ac_ct_CXX"; then + echo "$as_me:$LINENO: result: $ac_ct_CXX" >&5 +echo "${ECHO_T}$ac_ct_CXX" >&6 +else + echo "$as_me:$LINENO: result: no" >&5 +echo "${ECHO_T}no" >&6 +fi + + test -n "$ac_ct_CXX" && break +done +test -n "$ac_ct_CXX" || ac_ct_CXX="g++" + + CXX=$ac_ct_CXX +fi + + +# Provide some information about the compiler. +echo "$as_me:$LINENO:" \ + "checking for C++ compiler version" >&5 +ac_compiler=`set X $ac_compile; echo $2` +{ (eval echo "$as_me:$LINENO: \"$ac_compiler --version &5\"") >&5 + (eval $ac_compiler --version &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -v &5\"") >&5 + (eval $ac_compiler -v &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } +{ (eval echo "$as_me:$LINENO: \"$ac_compiler -V &5\"") >&5 + (eval $ac_compiler -V &5) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } + +echo "$as_me:$LINENO: checking whether we are using the GNU C++ compiler" >&5 +echo $ECHO_N "checking whether we are using the GNU C++ compiler... $ECHO_C" >&6 +if test "${ac_cv_cxx_compiler_gnu+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ +#ifndef __GNUC__ + choke me +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_compiler_gnu=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_compiler_gnu=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +ac_cv_cxx_compiler_gnu=$ac_compiler_gnu + +fi +echo "$as_me:$LINENO: result: $ac_cv_cxx_compiler_gnu" >&5 +echo "${ECHO_T}$ac_cv_cxx_compiler_gnu" >&6 +GXX=`test $ac_compiler_gnu = yes && echo yes` +ac_test_CXXFLAGS=${CXXFLAGS+set} +ac_save_CXXFLAGS=$CXXFLAGS +CXXFLAGS="-g" +echo "$as_me:$LINENO: checking whether $CXX accepts -g" >&5 +echo $ECHO_N "checking whether $CXX accepts -g... $ECHO_C" >&6 +if test "${ac_cv_prog_cxx_g+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ + +int +main () +{ + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_prog_cxx_g=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_prog_cxx_g=no +fi +rm -f conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_prog_cxx_g" >&5 +echo "${ECHO_T}$ac_cv_prog_cxx_g" >&6 +if test "$ac_test_CXXFLAGS" = set; then + CXXFLAGS=$ac_save_CXXFLAGS +elif test $ac_cv_prog_cxx_g = yes; then + if test "$GXX" = yes; then + CXXFLAGS="-g -O2" + else + CXXFLAGS="-g" + fi +else + if test "$GXX" = yes; then + CXXFLAGS="-O2" + else + CXXFLAGS= + fi +fi +for ac_declaration in \ + ''\ + '#include ' \ + 'extern "C" void std::exit (int) throw (); using std::exit;' \ + 'extern "C" void std::exit (int); using std::exit;' \ + 'extern "C" void exit (int) throw ();' \ + 'extern "C" void exit (int);' \ + 'void exit (int);' +do + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + : +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +continue +fi +rm -f conftest.$ac_objext conftest.$ac_ext + cat >conftest.$ac_ext <<_ACEOF +#line $LINENO "configure" +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +$ac_declaration +int +main () +{ +exit (42); + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + break +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +fi +rm -f conftest.$ac_objext conftest.$ac_ext +done +rm -f conftest* +if test -n "$ac_declaration"; then + echo '#ifdef __cplusplus' >>confdefs.h + echo $ac_declaration >>confdefs.h + echo '#endif' >>confdefs.h +fi + +ac_ext=c +ac_cpp='$CPP $CPPFLAGS' +ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5' +ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5' +ac_compiler_gnu=$ac_cv_c_compiler_gnu + # Was a --with-binutils option given? if test -n "$path_binutils"; then # Make absolute; ensure a single trailing slash. @@ -5203,7 +5534,7 @@ if test "${libc_cv_asm_underscores+set}" = set; then echo $ECHO_N "(cached) $ECHO_C" >&6 else cat > conftest.$ac_ext <&6 else cat > conftest.c <&6 else cat > conftest.c <&6 else cat > conftest.c < diff --git a/resolv/netdb.h b/resolv/netdb.h index 69c2f8a11c..cca9ffc830 100644 --- a/resolv/netdb.h +++ b/resolv/netdb.h @@ -569,6 +569,10 @@ struct gaicb # 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. */ diff --git a/sysdeps/gnu/ifaddrs.c b/sysdeps/gnu/ifaddrs.c index 6ecc457e50..5bc3224bea 100644 --- a/sysdeps/gnu/ifaddrs.c +++ b/sysdeps/gnu/ifaddrs.c @@ -1,5 +1,5 @@ /* getifaddrs -- get names and addresses of all network interfaces - Copyright (C) 2002 Free Software Foundation, Inc. + Copyright (C) 2002, 2003 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or @@ -151,9 +151,13 @@ getifaddrs (struct ifaddrs **ifap) return 0; } +#ifndef getifaddrs +libc_hidden_def (getifaddrs) +#endif void freeifaddrs (struct ifaddrs *ifa) { free (ifa); } +libc_hidden_def (freeifaddrs) diff --git a/sysdeps/posix/getaddrinfo.c b/sysdeps/posix/getaddrinfo.c index e016876b6c..819a85d9ef 100644 --- a/sysdeps/posix/getaddrinfo.c +++ b/sysdeps/posix/getaddrinfo.c @@ -37,6 +37,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include +#include #include #include #include @@ -111,12 +112,17 @@ struct gaih const struct addrinfo *req, struct addrinfo **pai); }; -#if PF_UNSPEC == 0 -static const struct addrinfo default_hints; -#else static const struct addrinfo default_hints = - { 0, PF_UNSPEC, 0, 0, 0, NULL, NULL, NULL }; -#endif + { + .ai_flags = AI_DEFAULT, + .ai_family = PF_UNSPEC, + .ai_socktype = 0, + .ai_protocol = 0, + .ai_addrlen = 0, + .ai_addr = NULL, + .ai_canonname = NULL, + .ai_next = NULL + }; #if 0 @@ -265,93 +271,137 @@ gaih_inet_serv (const char *servicename, const struct gaih_typeproto *tp, return 0; } -#define gethosts(_family, _type) \ - { \ - int i, herrno; \ - size_t tmpbuflen; \ - struct hostent th; \ - char *tmpbuf = NULL; \ - tmpbuflen = 512; \ - no_data = 0; \ - do { \ - tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ - rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \ - tmpbuflen, &h, &herrno); \ - } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ - if (rc != 0) \ - { \ - if (herrno == NETDB_INTERNAL) \ - { \ - __set_h_errno (herrno); \ - return -EAI_SYSTEM; \ - } \ - if (herrno == TRY_AGAIN) \ - no_data = EAI_AGAIN; \ - else \ - no_data = herrno == NO_DATA; \ - } \ - else if (h != NULL) \ - { \ - for (i = 0; h->h_addr_list[i]; i++) \ - { \ - if (*pat == NULL) { \ - *pat = __alloca (sizeof (struct gaih_addrtuple)); \ - (*pat)->scopeid = 0; \ - } \ - (*pat)->next = NULL; \ - (*pat)->family = _family; \ - memcpy ((*pat)->addr, h->h_addr_list[i], \ - sizeof(_type)); \ - pat = &((*pat)->next); \ - } \ - } \ +#define gethosts(_family, _type) \ + { \ + int i, herrno; \ + size_t tmpbuflen; \ + struct hostent th; \ + char *tmpbuf = NULL; \ + tmpbuflen = 512; \ + no_data = 0; \ + do { \ + tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ + rc = __gethostbyname2_r (name, _family, &th, tmpbuf, \ + tmpbuflen, &h, &herrno); \ + } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ + if (rc != 0) \ + { \ + if (herrno == NETDB_INTERNAL) \ + { \ + __set_h_errno (herrno); \ + return -EAI_SYSTEM; \ + } \ + if (herrno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ + else \ + no_data = herrno == NO_DATA; \ + } \ + else if (h != NULL) \ + { \ + for (i = 0; h->h_addr_list[i]; i++) \ + { \ + if (*pat == NULL) { \ + *pat = __alloca (sizeof (struct gaih_addrtuple)); \ + (*pat)->scopeid = 0; \ + } \ + (*pat)->next = NULL; \ + (*pat)->family = _family; \ + memcpy ((*pat)->addr, h->h_addr_list[i], \ + sizeof(_type)); \ + pat = &((*pat)->next); \ + } \ + if (_family == AF_INET6) \ + got_ipv6 = true; \ + } \ + else if (_family == AF_INET6 && (req->ai_flags & AI_V4MAPPED)) \ + { \ + /* We have to add V4 mapped addresses. Maybe we discard them \ + later again but we get them anyhow for now. */ \ + while ((rc = __gethostbyname2_r (name, AF_INET6, &th, tmpbuf, \ + tmpbuflen, &h, &herrno)) == ERANGE \ + && herrno == NETDB_INTERNAL) \ + tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ + \ + if (rc != 0) \ + { \ + if (herrno == NETDB_INTERNAL) \ + { \ + __set_h_errno (herrno); \ + return -EAI_SYSTEM; \ + } \ + if (herrno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ + else \ + no_data = herrno == NO_DATA; \ + } \ + else if (h != NULL) \ + { \ + for (i = 0; h->h_addr_list[i]; ++i) \ + { \ + if (*pat == NULL) \ + { \ + *pat = __alloca (sizeof (struct gaih_addrtuple)); \ + (*pat)->scopeid = 0; \ + } \ + uint32_t *addr = (uint32_t *) (*pat)->addr; \ + (*pat)->next = NULL; \ + (*pat)->family = _family; \ + addr[3] = *(uint32_t *) h->h_addr_list[i]; \ + addr[2] = htonl (0xffff); \ + addr[1] = 0; \ + addr[0] = 0; \ + pat = &((*pat)->next); \ + } \ + } \ + } \ } -#define gethosts2(_family, _type) \ - { \ - int i, herrno; \ - size_t tmpbuflen; \ - struct hostent th; \ - char *tmpbuf = NULL; \ - tmpbuflen = 512; \ - no_data = 0; \ - do { \ - tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ - rc = 0; \ - status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, \ - tmpbuflen, &rc, &herrno)); \ - } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ - if (status == NSS_STATUS_SUCCESS && rc == 0) \ - h = &th; \ - else \ - h = NULL; \ - if (rc != 0) \ - { \ - if (herrno == NETDB_INTERNAL) \ - { \ - __set_h_errno (herrno); \ - return -EAI_SYSTEM; \ - } \ - if (herrno == TRY_AGAIN) \ - no_data = EAI_AGAIN; \ - else \ - no_data = herrno == NO_DATA; \ - } \ - else if (h != NULL) \ - { \ - for (i = 0; h->h_addr_list[i]; i++) \ - { \ - if (*pat == NULL) { \ - *pat = __alloca (sizeof (struct gaih_addrtuple)); \ - (*pat)->scopeid = 0; \ - } \ - (*pat)->next = NULL; \ - (*pat)->family = _family; \ - memcpy ((*pat)->addr, h->h_addr_list[i], \ - sizeof(_type)); \ - pat = &((*pat)->next); \ - } \ - } \ + +#define gethosts2(_family, _type) \ + { \ + int i, herrno; \ + size_t tmpbuflen; \ + struct hostent th; \ + char *tmpbuf = NULL; \ + tmpbuflen = 512; \ + no_data = 0; \ + do { \ + tmpbuf = extend_alloca (tmpbuf, tmpbuflen, 2 * tmpbuflen); \ + rc = 0; \ + status = DL_CALL_FCT (fct, (name, _family, &th, tmpbuf, \ + tmpbuflen, &rc, &herrno)); \ + } while (rc == ERANGE && herrno == NETDB_INTERNAL); \ + if (status == NSS_STATUS_SUCCESS && rc == 0) \ + h = &th; \ + else \ + h = NULL; \ + if (rc != 0) \ + { \ + if (herrno == NETDB_INTERNAL) \ + { \ + __set_h_errno (herrno); \ + return -EAI_SYSTEM; \ + } \ + if (herrno == TRY_AGAIN) \ + no_data = EAI_AGAIN; \ + else \ + no_data = herrno == NO_DATA; \ + } \ + else if (h != NULL) \ + { \ + for (i = 0; h->h_addr_list[i]; i++) \ + { \ + if (*pat == NULL) { \ + *pat = __alloca (sizeof (struct gaih_addrtuple)); \ + (*pat)->scopeid = 0; \ + } \ + (*pat)->next = NULL; \ + (*pat)->family = _family; \ + memcpy ((*pat)->addr, h->h_addr_list[i], \ + sizeof(_type)); \ + pat = &((*pat)->next); \ + } \ + } \ } typedef enum nss_status (*nss_gethostbyname2_r) @@ -368,6 +418,7 @@ gaih_inet (const char *name, const struct gaih_service *service, struct gaih_servtuple *st = (struct gaih_servtuple *) &nullserv; struct gaih_addrtuple *at = NULL; int rc; + bool got_ipv6 = false; if (req->ai_protocol || req->ai_socktype) { @@ -490,6 +541,13 @@ gaih_inet (const char *name, const struct gaih_service *service, { if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET) at->family = AF_INET; + else if (req->ai_flags & AI_V4MAPPED) + { + ((uint32_t *) at->addr)[3] = *(uint32_t *) at->addr; + ((uint32_t *) at->addr)[2] = htonl (0xffff); + ((uint32_t *) at->addr)[1] = 0; + ((uint32_t *) at->addr)[0] = 0; + } else return -EAI_ADDRFAMILY; } @@ -507,6 +565,8 @@ gaih_inet (const char *name, const struct gaih_service *service, { if (req->ai_family == AF_UNSPEC || req->ai_family == AF_INET6) at->family = AF_INET6; + else if (IN6_IS_ADDR_V4MAPPED (at->addr)) + *(uint32_t *) at->addr = ((uint32_t *) at->addr)[3]; else return -EAI_ADDRFAMILY; @@ -747,6 +807,14 @@ gaih_inet (const char *name, const struct gaih_service *service, { family = AF_INET6; socklen = sizeof (struct sockaddr_in6); + + /* If we looked up IPv4 mapped address discard them here if + the caller isn't interested in all address and we have + found at least one IPv6 address. */ + if (! got_ipv6 + && (req->ai_flags & (AI_V4MAPPED|AI_ALL)) == AI_V4MAPPED + && IN6_IS_ADDR_V4MAPPED (at2->addr)) + goto ignore; } else { @@ -765,7 +833,7 @@ gaih_inet (const char *name, const struct gaih_service *service, (*pai)->ai_socktype = st2->socktype; (*pai)->ai_protocol = st2->protocol; (*pai)->ai_addrlen = socklen; - (*pai)->ai_addr = (void *) (*pai) + sizeof(struct addrinfo); + (*pai)->ai_addr = (void *) (*pai) + sizeof (struct addrinfo); #if SALEN (*pai)->ai_addr->sa_len = socklen; #endif /* SALEN */ @@ -805,6 +873,7 @@ gaih_inet (const char *name, const struct gaih_service *service, pai = &((*pai)->ai_next); } + ignore: at2 = at2->next; } } @@ -829,6 +898,7 @@ getaddrinfo (const char *name, const char *service, struct addrinfo *p = NULL, **end; struct gaih *g = gaih, *pg = NULL; struct gaih_service gaih_service, *pservice; + struct addrinfo local_hints; if (name != NULL && name[0] == '*' && name[1] == 0) name = NULL; @@ -842,12 +912,62 @@ getaddrinfo (const char *name, const char *service, if (hints == NULL) hints = &default_hints; - if (hints->ai_flags & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST)) + if (hints->ai_flags + & ~(AI_PASSIVE|AI_CANONNAME|AI_NUMERICHOST|AI_ADDRCONFIG|AI_V4MAPPED + |AI_ALL)) return EAI_BADFLAGS; if ((hints->ai_flags & AI_CANONNAME) && name == NULL) return EAI_BADFLAGS; + if (hints->ai_flags & AI_ADDRCONFIG) + { + /* Determine whether we have IPv4 or IPv6 interfaces or both. + We cannot cache the results since new interfaces could be + added at any time. + + XXX We are using getifaddrs here which is more costly than + it is really necessary. Once things are stable we will have + a special function which performs the task with less overhead. */ + struct ifaddrs* ifa = NULL; + + if (getifaddrs (&ifa) != 0) + /* Cannot get the interface list, very bad. */ + return EAI_SYSTEM; + + bool seen_ipv4 = false; + bool seen_ipv6 = false; + + while (ifa != NULL) + { + if (ifa->ifa_addr->sa_family == PF_INET) + seen_ipv4 = true; + else if (ifa->ifa_addr->sa_family == PF_INET6) + seen_ipv6 = true; + + ifa = ifa->ifa_next; + } + + (void) freeifaddrs (ifa); + + /* Now make a decision on what we return, if anything. */ + if (hints->ai_family == PF_UNSPEC) + { + /* If we haven't seen both IPv4 and IPv6 interfaces we can + narrow down the search. */ + if (! seen_ipv4 || ! seen_ipv6) + { + local_hints = *hints; + local_hints.ai_family = seen_ipv4 ? PF_INET : PF_INET6; + hints = &local_hints; + } + } + else if ((hints->ai_family == PF_INET && ! seen_ipv4) + || (hints->ai_family == PF_INET6 && ! seen_ipv6)) + /* We cannot possibly return a valid answer. */ + return EAI_NONAME; + } + if (service && service[0]) { char *c; diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c index b310043b6a..a6f928d846 100644 --- a/sysdeps/unix/sysv/linux/ifaddrs.c +++ b/sysdeps/unix/sysv/linux/ifaddrs.c @@ -796,6 +796,7 @@ getifaddrs (struct ifaddrs **ifap) return result; } +libc_hidden_def (getifaddrs) #if __ASSUME_NETLINK_SUPPORT != 0 @@ -804,4 +805,5 @@ freeifaddrs (struct ifaddrs *ifa) { free (ifa); } +libc_hidden_def (freeifaddrs) #endif