From f433b06b83edf37ec819dc1f99a4d14caa68f83f Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Mon, 11 Oct 2004 20:38:58 +0000 Subject: Update. * resolv/res_send.c (send_dg): Use nonblocking sockets. Add appropriate poll/select calls and restart operation if necessary. Also handle EINTR. --- resolv/res_send.c | 106 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 83 insertions(+), 23 deletions(-) (limited to 'resolv') diff --git a/resolv/res_send.c b/resolv/res_send.c index 2366f59cd2..44d8cb0fee 100644 --- a/resolv/res_send.c +++ b/resolv/res_send.c @@ -88,6 +88,7 @@ static const char rcsid[] = "$BINDId: res_send.c,v 8.38 2000/03/30 20:16:51 vixi #include #include +#include #include #include #include @@ -965,12 +966,73 @@ send_dg(res_state statp, return (0); } #endif /* !CANNOT_CONNECT_DGRAM */ + /* Make socket non-blocking. */ + int fl = __fcntl (EXT(statp).nssocks[ns], F_GETFL); + if (fl != -1) + __fcntl (EXT(statp).nssocks[ns], F_SETFL, + fl | O_NONBLOCK); Dprint(statp->options & RES_DEBUG, (stdout, ";; new DG socket\n")) } s = EXT(statp).nssocks[ns]; + /* + * Compute time for the total operation. + */ + seconds = (statp->retrans << ns); + if (ns > 0) + seconds /= statp->nscount; + if (seconds <= 0) + seconds = 1; + evNowTime(&now); + evConsTime(&timeout, seconds, 0); + evAddTime(&finish, &now, &timeout); + int need_recompute = 0; + resend: +#ifdef _LIBC + /* Convert struct timespec in milliseconds. */ + ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000; + + pfd[0].fd = s; + pfd[0].events = POLLOUT; + n = __poll (pfd, 1, 0); + if (__builtin_expect (n == 0, 0)) { + n = __poll (pfd, 1, ptimeout); + need_recompute = 1; + } +#else + FD_ZERO(&dsmask); + FD_SET(s, &dsmask); + struct timeval zerotime = { 0, 0 }; + n = pselect(s + 1, NULL, &dsmask, NULL, &zerotime, NULL); + if (n == 0) { + n = pselect(s + 1, NULL, &dsmask, NULL, &timeout, NULL); + need_recompute = 1; + } +#endif + if (n == 0) { + Dprint(statp->options & RES_DEBUG, (stdout, + ";; timeout sending\n")); + *gotsomewhere = 1; + return (0); + } + if (n < 0) { + if (errno == EINTR) { + recompute_resend: + evNowTime(&now); + if (evCmpTime(finish, now) > 0) { + evSubTime(&timeout, &finish, &now); + goto resend; + } + } + Perror(statp, stderr, "select", errno); + res_nclose(statp); + return (0); + } + __set_errno (0); #ifndef CANNOT_CONNECT_DGRAM if (send(s, (char*)buf, buflen, 0) != buflen) { + if (errno == EINTR || errno == EAGAIN) + goto recompute_resend; Perror(statp, stderr, "send", errno); res_nclose(statp); return (0); @@ -984,6 +1046,8 @@ send_dg(res_state statp, if (sendto(s, (char*)buf, buflen, 0, (struct sockaddr *)nsap, sizeof *nsap) != buflen) { + if (errno == EINTR || errno == EAGAIN) + goto recompute_resend; Aerror(statp, stderr, "sendto", errno, (struct sockaddr *) nsap); res_nclose(statp); @@ -991,46 +1055,38 @@ send_dg(res_state statp, } #endif /* !CANNOT_CONNECT_DGRAM */ - /* - * Wait for reply. - */ - seconds = (statp->retrans << ns); - if (ns > 0) - seconds /= statp->nscount; - if (seconds <= 0) - seconds = 1; - evNowTime(&now); - evConsTime(&timeout, seconds, 0); - evAddTime(&finish, &now, &timeout); wait: + if (need_recompute) { + evNowTime(&now); + if (evCmpTime(finish, now) <= 0) { + err_return: + Perror(statp, stderr, "select", errno); + res_nclose(statp); + return (0); + } + evSubTime(&timeout, &finish, &now); + } #ifdef _LIBC /* Convert struct timespec in milliseconds. */ ptimeout = timeout.tv_sec * 1000 + timeout.tv_nsec / 1000000; - pfd[0].fd = s; pfd[0].events = POLLIN; n = __poll (pfd, 1, ptimeout); #else - FD_ZERO(&dsmask); - FD_SET(s, &dsmask); n = pselect(s + 1, &dsmask, NULL, NULL, &timeout, NULL); #endif if (n == 0) { - Dprint(statp->options & RES_DEBUG, (stdout, ";; timeout\n")); + Dprint(statp->options & RES_DEBUG, (stdout, + ";; timeout receiving\n")); *gotsomewhere = 1; return (0); } if (n < 0) { if (errno == EINTR) { - evNowTime(&now); - if (evCmpTime(finish, now) > 0) { - evSubTime(&timeout, &finish, &now); - goto wait; - } + need_recompute = 1; + goto wait; } - Perror(statp, stderr, "select", errno); - res_nclose(statp); - return (0); + goto err_return; } __set_errno (0); #ifdef _LIBC @@ -1056,6 +1112,10 @@ send_dg(res_state statp, resplen = recvfrom(s, (char*)ans, anssiz,0, (struct sockaddr *)&from, &fromlen); if (resplen <= 0) { + if (errno == EINTR || errno == EAGAIN) { + need_recompute = 1; + goto wait; + } Perror(statp, stderr, "recvfrom", errno); res_nclose(statp); return (0); -- cgit v1.2.3