[Spice-devel] [PATCH spice-gtk 3/3] webdav: use a pipe to connect to server
Marc-André Lureau
marcandre.lureau at redhat.com
Thu Feb 12 05:12:41 PST 2015
Instead of listening on TCP sockets, and proxying connections there,
make the webdav server accept new connections from stream. The streams
are user-space GIOStream pipe, one side is connected to the Spice webdav
channel muxer/demuxer, the other side is a SoupSocket client.
This makes the server not exposed any local public access, avoid the
need for server threads, or proxying the connections through system
sockets.
---
gtk/channel-webdav.c | 85 +++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 64 insertions(+), 21 deletions(-)
diff --git a/gtk/channel-webdav.c b/gtk/channel-webdav.c
index 8cf53cf..18cc502 100644
--- a/gtk/channel-webdav.c
+++ b/gtk/channel-webdav.c
@@ -24,6 +24,7 @@
#include "spice-marshal.h"
#include "glib-compat.h"
#include "vmcstream.h"
+#include "giopipe.h"
/**
* SECTION:channel-webdav
@@ -70,6 +71,7 @@ static void spice_webdav_handle_msg(SpiceChannel *channel, SpiceMsgIn *msg);
struct _OutputQueue {
GOutputStream *output;
+ GMemoryInputStream *memory;
gboolean flushing;
guint idle_id;
GQueue *queue;
@@ -100,6 +102,7 @@ static void output_queue_free(OutputQueue *queue)
g_queue_free_full(queue->queue, g_free);
g_clear_object(&queue->output);
+ g_clear_object(&queue->memory);
if (queue->idle_id)
g_source_remove(queue->idle_id);
g_free(queue);
@@ -185,8 +188,7 @@ typedef struct Client
{
guint refs;
SpiceWebdavChannel *self;
- GIOStream *conn;
- OutputQueue *output;
+ GIOStream *pipe;
gint64 id;
GCancellable *cancellable;
@@ -204,9 +206,8 @@ client_unref(Client *client)
return;
g_free(client->mux.buf);
- output_queue_free(client->output);
- g_object_unref(client->conn);
+ g_object_unref(client->pipe);
g_object_unref(client->cancellable);
g_free(client);
@@ -289,7 +290,7 @@ static void client_start_read(SpiceWebdavChannel *self, Client *client)
{
GInputStream *input;
- input = g_io_stream_get_input_stream(G_IO_STREAM(client->conn));
+ input = g_io_stream_get_input_stream(G_IO_STREAM(client->pipe));
g_input_stream_read_async(input, client->mux.buf, MAX_MUX_SIZE,
G_PRIORITY_DEFAULT, client->cancellable, server_reply_cb,
client_ref(client));
@@ -297,43 +298,70 @@ static void client_start_read(SpiceWebdavChannel *self, Client *client)
static void start_demux(SpiceWebdavChannel *self);
-static void pushed_client_cb(OutputQueue *q, gpointer user_data)
+static void demux_to_client_finish(SpiceWebdavChannel *self,
+ Client *client, gssize size)
{
- Client *client = user_data;
- SpiceWebdavChannel *self = client->self;
SpiceWebdavChannelPrivate *c = self->priv;
+ if (size <= 0) {
+ remove_client(self, client);
+ }
+
c->demuxing = FALSE;
start_demux(self);
}
+static void demux_to_client_cb(GObject *source, GAsyncResult *result, gpointer user_data)
+{
+ Client *client = user_data;
+ SpiceWebdavChannelPrivate *c = client->self->priv;
+ GError *error = NULL;
+ gssize size;
+
+ size = g_output_stream_write_finish(G_OUTPUT_STREAM(source), result, &error);
+
+ if (error) {
+ CHANNEL_DEBUG(client->self, "write failed: %s", error->message);
+ g_clear_error(&error);
+ }
+
+ g_warn_if_fail(size == c->demux.size);
+ demux_to_client_finish(client->self, client, size);
+}
+
static void demux_to_client(SpiceWebdavChannel *self,
- Client *client)
+ Client *client)
{
SpiceWebdavChannelPrivate *c = self->priv;
gssize size = c->demux.size;
CHANNEL_DEBUG(self, "pushing %"G_GSSIZE_FORMAT" to client %p", size, client);
- if (size != 0) {
- output_queue_push(client->output, (guint8 *)c->demux.buf, size,
- (GFunc)pushed_client_cb, client);
+ if (size > 0) {
+ g_output_stream_write_async(g_io_stream_get_output_stream(client->pipe),
+ c->demux.buf, size, G_PRIORITY_DEFAULT,
+ c->cancellable, demux_to_client_cb, client);
+ return;
} else {
- remove_client(self, client);
- c->demuxing = FALSE;
- start_demux(self);
+ demux_to_client_finish(self, client, size);
}
}
static void start_client(SpiceWebdavChannel *self)
{
SpiceWebdavChannelPrivate *c = self->priv;
- GOutputStream *output;
Client *client;
+ GIOStream *peer = NULL;
+ SpiceSession *session;
+ SoupServer *server;
+ SoupSocket *socket;
+ GError *error = NULL;
+
+ session = spice_channel_get_session(SPICE_CHANNEL(self));
+ server = phodav_server_get_soup_server(spice_session_get_webdav_server(session));
CHANNEL_DEBUG(self, "starting client %" G_GINT64_FORMAT, c->demux.client);
- /* FIXME: connect to server */
client = g_new0(Client, 1);
client->refs = 1;
client->id = c->demux.client;
@@ -341,15 +369,30 @@ static void start_client(SpiceWebdavChannel *self)
client->mux.id = GINT64_TO_LE(client->id);
client->mux.buf = g_malloc0(MAX_MUX_SIZE);
client->cancellable = g_cancellable_new();
+ spice_make_pipe(&client->pipe, &peer);
- output = g_buffered_output_stream_new(g_io_stream_get_output_stream(G_IO_STREAM(client->conn)));
- client->output = output_queue_new(output);
- g_object_unref(output);
+ socket = g_initable_new (SOUP_TYPE_SOCKET, NULL, &error,
+ "giostream", peer,
+ NULL);
+ if (!socket)
+ goto fail;
+
+ soup_server_add_connection(server, socket);
+ g_object_unref(socket);
- client_start_read(self, client);
g_hash_table_insert(c->clients, &client->id, client);
+ client_start_read(self, client);
demux_to_client(self, client);
+ return;
+
+fail:
+ if (error)
+ CHANNEL_DEBUG(self, "failed to start client: %s", error->message);
+
+ g_clear_object(&peer);
+ g_clear_error(&error);
+ client_unref(client);
}
static void data_read_cb(GObject *source_object,
--
2.1.0
More information about the Spice-devel
mailing list