Update.
authorUlrich Drepper <drepper@redhat.com>
Fri, 29 Oct 1999 21:40:21 +0000 (21:40 +0000)
committerUlrich Drepper <drepper@redhat.com>
Fri, 29 Oct 1999 21:40:21 +0000 (21:40 +0000)
1999-10-27  Andreas Jaeger  <aj@suse.de>

* 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 <jdd@cs.toronto.edu>.

(_res_hconf_reorder_addrs): Made thread safe.
(free_mem): New function, needed for malloc debugging.

1999-10-29  Andreas Jaeger  <aj@suse.de>

* 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.

ChangeLog
include/sys/socket.h
resolv/res_hconf.c
socket/Makefile
sysdeps/generic/ifreq.h [new file with mode: 0644]
sysdeps/generic/opensock.c [new file with mode: 0644]
sysdeps/unix/sysv/linux/if_index.c

index c0e78f9..ef35f05 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,25 @@
+1999-10-27  Andreas Jaeger  <aj@suse.de>
+
+       * 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 <jdd@cs.toronto.edu>.
+
+       (_res_hconf_reorder_addrs): Made thread safe.
+       (free_mem): New function, needed for malloc debugging.
+
+1999-10-29  Andreas Jaeger  <aj@suse.de>
+
+       * 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  <aj@suse.de>
 
        * sysdeps/unix/sysv/linux/mips/bits/ioctl-types.h: Added missing
index d6737f5..dadd866 100644 (file)
@@ -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
index 56b9535..59da9d6 100644 (file)
@@ -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 <errno.h>
 #include <ctype.h>
 #include <memory.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <net/if.h>
-
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <bits/libc-lock.h>
+#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);
index 430b758..360a1dc 100644 (file)
@@ -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 (file)
index 0000000..6443c09
--- /dev/null
@@ -0,0 +1,76 @@
+/* Copyright (C) 1999 Free Software Foundation, Inc.
+   Contributed by Andreas Jaeger <aj@suse.de>.
+
+   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 <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+
+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 (file)
index 0000000..b3e29b5
--- /dev/null
@@ -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 <stdio.h>
+#include <sys/socket.h>
+#include <bits/libc-lock.h>
+
+/* 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;
+}
index 58fb164..44d310b 100644 (file)
@@ -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;