[glib] Add GSocketClient::event, for tracking socket client status
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Add GSocketClient::event, for tracking socket client status
- Date: Thu, 22 Dec 2011 20:45:08 +0000 (UTC)
commit 3f3e141ec8ffe8f40a2faced69d35cb161153107
Author: Dan Winship <danw gnome org>
Date: Fri Aug 20 13:04:19 2010 -0400
Add GSocketClient::event, for tracking socket client status
This can be used for debugging, or for progress UIs ("Connecting to
example.com..."), or to do low-level tweaking on the connection at
various points in the process.
https://bugzilla.gnome.org/show_bug.cgi?id=665805
docs/reference/gio/gio-sections.txt | 3 +-
gio/gio.symbols | 1 +
gio/gioenums.h | 38 +++++++
gio/gsocketclient.c | 194 +++++++++++++++++++++++++++++++++--
gio/gsocketclient.h | 6 +-
gio/tests/send-data.c | 23 ++++
6 files changed, 253 insertions(+), 12 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 31d3bb2..62b233a 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1838,7 +1838,7 @@ GSocketPrivate
<FILE>gsocketclient</FILE>
<TITLE>GSocketClient</TITLE>
GSocketClient
-g_socket_client_add_application_proxy
+GSocketClientEvent
g_socket_client_new
g_socket_client_connect
g_socket_client_connect_async
@@ -1868,6 +1868,7 @@ g_socket_client_get_timeout
g_socket_client_get_enable_proxy
g_socket_client_get_tls
g_socket_client_get_tls_validation_flags
+g_socket_client_add_application_proxy
<SUBSECTION Standard>
GSocketClientClass
G_IS_SOCKET_CLIENT
diff --git a/gio/gio.symbols b/gio/gio.symbols
index a23f8ad..e91be95 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -998,6 +998,7 @@ g_socket_client_connect_to_service_finish
g_socket_client_connect_to_uri
g_socket_client_connect_to_uri_async
g_socket_client_connect_to_uri_finish
+g_socket_client_event_get_type
g_socket_client_get_enable_proxy
g_socket_client_get_family
g_socket_client_get_local_address
diff --git a/gio/gioenums.h b/gio/gioenums.h
index 47d72bd..122eb7e 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1517,6 +1517,44 @@ typedef enum {
G_IO_MODULE_SCOPE_BLOCK_DUPLICATES
} GIOModuleScopeFlags;
+/**
+ * GSocketClientEvent:
+ * @G_SOCKET_CLIENT_RESOLVING: The client is doing a DNS lookup.
+ * @G_SOCKET_CLIENT_RESOLVED: The client has completed a DNS lookup.
+ * @G_SOCKET_CLIENT_CONNECTING: The client is connecting to a remote
+ * host (either a proxy or the destination server).
+ * @G_SOCKET_CLIENT_CONNECTED: The client has connected to a remote
+ * host.
+ * @G_SOCKET_CLIENT_PROXY_NEGOTIATING: The client is negotiating
+ * with a proxy to connect to the destination server.
+ * @G_SOCKET_CLIENT_PROXY_NEGOTIATED: The client has negotiated
+ * with the proxy server.
+ * @G_SOCKET_CLIENT_TLS_HANDSHAKING: The client is performing a
+ * TLS handshake.
+ * @G_SOCKET_CLIENT_TLS_HANDSHAKED: The client has performed a
+ * TLS handshake.
+ * @G_SOCKET_CLIENT_COMPLETE: The client is done with a particular
+ * #GSocketConnectable.
+ *
+ * Describes an event occurring on a #GSocketClient. See the
+ * #GSocketClient::event signal for more details.
+ *
+ * Additional values may be added to this type in the future.
+ *
+ * Since: 2.32
+ */
+typedef enum {
+ G_SOCKET_CLIENT_RESOLVING,
+ G_SOCKET_CLIENT_RESOLVED,
+ G_SOCKET_CLIENT_CONNECTING,
+ G_SOCKET_CLIENT_CONNECTED,
+ G_SOCKET_CLIENT_PROXY_NEGOTIATING,
+ G_SOCKET_CLIENT_PROXY_NEGOTIATED,
+ G_SOCKET_CLIENT_TLS_HANDSHAKING,
+ G_SOCKET_CLIENT_TLS_HANDSHAKED,
+ G_SOCKET_CLIENT_COMPLETE
+} GSocketClientEvent;
+
G_END_DECLS
#endif /* __GIO_ENUMS_H__ */
diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c
index 88f2b36..1a86bf5 100644
--- a/gio/gsocketclient.c
+++ b/gio/gsocketclient.c
@@ -75,6 +75,14 @@ G_DEFINE_TYPE (GSocketClient, g_socket_client, G_TYPE_OBJECT);
enum
{
+ EVENT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL] = { 0 };
+
+enum
+{
PROP_NONE,
PROP_FAMILY,
PROP_TYPE,
@@ -615,6 +623,14 @@ g_socket_client_get_tls (GSocketClient *client)
* g_tcp_wrapper_connection_get_base_io_stream() on the return value
* to extract the #GTlsClientConnection.
*
+ * If you need to modify the behavior of the TLS handshake (eg, by
+ * setting a client-side certificate to use, or connecting to the
+ * #GTlsConnection::accept-certificate signal), you can connect to
+ * @client's #GSocketClient::event signal and wait for it to be
+ * emitted with %G_SOCKET_CLIENT_TLS_HANDSHAKING, which will give you
+ * a chance to see the #GTlsClientConnection before the handshake
+ * starts.
+ *
* Since: 2.28
*/
void
@@ -678,6 +694,116 @@ g_socket_client_class_init (GSocketClientClass *class)
gobject_class->set_property = g_socket_client_set_property;
gobject_class->get_property = g_socket_client_get_property;
+ /**
+ * GSocketClient::event:
+ * @client: the #GSocketClient
+ * @event: the event that is occurring
+ * @connectable: the #GSocketConnectable that @event is occurring on
+ * @connection: the current representation of the connection
+ *
+ * Emitted when @client's activity on @connectable changes state.
+ * Among other things, this can be used to provide progress
+ * information about a network connection in the UI. The meanings of
+ * the different @event values are as follows:
+ *
+ * <variablelist>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_RESOLVING:</term>
+ * <listitem><para>
+ * @client is about to look up @connectable in DNS.
+ * @connection will be %NULL.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_RESOLVED:</term>
+ * <listitem><para>
+ * @client has successfully resolved @connectable in DNS.
+ * @connection will be %NULL.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_CONNECTING:</term>
+ * <listitem><para>
+ * @client is about to make a connection to a remote host;
+ * either a proxy server or the destination server itself.
+ * @connection is the #GSocketConnection, which is not yet
+ * connected.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_CONNECTED:</term>
+ * <listitem><para>
+ * @client has successfully connected to a remote host.
+ * @connection is the connected #GSocketConnection.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_PROXY_NEGOTIATING:</term>
+ * <listitem><para>
+ * @client is about to negotiate with a proxy to get it to
+ * connect to @connectable. @connection is the
+ * #GSocketConnection to the proxy server.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_PROXY_NEGOTIATED:</term>
+ * <listitem><para>
+ * @client has negotiated a connection to @connectable through
+ * a proxy server. @connection is the stream returned from
+ * g_proxy_connect(), which may or may not be a
+ * #GSocketConnection.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_TLS_HANDSHAKING:</term>
+ * <listitem><para>
+ * @client is about to begin a TLS handshake. @connection is a
+ * #GTlsClientConnection.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_TLS_HANDSHAKED:</term>
+ * <listitem><para>
+ * @client has successfully completed the TLS handshake.
+ * @connection is a #GTlsClientConnection.
+ * </para></listitem>
+ * </varlistentry>
+ * <varlistentry>
+ * <term>%G_SOCKET_CLIENT_COMPLETE:</term>
+ * <listitem><para>
+ * @client has either successfully connected to @connectable
+ * (in which case @connection is the #GSocketConnection that
+ * it will be returning to the caller) or has failed (in which
+ * case @connection is %NULL and the client is about to return
+ * an error).
+ * </para></listitem>
+ * </varlistentry>
+ * </variablelist>
+ *
+ * Each event except %G_SOCKET_CLIENT_COMPLETE may be emitted
+ * multiple times (or not at all) for a given connectable (in
+ * particular, if @client ends up attempting to connect to more than
+ * one address). However, if @client emits the #GSocketClient:event
+ * signal at all for a given connectable, that it will always emit
+ * it with %G_SOCKET_CLIENT_COMPLETE when it is done.
+ *
+ * Note that there may be additional #GSocketClientEvent values in
+ * the future; unrecognized @event values should be ignored.
+ *
+ * Since: 2.32
+ */
+ signals[EVENT] =
+ g_signal_new (I_("event"),
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GSocketClientClass, event),
+ NULL, NULL,
+ NULL,
+ G_TYPE_NONE, 3,
+ G_TYPE_SOCKET_CLIENT_EVENT,
+ G_TYPE_SOCKET_CONNECTABLE,
+ G_TYPE_IO_STREAM);
+
g_object_class_install_property (gobject_class, PROP_FAMILY,
g_param_spec_enum ("family",
P_("Socket family"),
@@ -754,6 +880,16 @@ g_socket_client_class_init (GSocketClientClass *class)
G_PARAM_STATIC_STRINGS));
}
+static void
+g_socket_client_emit_event (GSocketClient *client,
+ GSocketClientEvent event,
+ GSocketConnectable *connectable,
+ GIOStream *connection)
+{
+ g_signal_emit (client, signals[EVENT], 0,
+ event, connectable, connection);
+}
+
/**
* g_socket_client_connect:
* @client: a #GSocketClient.
@@ -806,6 +942,7 @@ g_socket_client_connect (GSocketClient *client,
GSocketAddress *address = NULL;
gboolean application_proxy = FALSE;
GSocket *socket;
+ gboolean using_proxy;
if (g_cancellable_is_cancelled (cancellable))
{
@@ -815,6 +952,8 @@ g_socket_client_connect (GSocketClient *client,
}
tmp_error = NULL;
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_RESOLVING,
+ connectable, NULL);
address = g_socket_address_enumerator_next (enumerator, cancellable,
&tmp_error);
@@ -834,6 +973,11 @@ g_socket_client_connect (GSocketClient *client,
_("Unknown error on connect"));
break;
}
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_RESOLVED,
+ connectable, NULL);
+
+ using_proxy = (G_IS_PROXY_ADDRESS (address) &&
+ client->priv->enable_proxy);
/* clear error from previous attempt */
g_clear_error (&last_error);
@@ -846,17 +990,21 @@ g_socket_client_connect (GSocketClient *client,
}
connection = (GIOStream *)g_socket_connection_factory_create_connection (socket);
- if (!g_socket_connection_connect (G_SOCKET_CONNECTION (connection),
- address, cancellable, &last_error))
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_CONNECTING, connectable, connection);
+
+ if (g_socket_connection_connect (G_SOCKET_CONNECTION (connection),
+ address, cancellable, &last_error))
+ {
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_CONNECTED, connectable, connection);
+ }
+ else
{
clarify_connect_error (last_error, connectable, address);
g_object_unref (connection);
connection = NULL;
}
- if (connection &&
- G_IS_PROXY_ADDRESS (address) &&
- client->priv->enable_proxy)
+ if (connection && using_proxy)
{
GProxyAddress *proxy_addr = G_PROXY_ADDRESS (address);
const gchar *protocol;
@@ -882,8 +1030,9 @@ g_socket_client_connect (GSocketClient *client,
}
else if (proxy)
{
- GIOStream *proxy_connection;
+ GIOStream *proxy_connection;
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_PROXY_NEGOTIATING, connectable, connection);
proxy_connection = g_proxy_connect (proxy,
connection,
proxy_addr,
@@ -892,6 +1041,9 @@ g_socket_client_connect (GSocketClient *client,
g_object_unref (connection);
connection = proxy_connection;
g_object_unref (proxy);
+
+ if (connection)
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_PROXY_NEGOTIATED, connectable, connection);
}
else if (!g_hash_table_lookup_extended (client->priv->app_proxies,
protocol, NULL, NULL))
@@ -920,8 +1072,13 @@ g_socket_client_connect (GSocketClient *client,
{
g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (tlsconn),
client->priv->tls_validation_flags);
- if (!g_tls_connection_handshake (G_TLS_CONNECTION (tlsconn),
- cancellable, &last_error))
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_TLS_HANDSHAKING, connectable, connection);
+ if (g_tls_connection_handshake (G_TLS_CONNECTION (tlsconn),
+ cancellable, &last_error))
+ {
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_TLS_HANDSHAKED, connectable, connection);
+ }
+ else
{
g_object_unref (tlsconn);
connection = NULL;
@@ -943,6 +1100,7 @@ g_socket_client_connect (GSocketClient *client,
}
g_object_unref (enumerator);
+ g_socket_client_emit_event (client, G_SOCKET_CLIENT_COMPLETE, connectable, connection);
return G_SOCKET_CONNECTION (connection);
}
@@ -1127,6 +1285,8 @@ typedef struct
static void
g_socket_client_async_connect_complete (GSocketClientAsyncConnectData *data)
{
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_COMPLETE, data->connectable, data->connection);
+
if (data->last_error)
{
g_simple_async_result_take_error (data->result, data->last_error);
@@ -1188,6 +1348,7 @@ enumerator_next_async (GSocketClientAsyncConnectData *data)
g_clear_object (&data->proxy_addr);
g_clear_object (&data->connection);
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVING, data->connectable, NULL);
g_socket_address_enumerator_next_async (data->enumerator,
data->cancellable,
g_socket_client_enumerator_callback,
@@ -1208,6 +1369,7 @@ g_socket_client_tls_handshake_callback (GObject *object,
g_object_unref (data->connection);
data->connection = G_IO_STREAM (object);
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_TLS_HANDSHAKED, data->connectable, data->connection);
g_socket_client_async_connect_complete (data);
}
else
@@ -1235,6 +1397,7 @@ g_socket_client_tls_handshake (GSocketClientAsyncConnectData *data)
{
g_tls_client_connection_set_validation_flags (G_TLS_CLIENT_CONNECTION (tlsconn),
data->client->priv->tls_validation_flags);
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_TLS_HANDSHAKING, data->connectable, G_IO_STREAM (tlsconn));
g_tls_connection_handshake_async (G_TLS_CONNECTION (tlsconn),
G_PRIORITY_DEFAULT,
data->cancellable,
@@ -1258,7 +1421,11 @@ g_socket_client_proxy_connect_callback (GObject *object,
data->connection = g_proxy_connect_finish (G_PROXY (object),
result,
&data->last_error);
- if (!data->connection)
+ if (data->connection)
+ {
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_PROXY_NEGOTIATED, data->connectable, data->connection);
+ }
+ else
{
enumerator_next_async (data);
return;
@@ -1289,6 +1456,8 @@ g_socket_client_connected_callback (GObject *source,
return;
}
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTED, data->connectable, data->connection);
+
/* wrong, but backward compatible */
g_socket_set_blocking (data->current_socket, TRUE);
@@ -1298,7 +1467,7 @@ g_socket_client_connected_callback (GObject *source,
return;
}
- protocol = g_proxy_address_get_protocol (data->proxy_addr);
+ protocol = g_proxy_address_get_protocol (data->proxy_addr);
proxy = g_proxy_get_default_for_protocol (protocol);
/* The connection should not be anything other than TCP,
@@ -1317,6 +1486,7 @@ g_socket_client_connected_callback (GObject *source,
}
else if (proxy)
{
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_PROXY_NEGOTIATING, data->connectable, data->connection);
g_proxy_connect_async (proxy,
data->connection,
data->proxy_addr,
@@ -1377,6 +1547,9 @@ g_socket_client_enumerator_callback (GObject *object,
return;
}
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVED,
+ data->connectable, NULL);
+
if (G_IS_PROXY_ADDRESS (address) &&
data->client->priv->enable_proxy)
data->proxy_addr = g_object_ref (G_PROXY_ADDRESS (address));
@@ -1395,6 +1568,7 @@ g_socket_client_enumerator_callback (GObject *object,
data->current_addr = address;
data->connection = (GIOStream *) g_socket_connection_factory_create_connection (socket);
+ g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTING, data->connectable, data->connection);
g_socket_connection_connect_async (G_SOCKET_CONNECTION (data->connection),
address, data->cancellable,
g_socket_client_connected_callback, data);
diff --git a/gio/gsocketclient.h b/gio/gsocketclient.h
index 180bedd..216310b 100644
--- a/gio/gsocketclient.h
+++ b/gio/gsocketclient.h
@@ -52,12 +52,16 @@ struct _GSocketClientClass
{
GObjectClass parent_class;
+ void (* event) (GSocketClient *client,
+ GSocketClientEvent event,
+ GSocketConnectable *connectable,
+ GIOStream *connection);
+
/* Padding for future expansion */
void (*_g_reserved1) (void);
void (*_g_reserved2) (void);
void (*_g_reserved3) (void);
void (*_g_reserved4) (void);
- void (*_g_reserved5) (void);
};
struct _GSocketClient
diff --git a/gio/tests/send-data.c b/gio/tests/send-data.c
index 01a42b4..201e710 100644
--- a/gio/tests/send-data.c
+++ b/gio/tests/send-data.c
@@ -8,6 +8,7 @@ int cancel_timeout = 0;
int io_timeout = 0;
gboolean async = FALSE;
gboolean graceful = FALSE;
+gboolean verbose = FALSE;
static GOptionEntry cmd_entries[] = {
{"cancel", 'c', 0, G_OPTION_ARG_INT, &cancel_timeout,
"Cancel any op after the specified amount of seconds", NULL},
@@ -17,6 +18,8 @@ static GOptionEntry cmd_entries[] = {
"Use graceful disconnect", NULL},
{"timeout", 't', 0, G_OPTION_ARG_INT, &io_timeout,
"Time out socket I/O after the specified number of seconds", NULL},
+ {"verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose,
+ "Verbose debugging output", NULL},
{NULL}
};
@@ -56,6 +59,24 @@ async_cb (GObject *source_object,
g_main_loop_quit (loop);
}
+static void
+socket_client_event (GSocketClient *client,
+ GSocketClientEvent event,
+ GSocketConnectable *connectable,
+ GSocketConnection *connection)
+{
+ static GEnumClass *event_class;
+ GTimeVal tv;
+
+ if (!event_class)
+ event_class = g_type_class_ref (G_TYPE_SOCKET_CLIENT_EVENT);
+
+ g_get_current_time (&tv);
+ printf ("% 12ld.%06ld GSocketClient => %s [%s]\n",
+ tv.tv_sec, tv.tv_usec,
+ g_enum_get_value (event_class, event)->value_nick,
+ connection ? G_OBJECT_TYPE_NAME (connection) : "");
+}
int
main (int argc, char *argv[])
@@ -103,6 +124,8 @@ main (int argc, char *argv[])
client = g_socket_client_new ();
if (io_timeout)
g_socket_client_set_timeout (client, io_timeout);
+ if (verbose)
+ g_signal_connect (client, "event", G_CALLBACK (socket_client_event), NULL);
if (async)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]