diff options
author | Ulrich Drepper <drepper@redhat.com> | 2007-11-23 03:03:59 +0000 |
---|---|---|
committer | Ulrich Drepper <drepper@redhat.com> | 2007-11-23 03:03:59 +0000 |
commit | 5c3a3dba227808f16a1dc2676c9fc49f66945b08 (patch) | |
tree | 1fd6c6ff9cecfe31a6cf215d31bf28e54c198c30 /resolv | |
parent | 8588312396635a2c5f13bd235217597456e0e4d2 (diff) | |
download | glibc-5c3a3dba227808f16a1dc2676c9fc49f66945b08.tar.gz glibc-5c3a3dba227808f16a1dc2676c9fc49f66945b08.tar.xz glibc-5c3a3dba227808f16a1dc2676c9fc49f66945b08.zip |
[BZ #5375]
* resolv/res_hconf.c (_res_hconf_reorder_addrs): Fix locking when initializing interface list.
Diffstat (limited to 'resolv')
-rw-r--r-- | resolv/res_hconf.c | 80 |
1 files changed, 44 insertions, 36 deletions
diff --git a/resolv/res_hconf.c b/resolv/res_hconf.c index c53b809ef7..25f7397927 100644 --- a/resolv/res_hconf.c +++ b/resolv/res_hconf.c @@ -377,9 +377,6 @@ static struct netaddr } 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. @@ -393,6 +390,8 @@ _res_hconf_reorder_addrs (struct hostent *hp) int i, j; /* Number of interfaces. */ static int num_ifs = -1; + /* We need to protect the dynamic buffer handling. */ + __libc_lock_define_initialized (static, lock); /* Only reorder if we're supposed to. */ if ((_res_hconf.flags & HCONF_FLAG_REORDER) == 0) @@ -411,8 +410,6 @@ _res_hconf_reorder_addrs (struct hostent *hp) /* Initialize interface table. */ - num_ifs = 0; - /* The SIOCGIFNETMASK ioctl will only work on an AF_INET socket. */ sd = __socket (AF_INET, SOCK_DGRAM, 0); if (sd < 0) @@ -421,45 +418,56 @@ _res_hconf_reorder_addrs (struct hostent *hp) /* Get lock. */ __libc_lock_lock (lock); - /* Get a list of interfaces. */ - __ifreq (&ifr, &num, sd); - if (!ifr) - goto cleanup; + /* Recheck, somebody else might have done the work by done. */ + if (num_ifs <= 0) + { + int new_num_ifs = 0; - ifaddrs = malloc (num * sizeof (ifaddrs[0])); - if (!ifaddrs) - goto cleanup1; + /* Get a list of interfaces. */ + __ifreq (&ifr, &num, sd); + if (!ifr) + goto cleanup; - /* Copy usable interfaces in ifaddrs structure. */ - for (cur_ifr = ifr, i = 0; i < num; cur_ifr = __if_nextreq (cur_ifr), ++i) - { - if (cur_ifr->ifr_addr.sa_family != AF_INET) - continue; + ifaddrs = malloc (num * sizeof (ifaddrs[0])); + if (!ifaddrs) + goto cleanup1; - ifaddrs[num_ifs].addrtype = AF_INET; - ifaddrs[num_ifs].u.ipv4.addr = - ((struct sockaddr_in *) &cur_ifr->ifr_addr)->sin_addr.s_addr; + /* Copy usable interfaces in ifaddrs structure. */ + for (cur_ifr = ifr, i = 0; i < num; + cur_ifr = __if_nextreq (cur_ifr), ++i) + { + if (cur_ifr->ifr_addr.sa_family != AF_INET) + continue; - if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0) - continue; + ifaddrs[new_num_ifs].addrtype = AF_INET; + ifaddrs[new_num_ifs].u.ipv4.addr = + ((struct sockaddr_in *) &cur_ifr->ifr_addr)->sin_addr.s_addr; - ifaddrs[num_ifs].u.ipv4.mask = - ((struct sockaddr_in *) &cur_ifr->ifr_netmask)->sin_addr.s_addr; + if (__ioctl (sd, SIOCGIFNETMASK, cur_ifr) < 0) + continue; - /* Now we're committed to this entry. */ - ++num_ifs; - } - /* Just keep enough memory to hold all the interfaces we want. */ - ifaddrs = realloc (ifaddrs, num_ifs * sizeof (ifaddrs[0])); - assert (ifaddrs != NULL); + ifaddrs[new_num_ifs].u.ipv4.mask = + ((struct sockaddr_in *) &cur_ifr->ifr_netmask)->sin_addr.s_addr; - cleanup1: - __if_freereq (ifr, num); + /* Now we're committed to this entry. */ + ++new_num_ifs; + } + /* Just keep enough memory to hold all the interfaces we want. */ + ifaddrs = realloc (ifaddrs, new_num_ifs * sizeof (ifaddrs[0])); + assert (ifaddrs != NULL); + + cleanup1: + __if_freereq (ifr, num); + + cleanup: + /* Release lock, preserve error value, and close socket. */ + save = errno; + + num_ifs = new_num_ifs; + + __libc_lock_unlock (lock); + } - cleanup: - /* Release lock, preserve error value, and close socket. */ - save = errno; - __libc_lock_unlock (lock); __close (sd); } |