From 1d46b2e900498a3f389fcbb89fc7b27d22f36d4a Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Fri, 7 Oct 2011 17:38:59 +0100 Subject: [PATCH] Fix handling of stream EOF Very occasionally the sequence of events from poll would result in getting a HANGUP on its own, instead of a HANGUP+READABLE at the same time. In the former case we would send back an error event to the client, but never send the empty packet to indicate EOF. --- daemon/stream.c | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/daemon/stream.c b/daemon/stream.c index 7df9952a20..50f8fd4ed8 100644 --- a/daemon/stream.c +++ b/daemon/stream.c @@ -143,7 +143,8 @@ daemonStreamEvent(virStreamPtr st, int events, void *opaque) VIR_DEBUG("st=%p events=%d EOF=%d closed=%d", st, events, stream->recvEOF, stream->closed); - if (events & VIR_STREAM_EVENT_WRITABLE) { + if (!stream->closed && + (events & VIR_STREAM_EVENT_WRITABLE)) { if (daemonStreamHandleWrite(client, stream) < 0) { daemonRemoveClientStream(client, stream); virNetServerClientClose(client); @@ -151,9 +152,9 @@ daemonStreamEvent(virStreamPtr st, int events, void *opaque) } } - if (!stream->recvEOF && - (events & (VIR_STREAM_EVENT_READABLE | VIR_STREAM_EVENT_HANGUP))) { - events = events & ~(VIR_STREAM_EVENT_READABLE | VIR_STREAM_EVENT_HANGUP); + if (!stream->closed && !stream->recvEOF && + (events & (VIR_STREAM_EVENT_READABLE))) { + events = events & ~(VIR_STREAM_EVENT_READABLE); if (daemonStreamHandleRead(client, stream) < 0) { daemonRemoveClientStream(client, stream); virNetServerClientClose(client); @@ -190,6 +191,37 @@ daemonStreamEvent(virStreamPtr st, int events, void *opaque) } } + + /* If we got HANGUP, we need to only send an empty + * packet so the client sees an EOF and cleans up + */ + if (!stream->closed && !stream->recvEOF && + (events & VIR_STREAM_EVENT_HANGUP)) { + virNetMessagePtr msg; + events &= ~(VIR_STREAM_EVENT_HANGUP); + stream->tx = 0; + stream->recvEOF = 1; + if (!(msg = virNetMessageNew(false))) { + daemonRemoveClientStream(client, stream); + virNetServerClientClose(client); + goto cleanup; + } + msg->cb = daemonStreamMessageFinished; + msg->opaque = stream; + stream->refs++; + if (virNetServerProgramSendStreamData(remoteProgram, + client, + msg, + stream->procedure, + stream->serial, + "", 0) < 0) { + virNetMessageFree(msg); + daemonRemoveClientStream(client, stream); + virNetServerClientClose(client); + goto cleanup; + } + } + if (!stream->closed && (events & (VIR_STREAM_EVENT_ERROR | VIR_STREAM_EVENT_HANGUP))) { int ret; -- GitLab