From 3a17941dbbfcc8e9fcf08004992615a774443a0d Mon Sep 17 00:00:00 2001 From: Ian Kent Date: Thu, 8 Nov 2018 13:26:57 -0500 Subject: Fix EOF detection on non-blocking socket From: Ian Kent EOF on a non-blocking socket is incorrectly detected causing the socket to be closed if a client sends the RPC request in more than one write. This is becuase ->read_vc() returns 0 for a real EOF and for the error cases of EAGAIN or EWOULDBLOCK when there could be more data to come. The caller of ->read_vc() also fails to handle this case correctly returning XPRT_DIED in both cases. Also the stream context setting that indicates the request header has been reveived is not set after receiving the header which causes incorrect interpretation of the input for the case of a multiple read receive. Signed-off-by: Ian Kent Signed-off-by: Steve Dickson --- src/svc_vc.c | 7 ++++++- src/xdr_rec.c | 18 ++++++++++++++++-- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/svc_vc.c b/src/svc_vc.c index 97a76a3..c23cd36 100644 --- a/src/svc_vc.c +++ b/src/svc_vc.c @@ -502,9 +502,14 @@ read_vc(xprtp, buf, len) cfp = (struct cf_conn *)xprt->xp_p1; if (cfp->nonblock) { + /* Since len == 0 is returned on zero length + * read or EOF errno needs to be reset before + * the read + */ + errno = 0; len = read(sock, buf, (size_t)len); if (len < 0) { - if (errno == EAGAIN) + if (errno == EAGAIN || errno == EWOULDBLOCK) len = 0; else goto fatal_err; diff --git a/src/xdr_rec.c b/src/xdr_rec.c index 7d535cf..676cc82 100644 --- a/src/xdr_rec.c +++ b/src/xdr_rec.c @@ -61,6 +61,7 @@ #include #include #include +#include #include "rpc_com.h" static bool_t xdrrec_getlong(XDR *, long *); static bool_t xdrrec_putlong(XDR *, const long *); @@ -537,7 +538,13 @@ __xdrrec_getrec(xdrs, statp, expectdata) n = rstrm->readit(rstrm->tcp_handle, rstrm->in_hdrp, (int)sizeof (rstrm->in_header) - rstrm->in_hdrlen); if (n == 0) { - *statp = expectdata ? XPRT_DIED : XPRT_IDLE; + /* EAGAIN or EWOULDBLOCK means a zero length + * read not an EOF. + */ + if (errno == EAGAIN || errno == EWOULDBLOCK) + *statp = XPRT_IDLE; + else + *statp = expectdata ? XPRT_DIED : XPRT_IDLE; return FALSE; } if (n < 0) { @@ -564,6 +571,7 @@ __xdrrec_getrec(xdrs, statp, expectdata) rstrm->in_header &= ~LAST_FRAG; rstrm->last_frag = TRUE; } + rstrm->in_haveheader = 1; } n = rstrm->readit(rstrm->tcp_handle, @@ -576,7 +584,13 @@ __xdrrec_getrec(xdrs, statp, expectdata) } if (n == 0) { - *statp = expectdata ? XPRT_DIED : XPRT_IDLE; + /* EAGAIN or EWOULDBLOCK means a zero length + * read not an EOF. + */ + if (errno == EAGAIN || errno == EWOULDBLOCK) + *statp = XPRT_IDLE; + else + *statp = expectdata ? XPRT_DIED : XPRT_IDLE; return FALSE; } -- cgit v1.2.1