diff options
author | Ian Kent <raven@themaw.net> | 2018-11-08 13:26:57 -0500 |
---|---|---|
committer | Steve Dickson <steved@redhat.com> | 2018-11-08 13:28:50 -0500 |
commit | 3a17941dbbfcc8e9fcf08004992615a774443a0d (patch) | |
tree | cd08bea437802860111f682f0cbcf2c8a392f60c | |
parent | e80e668683f2e573c2aae7457b8efad8b4541f26 (diff) | |
download | ti-rpc-3a17941dbbfcc8e9fcf08004992615a774443a0d.tar.gz |
Fix EOF detection on non-blocking socketlibtirpc-1-1-5-rc2
From: Ian Kent <raven@themaw.net>
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 <raven@themaw.net>
Signed-off-by: Steve Dickson <steved@redhat.com>
-rw-r--r-- | src/svc_vc.c | 7 | ||||
-rw-r--r-- | 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 <rpc/svc.h> #include <rpc/clnt.h> #include <stddef.h> +#include <errno.h> #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; } |