aboutsummaryrefslogtreecommitdiff
path: root/sunrpc
diff options
context:
space:
mode:
Diffstat (limited to 'sunrpc')
-rw-r--r--sunrpc/svc_tcp.c44
-rw-r--r--sunrpc/xdr_rec.c12
2 files changed, 34 insertions, 22 deletions
diff --git a/sunrpc/svc_tcp.c b/sunrpc/svc_tcp.c
index 41f95332e7..e162c02751 100644
--- a/sunrpc/svc_tcp.c
+++ b/sunrpc/svc_tcp.c
@@ -284,13 +284,19 @@ svctcp_destroy (SVCXPRT *xprt)
* All read operations timeout after 35 seconds.
* A timeout is fatal for the connection.
*/
-static struct timeval wait_per_try =
-{35, 0};
+static struct timeval wait_per_try = {35, 0};
/*
* reads data from the tcp connection.
* any error is fatal and the connection is closed.
* (And a read of zero bytes is a half closed stream => error.)
+ *
+ * Note: we have to be careful here not to allow ourselves to become
+ * blocked too long in this routine. While we're waiting for data from one
+ * client, another client may be trying to connect. To avoid this situation,
+ * some code from svc_run() is transplanted here: the select() loop checks
+ * all RPC descriptors including the one we want and calls svc_getreqset2()
+ * to handle new requests if any are detected.
*/
static int
readtcp (char *xprtptr, char *buf, int len)
@@ -298,39 +304,41 @@ readtcp (char *xprtptr, char *buf, int len)
SVCXPRT *xprt = (SVCXPRT *)xprtptr;
int sock = xprt->xp_sock;
#ifdef FD_SETSIZE
- fd_set mask;
fd_set readfds;
-
- FD_ZERO (&mask);
- FD_SET (sock, &mask);
#else
int mask = 1 << sock;
int readfds;
#endif /* def FD_SETSIZE */
- do
+ while (1)
{
struct timeval timeout = wait_per_try;
- readfds = mask;
+ readfds = svc_fdset;
+#ifdef FD_SETSIZE
+ FD_SET (sock, &readfds);
+#else
+ readfds |= (1 << sock);
+#endif /* def FD_SETSIZE */
if (select (_rpc_dtablesize (), &readfds, (fd_set *) NULL,
(fd_set *) NULL, &timeout) <= 0)
{
if (errno == EINTR)
- {
- continue;
- }
+ continue;
goto fatal_err;
}
+
#ifdef FD_SETSIZE
- }
- while (!FD_ISSET (sock, &readfds));
+ if (FD_ISSET (sock, &readfds))
#else
- }
- while (readfds != mask);
+ if (readfds == mask)
#endif /* def FD_SETSIZE */
- if ((len = read (sock, buf, len)) > 0)
- {
- return len;
+ break;
+
+ svc_getreqset (&readfds);
}
+
+ if ((len = read (sock, buf, len)) > 0)
+ return len;
+
fatal_err:
((struct tcp_conn *) (xprt->xp_p1))->strm_stat = XPRT_DIED;
return -1;
diff --git a/sunrpc/xdr_rec.c b/sunrpc/xdr_rec.c
index a4e28b0548..b2ab2faabc 100644
--- a/sunrpc/xdr_rec.c
+++ b/sunrpc/xdr_rec.c
@@ -565,16 +565,20 @@ set_input_fragment (RECSTREAM *rstrm)
{
u_long header;
- if (!get_input_bytes (rstrm, (caddr_t) & header, BYTES_PER_XDR_UNIT))
+ if (! get_input_bytes (rstrm, (caddr_t)&header, BYTES_PER_XDR_UNIT))
return FALSE;
header = ntohl (header);
rstrm->last_frag = ((header & LAST_FRAG) == 0) ? FALSE : TRUE;
/*
* Sanity check. Try not to accept wildly incorrect
- * record sizes.
+ * record sizes. Unfortunately, the only record size
+ * we can positively identify as being 'wildly incorrect'
+ * is zero. Ridiculously large record sizes may look wrong,
+ * but we don't have any way to be certain that they aren't
+ * what the client actually intended to send us.
*/
- if ((header & (~LAST_FRAG)) > rstrm->recvsize)
- return(FALSE);
+ if ((header & (~LAST_FRAG)) == 0)
+ return FALSE;
rstrm->fbtbc = header & ~LAST_FRAG;
return TRUE;
}