For details see: http://sourceware.org/bugzilla/show_bug.cgi?id=5379 --- sunrpc/clnt_udp.c.orig 2008-10-10 14:42:04.000000000 -0400 +++ sunrpc/clnt_udp.c 2008-10-10 16:15:33.000000000 -0400 @@ -38,6 +38,7 @@ */ #include +#include #include #include #include @@ -266,8 +267,7 @@ int inlen; socklen_t fromlen; struct pollfd fd; - int milliseconds = (cu->cu_wait.tv_sec * 1000) + - (cu->cu_wait.tv_usec / 1000); + int milliseconds; struct sockaddr_in from; struct rpc_msg reply_msg; XDR reply_xdrs; @@ -275,6 +275,8 @@ bool_t ok; int nrefreshes = 2; /* number of times to refresh cred */ struct timeval timeout; + uint64_t start_time, end_time; + struct timeval tmp_tv; int anyup; /* any network interface up */ if (cu->cu_total.tv_usec == -1) @@ -332,6 +334,18 @@ fd.fd = cu->cu_sock; fd.events = POLLIN; anyup = 0; + + poll_again: + milliseconds = (cu->cu_wait.tv_sec * 1000) + + (cu->cu_wait.tv_usec / 1000); + if (gettimeofday(&tmp_tv, NULL) != 0) + { + /* XXX: What is the correct return here? */ + return (cu->cu_error.re_status = RPC_CANTRECV); + } + start_time = (uint64_t)tmp_tv.tv_sec * 1000 + + (uint64_t)tmp_tv.tv_usec / 1000; + for (;;) { switch (__poll (&fd, 1, milliseconds)) @@ -364,7 +378,28 @@ */ case -1: if (errno == EINTR) - continue; + { + /* Decrement time already spent polling. */ + if (gettimeofday(&tmp_tv, NULL) != 0) + { + return (cu->cu_error.re_status = RPC_CANTRECV); + } + + end_time = (uint64_t)tmp_tv.tv_sec * 1000 + + (uint64_t)tmp_tv.tv_usec / 1000; + + if ((end_time - start_time) > (uint64_t)milliseconds) + { + milliseconds = 0; + } + else + { + milliseconds -= (int)(end_time - start_time); + } + start_time = end_time; + + continue; + } cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } @@ -420,19 +455,19 @@ if (inlen < 0) { if (errno == EWOULDBLOCK) - continue; + goto poll_again; cu->cu_error.re_errno = errno; return (cu->cu_error.re_status = RPC_CANTRECV); } if (inlen < 4) - continue; + goto poll_again; /* see if reply transaction id matches sent id. Don't do this if we only wait for a replay */ if (xargs != NULL && (*((u_int32_t *) (cu->cu_inbuf)) != *((u_int32_t *) (cu->cu_outbuf)))) - continue; + goto poll_again; /* we now assume we have the proper reply */ break; }