The previous patches (introducing GSocketClient & GProxy usage) turned the code into only sync calls. By using async() variants of resolve & connect functions, make the open host connection asynchronous again. --- gtk/spice-session.c | 195 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 123 insertions(+), 72 deletions(-) diff --git a/gtk/spice-session.c b/gtk/spice-session.c index ae70b73..1688c58 100644 --- a/gtk/spice-session.c +++ b/gtk/spice-session.c @@ -28,6 +28,7 @@ #include "gio-coroutine.h" #include "glib-compat.h" #include "wocky-http-proxy.h" +#include "spice-proxy.h" struct channel { SpiceChannel *channel; @@ -1511,59 +1512,123 @@ gboolean spice_session_has_channel_type(SpiceSession *session, gint type) /* ------------------------------------------------------------------ */ /* private functions */ -static GSocketAddress* get_proxy_address(SpiceSession *session, guint port, GError **error) +static SpiceProxy* get_proxy(GError **error) { - SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(session); - GSocketAddress *address = NULL; - const gchar *proxy = g_getenv("SPICE_PROXY"); - GList *addresses = NULL, *it; + SpiceProxy *proxy; - if (proxy == NULL) + const gchar *proxy_env = g_getenv("SPICE_PROXY"); + if (proxy_env == NULL || strlen(proxy_env) == 0) return NULL; - /* FIXME: use GUri when it is ready... */ - if (g_ascii_strncasecmp("http://", proxy, 7) == 0) - proxy += 7; - - gchar **proxyv = g_strsplit(proxy, ":", 0); - guint16 pport = 3128; - const gchar *proxy_host = NULL, *proxy_port = NULL; - - proxy_host = proxyv[0]; - if (proxy_host != NULL) - proxy_port = proxyv[1]; - - if (proxy_port != NULL) { - char *endptr; - pport = 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; - } - } + proxy = spice_proxy_new(); + if (!spice_proxy_parse(proxy, proxy_env, error)) + g_clear_object(&proxy); + + return proxy; +} + +typedef struct spice_open_host spice_open_host; - addresses = g_resolver_lookup_by_name(g_resolver_get_default(), - proxy_host, NULL, error); - if (*error != NULL) +struct spice_open_host { + struct coroutine *from; + SpiceSession *session; + SpiceChannel *channel; + SpiceProxy *proxy; + int port; + GCancellable *cancellable; + GError *error; + GSocket *socket; +}; + +static void socket_client_connect_ready(GObject *source_object, GAsyncResult *result, + gpointer data) +{ + GSocketClient *client = G_SOCKET_CLIENT(source_object); + spice_open_host *open_host = data; + GSocketConnection *connection = NULL; + + SPICE_DEBUG("connect ready"); + connection = g_socket_client_connect_finish(client, result, &open_host->error); + if (connection == NULL) goto end; - /* FIXME: iterate over all addresses - * gproxy makes it quite unconvenient to deal with hostname, - * it would make sense to do it once earlier? - */ + open_host->socket = g_socket_connection_get_socket(connection); + g_object_ref(open_host->socket); + +end: + g_object_unref(connection); + g_object_unref(client); + + coroutine_yieldto(open_host->from, NULL); +} + +/* main context */ +static void open_host_connectable_connect(spice_open_host *open_host, GSocketConnectable *connectable) +{ + GSocketClient *client; + + SPICE_DEBUG("connecting %p...", open_host); + client = g_socket_client_new(); + g_socket_client_connect_async(client, connectable, open_host->cancellable, + socket_client_connect_ready, open_host); +} + +/* main context */ +static void proxy_lookup_ready(GObject *source_object, GAsyncResult *result, + gpointer data) +{ + spice_open_host *open_host = data; + SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(open_host->session); + GList *addresses = NULL, *it; + GSocketAddress *address; + + SPICE_DEBUG("proxy lookup ready"); + addresses = g_resolver_lookup_by_name_finish(G_RESOLVER(source_object), + result, &open_host->error); + if (addresses == NULL || open_host->error) { + coroutine_yieldto(open_host->from, NULL); + return; + } + for (it = addresses; it != NULL; it = it->next) { - address = g_proxy_address_new(G_INET_ADDRESS(it->data), pport, "http", - s->host, port, NULL, NULL); + 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); if (address != NULL) break; } -end: + open_host_connectable_connect(open_host, G_SOCKET_CONNECTABLE(address)); g_resolver_free_addresses(addresses); - g_strfreev(proxyv); +} + +/* main context */ +static gboolean open_host_idle_cb(gpointer data) +{ + spice_open_host *open_host = data; + SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(open_host->session); + + g_return_val_if_fail(open_host != NULL, FALSE); + g_return_val_if_fail(open_host->socket == NULL, FALSE); + + open_host->proxy = get_proxy(&open_host->error); + if (open_host->proxy) { + g_resolver_lookup_by_name_async(g_resolver_get_default(), + spice_proxy_get_hostname(open_host->proxy), + open_host->cancellable, + proxy_lookup_ready, open_host); + } else if (open_host->error != NULL) { + coroutine_yieldto(open_host->from, NULL); + return FALSE; + } else + open_host_connectable_connect(open_host, + g_network_address_new(s->host, open_host->port)); + + SPICE_DEBUG("open host %s:%d", s->host, open_host->port); + if (open_host->proxy != NULL) + SPICE_DEBUG("(with proxy %p)", open_host->proxy); - return address; + return FALSE; } /* coroutine context */ @@ -1572,47 +1637,33 @@ GSocket* spice_session_channel_open_host(SpiceSession *session, SpiceChannel *ch gboolean use_tls) { SpiceSessionPrivate *s = SPICE_SESSION_GET_PRIVATE(session); - GSocketClient *client = NULL; - GSocketConnection *connection = NULL; - GSocketAddress *address = NULL; - GSocketConnectable *connectable = NULL; - GSocket *socket = NULL; - GError *error = NULL; - int port; + spice_open_host open_host = { 0, }; if ((use_tls && !s->tls_port) || (!use_tls && !s->port)) return NULL; - port = atoi(use_tls ? s->tls_port : s->port); - - /* FIXME: make all of this async again */ - client = g_socket_client_new(); - address = get_proxy_address(session, port, &error); - if (error != NULL) { - g_critical("%s", error->message); - goto end; - } + open_host.from = coroutine_self(); + open_host.session = session; + open_host.channel = channel; + open_host.port = atoi(use_tls ? s->tls_port : s->port); + g_idle_add(open_host_idle_cb, &open_host); - if (address != NULL) - connectable = G_SOCKET_CONNECTABLE(address); - else - connectable = g_network_address_new(s->host, port); + /* switch to main loop and wait for connection */ + coroutine_yield(NULL); + if (open_host.error != NULL) { + g_return_val_if_fail(open_host.socket == NULL, NULL); - connection = g_socket_client_connect(client, connectable, NULL, &error); - if (connection == NULL) - goto end; - - socket = g_socket_connection_get_socket(connection); - g_socket_set_blocking(socket, FALSE); - g_socket_set_keepalive(socket, TRUE); - g_object_ref(socket); + g_warning("%s", open_host.error->message); + g_clear_error(&open_host.error); + } else { + g_return_val_if_fail(open_host.socket != NULL, NULL); -end: - g_clear_object(&connection); - g_clear_object(&connectable); - g_clear_object(&client); + g_socket_set_blocking(open_host.socket, FALSE); + g_socket_set_keepalive(open_host.socket, TRUE); + } - return socket; + g_clear_object(&open_host.proxy); + return open_host.socket; } -- 1.7.11.4 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel