about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog22
-rw-r--r--include/sys/socket.h5
-rw-r--r--resolv/res_hconf.c156
-rw-r--r--socket/Makefile2
-rw-r--r--sysdeps/generic/ifreq.h76
-rw-r--r--sysdeps/generic/opensock.c70
-rw-r--r--sysdeps/unix/sysv/linux/if_index.c49
7 files changed, 267 insertions, 113 deletions
diff --git a/ChangeLog b/ChangeLog
index c0e78f9e3d..ef35f05cbc 100644
--- 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
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 <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);
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 <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
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 <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;
+}
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;