diff options
author | Roland McGrath <roland@gnu.org> | 2005-07-18 02:58:16 +0000 |
---|---|---|
committer | Roland McGrath <roland@gnu.org> | 2005-07-18 02:58:16 +0000 |
commit | 890b037f9485e5411f51aff73686c19d04746c7e (patch) | |
tree | 71dd974a135f1b5bbcfeed5673fc13de160d1195 | |
parent | 0c377110abe8cb2c55ca9007e45fd16c3621ae01 (diff) | |
download | glibc-890b037f9485e5411f51aff73686c19d04746c7e.tar.gz glibc-890b037f9485e5411f51aff73686c19d04746c7e.tar.xz glibc-890b037f9485e5411f51aff73686c19d04746c7e.zip |
2005-06-13 Jakub Jelinek <jakub@redhat.com>
[BZ #1096] * sysdeps/unix/sysv/linux/netlinkaccess.h (__netlink_sendreq, __netlink_receive): Remove prototypes. (__netlink_request): New prototype. * sysdeps/unix/sysv/linux/ifaddrs.c: Include <alloca.h> and <stdint.h>. (__netlink_sendreq): Make static. (__netlink_receive): Rename to... (__netlink_request): ... this. Add type argument, call __netlink_sendreq. If MSG_TRUNC is set after recvmsg, retry with a bigger buffer. Don't record buffers that contain no messages we are expecting. (getifaddrs): Use __netlink_request instead of __netlink_sendreq and __netlink_receive pairs. Formatting. * sysdeps/unix/sysv/linux/if_index.c (if_nameindex_netlink): Use __netlink_request instead of __netlink_sendreq and __netlink_receive pair.
-rw-r--r-- | sysdeps/unix/sysv/linux/if_index.c | 9 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/ifaddrs.c | 166 | ||||
-rw-r--r-- | sysdeps/unix/sysv/linux/netlinkaccess.h | 3 |
3 files changed, 124 insertions, 54 deletions
diff --git a/sysdeps/unix/sysv/linux/if_index.c b/sysdeps/unix/sysv/linux/if_index.c index 377ccf5199..f434bbe7d1 100644 --- a/sysdeps/unix/sysv/linux/if_index.c +++ b/sysdeps/unix/sysv/linux/if_index.c @@ -188,12 +188,8 @@ if_nameindex_netlink (void) /* Tell the kernel that we wish to get a list of all - active interfaces. */ - if (__netlink_sendreq (&nh, RTM_GETLINK) < 0) - goto exit_close; - - /* Collect all data for every interface. */ - if (__netlink_receive (&nh) < 0) + active interfaces. Collect all data for every interface. */ + if (__netlink_request (&nh, RTM_GETLINK) < 0) goto exit_free; /* Count the interfaces. */ @@ -290,7 +286,6 @@ if_nameindex_netlink (void) exit_free: __netlink_free_handle (&nh); - exit_close: __netlink_close (&nh); return idx; diff --git a/sysdeps/unix/sysv/linux/ifaddrs.c b/sysdeps/unix/sysv/linux/ifaddrs.c index 8a052e212d..6f43475ca9 100644 --- a/sysdeps/unix/sysv/linux/ifaddrs.c +++ b/sysdeps/unix/sysv/linux/ifaddrs.c @@ -17,6 +17,7 @@ Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ +#include <alloca.h> #include <assert.h> #include <errno.h> #include <ifaddrs.h> @@ -24,6 +25,7 @@ #include <netinet/in.h> #include <netpacket/packet.h> #include <stdbool.h> +#include <stdint.h> #include <stdlib.h> #include <string.h> #include <sys/ioctl.h> @@ -84,7 +86,7 @@ __netlink_free_handle (struct netlink_handle *h) } -int +static int __netlink_sendreq (struct netlink_handle *h, int type) { struct @@ -114,15 +116,39 @@ __netlink_sendreq (struct netlink_handle *h, int type) int -__netlink_receive (struct netlink_handle *h) +__netlink_request (struct netlink_handle *h, int type) { struct netlink_res *nlm_next; - char buf[4096]; - struct iovec iov = { buf, sizeof (buf) }; + struct netlink_res **new_nlm_list; + static volatile size_t buf_size = 4096; + char *buf; struct sockaddr_nl nladdr; struct nlmsghdr *nlmh; - int read_len; + ssize_t read_len; bool done = false; + bool use_malloc = false; + + if (__netlink_sendreq (h, type) < 0) + return -1; + + size_t this_buf_size = buf_size; + if (__libc_use_alloca (this_buf_size)) + buf = alloca (this_buf_size); + else + { + buf = malloc (this_buf_size); + if (buf != NULL) + use_malloc = true; + else + goto out_fail; + } + + struct iovec iov = { buf, this_buf_size }; + + if (h->nlm_list != NULL) + new_nlm_list = &h->end_ptr->next; + else + new_nlm_list = &h->nlm_list; while (! done) { @@ -136,33 +162,66 @@ __netlink_receive (struct netlink_handle *h) read_len = TEMP_FAILURE_RETRY (__recvmsg (h->fd, &msg, 0)); if (read_len < 0) - return -1; + goto out_fail; - if (msg.msg_flags & MSG_TRUNC) - return -1; + if (nladdr.nl_pid != 0) + continue; - nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res) - + read_len); - if (nlm_next == NULL) - return -1; - nlm_next->next = NULL; - nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len); - nlm_next->size = read_len; - nlm_next->seq = h->seq; - if (h->nlm_list == NULL) - h->nlm_list = nlm_next; - else - h->end_ptr->next = nlm_next; - h->end_ptr = nlm_next; + if (__builtin_expect (msg.msg_flags & MSG_TRUNC, 0)) + { + if (this_buf_size >= SIZE_MAX / 2) + goto out_fail; + + nlm_next = *new_nlm_list; + while (nlm_next != NULL) + { + struct netlink_res *tmpptr; + + tmpptr = nlm_next->next; + free (nlm_next); + nlm_next = tmpptr; + } + *new_nlm_list = NULL; + + if (__libc_use_alloca (2 * this_buf_size)) + buf = extend_alloca (buf, this_buf_size, 2 * this_buf_size); + else + { + this_buf_size *= 2; + + char *new_buf = realloc (use_malloc ? buf : NULL, this_buf_size); + if (new_buf == NULL) + goto out_fail; + new_buf = buf; + use_malloc = true; + } + buf_size = this_buf_size; + + iov.iov_base = buf; + iov.iov_len = this_buf_size; + + /* Increase sequence number, so that we can distinguish + between old and new request messages. */ + h->seq++; + + if (__netlink_sendreq (h, type) < 0) + goto out_fail; + + continue; + } + + size_t count = 0; + size_t remaining_len = read_len; for (nlmh = (struct nlmsghdr *) buf; - NLMSG_OK (nlmh, (size_t) read_len); - nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, read_len)) + NLMSG_OK (nlmh, remaining_len); + nlmh = (struct nlmsghdr *) NLMSG_NEXT (nlmh, remaining_len)) { - if (nladdr.nl_pid != 0 || (pid_t) nlmh->nlmsg_pid != h->pid + if ((pid_t) nlmh->nlmsg_pid != h->pid || nlmh->nlmsg_seq != h->seq) continue; + ++count; if (nlmh->nlmsg_type == NLMSG_DONE) { /* We found the end, leave the loop. */ @@ -176,11 +235,38 @@ __netlink_receive (struct netlink_handle *h) errno = EIO; else errno = -nlerr->error; - return -1; + goto out_fail; } } + + /* If there was nothing with the expected nlmsg_pid and nlmsg_seq, + there is no point to record it. */ + if (count == 0) + continue; + + nlm_next = (struct netlink_res *) malloc (sizeof (struct netlink_res) + + read_len); + if (nlm_next == NULL) + goto out_fail; + nlm_next->next = NULL; + nlm_next->nlh = memcpy (nlm_next + 1, buf, read_len); + nlm_next->size = read_len; + nlm_next->seq = h->seq; + if (h->nlm_list == NULL) + h->nlm_list = nlm_next; + else + h->end_ptr->next = nlm_next; + h->end_ptr = nlm_next; } + + if (use_malloc) + free (buf); return 0; + +out_fail: + if (use_malloc) + free (buf); + return -1; } @@ -268,7 +354,7 @@ getifaddrs (struct ifaddrs **ifap) unsigned int i, newlink, newaddr, newaddr_idx; int *map_newlink_data; size_t ifa_data_size = 0; /* Size to allocate for all ifa_data. */ - char *ifa_data_ptr; /* Pointer to the unused part of memory for + char *ifa_data_ptr; /* Pointer to the unused part of memory for ifa_data. */ int result = 0; @@ -288,28 +374,20 @@ getifaddrs (struct ifaddrs **ifap) #endif /* Tell the kernel that we wish to get a list of all - active interfaces. */ - if (__netlink_sendreq (&nh, RTM_GETLINK) < 0) - { - result = -1; - goto exit_close; - } - /* Collect all data for every interface. */ - if (__netlink_receive (&nh) < 0) + active interfaces, collect all data for every interface. */ + if (__netlink_request (&nh, RTM_GETLINK) < 0) { result = -1; goto exit_free; } - /* Now ask the kernel for all addresses which are assigned - to an interface. Since we store the addresses after the - interfaces in the list, we will later always find the - interface before the corresponding addresses. */ + to an interface and collect all data for every interface. + Since we store the addresses after the interfaces in the + list, we will later always find the interface before the + corresponding addresses. */ ++nh.seq; - if (__netlink_sendreq (&nh, RTM_GETADDR) < 0 - /* Collect all data for every interface. */ - || __netlink_receive (&nh) < 0) + if (__netlink_request (&nh, RTM_GETADDR) < 0) { result = -1; goto exit_free; @@ -327,7 +405,7 @@ getifaddrs (struct ifaddrs **ifap) continue; /* Walk through all entries we got from the kernel and look, which - message type they contain. */ + message type they contain. */ for (nlh = nlp->nlh; NLMSG_OK (nlh, size); nlh = NLMSG_NEXT (nlh, size)) { /* Check if the message is what we want. */ @@ -423,7 +501,7 @@ getifaddrs (struct ifaddrs **ifap) /* Interfaces are stored in the first "newlink" entries of our list, starting in the order as we got from the kernel. */ - ifa_index = map_newlink (ifim->ifi_index - 1, ifas, + ifa_index = map_newlink (ifim->ifi_index - 1, ifas, map_newlink_data, newlink); ifas[ifa_index].ifa.ifa_flags = ifim->ifi_flags; @@ -767,8 +845,6 @@ getifaddrs (struct ifaddrs **ifap) exit_free: __netlink_free_handle (&nh); - - exit_close: __netlink_close (&nh); return result; diff --git a/sysdeps/unix/sysv/linux/netlinkaccess.h b/sysdeps/unix/sysv/linux/netlinkaccess.h index 6672e714ff..f0b8e364bc 100644 --- a/sysdeps/unix/sysv/linux/netlinkaccess.h +++ b/sysdeps/unix/sysv/linux/netlinkaccess.h @@ -55,8 +55,7 @@ extern int __no_netlink_support attribute_hidden; extern int __netlink_open (struct netlink_handle *h); extern void __netlink_close (struct netlink_handle *h); extern void __netlink_free_handle (struct netlink_handle *h); -extern int __netlink_sendreq (struct netlink_handle *h, int type); -extern int __netlink_receive (struct netlink_handle *h); +extern int __netlink_request (struct netlink_handle *h, int type); #endif /* netlinkaccess.h */ |