diff --git a/ChangeLog b/ChangeLog index c0e78f9e3d..ef35f05cbc 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,25 @@ +1999-10-27 Andreas Jaeger + + * sysdeps/generic/ifreq.h: New file. + + * resolv/res_hconf.c: Add missing includes to get all prototypes. + (_res_hconf_reorder_addrs): Rewrite. This never worked before. + Reported by John DiMarco . + + (_res_hconf_reorder_addrs): Made thread safe. + (free_mem): New function, needed for malloc debugging. + +1999-10-29 Andreas Jaeger + + * sysdeps/unix/sysv/linux/if_index.c (opensock): Move function to ... + * sysdeps/generic/opensock.c (__opensock): ...here in a new file. + * sysdeps/unix/sysv/linux/if_index.c: Change all callers of + opensock to use __opensock. + + * socket/Makefile (routines): Add opensock. + + * include/sys/socket.h (__opensock): Add prototype declaration. + 1999-10-29 Andreas Jaeger * sysdeps/unix/sysv/linux/mips/bits/ioctl-types.h: Added missing diff --git a/include/sys/socket.h b/include/sys/socket.h index d6737f5b34..dadd866613 100644 --- a/include/sys/socket.h +++ b/include/sys/socket.h @@ -3,4 +3,9 @@ /* Now define the internal interfaces. */ extern int __socket (int __domain, int __type, int __protocol) __THROW; + +/* Return a socket of any type. The socket can be used in subsequent + ioctl calls to talk to the kernel. */ +extern int __opensock (void) internal_function; + #endif diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c index 56b9535d5e..59da9d6753 100644 --- a/resolv/res_hconf.c +++ b/resolv/res_hconf.c @@ -17,9 +17,9 @@ Boston, MA 02111-1307, USA. */ /* This file provides a Linux /etc/host.conf compatible front end to -the various name resolvers (/etc/hosts, named, NIS server, etc.). -Though mostly compatibly, the following differences exist compared -to the original implementation: + the various name resolvers (/etc/hosts, named, NIS server, etc.). + Though mostly compatibly, the following differences exist compared + to the original implementation: - new command "spoof" takes an arguments like RESOLV_SPOOF_CHECK environment variable (i.e., `off', `nowarn', or `warn'). @@ -27,13 +27,19 @@ to the original implementation: - line comments can appear anywhere (not just at the beginning of a line) */ + +#include #include #include #include #include #include #include - +#include +#include +#include +#include +#include "ifreq.h" #include "res_hconf.h" #define _PATH_HOSTCONF "/etc/host.conf" @@ -374,113 +380,118 @@ _res_hconf_init (void) } +/* List of known interfaces. */ +static struct netaddr +{ + int addrtype; + union + { + struct + { + u_int32_t addr; + u_int32_t mask; + } ipv4; + } u; +} *ifaddrs; + +/* We need to protect the dynamic buffer handling. */ +__libc_lock_define_initialized (static, lock); + /* Reorder addresses returned in a hostent such that the first address is an address on the local subnet, if there is such an address. - Otherwise, nothing is changed. */ + Otherwise, nothing is changed. + + Note that this function currently only handles IPv4 addresses. */ void _res_hconf_reorder_addrs (struct hostent *hp) { #if defined SIOCGIFCONF && defined SIOCGIFNETMASK - static int num_ifs = -1; /* number of interfaces */ - static struct netaddr - { - int addrtype; - union - { - struct - { - u_int32_t addr; - u_int32_t mask; - } ipv4 - } u; - } *ifaddrs; + int i, j; + /* Number of interfaces. */ + static int num_ifs = -1; + /* Only reorder if we're supposed to. */ + if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0) + return; + + /* Can't deal with anything but IPv4 for now... */ if (hp->h_addrtype != AF_INET) - return; /* can't deal with anything but IPv4 for now... */ + return; if (num_ifs <= 0) { - struct ifconf ifs; - struct ifreq *ifr; - size_t size, num; - int sd; - - /* initialize interface table: */ + struct ifreq *ifr, *cur_ifr; + int sd, num, i; + /* Save errno. */ + int save = errno; + + /* Initialize interface table. */ num_ifs = 0; - sd = __socket (AF_INET, SOCK_DGRAM, 0); + sd = __opensock (); if (sd < 0) return; - /* Now get list of interfaces. Since we don't know how many - interfaces there are, we keep increasing the buffer size - until we have at least sizeof(struct ifreq) too many bytes. - That implies that the ioctl() return because it ran out of - interfaces, not memory */ - size = 0; - ifs.ifc_buf = 0; - do - { - size += 4 * sizeof (struct ifreq); - ifs.ifc_buf = realloc (ifs.ifs_buf, size); - if (ifs.ifc_buf == NULL) - { - close (sd); - return; - } - ifs.ifc_len = size; - if (__ioctl (sd, SIOCGIFCONF, &ifs) < 0) - goto cleanup; - } - while (size - ifs.ifc_len < sizeof (struct ifreq)); + /* Get lock. */ + __libc_lock_lock (lock); - num = ifs.ifc_len / sizeof (struct ifreq); + /* Get a list of interfaces. */ + __ifreq (&ifr, &num); + if (!ifr) + goto cleanup; ifaddrs = malloc (num * sizeof (ifaddrs[0])); if (!ifaddrs) - goto cleanup; - - ifr = ifs.ifc_req; - for (i = 0; i < num; ++i) + goto cleanup1; + + /* Copy usable interfaces in ifaddrs structure. */ + for (cur_ifr = ifr, i = 0; i < num; ++cur_ifr, ++i) { - if (ifr->ifr_addr.sa_family != AF_INET) + if (cur_ifr->ifr_addr.sa_family != AF_INET) continue; + ifaddrs[num_ifs].addrtype = AF_INET; + ifaddrs[num_ifs].u.ipv4.addr = + ((struct sockaddr_in *) &cur_ifr->ifr_addr)->sin_addr.s_addr; - memcpy (&ifaddrs[num_ifs].u.ipv4.addr, - &((struct sockaddr_in *)ifr->ifr_addr)->sin_addr, 4); - - if (__ioctl (sd, SIOCGIFNETMASK, if) < 0) + if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0) continue; - memcpy (&ifaddrs[num_ifs].u.ipv4.mask, - ((struct sockaddr_in *)ifr->ifr_mask)->sin_addr, 4); - ++num_ifs; /* now we're committed to this entry */ + ifaddrs[num_ifs].u.ipv4.mask = + ((struct sockaddr_in *) &cur_ifr->ifr_netmask)->sin_addr.s_addr; + + /* Now we're committed to this entry. */ + ++num_ifs; } - /* just keep enough memory to hold all the interfaces we want: */ + /* Just keep enough memory to hold all the interfaces we want. */ ifaddrs = realloc (ifaddrs, num_ifs * sizeof (ifaddrs[0])); + cleanup1: + __if_freereq (ifr); + cleanup: + /* Release lock, preserve error value, and close socket. */ + save = errno; + __libc_lock_unlock (lock); close (sd); - free (ifs.ifc_buf); } if (num_ifs == 0) return; - /* find an address for which we have a direct connection: */ + /* Find an address for which we have a direct connection. */ for (i = 0; hp->h_addr_list[i]; ++i) { - h_addr = (struct in_addr *) hp->h_addr_list[i]; + struct in_addr *haddr = (struct in_addr *) hp->h_addr_list[i]; for (j = 0; j < num_ifs; ++j) { - if_addr = ifaddrs[j].u.ipv4.addr; - if_netmask = ifaddrs[j].u.ipv4.mask; + u_int32_t if_addr = ifaddrs[j].u.ipv4.addr; + u_int32_t if_netmask = ifaddrs[j].u.ipv4.mask; - if (((h_addr->s_addr ^ if_addr) & if_netmask) == 0) + if (((haddr->s_addr ^ if_addr) & if_netmask) == 0) { void *tmp; @@ -537,3 +548,14 @@ _res_hconf_trim_domains (struct hostent *hp) for (i = 0; hp->h_aliases[i]; ++i) _res_hconf_trim_domain (hp->h_aliases[i]); } + + +/* Free all resources if necessary. */ +static void __attribute__ ((unused)) +free_mem (void) +{ + if (ifaddrs != NULL) + free (ifaddrs); +} + +text_set_element (__libc_subfreeres, free_mem); diff --git a/socket/Makefile b/socket/Makefile index 430b7585af..360a1dc753 100644 --- a/socket/Makefile +++ b/socket/Makefile @@ -26,6 +26,6 @@ headers := sys/socket.h sys/un.h bits/sockaddr.h bits/socket.h \ routines := accept bind connect getpeername getsockname getsockopt \ listen recv recvfrom recvmsg send sendmsg sendto \ - setsockopt shutdown socket socketpair isfdtype + setsockopt shutdown socket socketpair isfdtype opensock include ../Rules diff --git a/sysdeps/generic/ifreq.h b/sysdeps/generic/ifreq.h new file mode 100644 index 0000000000..6443c0925b --- /dev/null +++ b/sysdeps/generic/ifreq.h @@ -0,0 +1,76 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + Contributed by Andreas Jaeger . + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include +#include +#include +#include + + +static inline void +__ifreq (struct ifreq **ifreqs, int *num_ifs) +{ + int fd = __opensock (); + struct ifconf ifc; + int rq_len; + int nifs; +# define RQ_IFS 4 + + if (fd < 0) + { + *num_ifs = 0; + *ifreqs = NULL; + return; + } + + ifc.ifc_buf = NULL; + rq_len = RQ_IFS * sizeof (struct ifreq); + do + { + ifc.ifc_len = rq_len; + ifc.ifc_buf = realloc (ifc.ifc_buf, ifc.ifc_len); + if (ifc.ifc_buf == NULL || __ioctl (fd, SIOCGIFCONF, &ifc) < 0) + { + if (ifc.ifc_buf) + free (ifc.ifc_buf); + + __close (fd); + *num_ifs = 0; + *ifreqs = NULL; + return; + } + rq_len *= 2; + } + while (rq_len < sizeof (struct ifreq) + ifc.ifc_len); + + nifs = ifc.ifc_len / sizeof (struct ifreq); + + __close (fd); + + *num_ifs = nifs; + *ifreqs = realloc (ifc.ifc_buf, nifs * sizeof (struct ifreq)); +} + + +static inline void +__if_freereq (struct ifreq *ifreqs) +{ + free (ifreqs); +} diff --git a/sysdeps/generic/opensock.c b/sysdeps/generic/opensock.c new file mode 100644 index 0000000000..b3e29b5794 --- /dev/null +++ b/sysdeps/generic/opensock.c @@ -0,0 +1,70 @@ +/* Copyright (C) 1999 Free Software Foundation, Inc. + + The GNU C Library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public License as + published by the Free Software Foundation; either version 2 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public + License along with the GNU C Library; see the file COPYING.LIB. If not, + write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, + Boston, MA 02111-1307, USA. */ + +#include +#include +#include + +/* Return a socket of any type. The socket can be used in subsequent + ioctl calls to talk to the kernel. */ +int internal_function +__opensock (void) +{ + /* Cache the last AF that worked, to avoid many redundant calls to + socket(). */ + static int sock_af = -1; + int fd = -1; + __libc_lock_define_initialized (static, lock); + + if (sock_af != -1) + { + fd = __socket (sock_af, SOCK_DGRAM, 0); + if (fd != -1) + return fd; + } + + __libc_lock_lock (lock); + + if (sock_af != -1) + fd = __socket (sock_af, SOCK_DGRAM, 0); + + if (fd == -1) + { +#ifdef AF_INET + fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0); +#endif +#ifdef AF_INET6 + if (fd < 0) + fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0); +#endif +#ifdef AF_IPX + if (fd < 0) + fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0); +#endif +#ifdef AF_AX25 + if (fd < 0) + fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0); +#endif +#ifdef AF_APPLETALK + if (fd < 0) + fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0); +#endif + } + + __libc_lock_unlock (lock); + return fd; +} diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c index 58fb1648f2..44d310befe 100644 --- a/sysdeps/unix/sysv/linux/if_index.c +++ b/sysdeps/unix/sysv/linux/if_index.c @@ -35,47 +35,6 @@ static int old_siocgifconf; # define old_siocgifconf 0 #endif -/* Try to get a socket to talk to the kernel. */ -#if defined SIOCGIFINDEX || defined SIOCGIFNAME -static int -internal_function -opensock (void) -{ - /* Cache the last AF that worked, to avoid many redundant calls to - socket(). */ - static int sock_af = -1; - int fd = -1; - __libc_lock_define_initialized (static, lock); - - if (sock_af != -1) - { - fd = __socket (sock_af, SOCK_DGRAM, 0); - if (fd != -1) - return fd; - } - - __libc_lock_lock (lock); - - if (sock_af != -1) - fd = __socket (sock_af, SOCK_DGRAM, 0); - - if (fd == -1) - { - fd = __socket (sock_af = AF_INET, SOCK_DGRAM, 0); - if (fd < 0) - fd = __socket (sock_af = AF_INET6, SOCK_DGRAM, 0); - if (fd < 0) - fd = __socket (sock_af = AF_IPX, SOCK_DGRAM, 0); - if (fd < 0) - fd = __socket (sock_af = AF_AX25, SOCK_DGRAM, 0); - if (fd < 0) - fd = __socket (sock_af = AF_APPLETALK, SOCK_DGRAM, 0); - } - - __libc_lock_unlock (lock); - return fd; -} -#endif unsigned int if_nametoindex (const char *ifname) @@ -85,7 +44,7 @@ if_nametoindex (const char *ifname) return 0; #else struct ifreq ifr; - int fd = opensock (); + int fd = __opensock (); if (fd < 0) return 0; @@ -124,7 +83,7 @@ if_nameindex (void) __set_errno (ENOSYS); return NULL; #else - int fd = opensock (); + int fd = __opensock (); struct ifconf ifc; unsigned int nifs, i; int rq_len; @@ -235,7 +194,7 @@ if_indextoname (unsigned int ifindex, char *ifname) # endif int status; - fd = opensock (); + fd = __opensock (); if (fd < 0) return NULL; @@ -285,7 +244,7 @@ void internal_function __protocol_available (int *have_inet, int *have_inet6) { - int fd = opensock (); + int fd = __opensock (); unsigned int nifs; int rq_len; struct ifconf ifc;