[Spice-commits] 18 commits - configure.ac doc/reference gtk/bio-gio.c gtk/bio-gio.h gtk/bio-gsocket.c gtk/bio-gsocket.h gtk/channel-base.c gtk/channel-port.c gtk/glib-compat.c gtk/glib-compat.h gtk/Makefile.am gtk/map-file gtk/spice-channel.c gtk/spice-channel.h gtk/spice-channel-priv.h gtk/spice-client.h gtk/spice-glib-sym-file gtk/spice-proxy.c gtk/spice-proxy.h gtk/spice-session.c gtk/spice-session.h gtk/spice-session-priv.h gtk/spice-uri.c gtk/spice-uri.h gtk/spice-uri-priv.h gtk/spicy.c gtk/vmcstream.c gtk/vmcstream.h gtk/wocky-http-proxy.c gtk/wocky-http-proxy.h spice-common
Marc-André Lureau
elmarco at kemper.freedesktop.org
Fri Feb 21 03:50:27 PST 2014
configure.ac | 2
doc/reference/Makefile.am | 1
doc/reference/spice-gtk-docs.xml | 1
doc/reference/spice-gtk-sections.txt | 28 +
gtk/Makefile.am | 11
gtk/bio-gio.c | 135 ++++++++
gtk/bio-gio.h | 34 ++
gtk/bio-gsocket.c | 111 -------
gtk/bio-gsocket.h | 30 -
gtk/channel-base.c | 48 +++
gtk/channel-port.c | 33 --
gtk/glib-compat.c | 35 ++
gtk/glib-compat.h | 9
gtk/map-file | 14
gtk/spice-channel-priv.h | 11
gtk/spice-channel.c | 113 +++++--
gtk/spice-channel.h | 2
gtk/spice-client.h | 1
gtk/spice-glib-sym-file | 14
gtk/spice-proxy.c | 270 -----------------
gtk/spice-proxy.h | 60 ---
gtk/spice-session-priv.h | 5
gtk/spice-session.c | 50 ++-
gtk/spice-session.h | 2
gtk/spice-uri-priv.h | 30 +
gtk/spice-uri.c | 460 ++++++++++++++++++++++++++++++
gtk/spice-uri.h | 52 +++
gtk/spicy.c | 6
gtk/vmcstream.c | 532 +++++++++++++++++++++++++++++++++++
gtk/vmcstream.h | 81 +++++
gtk/wocky-http-proxy.c | 177 +++++++++--
gtk/wocky-http-proxy.h | 14
spice-common | 2
33 files changed, 1783 insertions(+), 591 deletions(-)
New commits:
commit 8cbdc3d2d6ca6d8f9b8e75c0c11f0e89f4427eb2
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Mon Feb 3 15:56:31 2014 +0100
session: add spice_session_get_proxy_uri()
Learn to return the currently configured proxy, to allow
client to tweak parameters, such as username and password.
diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt
index 9f0cf67..08b1b4e 100644
--- a/doc/reference/spice-gtk-sections.txt
+++ b/doc/reference/spice-gtk-sections.txt
@@ -28,6 +28,7 @@ spice_session_disconnect
spice_session_get_channels
spice_session_get_read_only
spice_session_has_channel_type
+spice_session_get_proxy_uri
<SUBSECTION>
SpiceSessionMigration
SpiceSessionVerify
diff --git a/gtk/map-file b/gtk/map-file
index d9e596b..f98680c 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -90,6 +90,7 @@ spice_session_migration_get_type;
spice_session_new;
spice_session_open_fd;
spice_session_verify_get_type;
+spice_session_get_proxy_uri;
spice_set_session_option;
spice_smartcard_channel_get_type;
spice_smartcard_manager_get;
diff --git a/gtk/spice-glib-sym-file b/gtk/spice-glib-sym-file
index b90736b..2aa17cb 100644
--- a/gtk/spice-glib-sym-file
+++ b/gtk/spice-glib-sym-file
@@ -105,3 +105,4 @@ spice_uri_set_port
spice_uri_set_scheme
spice_uri_set_user
spice_uri_to_string
+spice_session_get_proxy_uri
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index 859f3cd..09556dc 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -2189,3 +2189,17 @@ guint32 spice_session_get_playback_latency(SpiceSession *session)
return 0;
}
}
+
+/**
+ * spice_session_get_proxy_uri:
+ * @session: a #SpiceSession
+ *
+ * Returns: (transfer none): the session proxy #SpiceURI or %NULL.
+ * Since: 0.24
+ **/
+SpiceURI *spice_session_get_proxy_uri(SpiceSession *session)
+{
+ SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(session);
+
+ return s->proxy;
+}
diff --git a/gtk/spice-session.h b/gtk/spice-session.h
index 4ea645e..665c609 100644
--- a/gtk/spice-session.h
+++ b/gtk/spice-session.h
@@ -93,6 +93,7 @@ void spice_session_disconnect(SpiceSession *session);
GList *spice_session_get_channels(SpiceSession *session);
gboolean spice_session_has_channel_type(SpiceSession *session, gint type);
gboolean spice_session_get_read_only(SpiceSession *session);
+SpiceURI *spice_session_get_proxy_uri(SpiceSession *session);
G_END_DECLS
commit 3edcc04f20b8e2360a05e16c337b26404f636081
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Mon Feb 3 15:47:11 2014 +0100
channel: add spice_channel_get_error()
Add a function to retrieve the last GError from a channel, this may be
useful to provide additional error details to the client.
diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt
index 411ca0e..9f0cf67 100644
--- a/doc/reference/spice-gtk-sections.txt
+++ b/doc/reference/spice-gtk-sections.txt
@@ -102,6 +102,7 @@ spice_channel_string_to_type
spice_channel_set_capability
spice_channel_flush_async
spice_channel_flush_finish
+spice_channel_get_error
<SUBSECTION Standard>
SPICE_TYPE_CHANNEL_EVENT
spice_channel_event_get_type
diff --git a/gtk/map-file b/gtk/map-file
index cf65db0..d9e596b 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -7,6 +7,7 @@ spice_channel_connect;
spice_channel_destroy;
spice_channel_disconnect;
spice_channel_event_get_type;
+spice_channel_get_error;
spice_channel_get_type;
spice_channel_new;
spice_channel_open_fd;
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index f38156e..607c0d4 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -136,6 +136,7 @@ struct _SpiceChannelPrivate {
GSList *flushing;
gboolean disable_channel_msg;
+ GError *error;
};
SpiceMsgIn *spice_msg_in_new(SpiceChannel *channel);
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index aff53ea..632a286 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -154,6 +154,8 @@ static void spice_channel_dispose(GObject *gobject)
c->session = NULL;
}
+ g_clear_error(&c->error);
+
/* Chain up to the parent class */
if (G_OBJECT_CLASS(spice_channel_parent_class)->dispose)
G_OBJECT_CLASS(spice_channel_parent_class)->dispose(gobject);
@@ -317,7 +319,9 @@ static void spice_channel_class_init(SpiceChannelClass *klass)
* @event: a #SpiceChannelEvent
*
* The #SpiceChannel::channel-event signal is emitted when the
- * state of the connection change.
+ * state of the connection is changed. In case of errors,
+ * spice_channel_get_error() may provide additional informations
+ * on the source of the error.
**/
signals[SPICE_CHANNEL_EVENT] =
g_signal_new("channel-event",
@@ -2214,6 +2218,25 @@ static int spice_channel_load_ca(SpiceChannel *channel)
return count;
}
+/**
+ * spice_channel_get_error:
+ * @channel:
+ *
+ * Retrieves the #GError currently set on channel, if the #SpiceChannel
+ * is in error state and can provide additional error details.
+ *
+ * Returns: the pointer to the error, or %NULL
+ * Since: 0.24
+ **/
+const GError* spice_channel_get_error(SpiceChannel *self)
+{
+ SpiceChannelPrivate *c;
+
+ g_return_val_if_fail(SPICE_IS_CHANNEL(self), NULL);
+ c = self->priv;
+
+ return c->error;
+}
/* coroutine context */
static void *spice_channel_coroutine(void *data)
@@ -2251,15 +2274,16 @@ static void *spice_channel_coroutine(void *data)
reconnect:
- c->conn = spice_session_channel_open_host(c->session, channel, &c->tls);
+ c->conn = spice_session_channel_open_host(c->session, channel, &c->tls, &c->error);
if (c->conn == NULL) {
- if (!c->tls) {
+ if (!c->error && !c->tls) {
CHANNEL_DEBUG(channel, "trying with TLS port");
c->tls = true; /* FIXME: does that really work with provided fd */
goto reconnect;
} else {
CHANNEL_DEBUG(channel, "Connect error");
emit_main_context(channel, SPICE_CHANNEL_EVENT, SPICE_CHANNEL_ERROR_CONNECT);
+ g_clear_error(&c->error);
goto cleanup;
}
}
diff --git a/gtk/spice-channel.h b/gtk/spice-channel.h
index 705dddf..1c303b4 100644
--- a/gtk/spice-channel.h
+++ b/gtk/spice-channel.h
@@ -123,6 +123,8 @@ void spice_channel_set_capability(SpiceChannel *channel, guint32 cap);
const gchar* spice_channel_type_to_string(gint type);
gint spice_channel_string_to_type(const gchar *str);
+const GError* spice_channel_get_error(SpiceChannel *channel);
+
G_END_DECLS
#endif /* __SPICE_CLIENT_CHANNEL_H__ */
diff --git a/gtk/spice-glib-sym-file b/gtk/spice-glib-sym-file
index ac7e871..b90736b 100644
--- a/gtk/spice-glib-sym-file
+++ b/gtk/spice-glib-sym-file
@@ -7,6 +7,7 @@ spice_channel_disconnect
spice_channel_event_get_type
spice_channel_flush_async
spice_channel_flush_finish
+spice_channel_get_error
spice_channel_get_type
spice_channel_new
spice_channel_open_fd
diff --git a/gtk/spice-session-priv.h b/gtk/spice-session-priv.h
index 0dc2bfb..1aae342 100644
--- a/gtk/spice-session-priv.h
+++ b/gtk/spice-session-priv.h
@@ -116,7 +116,7 @@ int spice_session_get_connection_id(SpiceSession *session);
gboolean spice_session_get_client_provided_socket(SpiceSession *session);
GSocketConnection* spice_session_channel_open_host(SpiceSession *session, SpiceChannel *channel,
- gboolean *use_tls);
+ gboolean *use_tls, GError **error);
void spice_session_channel_new(SpiceSession *session, SpiceChannel *channel);
void spice_session_channel_destroy(SpiceSession *session, SpiceChannel *channel);
void spice_session_channel_migrate(SpiceSession *session, SpiceChannel *channel);
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index 707fabd..859f3cd 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -1795,7 +1795,7 @@ static gboolean connect_timeout(gpointer data)
/* coroutine context */
G_GNUC_INTERNAL
GSocketConnection* spice_session_channel_open_host(SpiceSession *session, SpiceChannel *channel,
- gboolean *use_tls)
+ gboolean *use_tls, GError **error)
{
SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(session);
SpiceChannelPrivate *c = channel->priv;
@@ -1844,8 +1844,8 @@ GSocketConnection* spice_session_channel_open_host(SpiceSession *session, SpiceC
#endif
if (open_host.error != NULL) {
- g_warning("open host: %s", open_host.error->message);
- g_clear_error(&open_host.error);
+ SPICE_DEBUG("open host: %s", open_host.error->message);
+ g_propagate_error(error, open_host.error);
} else if (open_host.connection != NULL) {
GSocket *socket;
socket = g_socket_connection_get_socket(open_host.connection);
diff --git a/gtk/spicy.c b/gtk/spicy.c
index 3e280a0..038d622 100644
--- a/gtk/spicy.c
+++ b/gtk/spicy.c
@@ -1208,6 +1208,7 @@ static void recent_add(SpiceSession *session)
static void main_channel_event(SpiceChannel *channel, SpiceChannelEvent event,
gpointer data)
{
+ const GError *error = NULL;
spice_connection *conn = data;
char password[64];
int rc;
@@ -1231,7 +1232,12 @@ static void main_channel_event(SpiceChannel *channel, SpiceChannelEvent event,
case SPICE_CHANNEL_ERROR_TLS:
case SPICE_CHANNEL_ERROR_LINK:
case SPICE_CHANNEL_ERROR_CONNECT:
+ error = spice_channel_get_error(channel);
g_message("main channel: failed to connect");
+ if (error) {
+ g_message("channel error: %s", error->message);
+ }
+
rc = connect_dialog(conn->session);
if (rc == 0) {
connection_connect(conn);
commit 7c909790ca93d67347f830599f8611d387def743
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Mon Feb 3 15:38:52 2014 +0100
Make SpiceURI a public API
Generalize a little bit SpiceProxy to allow easy URI manipulation by
clients.
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am
index a0a856c..76c7d34 100644
--- a/doc/reference/Makefile.am
+++ b/doc/reference/Makefile.am
@@ -44,6 +44,7 @@ IGNORE_HFILES= \
spice-marshal.h \
spice-pulse.h \
spice-session-priv.h \
+ spice-uri-priv.h \
spice-util-priv.h \
spice-widget-priv.h \
usb-acl-helper.h \
diff --git a/doc/reference/spice-gtk-docs.xml b/doc/reference/spice-gtk-docs.xml
index 4a9a3cf..d2c1a2b 100644
--- a/doc/reference/spice-gtk-docs.xml
+++ b/doc/reference/spice-gtk-docs.xml
@@ -52,6 +52,7 @@
<xi:include href="xml/smartcard-manager.xml"/>
<xi:include href="xml/usb-device-manager.xml"/>
<xi:include href="xml/spice-util.xml"/>
+ <xi:include href="xml/spice-uri.xml"/>
</chapter>
</part>
diff --git a/doc/reference/spice-gtk-sections.txt b/doc/reference/spice-gtk-sections.txt
index 8d61aa9..411ca0e 100644
--- a/doc/reference/spice-gtk-sections.txt
+++ b/doc/reference/spice-gtk-sections.txt
@@ -429,3 +429,29 @@ SPICE_PORT_CHANNEL_GET_CLASS
SpicePortChannelPrivate
</SECTION>
+<SECTION>
+<FILE>spice-uri</FILE>
+spice_uri_get_scheme
+spice_uri_set_scheme
+spice_uri_get_hostname
+spice_uri_set_hostname
+spice_uri_get_port
+spice_uri_set_port
+spice_uri_get_user
+spice_uri_set_user
+spice_uri_get_password
+spice_uri_set_password
+spice_uri_to_string
+SpiceURIClass
+SpiceURI
+<SUBSECTION Standard>
+SPICE_IS_URI
+SPICE_IS_URI_CLASS
+SPICE_TYPE_URI
+SPICE_URI
+SPICE_URI_CLASS
+SPICE_URI_GET_CLASS
+spice_uri_get_type
+<SUBSECTION Private>
+SpiceURIPrivate
+</SECTION>
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 0c1ad9a..61ed88e 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -248,8 +248,8 @@ libspice_client_glib_2_0_la_SOURCES = \
channel-usbredir-priv.h \
smartcard-manager.c \
smartcard-manager-priv.h \
- spice-proxy.c \
- spice-proxy.h \
+ spice-uri.c \
+ spice-uri-priv.h \
usb-device-manager.c \
usb-device-manager-priv.h \
usbutil.c \
@@ -284,6 +284,7 @@ libspice_client_glibincludedir = $(includedir)/spice-client-glib-2.0
libspice_client_glibinclude_HEADERS = \
spice-audio.h \
spice-client.h \
+ spice-uri.h \
spice-types.h \
spice-session.h \
spice-channel.h \
diff --git a/gtk/map-file b/gtk/map-file
index 368b44f..cf65db0 100644
--- a/gtk/map-file
+++ b/gtk/map-file
@@ -118,6 +118,18 @@ spice_util_get_debug;
spice_util_get_version_string;
spice_util_set_debug;
spice_uuid_to_string;
+spice_uri_get_hostname;
+spice_uri_get_password;
+spice_uri_get_port;
+spice_uri_get_scheme;
+spice_uri_get_type;
+spice_uri_get_user;
+spice_uri_set_hostname;
+spice_uri_set_password;
+spice_uri_set_port;
+spice_uri_set_scheme;
+spice_uri_set_user;
+spice_uri_to_string;
local:
*;
};
diff --git a/gtk/spice-client.h b/gtk/spice-client.h
index 730d11a..975259a 100644
--- a/gtk/spice-client.h
+++ b/gtk/spice-client.h
@@ -31,6 +31,7 @@
#include "spice-session.h"
#include "spice-channel.h"
#include "spice-option.h"
+#include "spice-uri.h"
#include "channel-main.h"
#include "channel-display.h"
diff --git a/gtk/spice-glib-sym-file b/gtk/spice-glib-sym-file
index 4fc8643..ac7e871 100644
--- a/gtk/spice-glib-sym-file
+++ b/gtk/spice-glib-sym-file
@@ -92,3 +92,15 @@ spice_util_get_debug
spice_util_get_version_string
spice_util_set_debug
spice_uuid_to_string
+spice_uri_get_hostname
+spice_uri_get_password
+spice_uri_get_port
+spice_uri_get_scheme
+spice_uri_get_type
+spice_uri_get_user
+spice_uri_set_hostname
+spice_uri_set_password
+spice_uri_set_port
+spice_uri_set_scheme
+spice_uri_set_user
+spice_uri_to_string
diff --git a/gtk/spice-proxy.c b/gtk/spice-proxy.c
deleted file mode 100644
index cf4b6ad..0000000
--- a/gtk/spice-proxy.c
+++ /dev/null
@@ -1,369 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "glib-compat.h"
-#include "spice-client.h"
-#include "spice-proxy.h"
-
-struct _SpiceProxyPrivate {
- gchar *protocol;
- gchar *hostname;
- guint port;
- gchar *user;
- gchar *password;
-};
-
-#define SPICE_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), SPICE_TYPE_PROXY, SpiceProxyPrivate))
-
-G_DEFINE_TYPE(SpiceProxy, spice_proxy, G_TYPE_OBJECT);
-
-enum {
- SPICE_PROXY_DUMMY_PROPERTY,
- SPICE_PROXY_PROTOCOL,
- SPICE_PROXY_USER,
- SPICE_PROXY_PASSWORD,
- SPICE_PROXY_HOSTNAME,
- SPICE_PROXY_PORT
-};
-
-G_GNUC_INTERNAL
-SpiceProxy* spice_proxy_new(void)
-{
- SpiceProxy * self = NULL;
- self = (SpiceProxy*)g_object_new(SPICE_TYPE_PROXY, NULL);
- return self;
-}
-
-G_GNUC_INTERNAL
-gboolean spice_proxy_parse(SpiceProxy *self, const gchar *proxyuri, GError **error)
-{
- gchar *dup, *uri;
- gboolean success = FALSE;
- size_t len;
-
- g_return_val_if_fail(self != NULL, FALSE);
- g_return_val_if_fail(proxyuri != NULL, FALSE);
-
- uri = dup = g_strdup(proxyuri);
- /* FIXME: use GUri when it is ready... only support http atm */
- /* the code is voluntarily not parsing thoroughly the uri */
- if (g_ascii_strncasecmp("http://", uri, 7) == 0) {
- uri += 7;
- spice_proxy_set_protocol(self, "http");
- spice_proxy_set_port(self, 3128);
- } else if (g_ascii_strncasecmp("https://", uri, 8) == 0) {
- uri += 8;
- spice_proxy_set_protocol(self, "https");
- spice_proxy_set_port(self, 3129);
- } else {
- return FALSE;
- }
- /* remove trailing slash */
- len = strlen(uri);
- for (; len > 0; len--)
- if (uri[len-1] == '/')
- uri[len-1] = '\0';
- else
- break;
-
-
- /* yes, that parser is bad, we need GUri... */
- if (strstr(uri, "@")) {
- gchar *saveptr, *saveptr2;
- gchar *next = strstr(uri, "@") + 1;
- gchar *auth = strtok_r(uri, "@", &saveptr);
- const gchar *user = strtok_r(auth, ":", &saveptr2);
- const gchar *pass = strtok_r(NULL, ":", &saveptr2);
- spice_proxy_set_user(self, user);
- spice_proxy_set_password(self, pass);
- uri = next;
- }
-
- /* max 2 parts, host:port */
- gchar **proxyv = g_strsplit(uri, ":", 2);
- const gchar *proxy_port = NULL;
-
- if (proxyv[0] == NULL || strlen(proxyv[0]) == 0) {
- g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
- "Invalid hostname in proxy address");
- goto end;
- }
-
- spice_proxy_set_hostname(self, proxyv[0]);
- if (proxyv[0] != NULL)
- proxy_port = proxyv[1];
-
- if (proxy_port != NULL) {
- char *endptr;
- guint port = strtoul(proxy_port, &endptr, 10);
- if (*endptr != '\0') {
- g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
- "Invalid proxy port: %s", proxy_port);
- goto end;
- }
- spice_proxy_set_port(self, port);
- }
-
- success = TRUE;
-
-end:
- g_free(dup);
- g_strfreev(proxyv);
- return success;
-}
-
-G_GNUC_INTERNAL
-const gchar* spice_proxy_get_protocol(SpiceProxy *self)
-{
- g_return_val_if_fail(SPICE_IS_PROXY(self), NULL);
- return self->priv->protocol;
-}
-
-G_GNUC_INTERNAL
-void spice_proxy_set_protocol(SpiceProxy *self, const gchar *value)
-{
- g_return_if_fail(SPICE_IS_PROXY(self));
-
- g_free(self->priv->protocol);
- self->priv->protocol = g_strdup(value);
- g_object_notify((GObject *)self, "protocol");
-}
-
-G_GNUC_INTERNAL
-const gchar* spice_proxy_get_hostname(SpiceProxy *self)
-{
- g_return_val_if_fail(SPICE_IS_PROXY(self), NULL);
- return self->priv->hostname;
-}
-
-
-G_GNUC_INTERNAL
-void spice_proxy_set_hostname(SpiceProxy *self, const gchar *value)
-{
- g_return_if_fail(SPICE_IS_PROXY(self));
-
- g_free(self->priv->hostname);
- self->priv->hostname = g_strdup(value);
- g_object_notify((GObject *)self, "hostname");
-}
-
-G_GNUC_INTERNAL
-guint spice_proxy_get_port(SpiceProxy *self)
-{
- g_return_val_if_fail(SPICE_IS_PROXY(self), 0);
- return self->priv->port;
-}
-
-G_GNUC_INTERNAL
-void spice_proxy_set_port(SpiceProxy *self, guint port)
-{
- g_return_if_fail(SPICE_IS_PROXY(self));
- self->priv->port = port;
- g_object_notify((GObject *)self, "port");
-}
-
-static void spice_proxy_get_property(GObject *object, guint property_id,
- GValue *value, GParamSpec *pspec)
-{
- SpiceProxy *self;
- self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_PROXY, SpiceProxy);
-
- switch (property_id) {
- case SPICE_PROXY_PROTOCOL:
- g_value_set_string(value, spice_proxy_get_protocol(self));
- break;
- case SPICE_PROXY_HOSTNAME:
- g_value_set_string(value, spice_proxy_get_hostname(self));
- break;
- case SPICE_PROXY_PORT:
- g_value_set_uint(value, spice_proxy_get_port(self));
- break;
- case SPICE_PROXY_USER:
- g_value_set_string(value, spice_proxy_get_user(self));
- break;
- case SPICE_PROXY_PASSWORD:
- g_value_set_string(value, spice_proxy_get_password(self));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
- break;
- }
-}
-
-
-static void spice_proxy_set_property(GObject *object, guint property_id,
- const GValue *value, GParamSpec *pspec)
-{
- SpiceProxy * self;
- self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_PROXY, SpiceProxy);
-
- switch (property_id) {
- case SPICE_PROXY_PROTOCOL:
- spice_proxy_set_protocol(self, g_value_get_string(value));
- break;
- case SPICE_PROXY_HOSTNAME:
- spice_proxy_set_hostname(self, g_value_get_string(value));
- break;
- case SPICE_PROXY_USER:
- spice_proxy_set_user(self, g_value_get_string(value));
- break;
- case SPICE_PROXY_PASSWORD:
- spice_proxy_set_password(self, g_value_get_string(value));
- break;
- case SPICE_PROXY_PORT:
- spice_proxy_set_port(self, g_value_get_uint(value));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
- break;
- }
-}
-
-static void spice_proxy_finalize(GObject* obj)
-{
- SpiceProxy *self;
-
- self = G_TYPE_CHECK_INSTANCE_CAST(obj, SPICE_TYPE_PROXY, SpiceProxy);
- g_free(self->priv->protocol);
- g_free(self->priv->hostname);
- g_free(self->priv->user);
- g_free(self->priv->password);
-
- G_OBJECT_CLASS (spice_proxy_parent_class)->finalize (obj);
-}
-
-static void spice_proxy_init (SpiceProxy *self)
-{
- self->priv = SPICE_PROXY_GET_PRIVATE(self);
-}
-
-
-static void spice_proxy_class_init(SpiceProxyClass *klass)
-{
- spice_proxy_parent_class = g_type_class_peek_parent (klass);
- g_type_class_add_private(klass, sizeof(SpiceProxyPrivate));
-
- G_OBJECT_CLASS (klass)->get_property = spice_proxy_get_property;
- G_OBJECT_CLASS (klass)->set_property = spice_proxy_set_property;
- G_OBJECT_CLASS (klass)->finalize = spice_proxy_finalize;
-
- g_object_class_install_property(G_OBJECT_CLASS (klass),
- SPICE_PROXY_PROTOCOL,
- g_param_spec_string ("protocol",
- "protocol",
- "protocol",
- NULL,
- G_PARAM_STATIC_STRINGS |
- G_PARAM_READWRITE));
-
- g_object_class_install_property(G_OBJECT_CLASS (klass),
- SPICE_PROXY_HOSTNAME,
- g_param_spec_string ("hostname",
- "hostname",
- "hostname",
- NULL,
- G_PARAM_STATIC_STRINGS |
- G_PARAM_READWRITE));
-
- g_object_class_install_property(G_OBJECT_CLASS (klass),
- SPICE_PROXY_PORT,
- g_param_spec_uint ("port",
- "port",
- "port",
- 0, G_MAXUINT, 0,
- G_PARAM_STATIC_STRINGS |
- G_PARAM_READWRITE));
-
- g_object_class_install_property(G_OBJECT_CLASS (klass),
- SPICE_PROXY_USER,
- g_param_spec_string ("user",
- "user",
- "user",
- NULL,
- G_PARAM_STATIC_STRINGS |
- G_PARAM_READWRITE));
-
- g_object_class_install_property(G_OBJECT_CLASS (klass),
- SPICE_PROXY_PASSWORD,
- g_param_spec_string ("password",
- "password",
- "password",
- NULL,
- G_PARAM_STATIC_STRINGS |
- G_PARAM_READWRITE));
-}
-
-G_GNUC_INTERNAL
-gchar* spice_proxy_to_string(SpiceProxy* self)
-{
- SpiceProxyPrivate *p;
-
- g_return_val_if_fail(SPICE_IS_PROXY(self), NULL);
- p = self->priv;
-
- if (p->protocol == NULL || p->hostname == NULL)
- return NULL;
-
- if (p->user || p->password)
- return g_strdup_printf("%s://%s:%s@%s:%u",
- p->protocol,
- p->user, p->password,
- p->hostname, p->port);
- else
- return g_strdup_printf("%s://%s:%u",
- p->protocol, p->hostname, p->port);
-}
-
-G_GNUC_INTERNAL
-const gchar* spice_proxy_get_user(SpiceProxy *self)
-{
- g_return_val_if_fail(SPICE_IS_PROXY(self), NULL);
- return self->priv->user;
-}
-
-
-G_GNUC_INTERNAL
-void spice_proxy_set_user(SpiceProxy *self, const gchar *value)
-{
- g_return_if_fail(SPICE_IS_PROXY(self));
-
- g_free(self->priv->user);
- self->priv->user = g_strdup(value);
- g_object_notify((GObject *)self, "user");
-}
-
-G_GNUC_INTERNAL
-const gchar* spice_proxy_get_password(SpiceProxy *self)
-{
- g_return_val_if_fail(SPICE_IS_PROXY(self), NULL);
- return self->priv->password;
-}
-
-
-G_GNUC_INTERNAL
-void spice_proxy_set_password(SpiceProxy *self, const gchar *value)
-{
- g_return_if_fail(SPICE_IS_PROXY(self));
-
- g_free(self->priv->password);
- self->priv->password = g_strdup(value);
- g_object_notify((GObject *)self, "password");
-}
diff --git a/gtk/spice-proxy.h b/gtk/spice-proxy.h
deleted file mode 100644
index e74053b..0000000
--- a/gtk/spice-proxy.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef __SPICE_PROXY_H__
-#define __SPICE_PROXY_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define SPICE_TYPE_PROXY (spice_proxy_get_type ())
-#define SPICE_PROXY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SPICE_TYPE_PROXY, SpiceProxy))
-#define SPICE_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SPICE_TYPE_PROXY, SpiceProxyClass))
-#define SPICE_IS_PROXY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SPICE_TYPE_PROXY))
-#define SPICE_IS_PROXY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPICE_TYPE_PROXY))
-#define SPICE_PROXY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SPICE_TYPE_PROXY, SpiceProxyClass))
-
-typedef struct _SpiceProxy SpiceProxy;
-typedef struct _SpiceProxyClass SpiceProxyClass;
-typedef struct _SpiceProxyPrivate SpiceProxyPrivate;
-
-struct _SpiceProxy {
- GObject parent_instance;
- SpiceProxyPrivate * priv;
-};
-
-struct _SpiceProxyClass {
- GObjectClass parent_class;
-};
-
-
-GType spice_proxy_get_type(void) G_GNUC_CONST;
-
-SpiceProxy* spice_proxy_new(void);
-gboolean spice_proxy_parse(SpiceProxy* self, const gchar* uri, GError** error);
-const gchar* spice_proxy_get_protocol(SpiceProxy* self);
-void spice_proxy_set_protocol(SpiceProxy* self, const gchar* value);
-const gchar* spice_proxy_get_hostname(SpiceProxy* self);
-void spice_proxy_set_hostname(SpiceProxy* self, const gchar* value);
-guint spice_proxy_get_port(SpiceProxy* self);
-void spice_proxy_set_port(SpiceProxy* self, guint port);
-gchar *spice_proxy_to_string(SpiceProxy* self);
-const gchar* spice_proxy_get_user(SpiceProxy* self);
-void spice_proxy_set_user(SpiceProxy* self, const gchar* value);
-const gchar* spice_proxy_get_password(SpiceProxy* self);
-void spice_proxy_set_password(SpiceProxy* self, const gchar* value);
-
-G_END_DECLS
-
-#endif /* __SPICE_PROXY_H__ */
diff --git a/gtk/spice-session-priv.h b/gtk/spice-session-priv.h
index 55fee47..0dc2bfb 100644
--- a/gtk/spice-session-priv.h
+++ b/gtk/spice-session-priv.h
@@ -22,7 +22,6 @@
#include <gio/gio.h>
#include "desktop-integration.h"
#include "spice-session.h"
-#include "spice-proxy.h"
#include "spice-gtk-session.h"
#include "spice-channel-cache.h"
#include "decode.h"
@@ -45,7 +44,7 @@ struct _SpiceSessionPrivate {
char *cert_subject;
guint verify;
gboolean read_only;
- SpiceProxy *proxy;
+ SpiceURI *proxy;
/* whether to enable audio */
gboolean audio;
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index 833992e..707fabd 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -28,7 +28,7 @@
#include "gio-coroutine.h"
#include "glib-compat.h"
#include "wocky-http-proxy.h"
-#include "spice-proxy.h"
+#include "spice-uri-priv.h"
#include "channel-playback-priv.h"
struct channel {
@@ -139,7 +139,7 @@ static void do_emit_main_context(GObject *object, int signum, gpointer params)
static void update_proxy(SpiceSession *self, const gchar *str)
{
SpiceSessionPrivate *s = self->priv;
- SpiceProxy *proxy = NULL;
+ SpiceURI *proxy = NULL;
GError *error = NULL;
if (str == NULL)
@@ -149,8 +149,8 @@ static void update_proxy(SpiceSession *self, const gchar *str)
return;
}
- proxy = spice_proxy_new();
- if (!spice_proxy_parse(proxy, str, &error))
+ proxy = spice_uri_new();
+ if (!spice_uri_parse(proxy, str, &error))
g_clear_object(&proxy);
if (error) {
g_warning("%s", error->message);
@@ -269,7 +269,7 @@ static int spice_uri_create(SpiceSession *session, char *dest, int len)
return pos;
}
-static int spice_uri_parse(SpiceSession *session, const char *original_uri)
+static int spice_parse_uri(SpiceSession *session, const char *original_uri)
{
SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(session);
gchar *host = NULL, *port = NULL, *tls_port = NULL, *uri = NULL, *password = NULL;
@@ -499,7 +499,7 @@ static void spice_session_get_property(GObject *gobject,
g_value_set_pointer(value, s->uuid);
break;
case PROP_PROXY:
- g_value_take_string(value, spice_proxy_to_string(s->proxy));
+ g_value_take_string(value, spice_uri_to_string(s->proxy));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(gobject, prop_id, pspec);
@@ -547,7 +547,7 @@ static void spice_session_set_property(GObject *gobject,
case PROP_URI:
str = g_value_get_string(value);
if (str != NULL)
- spice_uri_parse(session, str);
+ spice_parse_uri(session, str);
break;
case PROP_CLIENT_SOCKETS:
s->client_provided_sockets = g_value_get_boolean(value);
@@ -1664,7 +1664,7 @@ struct spice_open_host {
struct coroutine *from;
SpiceSession *session;
SpiceChannel *channel;
- SpiceProxy *proxy;
+ SpiceURI *proxy;
int port;
GCancellable *cancellable;
GError *error;
@@ -1723,11 +1723,11 @@ static void proxy_lookup_ready(GObject *source_object, GAsyncResult *result,
for (it = addresses; it != NULL; it = it->next) {
address = g_proxy_address_new(G_INET_ADDRESS(it->data),
- spice_proxy_get_port(open_host->proxy),
- spice_proxy_get_protocol(open_host->proxy),
+ spice_uri_get_port(open_host->proxy),
+ spice_uri_get_scheme(open_host->proxy),
s->host, open_host->port,
- spice_proxy_get_user(open_host->proxy),
- spice_proxy_get_password(open_host->proxy));
+ spice_uri_get_user(open_host->proxy),
+ spice_uri_get_password(open_host->proxy));
if (address != NULL)
break;
}
@@ -1755,7 +1755,7 @@ static gboolean open_host_idle_cb(gpointer data)
if (open_host->proxy)
g_resolver_lookup_by_name_async(g_resolver_get_default(),
- spice_proxy_get_hostname(open_host->proxy),
+ spice_uri_get_hostname(open_host->proxy),
open_host->cancellable,
proxy_lookup_ready, open_host);
else
@@ -1770,7 +1770,7 @@ static gboolean open_host_idle_cb(gpointer data)
SPICE_DEBUG("open host %s:%d", s->host, open_host->port);
if (open_host->proxy != NULL) {
- gchar *str = spice_proxy_to_string(open_host->proxy);
+ gchar *str = spice_uri_to_string(open_host->proxy);
SPICE_DEBUG("(with proxy %s)", str);
g_free(str);
}
diff --git a/gtk/spice-session.h b/gtk/spice-session.h
index b07f525..4ea645e 100644
--- a/gtk/spice-session.h
+++ b/gtk/spice-session.h
@@ -20,6 +20,7 @@
#include <glib-object.h>
#include "spice-types.h"
+#include "spice-uri.h"
#include "spice-glib-enums.h"
#include "spice-util.h"
diff --git a/gtk/spice-uri-priv.h b/gtk/spice-uri-priv.h
new file mode 100644
index 0000000..54351de
--- /dev/null
+++ b/gtk/spice-uri-priv.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef __SPICE_URI_PRIV_H__
+#define __SPICE_URI_PRIV_H__
+
+#include "spice-uri.h"
+
+G_BEGIN_DECLS
+
+SpiceURI* spice_uri_new(void);
+gboolean spice_uri_parse(SpiceURI* self, const gchar* uri, GError** error);
+
+G_END_DECLS
+
+#endif /* __SPICE_URI_PRIV_H__ */
diff --git a/gtk/spice-uri.c b/gtk/spice-uri.c
new file mode 100644
index 0000000..03b8c22
--- /dev/null
+++ b/gtk/spice-uri.c
@@ -0,0 +1,460 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "glib-compat.h"
+#include "spice-client.h"
+#include "spice-uri.h"
+
+/**
+ * SECTION:spice-uri
+ * @short_description: URIs handling
+ * @title: SpiceURI
+ * @section_id:
+ * @stability: Stable
+ * @include: spice-uri.h
+ *
+ * A SpiceURI represents a (parsed) URI.
+ * Since: 0.24
+ */
+
+struct _SpiceURI {
+ GObject parent_instance;
+ gchar *scheme;
+ gchar *hostname;
+ guint port;
+ gchar *user;
+ gchar *password;
+};
+
+struct _SpiceURIClass {
+ GObjectClass parent_class;
+};
+
+G_DEFINE_TYPE(SpiceURI, spice_uri, G_TYPE_OBJECT);
+
+enum {
+ SPICE_URI_DUMMY_PROPERTY,
+ SPICE_URI_SCHEME,
+ SPICE_URI_USER,
+ SPICE_URI_PASSWORD,
+ SPICE_URI_HOSTNAME,
+ SPICE_URI_PORT
+};
+
+G_GNUC_INTERNAL
+SpiceURI* spice_uri_new(void)
+{
+ SpiceURI * self = NULL;
+ self = (SpiceURI*)g_object_new(SPICE_TYPE_URI, NULL);
+ return self;
+}
+
+G_GNUC_INTERNAL
+gboolean spice_uri_parse(SpiceURI *self, const gchar *_uri, GError **error)
+{
+ gchar *dup, *uri;
+ gboolean success = FALSE;
+ size_t len;
+
+ g_return_val_if_fail(self != NULL, FALSE);
+ g_return_val_if_fail(_uri != NULL, FALSE);
+
+ uri = dup = g_strdup(_uri);
+ /* FIXME: use GUri when it is ready... only support http atm */
+ /* the code is voluntarily not parsing thoroughly the uri */
+ if (g_ascii_strncasecmp("http://", uri, 7) == 0) {
+ uri += 7;
+ spice_uri_set_scheme(self, "http");
+ spice_uri_set_port(self, 3128);
+ } else if (g_ascii_strncasecmp("https://", uri, 8) == 0) {
+ uri += 8;
+ spice_uri_set_scheme(self, "https");
+ spice_uri_set_port(self, 3129);
+ } else {
+ return FALSE;
+ }
+ /* remove trailing slash */
+ len = strlen(uri);
+ for (; len > 0; len--)
+ if (uri[len-1] == '/')
+ uri[len-1] = '\0';
+ else
+ break;
+
+
+ /* yes, that parser is bad, we need GUri... */
+ if (strstr(uri, "@")) {
+ gchar *saveptr, *saveptr2;
+ gchar *next = strstr(uri, "@") + 1;
+ gchar *auth = strtok_r(uri, "@", &saveptr);
+ const gchar *user = strtok_r(auth, ":", &saveptr2);
+ const gchar *pass = strtok_r(NULL, ":", &saveptr2);
+ spice_uri_set_user(self, user);
+ spice_uri_set_password(self, pass);
+ uri = next;
+ }
+
+ /* max 2 parts, host:port */
+ gchar **uriv = g_strsplit(uri, ":", 2);
+ const gchar *uri_port = NULL;
+
+ if (uriv[0] == NULL || strlen(uriv[0]) == 0) {
+ g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+ "Invalid hostname in uri address");
+ goto end;
+ }
+
+ spice_uri_set_hostname(self, uriv[0]);
+ if (uriv[0] != NULL)
+ uri_port = uriv[1];
+
+ if (uri_port != NULL) {
+ char *endptr;
+ guint port = strtoul(uri_port, &endptr, 10);
+ if (*endptr != '\0') {
+ g_set_error(error, SPICE_CLIENT_ERROR, SPICE_CLIENT_ERROR_FAILED,
+ "Invalid uri port: %s", uri_port);
+ goto end;
+ }
+ spice_uri_set_port(self, port);
+ }
+
+ success = TRUE;
+
+end:
+ g_free(dup);
+ g_strfreev(uriv);
+ return success;
+}
+
+/**
+ * spice_uri_get_scheme:
+ * @uri: a #SpiceURI
+ *
+ * Gets @uri's scheme.
+ *
+ * Returns: @uri's scheme.
+ * Since: 0.24
+ **/
+const gchar* spice_uri_get_scheme(SpiceURI *self)
+{
+ g_return_val_if_fail(SPICE_IS_URI(self), NULL);
+ return self->scheme;
+}
+
+/**
+ * spice_uri_set_scheme:
+ * @uri: a #SpiceURI
+ * @scheme: the scheme
+ *
+ * Sets @uri's scheme to @scheme.
+ * Since: 0.24
+ **/
+void spice_uri_set_scheme(SpiceURI *self, const gchar *scheme)
+{
+ g_return_if_fail(SPICE_IS_URI(self));
+
+ g_free(self->scheme);
+ self->scheme = g_strdup(scheme);
+ g_object_notify((GObject *)self, "scheme");
+}
+
+/**
+ * spice_uri_get_hostname:
+ * @uri: a #SpiceURI
+ *
+ * Gets @uri's hostname.
+ *
+ * Returns: @uri's hostname.
+ * Since: 0.24
+ **/
+const gchar* spice_uri_get_hostname(SpiceURI *self)
+{
+ g_return_val_if_fail(SPICE_IS_URI(self), NULL);
+ return self->hostname;
+}
+
+
+/**
+ * spice_uri_set_hostname:
+ * @uri: a #SpiceURI
+ * @hostname: the hostname
+ *
+ * Sets @uri's hostname to @hostname.
+ * Since: 0.24
+ **/
+void spice_uri_set_hostname(SpiceURI *self, const gchar *hostname)
+{
+ g_return_if_fail(SPICE_IS_URI(self));
+
+ g_free(self->hostname);
+ self->hostname = g_strdup(hostname);
+ g_object_notify((GObject *)self, "hostname");
+}
+
+/**
+ * spice_uri_get_port:
+ * @uri: a #SpiceURI
+ *
+ * Gets @uri's port.
+ *
+ * Returns: @uri's port.
+ * Since: 0.24
+ **/
+guint spice_uri_get_port(SpiceURI *self)
+{
+ g_return_val_if_fail(SPICE_IS_URI(self), 0);
+ return self->port;
+}
+
+/**
+ * spice_uri_set_port:
+ * @uri: a #SpiceURI
+ * @port: the port
+ *
+ * Sets @uri's port to @port.
+ * Since: 0.24
+ **/
+void spice_uri_set_port(SpiceURI *self, guint port)
+{
+ g_return_if_fail(SPICE_IS_URI(self));
+ self->port = port;
+ g_object_notify((GObject *)self, "port");
+}
+
+static void spice_uri_get_property(GObject *object, guint property_id,
+ GValue *value, GParamSpec *pspec)
+{
+ SpiceURI *self;
+ self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_URI, SpiceURI);
+
+ switch (property_id) {
+ case SPICE_URI_SCHEME:
+ g_value_set_string(value, spice_uri_get_scheme(self));
+ break;
+ case SPICE_URI_HOSTNAME:
+ g_value_set_string(value, spice_uri_get_hostname(self));
+ break;
+ case SPICE_URI_PORT:
+ g_value_set_uint(value, spice_uri_get_port(self));
+ break;
+ case SPICE_URI_USER:
+ g_value_set_string(value, spice_uri_get_user(self));
+ break;
+ case SPICE_URI_PASSWORD:
+ g_value_set_string(value, spice_uri_get_password(self));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+
+static void spice_uri_set_property(GObject *object, guint property_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ SpiceURI * self;
+ self = G_TYPE_CHECK_INSTANCE_CAST(object, SPICE_TYPE_URI, SpiceURI);
+
+ switch (property_id) {
+ case SPICE_URI_SCHEME:
+ spice_uri_set_scheme(self, g_value_get_string(value));
+ break;
+ case SPICE_URI_HOSTNAME:
+ spice_uri_set_hostname(self, g_value_get_string(value));
+ break;
+ case SPICE_URI_USER:
+ spice_uri_set_user(self, g_value_get_string(value));
+ break;
+ case SPICE_URI_PASSWORD:
+ spice_uri_set_password(self, g_value_get_string(value));
+ break;
+ case SPICE_URI_PORT:
+ spice_uri_set_port(self, g_value_get_uint(value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
+ break;
+ }
+}
+
+static void spice_uri_finalize(GObject* obj)
+{
+ SpiceURI *self;
+
+ self = G_TYPE_CHECK_INSTANCE_CAST(obj, SPICE_TYPE_URI, SpiceURI);
+ g_free(self->scheme);
+ g_free(self->hostname);
+ g_free(self->user);
+ g_free(self->password);
+
+ G_OBJECT_CLASS (spice_uri_parent_class)->finalize (obj);
+}
+
+static void spice_uri_init (SpiceURI *self)
+{
+}
+
+
+static void spice_uri_class_init(SpiceURIClass *klass)
+{
+ spice_uri_parent_class = g_type_class_peek_parent (klass);
+
+ G_OBJECT_CLASS (klass)->get_property = spice_uri_get_property;
+ G_OBJECT_CLASS (klass)->set_property = spice_uri_set_property;
+ G_OBJECT_CLASS (klass)->finalize = spice_uri_finalize;
+
+ g_object_class_install_property(G_OBJECT_CLASS (klass),
+ SPICE_URI_SCHEME,
+ g_param_spec_string ("scheme",
+ "scheme",
+ "scheme",
+ NULL,
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property(G_OBJECT_CLASS (klass),
+ SPICE_URI_HOSTNAME,
+ g_param_spec_string ("hostname",
+ "hostname",
+ "hostname",
+ NULL,
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property(G_OBJECT_CLASS (klass),
+ SPICE_URI_PORT,
+ g_param_spec_uint ("port",
+ "port",
+ "port",
+ 0, G_MAXUINT, 0,
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property(G_OBJECT_CLASS (klass),
+ SPICE_URI_USER,
+ g_param_spec_string ("user",
+ "user",
+ "user",
+ NULL,
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property(G_OBJECT_CLASS (klass),
+ SPICE_URI_PASSWORD,
+ g_param_spec_string ("password",
+ "password",
+ "password",
+ NULL,
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READWRITE));
+}
+
+/**
+ * spice_uri_to_string:
+ * @uri: a #SpiceURI
+ *
+ * Returns a string representing @uri.
+ *
+ * Returns: a string representing @uri, which the caller must free.
+ * Since: 0.24
+ **/
+gchar* spice_uri_to_string(SpiceURI* self)
+{
+ g_return_val_if_fail(SPICE_IS_URI(self), NULL);
+
+ if (self->scheme == NULL || self->hostname == NULL)
+ return NULL;
+
+ if (self->user || self->password)
+ return g_strdup_printf("%s://%s:%s@%s:%u",
+ self->scheme,
+ self->user, self->password,
+ self->hostname, self->port);
+ else
+ return g_strdup_printf("%s://%s:%u",
+ self->scheme, self->hostname, self->port);
+}
+
+/**
+ * spice_uri_get_user:
+ * @uri: a #SpiceURI
+ *
+ * Gets @uri's user.
+ *
+ * Returns: @uri's user.
+ * Since: 0.24
+ **/
+const gchar* spice_uri_get_user(SpiceURI *self)
+{
+ g_return_val_if_fail(SPICE_IS_URI(self), NULL);
+ return self->user;
+}
+
+/**
+ * spice_uri_set_user:
+ * @uri: a #SpiceURI
+ * @user: the user, or %NULL.
+ *
+ * Sets @uri's user to @user.
+ * Since: 0.24
+ **/
+void spice_uri_set_user(SpiceURI *self, const gchar *user)
+{
+ g_return_if_fail(SPICE_IS_URI(self));
+
+ g_free(self->user);
+ self->user = g_strdup(user);
+ g_object_notify((GObject *)self, "user");
+}
+
+/**
+ * spice_uri_get_password:
+ * @uri: a #SpiceURI
+ *
+ * Gets @uri's password.
+ *
+ * Returns: @uri's password.
+ * Since: 0.24
+ **/
+const gchar* spice_uri_get_password(SpiceURI *self)
+{
+ g_return_val_if_fail(SPICE_IS_URI(self), NULL);
+ return self->password;
+}
+
+/**
+ * spice_uri_set_password:
+ * @uri: a #SpiceURI
+ * @password: the password, or %NULL.
+ *
+ * Sets @uri's password to @password.
+ * Since: 0.24
+ **/
+void spice_uri_set_password(SpiceURI *self, const gchar *password)
+{
+ g_return_if_fail(SPICE_IS_URI(self));
+
+ g_free(self->password);
+ self->password = g_strdup(password);
+ g_object_notify((GObject *)self, "password");
+}
diff --git a/gtk/spice-uri.h b/gtk/spice-uri.h
new file mode 100644
index 0000000..9e8d590
--- /dev/null
+++ b/gtk/spice-uri.h
@@ -0,0 +1,52 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef __SPICE_URI_H__
+#define __SPICE_URI_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define SPICE_TYPE_URI (spice_uri_get_type ())
+#define SPICE_URI(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SPICE_TYPE_URI, SpiceURI))
+#define SPICE_URI_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), SPICE_TYPE_URI, SpiceURIClass))
+#define SPICE_IS_URI(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), SPICE_TYPE_URI))
+#define SPICE_IS_URI_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), SPICE_TYPE_URI))
+#define SPICE_URI_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), SPICE_TYPE_URI, SpiceURIClass))
+
+typedef struct _SpiceURI SpiceURI;
+typedef struct _SpiceURIClass SpiceURIClass;
+typedef struct _SpiceURIPrivate SpiceURIPrivate;
+
+GType spice_uri_get_type(void) G_GNUC_CONST;
+
+const gchar* spice_uri_get_scheme(SpiceURI* uri);
+void spice_uri_set_scheme(SpiceURI* uri, const gchar* scheme);
+const gchar* spice_uri_get_hostname(SpiceURI* uri);
+void spice_uri_set_hostname(SpiceURI* uri, const gchar* hostname);
+guint spice_uri_get_port(SpiceURI* uri);
+void spice_uri_set_port(SpiceURI* uri, guint port);
+gchar *spice_uri_to_string(SpiceURI* uri);
+const gchar* spice_uri_get_user(SpiceURI* uri);
+void spice_uri_set_user(SpiceURI* uri, const gchar* user);
+const gchar* spice_uri_get_password(SpiceURI* uri);
+void spice_uri_set_password(SpiceURI* uri, const gchar* password);
+
+G_END_DECLS
+
+#endif /* __SPICE_URI_H__ */
commit 68370795f08af3f834d5814ca8d71b82ca4a1396
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Thu Jan 30 18:20:00 2014 +0100
channel: talk to giostream instead of gsocket
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index 35704ea..f38156e 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -82,6 +82,8 @@ struct _SpiceChannelPrivate {
SpiceOpenSSLVerify *sslverify;
GSocket *sock;
GSocketConnection *conn;
+ GInputStream *in;
+ GOutputStream *out;
#if HAVE_SASL
sasl_conn_t *sasl_conn;
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index e729ffc..aff53ea 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -763,7 +763,8 @@ static void spice_channel_flush_wire(SpiceChannel *channel,
GIOCondition cond;
while (offset < datalen) {
- int ret;
+ gssize ret;
+ GError *error = NULL;
if (c->has_error) return;
@@ -779,9 +780,12 @@ static void spice_channel_flush_wire(SpiceChannel *channel,
ret = -1;
}
} else {
- GError *error = NULL;
- ret = g_socket_send(c->sock, ptr+offset, datalen-offset,
- NULL, &error);
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ ret = g_pollable_output_stream_write_nonblocking(G_POLLABLE_OUTPUT_STREAM(c->out),
+ ptr+offset, datalen-offset, NULL, &error);
+#else
+ ret = g_socket_send(c->sock, ptr+offset, datalen-offset, NULL, &error);
+#endif
if (ret < 0) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
cond = G_IO_OUT;
@@ -794,6 +798,7 @@ static void spice_channel_flush_wire(SpiceChannel *channel,
}
if (ret == -1) {
if (cond != 0) {
+ // TODO: should use g_pollable_input/output_stream_create_source() in 2.28 ?
g_coroutine_socket_wait(&c->coroutine, c->sock, cond);
continue;
} else {
@@ -888,7 +893,7 @@ static void spice_channel_write_msg(SpiceChannel *channel, SpiceMsgOut *out)
static int spice_channel_read_wire(SpiceChannel *channel, void *data, size_t len)
{
SpiceChannelPrivate *c = channel->priv;
- int ret;
+ gssize ret;
GIOCondition cond;
reread:
@@ -908,7 +913,13 @@ reread:
}
} else {
GError *error = NULL;
- ret = g_socket_receive(c->sock, data, len, NULL, &error);
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ ret = g_pollable_input_stream_read_nonblocking(G_POLLABLE_INPUT_STREAM(c->in),
+ data, len, NULL, &error);
+#else
+ ret = g_socket_receive(c->sock,
+ data, len, NULL, &error);
+#endif
if (ret < 0) {
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK)) {
cond = G_IO_IN;
@@ -922,6 +933,7 @@ reread:
if (ret == -1) {
if (cond != 0) {
+ // TODO: should use g_pollable_input/output_stream_create_source() ?
g_coroutine_socket_wait(&c->coroutine, c->sock, cond);
goto reread;
} else {
@@ -2061,9 +2073,12 @@ static void spice_channel_iterate_read(SpiceChannel *channel)
/* treat all incoming data (block on message completion) */
while (!c->has_error &&
c->state != SPICE_CHANNEL_STATE_MIGRATING &&
- g_socket_condition_check(c->sock, G_IO_IN) & G_IO_IN) {
-
- do
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ g_pollable_input_stream_is_readable(G_POLLABLE_INPUT_STREAM(c->in))
+#else
+ g_socket_condition_check(c->sock, G_IO_IN) & G_IO_IN
+#endif
+ ) { do
spice_channel_recv_msg(channel,
(handler_msg_in)SPICE_CHANNEL_GET_CLASS(channel)->handle_msg, NULL);
#if HAVE_SASL
@@ -2230,9 +2245,11 @@ static void *spice_channel_coroutine(void *data)
g_socket_set_blocking(c->sock, FALSE);
g_socket_set_keepalive(c->sock, TRUE);
+ c->conn = g_socket_connection_factory_create_connection(c->sock);
goto connected;
}
+
reconnect:
c->conn = spice_session_channel_open_host(c->session, channel, &c->tls);
if (c->conn == NULL) {
@@ -2293,7 +2310,11 @@ reconnect:
}
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ BIO *bio = bio_new_giostream(G_IO_STREAM(c->conn));
+#else
BIO *bio = bio_new_gsocket(c->sock);
+#endif
SSL_set_bio(c->ssl, bio, bio);
{
@@ -2324,6 +2345,9 @@ ssl_reconnect:
}
connected:
+ c->in = g_io_stream_get_input_stream(G_IO_STREAM(c->conn));
+ c->out = g_io_stream_get_output_stream(G_IO_STREAM(c->conn));
+
rc = setsockopt(g_socket_get_fd(c->sock), IPPROTO_TCP, TCP_NODELAY,
(const char*)&delay_val, sizeof(delay_val));
if ((rc != 0)
@@ -2497,10 +2521,9 @@ static void channel_reset(SpiceChannel *channel, gboolean migrating)
g_object_unref(c->conn);
c->conn = NULL;
}
- if (c->sock) {
- g_object_unref(c->sock);
- c->sock = NULL;
- }
+
+ g_clear_object(&c->sock);
+
c->fd = -1;
free(c->peer_msg);
@@ -2726,8 +2749,10 @@ void spice_channel_swap(SpiceChannel *channel, SpiceChannel *swap, gboolean swap
/* TODO: split channel in 2 objects: a controller and a swappable
state object */
- SWAP(conn);
SWAP(sock);
+ SWAP(conn);
+ SWAP(in);
+ SWAP(out);
SWAP(ctx);
SWAP(ssl);
SWAP(sslverify);
commit 9cf9ca4348a58c99dc1bd849933687724be18748
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Thu Jan 30 18:21:31 2014 +0100
channel: simplify has error code
Get rid of a superflous g_socket_condition_check().
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index 9e97f28..e729ffc 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -2093,29 +2093,23 @@ static gboolean wait_migration(gpointer data)
static gboolean spice_channel_iterate(SpiceChannel *channel)
{
SpiceChannelPrivate *c = channel->priv;
- GIOCondition ret;
if (c->state == SPICE_CHANNEL_STATE_MIGRATING &&
!g_coroutine_condition_wait(&c->coroutine, wait_migration, channel))
CHANNEL_DEBUG(channel, "migration wait cancelled");
- if (c->has_error) {
- CHANNEL_DEBUG(channel, "channel has error, breaking loop");
- return FALSE;
- }
-
/* flush any pending write and read */
- SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
- SPICE_CHANNEL_GET_CLASS(channel)->iterate_read(channel);
-
- ret = g_socket_condition_check(c->sock, G_IO_IN | G_IO_ERR | G_IO_HUP);
- if (c->state > SPICE_CHANNEL_STATE_CONNECTING &&
- ret & (G_IO_ERR|G_IO_HUP)) {
- SPICE_DEBUG("got socket error: %d", ret);
- emit_main_context(channel, SPICE_CHANNEL_EVENT,
- c->state == SPICE_CHANNEL_STATE_READY ?
- SPICE_CHANNEL_ERROR_IO : SPICE_CHANNEL_ERROR_LINK);
- c->has_error = TRUE;
+ if (!c->has_error)
+ SPICE_CHANNEL_GET_CLASS(channel)->iterate_write(channel);
+ if (!c->has_error)
+ SPICE_CHANNEL_GET_CLASS(channel)->iterate_read(channel);
+
+ if (c->has_error) {
+ CHANNEL_DEBUG(channel, "channel got error");
+ if (c->state > SPICE_CHANNEL_STATE_CONNECTING)
+ emit_main_context(channel, SPICE_CHANNEL_EVENT,
+ c->state == SPICE_CHANNEL_STATE_READY ?
+ SPICE_CHANNEL_ERROR_IO : SPICE_CHANNEL_ERROR_LINK);
return FALSE;
}
commit 35f06b8fda1115bee6dfd54e6e041e63f62c10fe
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Thu Jan 30 18:06:12 2014 +0100
openssl: learn to handle a new kind of BIO based on GIOStream
Although reusing BIO_new_socket() once again is a hack, it seems
to be the easiest way... The proper solution is certainly to start
using GTls instead, but that will require a glib 2.28 dep bump.
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 7ceb22f..0c1ad9a 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -210,8 +210,8 @@ USB_ACL_HELPER_SRCS =
endif
libspice_client_glib_2_0_la_SOURCES = \
- bio-gsocket.c \
- bio-gsocket.h \
+ bio-gio.c \
+ bio-gio.h \
glib-compat.c \
glib-compat.h \
spice-audio.c \
diff --git a/gtk/bio-gio.c b/gtk/bio-gio.c
new file mode 100644
index 0000000..22d58b6
--- /dev/null
+++ b/gtk/bio-gio.c
@@ -0,0 +1,135 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
+*/
+
+#include <string.h>
+#include <glib.h>
+
+#include "spice-util.h"
+#include "bio-gio.h"
+
+typedef struct bio_gsocket_method {
+ BIO_METHOD method;
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ GIOStream *stream;
+#else
+ GSocket *gsocket;
+#endif
+} bio_gsocket_method;
+
+#define BIO_GET_GSOCKET(bio) (((bio_gsocket_method*)bio->method)->gsocket)
+#define BIO_GET_ISTREAM(bio) (g_io_stream_get_input_stream(((bio_gsocket_method*)bio->method)->stream))
+#define BIO_GET_OSTREAM(bio) (g_io_stream_get_output_stream(((bio_gsocket_method*)bio->method)->stream))
+
+static int bio_gio_write(BIO *bio, const char *in, int inl)
+{
+ gssize ret;
+ GError *error = NULL;
+
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ ret = g_pollable_output_stream_write_nonblocking(G_POLLABLE_OUTPUT_STREAM(BIO_GET_OSTREAM(bio)),
+#else
+ ret = g_socket_send(BIO_GET_GSOCKET(bio),
+#endif
+ in, inl, NULL, &error);
+ BIO_clear_retry_flags(bio);
+
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+ BIO_set_retry_write(bio);
+ if (error != NULL) {
+ g_warning("%s", error->message);
+ g_clear_error(&error);
+ }
+
+ return ret;
+}
+
+static int bio_gio_read(BIO *bio, char *out, int outl)
+{
+ gssize ret;
+ GError *error = NULL;
+
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ ret = g_pollable_input_stream_read_nonblocking(G_POLLABLE_INPUT_STREAM(BIO_GET_ISTREAM(bio)),
+#else
+ ret = g_socket_receive(BIO_GET_GSOCKET(bio),
+#endif
+ out, outl, NULL, &error);
+ BIO_clear_retry_flags(bio);
+
+ if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
+ BIO_set_retry_read(bio);
+ else if (error != NULL)
+ g_warning("%s", error->message);
+
+ g_clear_error(&error);
+
+ return ret;
+}
+
+static int bio_gio_destroy(BIO *bio)
+{
+ if (bio == NULL || bio->method == NULL)
+ return 0;
+
+ SPICE_DEBUG("bio gsocket destroy");
+ g_free(bio->method);
+ bio->method = NULL;;
+
+ return 1;
+}
+
+static int bio_gio_puts(BIO *bio, const char *str)
+{
+ int n, ret;
+
+ n = strlen(str);
+ ret = bio_gio_write(bio, str, n);
+
+ return ret;
+}
+
+G_GNUC_INTERNAL
+#if GLIB_CHECK_VERSION(2, 28, 0)
+BIO* bio_new_giostream(GIOStream *stream)
+{
+ // TODO: make an actual new BIO type, or just switch to GTls already...
+ BIO *bio = BIO_new_socket(-1, BIO_NOCLOSE);
+#else
+BIO* bio_new_gsocket(GSocket *gsocket)
+{
+ BIO *bio = BIO_new_socket(g_socket_get_fd(gsocket), BIO_NOCLOSE);
+#endif
+
+ bio_gsocket_method *bio_method = g_new(bio_gsocket_method, 1);
+ bio_method->method = *bio->method;
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ bio_method->stream = stream;
+#else
+ bio_method->gsocket = gsocket;
+#endif
+
+ bio->method->destroy(bio);
+ bio->method = (BIO_METHOD*)bio_method;
+
+ bio->method->bwrite = bio_gio_write;
+ bio->method->bread = bio_gio_read;
+ bio->method->bputs = bio_gio_puts;
+ bio->method->destroy = bio_gio_destroy;
+
+ return bio;
+}
diff --git a/gtk/bio-gio.h b/gtk/bio-gio.h
new file mode 100644
index 0000000..9bd3566
--- /dev/null
+++ b/gtk/bio-gio.h
@@ -0,0 +1,34 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef BIO_GIO_H_
+# define BIO_GIO_H_
+
+#include <openssl/bio.h>
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+#if GLIB_CHECK_VERSION(2, 28, 0)
+BIO* bio_new_giostream(GIOStream *stream);
+#else
+BIO* bio_new_gsocket(GSocket *gsocket);
+#endif
+
+G_END_DECLS
+
+#endif /* !BIO_GIO_H_ */
diff --git a/gtk/bio-gsocket.c b/gtk/bio-gsocket.c
deleted file mode 100644
index dbf17a2..0000000
--- a/gtk/bio-gsocket.c
+++ /dev/null
@@ -1,111 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
-*/
-
-#include <string.h>
-#include <glib.h>
-
-#include "spice-util.h"
-#include "bio-gsocket.h"
-
-typedef struct bio_gsocket_method {
- BIO_METHOD method;
- GSocket *gsocket;
-} bio_gsocket_method;
-
-#define BIO_GET_GSOCKET(bio) (((bio_gsocket_method*)bio->method)->gsocket)
-
-static int bio_gsocket_bwrite(BIO *bio, const char *in, int inl)
-{
- int ret;
- GError *error = NULL;
-
- ret = g_socket_send(BIO_GET_GSOCKET(bio),
- in, inl, NULL, &error);
- BIO_clear_retry_flags(bio);
-
- if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
- BIO_set_retry_write(bio);
- if (error != NULL) {
- g_warning("%s", error->message);
- g_clear_error(&error);
- }
-
- return ret;
-}
-
-static int bio_gsocket_bread(BIO *bio, char *out, int outl)
-{
- int ret;
- GError *error = NULL;
-
- ret = g_socket_receive(BIO_GET_GSOCKET(bio),
- out, outl, NULL, &error);
- BIO_clear_retry_flags(bio);
-
- if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_WOULD_BLOCK))
- BIO_set_retry_read(bio);
- else if (error != NULL)
- g_warning("%s", error->message);
-
- g_clear_error(&error);
-
- return ret;
-}
-
-static int bio_gsocket_destroy(BIO *bio)
-{
- if (bio == NULL || bio->method == NULL)
- return 0;
-
- SPICE_DEBUG("bio gsocket destroy");
- g_free(bio->method);
- bio->method = NULL;;
-
- return 1;
-}
-
-static int bio_gsocket_bputs(BIO *bio, const char *str)
-{
- int n, ret;
-
- n = strlen(str);
- ret = bio_gsocket_bwrite(bio, str, n);
-
- return ret;
-}
-
-G_GNUC_INTERNAL
-BIO* bio_new_gsocket(GSocket *gsocket)
-{
- BIO *bio = BIO_new_socket(g_socket_get_fd(gsocket), BIO_NOCLOSE);
-
- bio_gsocket_method *bio_method = g_new(bio_gsocket_method, 1);
- bio_method->method = *bio->method;
- bio_method->gsocket = gsocket;
-
- bio->method->destroy(bio);
- bio->method = (BIO_METHOD*)bio_method;
-
- bio->method->bwrite = bio_gsocket_bwrite;
- bio->method->bread = bio_gsocket_bread;
- bio->method->bputs = bio_gsocket_bputs;
- bio->method->destroy = bio_gsocket_destroy;
-
- return bio;
-}
-
diff --git a/gtk/bio-gsocket.h b/gtk/bio-gsocket.h
deleted file mode 100644
index 7ee5e64..0000000
--- a/gtk/bio-gsocket.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
-/*
- Copyright (C) 2012 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, see <http://www.gnu.org/licenses/>.
-*/
-#ifndef BIO_GSOCKET_H_
-# define BIO_GSOCKET_H_
-
-#include <openssl/bio.h>
-#include <gio/gio.h>
-
-G_BEGIN_DECLS
-
-BIO* bio_new_gsocket(GSocket *gsocket);
-
-G_END_DECLS
-
-#endif /* !BIO_GSOCKET_H_ */
diff --git a/gtk/spice-channel.c b/gtk/spice-channel.c
index f101c3a..9e97f28 100644
--- a/gtk/spice-channel.c
+++ b/gtk/spice-channel.c
@@ -22,7 +22,7 @@
#include "spice-channel-priv.h"
#include "spice-session-priv.h"
#include "spice-marshal.h"
-#include "bio-gsocket.h"
+#include "bio-gio.h"
#include <openssl/rsa.h>
#include <openssl/evp.h>
commit 263e3014b949f7d3d4e3c8372997c01bee2bb2b5
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Fri Jan 24 21:08:23 2014 +0100
Fill g_proxy_address_new() with protocol, user and password
This way, the call might eventually support more proxy and
authentication.
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index 7fe85e8..833992e 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -1723,8 +1723,11 @@ static void proxy_lookup_ready(GObject *source_object, GAsyncResult *result,
for (it = addresses; it != NULL; it = it->next) {
address = g_proxy_address_new(G_INET_ADDRESS(it->data),
- spice_proxy_get_port(open_host->proxy), "http",
- s->host, open_host->port, NULL, NULL);
+ spice_proxy_get_port(open_host->proxy),
+ spice_proxy_get_protocol(open_host->proxy),
+ s->host, open_host->port,
+ spice_proxy_get_user(open_host->proxy),
+ spice_proxy_get_password(open_host->proxy));
if (address != NULL)
break;
}
commit 8fa0eb30ff791a159fb6b259c2be9604f0aaf556
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Fri Jan 24 21:07:15 2014 +0100
http-proxy: add https proxy
This will require glib 2.28 for GTls support, atm
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index e6f66c5..7fe85e8 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -636,6 +636,9 @@ static void spice_session_class_init(SpiceSessionClass *klass)
#if GLIB_CHECK_VERSION(2, 26, 0)
_wocky_http_proxy_get_type();
#endif
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ _wocky_https_proxy_get_type();
+#endif
gobject_class->dispose = spice_session_dispose;
gobject_class->finalize = spice_session_finalize;
diff --git a/gtk/wocky-http-proxy.c b/gtk/wocky-http-proxy.c
index 11f557e..4226b10 100644
--- a/gtk/wocky-http-proxy.c
+++ b/gtk/wocky-http-proxy.c
@@ -1,7 +1,9 @@
/* wocky-http-proxy.c: Source for WockyHttpProxy
*
* Copyright (C) 2010 Collabora, Ltd.
+ * Copyright (C) 2014 Red Hat, Inc.
* @author Nicolas Dufresne <nicolas.dufresne at collabora.co.uk>
+ * @author Marc-André Lureau <marcandre.lureau at redhat.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -180,9 +182,32 @@ wocky_http_proxy_connect (GProxy *proxy,
{
GInputStream *in;
GOutputStream *out;
- GDataInputStream *data_in;
- gchar *buffer;
+ GDataInputStream *data_in = NULL;
+ gchar *buffer = NULL;
gboolean has_cred;
+ GIOStream *tlsconn = NULL;
+
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ if (WOCKY_IS_HTTPS_PROXY (proxy))
+ {
+ tlsconn = g_tls_client_connection_new (io_stream,
+ G_SOCKET_CONNECTABLE(proxy_address),
+ error);
+ if (!tlsconn)
+ goto error;
+
+ GTlsCertificateFlags tls_validation_flags = G_TLS_CERTIFICATE_VALIDATE_ALL;
+#ifdef DEBUG
+ tls_validation_flags &= ~(G_TLS_CERTIFICATE_UNKNOWN_CA | G_TLS_CERTIFICATE_BAD_IDENTITY);
+#endif
+ g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (tlsconn),
+ tls_validation_flags);
+ if (!g_tls_connection_handshake (G_TLS_CONNECTION (tlsconn), cancellable, error))
+ goto error;
+
+ io_stream = tlsconn;
+ }
+#endif
in = g_io_stream_get_input_stream (io_stream);
out = g_io_stream_get_output_stream (io_stream);
@@ -215,12 +240,14 @@ wocky_http_proxy_connect (GProxy *proxy,
g_free (buffer);
- return g_object_ref (io_stream);
+ g_object_ref (io_stream);
+ g_clear_object (&tlsconn);
-error:
- if (data_in != NULL)
- g_object_unref (data_in);
+ return io_stream;
+error:
+ g_clear_object (&tlsconn);
+ g_clear_object (&data_in);
g_free (buffer);
return NULL;
}
@@ -291,6 +318,41 @@ do_write (GAsyncReadyCallback callback, ConnectAsyncData *data)
}
static void
+stream_connected (ConnectAsyncData *data,
+ GIOStream *io_stream)
+{
+ GInputStream *in;
+
+ data->io_stream = g_object_ref (io_stream);
+ in = g_io_stream_get_input_stream (io_stream);
+ data->data_in = g_data_input_stream_new (in);
+ g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (data->data_in),
+ FALSE);
+
+ do_write (request_write_cb, data);
+}
+
+#if GLIB_CHECK_VERSION(2, 28, 0)
+static void
+handshake_completed (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GTlsConnection *conn = G_TLS_CONNECTION (source_object);
+ ConnectAsyncData *data = user_data;
+ GError *error = NULL;
+
+ if (!g_tls_connection_handshake_finish (conn, res, &error))
+ {
+ complete_async_from_error (data, error);
+ return;
+ }
+
+ stream_connected (data, G_IO_STREAM (conn));
+}
+#endif
+
+static void
wocky_http_proxy_connect_async (GProxy *proxy,
GIOStream *io_stream,
GProxyAddress *proxy_address,
@@ -300,34 +362,55 @@ wocky_http_proxy_connect_async (GProxy *proxy,
{
GSimpleAsyncResult *simple;
ConnectAsyncData *data;
- GInputStream *in;
simple = g_simple_async_result_new (G_OBJECT (proxy),
- callback, user_data,
- wocky_http_proxy_connect_async);
+ callback, user_data,
+ wocky_http_proxy_connect_async);
data = g_slice_new0 (ConnectAsyncData);
-
- data->simple = simple;
- data->io_stream = g_object_ref (io_stream);
-
if (cancellable != NULL)
data->cancellable = g_object_ref (cancellable);
-
- in = g_io_stream_get_input_stream (io_stream);
-
- data->data_in = g_data_input_stream_new (in);
- g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (data->data_in),
- FALSE);
-
- g_simple_async_result_set_op_res_gpointer (simple, data,
- (GDestroyNotify) free_connect_data);
+ data->simple = simple;
data->buffer = create_request (proxy_address, &data->has_cred);
data->length = strlen (data->buffer);
data->offset = 0;
- do_write (request_write_cb, data);
+ g_simple_async_result_set_op_res_gpointer (simple, data,
+ (GDestroyNotify) free_connect_data);
+
+#if GLIB_CHECK_VERSION(2, 28, 0)
+ if (WOCKY_IS_HTTPS_PROXY (proxy))
+ {
+ GError *error = NULL;
+ GIOStream *tlsconn;
+
+ tlsconn = g_tls_client_connection_new (io_stream,
+ G_SOCKET_CONNECTABLE(proxy_address),
+ &error);
+ if (!tlsconn)
+ {
+ complete_async_from_error (data, error);
+ return;
+ }
+
+ g_return_if_fail (tlsconn != NULL);
+
+ GTlsCertificateFlags tls_validation_flags = G_TLS_CERTIFICATE_VALIDATE_ALL;
+#ifdef DEBUG
+ tls_validation_flags &= ~(G_TLS_CERTIFICATE_UNKNOWN_CA | G_TLS_CERTIFICATE_BAD_IDENTITY);
+#endif
+ g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (tlsconn),
+ tls_validation_flags);
+ g_tls_connection_handshake_async (G_TLS_CONNECTION (tlsconn),
+ G_PRIORITY_DEFAULT, cancellable,
+ handshake_completed, data);
+ }
+ else
+#endif
+ {
+ stream_connected (data, io_stream);
+ }
}
static void
@@ -427,3 +510,35 @@ wocky_http_proxy_iface_init (GProxyInterface *proxy_iface)
proxy_iface->connect_finish = wocky_http_proxy_connect_finish;
proxy_iface->supports_hostname = wocky_http_proxy_supports_hostname;
}
+
+#if GLIB_CHECK_VERSION(2, 28, 0)
+struct _WockyHttpsProxy
+{
+ WockyHttpProxy parent;
+};
+
+struct _WockyHttpsProxyClass
+{
+ WockyHttpProxyClass parent_class;
+};
+
+#define wocky_https_proxy_get_type _wocky_https_proxy_get_type
+G_DEFINE_TYPE_WITH_CODE (WockyHttpsProxy, wocky_https_proxy, WOCKY_TYPE_HTTP_PROXY,
+ G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
+ wocky_http_proxy_iface_init)
+ g_io_extension_point_set_required_type (
+ g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME),
+ G_TYPE_PROXY);
+ g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
+ g_define_type_id, "https", 0))
+
+static void
+wocky_https_proxy_init (WockyHttpsProxy *proxy)
+{
+}
+
+static void
+wocky_https_proxy_class_init (WockyHttpsProxyClass *class)
+{
+}
+#endif
diff --git a/gtk/wocky-http-proxy.h b/gtk/wocky-http-proxy.h
index 3b91e63..9484b51 100644
--- a/gtk/wocky-http-proxy.h
+++ b/gtk/wocky-http-proxy.h
@@ -37,6 +37,20 @@ typedef struct _WockyHttpProxyClass WockyHttpProxyClass;
GType _wocky_http_proxy_get_type (void);
+#if GLIB_CHECK_VERSION(2, 28, 0)
+#define WOCKY_TYPE_HTTPS_PROXY (_wocky_https_proxy_get_type ())
+#define WOCKY_HTTPS_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), WOCKY_TYPE_HTTPS_PROXY, WockyHttpsProxy))
+#define WOCKY_HTTPS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), WOCKY_TYPE_HTTPS_PROXY, WockyHttpsProxyClass))
+#define WOCKY_IS_HTTPS_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), WOCKY_TYPE_HTTPS_PROXY))
+#define WOCKY_IS_HTTPS_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), WOCKY_TYPE_HTTPS_PROXY))
+#define WOCKY_HTTPS_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), WOCKY_TYPE_HTTPS_PROXY, WockyHttpsProxyClass))
+
+typedef struct _WockyHttpsProxy WockyHttpsProxy;
+typedef struct _WockyHttpsProxyClass WockyHttpsProxyClass;
+
+GType _wocky_https_proxy_get_type (void);
+#endif
+
G_END_DECLS
#endif /* _WOCKY_HTTP_PROXY_H_ */
commit 5dcab09ac32d0578cdd74540abdaea8eea3858d5
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Fri Jan 24 21:05:56 2014 +0100
spice-proxy: parse https protocol
diff --git a/gtk/spice-proxy.c b/gtk/spice-proxy.c
index 8613469..cf4b6ad 100644
--- a/gtk/spice-proxy.c
+++ b/gtk/spice-proxy.c
@@ -65,9 +65,17 @@ gboolean spice_proxy_parse(SpiceProxy *self, const gchar *proxyuri, GError **err
uri = dup = g_strdup(proxyuri);
/* FIXME: use GUri when it is ready... only support http atm */
/* the code is voluntarily not parsing thoroughly the uri */
- if (g_ascii_strncasecmp("http://", uri, 7) == 0)
+ if (g_ascii_strncasecmp("http://", uri, 7) == 0) {
uri += 7;
-
+ spice_proxy_set_protocol(self, "http");
+ spice_proxy_set_port(self, 3128);
+ } else if (g_ascii_strncasecmp("https://", uri, 8) == 0) {
+ uri += 8;
+ spice_proxy_set_protocol(self, "https");
+ spice_proxy_set_port(self, 3129);
+ } else {
+ return FALSE;
+ }
/* remove trailing slash */
len = strlen(uri);
for (; len > 0; len--)
@@ -76,8 +84,6 @@ gboolean spice_proxy_parse(SpiceProxy *self, const gchar *proxyuri, GError **err
else
break;
- spice_proxy_set_protocol(self, "http");
- spice_proxy_set_port(self, 3128);
/* yes, that parser is bad, we need GUri... */
if (strstr(uri, "@")) {
commit 3437c442663cdf761e59a5b8353e35efeb841c43
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Fri Jan 24 21:04:09 2014 +0100
http-proxy: specify Basic scheme
Or Squid will fail with:
WARNING: Unsupported or unconfigured/inactive proxy-auth scheme
diff --git a/gtk/wocky-http-proxy.c b/gtk/wocky-http-proxy.c
index d73990b..11f557e 100644
--- a/gtk/wocky-http-proxy.c
+++ b/gtk/wocky-http-proxy.c
@@ -98,7 +98,7 @@ create_request (GProxyAddress *proxy_address, gboolean *has_cred)
base64_cred = g_base64_encode ((guchar *) cred, strlen (cred));
g_free (cred);
g_string_append_printf (request,
- "Proxy-Authorization: %s\r\n",
+ "Proxy-Authorization: Basic %s\r\n",
base64_cred);
g_free (base64_cred);
}
commit 471ce3991b2220fb5d542d788e8191111ca0d81f
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Wed Feb 12 11:04:23 2014 +0100
proxy: parse user and pass from uri
diff --git a/gtk/spice-proxy.c b/gtk/spice-proxy.c
index 26e9dff..8613469 100644
--- a/gtk/spice-proxy.c
+++ b/gtk/spice-proxy.c
@@ -19,6 +19,7 @@
#include <stdlib.h>
#include <string.h>
+#include "glib-compat.h"
#include "spice-client.h"
#include "spice-proxy.h"
@@ -78,6 +79,18 @@ gboolean spice_proxy_parse(SpiceProxy *self, const gchar *proxyuri, GError **err
spice_proxy_set_protocol(self, "http");
spice_proxy_set_port(self, 3128);
+ /* yes, that parser is bad, we need GUri... */
+ if (strstr(uri, "@")) {
+ gchar *saveptr, *saveptr2;
+ gchar *next = strstr(uri, "@") + 1;
+ gchar *auth = strtok_r(uri, "@", &saveptr);
+ const gchar *user = strtok_r(auth, ":", &saveptr2);
+ const gchar *pass = strtok_r(NULL, ":", &saveptr2);
+ spice_proxy_set_user(self, user);
+ spice_proxy_set_password(self, pass);
+ uri = next;
+ }
+
/* max 2 parts, host:port */
gchar **proxyv = g_strsplit(uri, ":", 2);
const gchar *proxy_port = NULL;
commit 809cf4c7b8143691009b633d338794fadc851531
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Wed Feb 12 11:04:05 2014 +0100
proxy: add user and pass properties
diff --git a/gtk/spice-proxy.c b/gtk/spice-proxy.c
index f338213..26e9dff 100644
--- a/gtk/spice-proxy.c
+++ b/gtk/spice-proxy.c
@@ -26,6 +26,8 @@ struct _SpiceProxyPrivate {
gchar *protocol;
gchar *hostname;
guint port;
+ gchar *user;
+ gchar *password;
};
#define SPICE_PROXY_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE((o), SPICE_TYPE_PROXY, SpiceProxyPrivate))
@@ -35,6 +37,8 @@ G_DEFINE_TYPE(SpiceProxy, spice_proxy, G_TYPE_OBJECT);
enum {
SPICE_PROXY_DUMMY_PROPERTY,
SPICE_PROXY_PROTOCOL,
+ SPICE_PROXY_USER,
+ SPICE_PROXY_PASSWORD,
SPICE_PROXY_HOSTNAME,
SPICE_PROXY_PORT
};
@@ -173,6 +177,12 @@ static void spice_proxy_get_property(GObject *object, guint property_id,
case SPICE_PROXY_PORT:
g_value_set_uint(value, spice_proxy_get_port(self));
break;
+ case SPICE_PROXY_USER:
+ g_value_set_string(value, spice_proxy_get_user(self));
+ break;
+ case SPICE_PROXY_PASSWORD:
+ g_value_set_string(value, spice_proxy_get_password(self));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID(object, property_id, pspec);
break;
@@ -193,6 +203,12 @@ static void spice_proxy_set_property(GObject *object, guint property_id,
case SPICE_PROXY_HOSTNAME:
spice_proxy_set_hostname(self, g_value_get_string(value));
break;
+ case SPICE_PROXY_USER:
+ spice_proxy_set_user(self, g_value_get_string(value));
+ break;
+ case SPICE_PROXY_PASSWORD:
+ spice_proxy_set_password(self, g_value_get_string(value));
+ break;
case SPICE_PROXY_PORT:
spice_proxy_set_port(self, g_value_get_uint(value));
break;
@@ -209,6 +225,8 @@ static void spice_proxy_finalize(GObject* obj)
self = G_TYPE_CHECK_INSTANCE_CAST(obj, SPICE_TYPE_PROXY, SpiceProxy);
g_free(self->priv->protocol);
g_free(self->priv->hostname);
+ g_free(self->priv->user);
+ g_free(self->priv->password);
G_OBJECT_CLASS (spice_proxy_parent_class)->finalize (obj);
}
@@ -254,6 +272,24 @@ static void spice_proxy_class_init(SpiceProxyClass *klass)
0, G_MAXUINT, 0,
G_PARAM_STATIC_STRINGS |
G_PARAM_READWRITE));
+
+ g_object_class_install_property(G_OBJECT_CLASS (klass),
+ SPICE_PROXY_USER,
+ g_param_spec_string ("user",
+ "user",
+ "user",
+ NULL,
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property(G_OBJECT_CLASS (klass),
+ SPICE_PROXY_PASSWORD,
+ g_param_spec_string ("password",
+ "password",
+ "password",
+ NULL,
+ G_PARAM_STATIC_STRINGS |
+ G_PARAM_READWRITE));
}
G_GNUC_INTERNAL
@@ -267,5 +303,48 @@ gchar* spice_proxy_to_string(SpiceProxy* self)
if (p->protocol == NULL || p->hostname == NULL)
return NULL;
- return g_strdup_printf("%s://%s:%u", p->protocol, p->hostname, p->port);
+ if (p->user || p->password)
+ return g_strdup_printf("%s://%s:%s@%s:%u",
+ p->protocol,
+ p->user, p->password,
+ p->hostname, p->port);
+ else
+ return g_strdup_printf("%s://%s:%u",
+ p->protocol, p->hostname, p->port);
+}
+
+G_GNUC_INTERNAL
+const gchar* spice_proxy_get_user(SpiceProxy *self)
+{
+ g_return_val_if_fail(SPICE_IS_PROXY(self), NULL);
+ return self->priv->user;
+}
+
+
+G_GNUC_INTERNAL
+void spice_proxy_set_user(SpiceProxy *self, const gchar *value)
+{
+ g_return_if_fail(SPICE_IS_PROXY(self));
+
+ g_free(self->priv->user);
+ self->priv->user = g_strdup(value);
+ g_object_notify((GObject *)self, "user");
+}
+
+G_GNUC_INTERNAL
+const gchar* spice_proxy_get_password(SpiceProxy *self)
+{
+ g_return_val_if_fail(SPICE_IS_PROXY(self), NULL);
+ return self->priv->password;
+}
+
+
+G_GNUC_INTERNAL
+void spice_proxy_set_password(SpiceProxy *self, const gchar *value)
+{
+ g_return_if_fail(SPICE_IS_PROXY(self));
+
+ g_free(self->priv->password);
+ self->priv->password = g_strdup(value);
+ g_object_notify((GObject *)self, "password");
}
diff --git a/gtk/spice-proxy.h b/gtk/spice-proxy.h
index 1e7b6d7..e74053b 100644
--- a/gtk/spice-proxy.h
+++ b/gtk/spice-proxy.h
@@ -54,6 +54,10 @@ void spice_proxy_set_hostname(SpiceProxy* self, const gchar* value);
guint spice_proxy_get_port(SpiceProxy* self);
void spice_proxy_set_port(SpiceProxy* self, guint port);
gchar *spice_proxy_to_string(SpiceProxy* self);
+const gchar* spice_proxy_get_user(SpiceProxy* self);
+void spice_proxy_set_user(SpiceProxy* self, const gchar* value);
+const gchar* spice_proxy_get_password(SpiceProxy* self);
+void spice_proxy_set_password(SpiceProxy* self, const gchar* value);
G_END_DECLS
commit 614821078ff8d115fe63f3a593fba8e7fd36c313
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Wed Feb 12 11:02:58 2014 +0100
proxy: split uri with : in only 2 parts
We want just host:port here.
diff --git a/gtk/spice-proxy.c b/gtk/spice-proxy.c
index bc4037e..f338213 100644
--- a/gtk/spice-proxy.c
+++ b/gtk/spice-proxy.c
@@ -74,7 +74,8 @@ gboolean spice_proxy_parse(SpiceProxy *self, const gchar *proxyuri, GError **err
spice_proxy_set_protocol(self, "http");
spice_proxy_set_port(self, 3128);
- gchar **proxyv = g_strsplit(uri, ":", 0);
+ /* max 2 parts, host:port */
+ gchar **proxyv = g_strsplit(uri, ":", 2);
const gchar *proxy_port = NULL;
if (proxyv[0] == NULL || strlen(proxyv[0]) == 0) {
commit 2e720c207640b01a373c3e3e438723190c30a719
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Thu Jan 30 18:48:10 2014 +0100
compat: add strtok_r fallback
The following Spice proxy URI parsing code makes use of it, but it is
not available on Windows
Origin:
http://git.videolan.org/gitweb.cgi/vlc.git/?p=vlc.git;a=blob;f=compat/strtok_r.c
diff --git a/configure.ac b/configure.ac
index e2dd742..6e4b29a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -233,7 +233,7 @@ else
EXTERNAL_PNP_IDS="$with_pnp_ids_path"
fi
-AC_CHECK_FUNCS(clearenv)
+AC_CHECK_FUNCS(clearenv strtok_r)
PKG_CHECK_MODULES(GLIB2, glib-2.0 >= 2.22)
AC_SUBST(GLIB2_CFLAGS)
diff --git a/gtk/glib-compat.c b/gtk/glib-compat.c
index 9ffadbb..20cbc8b 100644
--- a/gtk/glib-compat.c
+++ b/gtk/glib-compat.c
@@ -1,5 +1,8 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
+ Copyright (C) 2012-2014 Red Hat, Inc.
+ Copyright © 1998-2009 VLC authors and VideoLAN
+
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
@@ -14,6 +17,8 @@
License along with this library; if not, see <http://www.gnu.org/licenses/>.
*/
+#include <string.h>
+
#include "glib-compat.h"
#if !GLIB_CHECK_VERSION(2,26,0)
@@ -105,3 +110,33 @@ guint64 g_get_monotonic_time(void)
return (((gint64) tv.tv_sec) * 1000000) + tv.tv_usec;
}
#endif
+
+#ifndef HAVE_STRTOK_R
+G_GNUC_INTERNAL
+char *strtok_r(char *s, const char *delim, char **save_ptr)
+{
+ char *token;
+
+ if (s == NULL)
+ s = *save_ptr;
+
+ /* Scan leading delimiters. */
+ s += strspn (s, delim);
+ if (*s == '\0')
+ return NULL;
+
+ /* Find the end of the token. */
+ token = s;
+ s = strpbrk (token, delim);
+ if (s == NULL)
+ /* This token finishes the string. */
+ *save_ptr = strchr (token, '\0');
+ else
+ {
+ /* Terminate the token and make *SAVE_PTR point past it. */
+ *s = '\0';
+ *save_ptr = s + 1;
+ }
+ return token;
+}
+#endif
diff --git a/gtk/glib-compat.h b/gtk/glib-compat.h
index c30a735..4acf401 100644
--- a/gtk/glib-compat.h
+++ b/gtk/glib-compat.h
@@ -1,5 +1,8 @@
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
+ Copyright (C) 2012-2014 Red Hat, Inc.
+ Copyright © 1998-2009 VLC authors and VideoLAN
+
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
@@ -16,6 +19,8 @@
#ifndef GLIB_COMPAT_H
#define GLIB_COMPAT_H
+#include "config.h"
+
#include <glib-object.h>
#include <gio/gio.h>
@@ -133,4 +138,8 @@ GType spice_main_context_get_type (void) G_GNUC_CONST;
guint64 g_get_monotonic_time(void);
#endif
+#ifndef HAVE_STRTOK_R
+char* strtok_r(char *s, const char *delim, char **save_ptr);
+#endif
+
#endif /* GLIB_COMPAT_H */
diff --git a/spice-common b/spice-common
index 96ca358..1cb93fa 160000
--- a/spice-common
+++ b/spice-common
@@ -1 +1 @@
-Subproject commit 96ca358669cd32d17ce51f30de3cdbf0a1c0518c
+Subproject commit 1cb93fab09164e4e285dbf972c2ca34e89e768b7
commit 55b7979c37fc9c8af7634456894f830678f013fe
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Tue Feb 11 19:19:04 2014 +0100
misc: indent wocky proxy with 2-spaces
diff --git a/gtk/wocky-http-proxy.c b/gtk/wocky-http-proxy.c
index 639cfb0..d73990b 100644
--- a/gtk/wocky-http-proxy.c
+++ b/gtk/wocky-http-proxy.c
@@ -40,13 +40,13 @@ static void wocky_http_proxy_iface_init (GProxyInterface *proxy_iface);
#define wocky_http_proxy_get_type _wocky_http_proxy_get_type
G_DEFINE_TYPE_WITH_CODE (WockyHttpProxy, wocky_http_proxy, G_TYPE_OBJECT,
- G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
- wocky_http_proxy_iface_init)
- g_io_extension_point_set_required_type (
- g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME),
- G_TYPE_PROXY);
- g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
- g_define_type_id, "http", 0))
+ G_IMPLEMENT_INTERFACE (G_TYPE_PROXY,
+ wocky_http_proxy_iface_init)
+ g_io_extension_point_set_required_type (
+ g_io_extension_point_register (G_PROXY_EXTENSION_POINT_NAME),
+ G_TYPE_PROXY);
+ g_io_extension_point_implement (G_PROXY_EXTENSION_POINT_NAME,
+ g_define_type_id, "http", 0))
static void
wocky_http_proxy_init (WockyHttpProxy *proxy)
commit 0a2be0ac8abbcc2248a1783ffe5789c3f9143877
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Tue Feb 11 19:15:13 2014 +0100
misc: make warning more explicit
diff --git a/gtk/spice-session.c b/gtk/spice-session.c
index 9e6c154..e6f66c5 100644
--- a/gtk/spice-session.c
+++ b/gtk/spice-session.c
@@ -1838,7 +1838,7 @@ GSocketConnection* spice_session_channel_open_host(SpiceSession *session, SpiceC
#endif
if (open_host.error != NULL) {
- g_warning("%s", open_host.error->message);
+ g_warning("open host: %s", open_host.error->message);
g_clear_error(&open_host.error);
} else if (open_host.connection != NULL) {
GSocket *socket;
commit bc913ce8f8fd7196a1be01eea4795bac45bdf788
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Wed Jun 5 03:18:08 2013 +0200
Add SpiceVMC GIOStream
This allows to use conveniently GIOStream APIs without caring about
coroutine and Spice messages details.
diff --git a/gtk/Makefile.am b/gtk/Makefile.am
index 62afd36..7ceb22f 100644
--- a/gtk/Makefile.am
+++ b/gtk/Makefile.am
@@ -255,6 +255,8 @@ libspice_client_glib_2_0_la_SOURCES = \
usbutil.c \
usbutil.h \
$(USB_ACL_HELPER_SRCS) \
+ vmcstream.c \
+ vmcstream.h \
\
decode.h \
decode-glz.c \
diff --git a/gtk/vmcstream.c b/gtk/vmcstream.c
new file mode 100644
index 0000000..61990e7
--- /dev/null
+++ b/gtk/vmcstream.c
@@ -0,0 +1,532 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2013 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, see <http://www.gnu.org/licenses/>.
+*/
+#include <string.h>
+
+#include "vmcstream.h"
+#include "spice-channel-priv.h"
+#include "gio-coroutine.h"
+
+struct _SpiceVmcInputStream
+{
+ GInputStream parent_instance;
+ GSimpleAsyncResult *result;
+ struct coroutine *coroutine;
+
+ SpiceChannel *channel;
+ gboolean all;
+ guint8 *buffer;
+ gsize count;
+ gsize pos;
+
+ GCancellable *cancellable;
+ gulong cancel_id;
+};
+
+struct _SpiceVmcInputStreamClass
+{
+ GInputStreamClass parent_class;
+};
+
+static gssize spice_vmc_input_stream_read (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error);
+static void spice_vmc_input_stream_read_async (GInputStream *stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static gssize spice_vmc_input_stream_read_finish (GInputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+static gssize spice_vmc_input_stream_skip (GInputStream *stream,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error);
+static gboolean spice_vmc_input_stream_close (GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+
+G_DEFINE_TYPE(SpiceVmcInputStream, spice_vmc_input_stream, G_TYPE_INPUT_STREAM)
+
+
+static void
+spice_vmc_input_stream_class_init(SpiceVmcInputStreamClass *klass)
+{
+ GInputStreamClass *istream_class;
+
+ istream_class = G_INPUT_STREAM_CLASS(klass);
+ istream_class->read_fn = spice_vmc_input_stream_read;
+ istream_class->read_async = spice_vmc_input_stream_read_async;
+ istream_class->read_finish = spice_vmc_input_stream_read_finish;
+ istream_class->skip = spice_vmc_input_stream_skip;
+ istream_class->close_fn = spice_vmc_input_stream_close;
+}
+
+static void
+spice_vmc_input_stream_init(SpiceVmcInputStream *self)
+{
+}
+
+static SpiceVmcInputStream *
+spice_vmc_input_stream_new(void)
+{
+ SpiceVmcInputStream *self;
+
+ self = g_object_new(SPICE_TYPE_VMC_INPUT_STREAM, NULL);
+
+ return self;
+}
+
+/* coroutine */
+/**
+ * Feed a SpiceVmc stream with new data from a coroutine
+ *
+ * The other end will be waiting on read_async() until data is fed
+ * here.
+ */
+G_GNUC_INTERNAL void
+spice_vmc_input_stream_co_data(SpiceVmcInputStream *self,
+ const gpointer d, gsize size)
+{
+ guint8 *data = d;
+
+ g_return_if_fail(SPICE_IS_VMC_INPUT_STREAM(self));
+ g_return_if_fail(self->coroutine == NULL);
+
+ self->coroutine = coroutine_self();
+
+ while (size > 0) {
+ SPICE_DEBUG("spicevmc co_data %p", self->result);
+ if (!self->result)
+ coroutine_yield(NULL);
+
+ g_return_if_fail(self->result != NULL);
+
+ gsize min = MIN(self->count, size);
+ memcpy(self->buffer, data, min);
+
+ size -= min;
+ data += min;
+
+ SPICE_DEBUG("spicevmc co_data complete: %" G_GSIZE_FORMAT
+ "/%" G_GSIZE_FORMAT, min, self->count);
+
+ self->pos += min;
+ self->buffer += min;
+
+ if (self->all && min > 0 && self->pos != self->count)
+ continue;
+
+ g_simple_async_result_set_op_res_gssize(self->result, self->pos);
+
+ g_simple_async_result_complete_in_idle(self->result);
+ g_clear_object(&self->result);
+ if (self->cancellable) {
+ g_cancellable_disconnect(self->cancellable, self->cancel_id);
+ g_clear_object(&self->cancellable);
+ }
+ }
+
+ self->coroutine = NULL;
+}
+
+static void
+read_cancelled(GCancellable *cancellable,
+ gpointer user_data)
+{
+ SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(user_data);
+
+ SPICE_DEBUG("read cancelled, %p", self->result);
+ g_simple_async_result_set_error(self->result,
+ G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "read cancelled");
+ g_simple_async_result_complete_in_idle(self->result);
+
+ g_clear_object(&self->result);
+
+ /* See FIXME */
+ /* if (self->cancellable) { */
+ /* g_cancellable_disconnect(self->cancellable, self->cancel_id); */
+ /* g_clear_object(&self->cancellable); */
+ /* } */
+}
+
+G_GNUC_INTERNAL void
+spice_vmc_input_stream_read_all_async(GInputStream *stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream);
+ GSimpleAsyncResult *result;
+
+ /* no concurrent read permitted by ginputstream */
+ g_return_if_fail(self->result == NULL);
+ g_return_if_fail(self->cancellable == NULL);
+ self->all = TRUE;
+ self->buffer = buffer;
+ self->count = count;
+ self->pos = 0;
+ result = g_simple_async_result_new(G_OBJECT(self),
+ callback,
+ user_data,
+ spice_vmc_input_stream_read_async);
+ self->result = result;
+ self->cancellable = g_object_ref(cancellable);
+ if (cancellable)
+ self->cancel_id =
+ g_cancellable_connect(cancellable, G_CALLBACK(read_cancelled), self, NULL);
+
+ if (self->coroutine)
+ coroutine_yieldto(self->coroutine, NULL);
+}
+
+G_GNUC_INTERNAL gssize
+spice_vmc_input_stream_read_all_finish(GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream);
+
+ g_return_val_if_fail(g_simple_async_result_is_valid(result,
+ G_OBJECT(self),
+ spice_vmc_input_stream_read_async),
+ -1);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ /* FIXME: calling _finish() is required. Disconnecting in
+ read_cancelled() causes a deadlock. #705395 */
+ if (self->cancellable) {
+ g_cancellable_disconnect(self->cancellable, self->cancel_id);
+ g_clear_object(&self->cancellable);
+ }
+
+ if (g_simple_async_result_propagate_error(simple, error))
+ return -1;
+
+ return g_simple_async_result_get_op_res_gssize(simple);
+}
+
+static void
+spice_vmc_input_stream_read_async(GInputStream *stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream);
+ GSimpleAsyncResult *result;
+
+ /* no concurrent read permitted by ginputstream */
+ g_return_if_fail(self->result == NULL);
+ g_return_if_fail(self->cancellable == NULL);
+ self->all = FALSE;
+ self->buffer = buffer;
+ self->count = count;
+ self->pos = 0;
+ result = g_simple_async_result_new(G_OBJECT(self),
+ callback,
+ user_data,
+ spice_vmc_input_stream_read_async);
+ self->result = result;
+ self->cancellable = g_object_ref(cancellable);
+ if (cancellable)
+ self->cancel_id =
+ g_cancellable_connect(cancellable, G_CALLBACK(read_cancelled), self, NULL);
+
+ if (self->coroutine)
+ coroutine_yieldto(self->coroutine, NULL);
+}
+
+static gssize
+spice_vmc_input_stream_read_finish(GInputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ SpiceVmcInputStream *self = SPICE_VMC_INPUT_STREAM(stream);
+
+ g_return_val_if_fail(g_simple_async_result_is_valid(result,
+ G_OBJECT(self),
+ spice_vmc_input_stream_read_async),
+ -1);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ /* FIXME: calling _finish() is required. Disconnecting in
+ read_cancelled() causes a deadlock. #705395 */
+ if (self->cancellable) {
+ g_cancellable_disconnect(self->cancellable, self->cancel_id);
+ g_clear_object(&self->cancellable);
+ }
+
+ if (g_simple_async_result_propagate_error(simple, error))
+ return -1;
+
+ return g_simple_async_result_get_op_res_gssize(simple);
+}
+
+static gssize
+spice_vmc_input_stream_read(GInputStream *stream,
+ void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_reached(-1);
+}
+
+static gssize
+spice_vmc_input_stream_skip(GInputStream *stream,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_reached(-1);
+}
+
+static gboolean
+spice_vmc_input_stream_close(GInputStream *stream,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SPICE_DEBUG("fake close");
+ return TRUE;
+}
+
+/* OUTPUT */
+
+struct _SpiceVmcOutputStream
+{
+ GOutputStream parent_instance;
+
+ SpiceChannel *channel; /* weak */
+};
+
+struct _SpiceVmcOutputStreamClass
+{
+ GOutputStreamClass parent_class;
+};
+
+static gssize spice_vmc_output_stream_write_fn (GOutputStream *stream,
+ const void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error);
+static gssize spice_vmc_output_stream_write_finish (GOutputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+static void spice_vmc_output_stream_write_async (GOutputStream *stream,
+ const void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+G_DEFINE_TYPE(SpiceVmcOutputStream, spice_vmc_output_stream, G_TYPE_OUTPUT_STREAM)
+
+
+static void
+spice_vmc_output_stream_class_init(SpiceVmcOutputStreamClass *klass)
+{
+ GOutputStreamClass *ostream_class;
+
+ ostream_class = G_OUTPUT_STREAM_CLASS(klass);
+ ostream_class->write_fn = spice_vmc_output_stream_write_fn;
+ ostream_class->write_async = spice_vmc_output_stream_write_async;
+ ostream_class->write_finish = spice_vmc_output_stream_write_finish;
+}
+
+static void
+spice_vmc_output_stream_init(SpiceVmcOutputStream *self)
+{
+}
+
+static SpiceVmcOutputStream *
+spice_vmc_output_stream_new(SpiceChannel *channel)
+{
+ SpiceVmcOutputStream *self;
+
+ self = g_object_new(SPICE_TYPE_VMC_OUTPUT_STREAM, NULL);
+ self->channel = channel;
+
+ return self;
+}
+
+static gssize
+spice_vmc_output_stream_write_fn(GOutputStream *stream,
+ const void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error)
+{
+ SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream);
+ SpiceMsgOut *msg_out;
+
+ msg_out = spice_msg_out_new(SPICE_CHANNEL(self->channel),
+ SPICE_MSGC_SPICEVMC_DATA);
+ spice_marshaller_add(msg_out->marshaller, buffer, count);
+ spice_msg_out_send(msg_out);
+
+ return count;
+}
+
+static gssize
+spice_vmc_output_stream_write_finish(GOutputStream *stream,
+ GAsyncResult *simple,
+ GError **error)
+{
+ SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream);
+ GSimpleAsyncResult *res =
+ g_simple_async_result_get_op_res_gpointer(G_SIMPLE_ASYNC_RESULT(simple));
+
+ SPICE_DEBUG("spicevmc write finish");
+ return spice_vmc_write_finish(self->channel, G_ASYNC_RESULT(res), error);
+}
+
+static void
+write_cb(GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+
+ g_simple_async_result_set_op_res_gpointer(simple, res, NULL);
+
+ g_simple_async_result_complete(simple);
+ g_object_unref(simple);
+}
+
+static void
+spice_vmc_output_stream_write_async(GOutputStream *stream,
+ const void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SpiceVmcOutputStream *self = SPICE_VMC_OUTPUT_STREAM(stream);
+ GSimpleAsyncResult *simple;
+
+ SPICE_DEBUG("spicevmc write async");
+ /* an AsyncResult to forward async op to channel */
+ simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
+ spice_vmc_output_stream_write_async);
+
+ spice_vmc_write_async(self->channel, buffer, count,
+ cancellable, write_cb,
+ simple);
+}
+
+/* STREAM */
+
+struct _SpiceVmcStream
+{
+ GIOStream parent_instance;
+
+ SpiceChannel *channel; /* weak */
+ SpiceVmcInputStream *in;
+ SpiceVmcOutputStream *out;
+};
+
+struct _SpiceVmcStreamClass
+{
+ GIOStreamClass parent_class;
+};
+
+static void spice_vmc_stream_finalize (GObject *object);
+static GInputStream * spice_vmc_stream_get_input_stream (GIOStream *stream);
+static GOutputStream * spice_vmc_stream_get_output_stream (GIOStream *stream);
+
+G_DEFINE_TYPE(SpiceVmcStream, spice_vmc_stream, G_TYPE_IO_STREAM)
+
+static void
+spice_vmc_stream_class_init(SpiceVmcStreamClass *klass)
+{
+ GObjectClass *object_class;
+ GIOStreamClass *iostream_class;
+
+ object_class = G_OBJECT_CLASS(klass);
+ object_class->finalize = spice_vmc_stream_finalize;
+
+ iostream_class = G_IO_STREAM_CLASS(klass);
+ iostream_class->get_input_stream = spice_vmc_stream_get_input_stream;
+ iostream_class->get_output_stream = spice_vmc_stream_get_output_stream;
+}
+
+static void
+spice_vmc_stream_finalize(GObject *object)
+{
+ SpiceVmcStream *self = SPICE_VMC_STREAM(object);
+
+ g_clear_object(&self->in);
+ g_clear_object(&self->out);
+
+ G_OBJECT_CLASS(spice_vmc_stream_parent_class)->finalize(object);
+}
+
+static void
+spice_vmc_stream_init(SpiceVmcStream *self)
+{
+}
+
+G_GNUC_INTERNAL SpiceVmcStream *
+spice_vmc_stream_new(SpiceChannel *channel)
+{
+ SpiceVmcStream *self;
+
+ self = g_object_new(SPICE_TYPE_VMC_STREAM, NULL);
+ self->channel = channel;
+
+ return self;
+}
+
+static GInputStream *
+spice_vmc_stream_get_input_stream(GIOStream *stream)
+{
+ SpiceVmcStream *self = SPICE_VMC_STREAM(stream);
+
+ if (!self->in)
+ self->in = spice_vmc_input_stream_new();
+
+ return G_INPUT_STREAM(self->in);
+}
+
+static GOutputStream *
+spice_vmc_stream_get_output_stream(GIOStream *stream)
+{
+ SpiceVmcStream *self = SPICE_VMC_STREAM(stream);
+
+ if (!self->out)
+ self->out = spice_vmc_output_stream_new(self->channel);
+
+ return G_OUTPUT_STREAM(self->out);
+}
diff --git a/gtk/vmcstream.h b/gtk/vmcstream.h
new file mode 100644
index 0000000..1316b77
--- /dev/null
+++ b/gtk/vmcstream.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
+/*
+ Copyright (C) 2013 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, see <http://www.gnu.org/licenses/>.
+*/
+#ifndef __SPICE_VMC_STREAM_H__
+#define __SPICE_VMC_STREAM_H__
+
+#include <gio/gio.h>
+
+#include "spice-types.h"
+
+G_BEGIN_DECLS
+
+#define SPICE_TYPE_VMC_INPUT_STREAM (spice_vmc_input_stream_get_type ())
+#define SPICE_VMC_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStream))
+#define SPICE_VMC_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStreamClass))
+#define SPICE_IS_VMC_INPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_INPUT_STREAM))
+#define SPICE_IS_VMC_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_INPUT_STREAM))
+#define SPICE_VMC_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_INPUT_STREAM, SpiceVmcInputStreamClass))
+
+typedef struct _SpiceVmcInputStreamClass SpiceVmcInputStreamClass;
+typedef struct _SpiceVmcInputStream SpiceVmcInputStream;
+
+GType spice_vmc_input_stream_get_type (void) G_GNUC_CONST;
+void spice_vmc_input_stream_co_data (SpiceVmcInputStream *input,
+ const gpointer data,
+ gsize size);
+
+void spice_vmc_input_stream_read_all_async(GInputStream *stream,
+ void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gssize spice_vmc_input_stream_read_all_finish(GInputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+
+
+#define SPICE_TYPE_VMC_OUTPUT_STREAM (spice_vmc_output_stream_get_type ())
+#define SPICE_VMC_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStream))
+#define SPICE_VMC_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStreamClass))
+#define SPICE_IS_VMC_OUTPUT_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_OUTPUT_STREAM))
+#define SPICE_IS_VMC_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_OUTPUT_STREAM))
+#define SPICE_VMC_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_OUTPUT_STREAM, SpiceVmcOutputStreamClass))
+
+typedef struct _SpiceVmcOutputStreamClass SpiceVmcOutputStreamClass;
+typedef struct _SpiceVmcOutputStream SpiceVmcOutputStream;
+
+GType spice_vmc_output_stream_get_type (void) G_GNUC_CONST;
+
+#define SPICE_TYPE_VMC_STREAM (spice_vmc_stream_get_type ())
+#define SPICE_VMC_STREAM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), SPICE_TYPE_VMC_STREAM, SpiceVmcStream))
+#define SPICE_VMC_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), SPICE_TYPE_VMC_STREAM, SpiceVmcStreamClass))
+#define SPICE_IS_VMC_STREAM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), SPICE_TYPE_VMC_STREAM))
+#define SPICE_IS_VMC_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), SPICE_TYPE_VMC_STREAM))
+#define SPICE_VMC_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), SPICE_TYPE_VMC_STREAM, SpiceVmcStreamClass))
+
+typedef struct _SpiceVmcStreamClass SpiceVmcStreamClass;
+typedef struct _SpiceVmcStream SpiceVmcStream;
+
+GType spice_vmc_stream_get_type (void) G_GNUC_CONST;
+SpiceVmcStream* spice_vmc_stream_new (SpiceChannel *channel);
+
+G_END_DECLS
+
+#endif /* __SPICE_VMC_STREAM_H__ */
commit d4ff79d140311b5de4d788ba249209c77013d8e5
Author: Marc-André Lureau <marcandre.lureau at redhat.com>
Date: Thu Feb 6 17:52:20 2014 +0100
channel: add spice_vmc_write_async()
Refactor port code to create a private GIO async function that can send
SPICE_MSGC_SPICEVMC_DATA message over any channel.
diff --git a/gtk/channel-base.c b/gtk/channel-base.c
index 646042d..363dda5 100644
--- a/gtk/channel-base.c
+++ b/gtk/channel-base.c
@@ -232,3 +232,51 @@ void spice_channel_set_handlers(SpiceChannelClass *klass,
spice_channel_add_base_handlers(klass);
set_handlers(klass, handlers, n);
}
+
+static void
+vmc_write_free_cb(uint8_t *data, void *user_data)
+{
+ GSimpleAsyncResult *result = user_data;
+
+ g_simple_async_result_complete_in_idle(result);
+ g_object_unref(result);
+}
+
+G_GNUC_INTERNAL
+void spice_vmc_write_async(SpiceChannel *self,
+ const void *buffer, gsize count,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ SpiceMsgOut *msg;
+ GSimpleAsyncResult *simple;
+
+ simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
+ spice_port_write_async);
+ g_simple_async_result_set_op_res_gssize(simple, count);
+
+ msg = spice_msg_out_new(SPICE_CHANNEL(self), SPICE_MSGC_SPICEVMC_DATA);
+ spice_marshaller_add_ref_full(msg->marshaller, (uint8_t*)buffer, count,
+ vmc_write_free_cb, simple);
+ spice_msg_out_send(msg);
+}
+
+G_GNUC_INTERNAL
+gssize spice_vmc_write_finish(SpiceChannel *self,
+ GAsyncResult *result, GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail(result != NULL, -1);
+
+ simple = (GSimpleAsyncResult *)result;
+
+ if (g_simple_async_result_propagate_error(simple, error))
+ return -1;
+
+ g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(self),
+ spice_port_write_async), -1);
+
+ return g_simple_async_result_get_op_res_gssize(simple);
+}
diff --git a/gtk/channel-port.c b/gtk/channel-port.c
index 0a8b37f..5512713 100644
--- a/gtk/channel-port.c
+++ b/gtk/channel-port.c
@@ -289,14 +289,6 @@ static void port_handle_msg(SpiceChannel *channel, SpiceMsgIn *in)
emit_main_context(channel, SPICE_PORT_DATA, buf, size);
}
-static void port_write_free_cb(uint8_t *data, void *user_data)
-{
- GSimpleAsyncResult *result = user_data;
-
- g_simple_async_result_complete(result);
- g_object_unref(result);
-}
-
/**
* spice_port_write_async:
* @port: A #SpicePortChannel
@@ -320,9 +312,7 @@ void spice_port_write_async(SpicePortChannel *self,
GAsyncReadyCallback callback,
gpointer user_data)
{
- GSimpleAsyncResult *simple;
SpicePortChannelPrivate *c;
- SpiceMsgOut *msg;
g_return_if_fail(SPICE_IS_PORT_CHANNEL(self));
g_return_if_fail(buffer != NULL);
@@ -335,14 +325,8 @@ void spice_port_write_async(SpicePortChannel *self,
return;
}
- simple = g_simple_async_result_new(G_OBJECT(self), callback, user_data,
- spice_port_write_async);
- g_simple_async_result_set_op_res_gssize(simple, count);
-
- msg = spice_msg_out_new(SPICE_CHANNEL(self), SPICE_MSGC_SPICEVMC_DATA);
- spice_marshaller_add_ref_full(msg->marshaller, (uint8_t*)buffer, count,
- port_write_free_cb, simple);
- spice_msg_out_send(msg);
+ spice_vmc_write_async(SPICE_CHANNEL(self), buffer, count,
+ cancellable, callback, user_data);
}
/**
@@ -360,20 +344,9 @@ void spice_port_write_async(SpicePortChannel *self,
gssize spice_port_write_finish(SpicePortChannel *self,
GAsyncResult *result, GError **error)
{
- GSimpleAsyncResult *simple;
-
g_return_val_if_fail(SPICE_IS_PORT_CHANNEL(self), -1);
- g_return_val_if_fail(result != NULL, -1);
-
- simple = (GSimpleAsyncResult *)result;
-
- if (g_simple_async_result_propagate_error(simple, error))
- return -1;
-
- g_return_val_if_fail(g_simple_async_result_is_valid(result, G_OBJECT(self),
- spice_port_write_async), -1);
- return g_simple_async_result_get_op_res_gssize(simple);
+ return spice_vmc_write_finish(SPICE_CHANNEL(self), result, error);
}
/**
diff --git a/gtk/spice-channel-priv.h b/gtk/spice-channel-priv.h
index 0816061..35704ea 100644
--- a/gtk/spice-channel-priv.h
+++ b/gtk/spice-channel-priv.h
@@ -196,6 +196,14 @@ void spice_caps_set(GArray *caps, guint32 cap, const gchar *desc);
gchar *spice_channel_supported_string(void);
+void spice_vmc_write_async(SpiceChannel *self,
+ const void *buffer, gsize count,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gssize spice_vmc_write_finish(SpiceChannel *self,
+ GAsyncResult *result, GError **error);
+
G_END_DECLS
#endif /* __SPICE_CLIENT_CHANNEL_PRIV_H__ */
More information about the Spice-commits
mailing list