summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorume <ume@FreeBSD.org>2002-07-25 08:08:30 +0000
committerume <ume@FreeBSD.org>2002-07-25 08:08:30 +0000
commit4b45c00ba2ff9582e2b76a588816500d11f09df7 (patch)
treece27716088c84c55e6af8f8e5f893bd9b349e31e
parent01685498260896305007adc292e89f474caa6ee6 (diff)
downloadFreeBSD-src-4b45c00ba2ff9582e2b76a588816500d11f09df7.zip
FreeBSD-src-4b45c00ba2ff9582e2b76a588816500d11f09df7.tar.gz
sysctl(NET_RT_IFLIST) up to several (currently 5) times.
This will make the behavior robuster if many addresses are added after the size estimation of storage at the first sysctl. Reviewed by: JINMEI Tatuya <jinmei@isl.rdc.toshiba.co.jp> MFC after: 1 week
-rw-r--r--lib/libc/net/getifaddrs.c37
1 files changed, 29 insertions, 8 deletions
diff --git a/lib/libc/net/getifaddrs.c b/lib/libc/net/getifaddrs.c
index 3a2329f..41ef3f4 100644
--- a/lib/libc/net/getifaddrs.c
+++ b/lib/libc/net/getifaddrs.c
@@ -44,6 +44,7 @@ __FBSDID("$FreeBSD$");
#include <net/if_dl.h>
#endif
+#include <errno.h>
#include <ifaddrs.h>
#include <stdlib.h>
#include <string.h>
@@ -84,6 +85,8 @@ __FBSDID("$FreeBSD$");
#define HAVE_IFM_DATA
#endif
+#define MAX_SYSCTL_TRY 5
+
int
getifaddrs(struct ifaddrs **pif)
{
@@ -91,6 +94,7 @@ getifaddrs(struct ifaddrs **pif)
int dcnt = 0;
int ncnt = 0;
#ifdef NET_RT_IFLIST
+ int ntry = 0;
int mib[6];
size_t needed;
char *buf;
@@ -123,14 +127,31 @@ getifaddrs(struct ifaddrs **pif)
mib[3] = 0; /* wildcard address family */
mib[4] = NET_RT_IFLIST;
mib[5] = 0; /* no flags */
- if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
- return (-1);
- if ((buf = malloc(needed)) == NULL)
- return (-1);
- if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
- free(buf);
- return (-1);
- }
+ do {
+ /*
+ * We'll try to get addresses several times in case that
+ * the number of addresses is unexpectedly increased during
+ * the two sysctl calls. This should rarely happen, but we'll
+ * try to do our best for applications that assume success of
+ * this library (which should usually be the case).
+ * Portability note: since FreeBSD does not add margin of
+ * memory at the first sysctl, the possibility of failure on
+ * the second sysctl call is a bit higher.
+ */
+
+ if (sysctl(mib, 6, NULL, &needed, NULL, 0) < 0)
+ return (-1);
+ if ((buf = malloc(needed)) == NULL)
+ return (-1);
+ if (sysctl(mib, 6, buf, &needed, NULL, 0) < 0) {
+ if (errno != ENOMEM || ++ntry >= MAX_SYSCTL_TRY) {
+ free(buf);
+ return (-1);
+ }
+ free(buf);
+ buf = NULL;
+ }
+ } while (buf == NULL);
for (next = buf; next < buf + needed; next += rtm->rtm_msglen) {
rtm = (struct rt_msghdr *)(void *)next;
OpenPOWER on IntegriCloud