Helper functions for processing data streams in libvirtd

Defines the extensions to the remote protocol for generic
data streams. Adds a bunch of helper code to the libvirtd
daemon for working with data streams.

* daemon/Makefile.am: Add stream.c/stream.h to build
* daemon/stream.c, qemud/stream.h: Generic helper functions for
  creating new streams, associating streams with clients, finding
  existing streams for a client and removing/deleting streams.
* src/remote/remote_protocol.x: Add a new 'REMOTE_STREAM' constant
  for the 'enum remote_message_type' for encoding stream data
  in wire messages. Add a new 'REMOTE_CONTINUE' constant to
  'enum remote_message_status' to indicate further data stream
  messsages are expected to follow.  Document how the
  remote_message_header is used to encode data streams
* src/remote/remote_protocol.h: Regenerate
* daemon/dispatch.c: Remove assumption that a error message
  sent to client is always type=REMOTE_REPLY. It may now
  also be type=REMOTE_STREAM. Add convenient method for
  sending outgoing stream data packets. Log and ignore
  non-filtered incoming stream packets. Add a method for
  serializing a stream error message
* daemon/dispatch.h:  Add API for serializing stream errors
  and sending stream data packets
* daemon/qemud.h: Add struct qemud_client_stream for tracking
  active data streams for clients. Tweak filter function
  operation so that it accepts a client object too.
* daemon/qemud.c: Refactor code for free'ing message objects
  which have been fully transmitted into separate method.
  Release all active streams when client shuts down. Change
  filter function to be responsible for queueing the message
This commit is contained in:
Daniel P. Berrange
2009-07-10 13:06:36 +01:00
parent 182eba1bc6
commit 11573f3ec1
9 changed files with 509 additions and 29 deletions

210
daemon/stream.c Normal file
View File

@@ -0,0 +1,210 @@
/*
* stream.c: APIs for managing client streams
*
* Copyright (C) 2009 Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* Author: Daniel P. Berrange <berrange@redhat.com>
*/
#include <config.h>
#include "stream.h"
#include "memory.h"
#include "dispatch.h"
#include "logging.h"
/*
* @client: a locked client object
*
* Invoked by the main loop when filtering incoming messages.
*
* Returns 1 if the message was processed, 0 if skipped,
* -1 on fatal client error
*/
static int
remoteStreamFilter(struct qemud_client *client ATTRIBUTE_UNUSED,
struct qemud_client_message *msg ATTRIBUTE_UNUSED,
void *opaque ATTRIBUTE_UNUSED)
{
return 0;
}
/*
* @conn: a connection object to associate the stream with
* @hdr: the method call to associate with the stram
*
* Creates a new stream for this conn
*
* Returns a new stream object, or NULL upon OOM
*/
struct qemud_client_stream *
remoteCreateClientStream(virConnectPtr conn,
remote_message_header *hdr)
{
struct qemud_client_stream *stream;
DEBUG("proc=%d serial=%d", hdr->proc, hdr->serial);
if (VIR_ALLOC(stream) < 0)
return NULL;
stream->procedure = hdr->proc;
stream->serial = hdr->serial;
stream->st = virStreamNew(conn, VIR_STREAM_NONBLOCK);
if (!stream->st) {
VIR_FREE(stream);
return NULL;
}
stream->filter.query = remoteStreamFilter;
stream->filter.opaque = stream;
return stream;
}
/*
* @stream: an unused client stream
*
* Frees the memory associated with this inactive client
* stream
*/
void remoteFreeClientStream(struct qemud_client *client,
struct qemud_client_stream *stream)
{
struct qemud_client_message *msg;
if (!stream)
return;
DEBUG("proc=%d serial=%d", stream->procedure, stream->serial);
msg = stream->rx;
while (msg) {
struct qemud_client_message *tmp = msg->next;
qemudClientMessageRelease(client, msg);
msg = tmp;
}
virStreamFree(stream->st);
VIR_FREE(stream);
}
/*
* @client: a locked client to add the stream to
* @stream: a stream to add
*/
int remoteAddClientStream(struct qemud_client *client,
struct qemud_client_stream *stream)
{
struct qemud_client_stream *tmp = client->streams;
DEBUG("client=%p proc=%d serial=%d", client, stream->procedure, stream->serial);
if (tmp) {
while (tmp->next)
tmp = tmp->next;
tmp->next = stream;
} else {
client->streams = stream;
}
stream->filter.next = client->filters;
client->filters = &stream->filter;
stream->tx = 1;
return 0;
}
/*
* @client: a locked client object
* @procedure: procedure associated with the stream
* @serial: serial number associated with the stream
*
* Finds a existing active stream
*
* Returns a stream object matching the procedure+serial number, or NULL
*/
struct qemud_client_stream *
remoteFindClientStream(struct qemud_client *client,
virStreamPtr st)
{
struct qemud_client_stream *stream = client->streams;
while (stream) {
if (stream->st == st)
return stream;
stream = stream->next;
}
return NULL;
}
/*
* @client: a locked client object
* @stream: an inactive, closed stream object
*
* Removes a stream from the list of active streams for the client
*
* Returns 0 if the stream was removd, -1 if it doesn't exist
*/
int
remoteRemoveClientStream(struct qemud_client *client,
struct qemud_client_stream *stream)
{
DEBUG("client=%p proc=%d serial=%d", client, stream->procedure, stream->serial);
struct qemud_client_stream *curr = client->streams;
struct qemud_client_stream *prev = NULL;
struct qemud_client_filter *filter = NULL;
if (client->filters == &stream->filter) {
client->filters = client->filters->next;
} else {
filter = client->filters;
while (filter) {
if (filter->next == &stream->filter) {
filter->next = filter->next->next;
break;
}
}
}
if (!stream->closed)
virStreamAbort(stream->st);
while (curr) {
if (curr == stream) {
if (prev)
prev->next = curr->next;
else
client->streams = curr->next;
remoteFreeClientStream(client, stream);
return 0;
}
prev = curr;
curr = curr->next;
}
return -1;
}