From 2981d1c95ea43c4c71237b7dec1ad70e08250435 Mon Sep 17 00:00:00 2001 From: Michal Privoznik Date: Tue, 7 Dec 2021 14:04:35 +0100 Subject: [PATCH] rpc: Introduce virNetClientStreamInData() The aim of this function is to look at a virNetClientStream and tell whether the incoming packet (if there's one) contains data (type VIR_NET_STREAM) or a hole (type VIR_NET_STREAM_HOLE) and how big the section is. This function will be called from the remote driver in one of future commits. Signed-off-by: Michal Privoznik Reviewed-by: Martin Kletzander --- src/libvirt_remote.syms | 1 + src/rpc/virnetclientstream.c | 64 ++++++++++++++++++++++++++++++++++++ src/rpc/virnetclientstream.h | 4 +++ 3 files changed, 69 insertions(+) diff --git a/src/libvirt_remote.syms b/src/libvirt_remote.syms index 942e1013a6..07d22e368b 100644 --- a/src/libvirt_remote.syms +++ b/src/libvirt_remote.syms @@ -66,6 +66,7 @@ virNetClientStreamEOF; virNetClientStreamEventAddCallback; virNetClientStreamEventRemoveCallback; virNetClientStreamEventUpdateCallback; +virNetClientStreamInData; virNetClientStreamMatches; virNetClientStreamNew; virNetClientStreamQueuePacket; diff --git a/src/rpc/virnetclientstream.c b/src/rpc/virnetclientstream.c index 1ba6167a1d..eb4dc6854d 100644 --- a/src/rpc/virnetclientstream.c +++ b/src/rpc/virnetclientstream.c @@ -801,3 +801,67 @@ bool virNetClientStreamEOF(virNetClientStream *st) { return st->incomingEOF; } + + +int virNetClientStreamInData(virNetClientStream *st, + int *inData, + long long *length) +{ + int ret = -1; + bool msgPopped = false; + virNetMessage *msg = NULL; + + virObjectLock(st); + + if (!st->allowSkip) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Holes are not supported with this stream")); + goto cleanup; + } + + if (virNetClientStreamCheckState(st) < 0) + goto cleanup; + + msg = st->rx; + + if (!msg) { + /* No incoming message. This means that the stream is at its end. In + * this case, virStreamInData() should set both inData and length to + * zero and return success. If there is a trailing hole though (there + * shouldn't be), signal that to the caller. */ + *inData = 0; + *length = st->holeLength; + st->holeLength = 0; + } else if (msg->header.type == VIR_NET_STREAM) { + *inData = 1; + *length = msg->bufferLength - msg->bufferOffset; + } else if (msg->header.type == VIR_NET_STREAM_HOLE) { + *inData = 0; + + if (st->holeLength == 0) { + if (virNetClientStreamHandleHole(NULL, st) < 0) + goto cleanup; + + /* virNetClientStreamHandleHole() called above did pop the message from + * the queue (and freed it). Instead of trying to push it back let's + * just signal to the caller what we did. */ + msgPopped = true; + } + + *length = st->holeLength; + st->holeLength = 0; + } else { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Invalid message prog=%d type=%d serial=%u proc=%d"), + msg->header.prog, + msg->header.type, + msg->header.serial, + msg->header.proc); + goto cleanup; + } + + ret = msgPopped ? 1 : 0; + cleanup: + virObjectUnlock(st); + return ret; +} diff --git a/src/rpc/virnetclientstream.h b/src/rpc/virnetclientstream.h index e16d6e4a9a..7428843f9b 100644 --- a/src/rpc/virnetclientstream.h +++ b/src/rpc/virnetclientstream.h @@ -90,3 +90,7 @@ int virNetClientStreamEventRemoveCallback(virNetClientStream *st); bool virNetClientStreamEOF(virNetClientStream *st) ATTRIBUTE_NONNULL(1); + +int virNetClientStreamInData(virNetClientStream *st, + int *inData, + long long *length);