[Spice-devel] [PATCH spice-gtk 3/5] webdav: use a pipe to connect to server
Marc-André Lureau
marcandre.lureau at redhat.com
Fri Feb 20 16:40:14 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 | 83 +++++++++++++++++++++++++++++++++++++++-------------
1 file changed, 62 insertions(+), 21 deletions(-)
diff --git a/gtk/channel-webdav.c b/gtk/channel-webdav.c
index 8cf53cf..95c0521 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
@@ -185,8 +186,7 @@ typedef struct Client
{
guint refs;
SpiceWebdavChannel *self;
- GIOStream *conn;
- OutputQueue *output;
+ GIOStream *pipe;
gint64 id;
GCancellable *cancellable;
@@ -204,9 +204,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 +288,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 +296,71 @@ 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)
{
+#ifdef USE_PHODAV
SpiceWebdavChannelPrivate *c = self->priv;
- GOutputStream *output;
Client *client;
+ GIOStream *peer = NULL;
+ SpiceSession *session;
+ SoupServer *server;
+ GSocketAddress *addr;
+ 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 +368,29 @@ 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);
+ addr = g_inet_socket_address_new_from_string ("127.0.0.1", 0);
+ if (!soup_server_accept_iostream(server, peer, addr, addr, &error))
+ goto fail;
- client_start_read(self, client);
g_hash_table_insert(c->clients, &client->id, client);
+ client_start_read(self, client);
demux_to_client(self, client);
+
+ g_clear_object(&addr);
+ return;
+
+fail:
+ if (error)
+ CHANNEL_DEBUG(self, "failed to start client: %s", error->message);
+
+ g_clear_object(&addr);
+ g_clear_object(&peer);
+ g_clear_error(&error);
+ client_unref(client);
+#endif
}
static void data_read_cb(GObject *source_object,
--
2.1.0
More information about the Spice-devel
mailing list