diff options
author | Peter Kjellerstedt <peter.kjellerstedt@axis.com> | 2008-01-11 09:03:27 +0000 |
---|---|---|
committer | Peter Kjellerstedt <peter.kjellerstedt@axis.com> | 2008-01-11 09:03:27 +0000 |
commit | e4f07e7d1b9c6b2eab58fdebd3b9031f361d59aa (patch) | |
tree | aa453fbe2eda27ed1b993931c8e811d17a0b622f | |
parent | 3a59892925d185dbfd2d3c3b15e1fcfac0848625 (diff) |
Use poll() rather than select() if the former is available to wait in
__dns_lookup(). This avoids segmentation faults when more than 1024
file descriptors are used by an application.
-rw-r--r-- | libc/inet/resolv.c | 26 |
1 files changed, 26 insertions, 0 deletions
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c index 591106a24..5df8fecaa 100644 --- a/libc/inet/resolv.c +++ b/libc/inet/resolv.c @@ -140,6 +140,7 @@ #include <stdio.h> #include <signal.h> #include <errno.h> +#include <sys/poll.h> #include <sys/socket.h> #include <sys/types.h> #include <sys/time.h> @@ -157,6 +158,14 @@ #include <sys/un.h> #include <bits/uClibc_mutex.h> +/* poll() is not supported in kernel <= 2.0, therefore if __NR_poll is + * not available, we assume an old Linux kernel is in use and we will + * use select() instead. */ +#include <sys/syscall.h> +#ifndef __NR_poll +# define USE_SELECT +#endif + __UCLIBC_MUTEX_EXTERN(__resolv_lock); libc_hidden_proto(memcpy) @@ -185,6 +194,7 @@ libc_hidden_proto(inet_aton) libc_hidden_proto(inet_pton) libc_hidden_proto(inet_ntop) libc_hidden_proto(connect) +libc_hidden_proto(poll) libc_hidden_proto(select) libc_hidden_proto(recv) libc_hidden_proto(send) @@ -721,8 +731,12 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char unsigned char **outpacket, struct resolv_answer *a) { int i, j, len, fd, pos, rc; +#ifdef USE_SELECT struct timeval tv; fd_set fds; +#else + struct pollfd fds; +#endif struct resolv_header h; struct resolv_question q; struct resolv_answer ma; @@ -851,6 +865,7 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char send(fd, packet, len, 0); +#ifdef USE_SELECT FD_ZERO(&fds); FD_SET(fd, &fds); tv.tv_sec = REPLY_TIMEOUT; @@ -862,6 +877,17 @@ int attribute_hidden __dns_lookup(const char *name, int type, int nscount, char * to next nameserver on queue */ goto tryall; } +#else + fds.fd = fd; + fds.events = POLLIN; + if (poll(&fds, 1, REPLY_TIMEOUT * 1000) <= 0) { + DPRINTF("Timeout\n"); + + /* timed out, so retry send and receive, + * to next nameserver on queue */ + goto tryall; + } +#endif len = recv(fd, packet, 512, 0); if (len < HFIXEDSZ) { |