@@ -73,6 +73,21 @@ __deadline_from_timeval (struct deadline_current_time current,
return (struct deadline) { { sec, nsec } };
}
+struct deadline
+__deadline_from_sec (struct deadline_current_time current, int sec)
+{
+ assert (sec >= 0);
+
+ /* Compute second-based deadline. Perform the addition in
+ uintmax_t, which is unsigned, to simply overflow detection. */
+ uintmax_t deadline_sec = current.current.tv_sec;
+ deadline_sec += sec;
+ if (deadline_sec < (uintmax_t) sec)
+ return infinite_deadline ();
+
+ return (struct deadline) { { deadline_sec, 0 } };
+}
+
int
__deadline_to_ms (struct deadline_current_time current,
struct deadline deadline)
@@ -139,6 +139,11 @@ DIAG_POP_NEEDS_COMMENT;
struct deadline __deadline_from_timeval (struct deadline_current_time,
struct timeval tv) attribute_hidden;
+/* Add time in second to the current time and return it. Returns a special
+ infinite absolute deadline on overflow. */
+struct deadline __deadline_from_sec (struct deadline_current_time,
+ int sec) attribute_hidden;
+
/* Compute the number of milliseconds until the specified deadline,
from the current time in the argument. The result is mainly for
use with poll. If the deadline has already passed, return 0. If
@@ -110,6 +110,7 @@
#include <kernel-features.h>
#include <libc-diag.h>
#include <random-bits.h>
+#include <inet/net-internal.h>
#if PACKETSZ > 65536
#define MAXPACKET PACKETSZ
@@ -190,6 +191,30 @@ static int send_dg(res_state, const u_char *, int,
int *, int *, u_char **,
u_char **, int *, int *, int *);
static int sock_eq(struct sockaddr_in6 *, struct sockaddr_in6 *);
+static int wait_on_socket(struct pollfd *, struct deadline);
+
+static int
+wait_on_socket (struct pollfd *pfd, struct deadline wait_deadline)
+{
+ do
+ {
+ int timeout = __deadline_to_ms (__deadline_current_time(),
+ wait_deadline);
+ switch (__poll (pfd, 1, timeout))
+ {
+ case -1:
+ if (errno == EINTR)
+ continue;
+ /* FALLTHROUGH */
+ case 0:
+ return -1;
+ default:
+ break;
+ }
+ } while ((pfd->revents & POLLIN) == 0);
+
+ return 1;
+}
/* Returns a shift value for the name server index. Used to implement
RES_ROTATE. */
@@ -570,6 +595,8 @@ send_vc(res_state statp,
UHEADER *anhp = (UHEADER *) *ansp;
struct sockaddr *nsap = __res_get_nsaddr (statp, ns);
int truncating, connreset, n;
+ struct pollfd pfd[1] = { [0] = { .events = POLLIN } };
+ struct deadline read_deadline;
/* On some architectures compiler might emit a warning indicating
'resplen' may be used uninitialized. However if buf2 == NULL
then this code won't be executed; if buf2 != NULL, then first
@@ -589,6 +616,16 @@ send_vc(res_state statp,
u_char *cp;
connreset = 0;
+
+ /* Compute and set timeout for each socket read. The timeout is
+ currently twice the lengh of send_dg routine. */
+ int seconds = (statp->retrans << (ns+1));
+ if (ns > 0)
+ seconds /= statp->nscount;
+ if (seconds <= 0)
+ seconds = 1;
+ read_deadline =
+ __deadline_from_sec (__deadline_current_time(), seconds);
same_ns:
truncating = 0;
@@ -657,10 +694,13 @@ send_vc(res_state statp,
int recvresp2 = buf2 == NULL;
uint16_t rlen16;
read_len:
+ pfd[0].fd = statp->_vcsock;
cp = (u_char *)&rlen16;
len = sizeof(rlen16);
- while ((n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
- (int)len))) > 0) {
+
+ while ((n = wait_on_socket (pfd, read_deadline)) > 0
+ && (n = TEMP_FAILURE_RETRY (read(statp->_vcsock, cp,
+ (int)len))) > 0) {
cp += n;
if ((len -= n) <= 0)
break;
@@ -744,10 +784,14 @@ send_vc(res_state statp,
}
cp = *thisansp;
- while (len != 0 && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0){
+
+ while (len != 0
+ && (n = wait_on_socket (pfd, read_deadline)) > 0
+ && (n = read(statp->_vcsock, (char *)cp, (int)len)) > 0) {
cp += n;
len -= n;
}
+
if (__glibc_unlikely (n <= 0)) {
*terrno = errno;
return close_and_return_error (statp, resplen2);
@@ -758,9 +802,10 @@ send_vc(res_state statp,
*/
anhp->tc = 1;
len = rlen - *thisanssizp;
- while (len != 0) {
- char junk[PACKETSZ];
+ while (len != 0
+ && (n = wait_on_socket (pfd, read_deadline)) > 0) {
+ char junk[PACKETSZ];
n = read(statp->_vcsock, junk,
(len > sizeof junk) ? sizeof junk : len);
if (n > 0)