aboutsummaryrefslogtreecommitdiff
path: root/lib/tran_sock.c
diff options
context:
space:
mode:
authorJohn Levon <john.levon@nutanix.com>2021-04-06 15:26:19 +0100
committerGitHub <noreply@github.com>2021-04-06 15:26:19 +0100
commit996d4f3cdae229fee9b5c8867d87beeb9172b97f (patch)
tree099dc048724bb0d895c2bbc886e8e0448ab35dc0 /lib/tran_sock.c
parente97a5e8c911acd8826542b1de30fb834901f4e76 (diff)
downloadlibvfio-user-996d4f3cdae229fee9b5c8867d87beeb9172b97f.zip
libvfio-user-996d4f3cdae229fee9b5c8867d87beeb9172b97f.tar.gz
libvfio-user-996d4f3cdae229fee9b5c8867d87beeb9172b97f.tar.bz2
implement short read/write, EOF handling (#415)
Report any short reads to callers as ECONNRESET, which is the closest we can meaningfully get right now. This also fixes get_next_command(), which previously wasn't checking for short reads at all. When we fail to send or recv from the socket due to the client disappearing in some manner, call into vfu_reset_ctx() to clean up the connection fd, allowing a subsequent vfu_attach_ctx() to work. If we get 0 bytes from recv[msg](), this is reported by the transport as ENOMSG, and is a normal EOF condition. We can also get ECONNRESET: this can happen when we've written unacknowledged data to the socket, the client side socket is closed, and we try a subsequent read. Finally, we can get a short read or write. Our handling of these still has issues, but for now we'll presume this means the client has gone too. It may in fact be due to a client bug - if it failed to write enough data - but right now, we can't easily tell that. Signed-off-by: John Levon <john.levon@nutanix.com> Reviewed-by: Thanos Makatos <thanos.makatos@nutanix.com>
Diffstat (limited to 'lib/tran_sock.c')
-rw-r--r--lib/tran_sock.c14
1 files changed, 7 insertions, 7 deletions
diff --git a/lib/tran_sock.c b/lib/tran_sock.c
index 9a58570..ea01a68 100644
--- a/lib/tran_sock.c
+++ b/lib/tran_sock.c
@@ -173,6 +173,8 @@ get_msg(void *data, size_t len, int *fds, size_t *nr_fds, int sock_fd,
return -errno;
} else if (ret == 0) {
return -ENOMSG;
+ } else if ((size_t)ret < len) {
+ return -ECONNRESET;
}
if (msg.msg_flags & MSG_CTRUNC || msg.msg_flags & MSG_TRUNC) {
@@ -222,9 +224,6 @@ tran_sock_recv_fds(int sock, struct vfio_user_header *hdr, bool is_reply,
if (ret < 0) {
return ret;
}
- if (ret < (int)sizeof(*hdr)) {
- return -EINVAL;
- }
if (is_reply) {
if (msg_id != NULL && hdr->msg_id != *msg_id) {
@@ -257,11 +256,12 @@ tran_sock_recv_fds(int sock, struct vfio_user_header *hdr, bool is_reply,
return -errno;
} else if (ret == 0) {
return -ENOMSG;
- } else if (*len != (size_t)ret) { /* FIXME we should allow receiving less */
- return -EINVAL;
+ } else if (*len != (size_t)ret) {
+ return -ECONNRESET;
}
*len = ret;
}
+
return 0;
}
@@ -318,7 +318,7 @@ tran_sock_recv_alloc(int sock, struct vfio_user_header *hdr, bool is_reply,
return -ENOMSG;
} else if (len != (size_t)ret) {
free(data);
- return -EINVAL;
+ return -ECONNRESET;
}
*datap = data;
@@ -818,7 +818,7 @@ tran_sock_recv_body(vfu_ctx_t *vfu_ctx, const struct vfio_user_header *hdr,
vfu_log(vfu_ctx, LOG_ERR, "msg%#hx: short read: expected=%d, actual=%d",
hdr->msg_id, body_size, ret);
free(data);
- return -EINVAL;
+ return -ECONNRESET;
}
*datap = data;