diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 1cea4f31a..31d3bb2b8 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1885,6 +1885,11 @@ g_socket_client_get_type
gsocketconnection
GSocketConnection
GSocketConnection
+g_socket_connection_connect
+g_socket_connection_connect_async
+g_socket_connection_connect_finish
+
+g_socket_connection_is_connected
g_socket_connection_get_local_address
g_socket_connection_get_remote_address
g_socket_connection_get_socket
diff --git a/gio/gio.symbols b/gio/gio.symbols
index 3ea45b7aa..a23f8ad78 100644
--- a/gio/gio.symbols
+++ b/gio/gio.symbols
@@ -1022,6 +1022,10 @@ g_socket_connection_factory_register_type
g_socket_connection_get_local_address
g_socket_connection_get_remote_address
g_socket_connection_get_socket
+g_socket_connection_is_connected
+g_socket_connection_connect
+g_socket_connection_connect_async
+g_socket_connection_connect_finish
g_socket_listener_get_type
g_socket_listener_accept
g_socket_listener_accept_async
diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c
index da534e72c..88f2b36d2 100644
--- a/gio/gsocketclient.c
+++ b/gio/gsocketclient.c
@@ -845,10 +845,14 @@ g_socket_client_connect (GSocketClient *client,
continue;
}
- if (g_socket_connect (socket, address, cancellable, &last_error))
- connection = (GIOStream *)g_socket_connection_factory_create_connection (socket);
- else
- clarify_connect_error (last_error, connectable, address);
+ connection = (GIOStream *)g_socket_connection_factory_create_connection (socket);
+ if (!g_socket_connection_connect (G_SOCKET_CONNECTION (connection),
+ address, cancellable, &last_error))
+ {
+ clarify_connect_error (last_error, connectable, address);
+ g_object_unref (connection);
+ connection = NULL;
+ }
if (connection &&
G_IS_PROXY_ADDRESS (address) &&
@@ -1264,11 +1268,30 @@ g_socket_client_proxy_connect_callback (GObject *object,
}
static void
-g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data)
+g_socket_client_connected_callback (GObject *source,
+ GAsyncResult *result,
+ gpointer user_data)
{
+ GSocketClientAsyncConnectData *data = user_data;
+ GError *error = NULL;
GProxy *proxy;
const gchar *protocol;
+ if (!g_socket_connection_connect_finish (G_SOCKET_CONNECTION (source),
+ result, &error))
+ {
+ clarify_connect_error (error, data->connectable,
+ data->current_addr);
+ set_last_error (data, error);
+
+ /* try next one */
+ enumerator_next_async (data);
+ return;
+ }
+
+ /* wrong, but backward compatible */
+ g_socket_set_blocking (data->current_socket, TRUE);
+
if (!data->proxy_addr)
{
g_socket_client_tls_handshake (data);
@@ -1278,7 +1301,7 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data)
protocol = g_proxy_address_get_protocol (data->proxy_addr);
proxy = g_proxy_get_default_for_protocol (protocol);
- /* The connection should not be anything else then TCP Connection,
+ /* The connection should not be anything other than TCP,
* but let's put a safety guard in case
*/
if (!G_IS_TCP_CONNECTION (data->connection))
@@ -1321,54 +1344,6 @@ g_socket_client_proxy_connect (GSocketClientAsyncConnectData *data)
}
}
-static void
-g_socket_client_socket_connected (GSocketClientAsyncConnectData *data)
-{
- g_socket_set_blocking (data->current_socket, TRUE);
-
- data->connection = (GIOStream *)
- g_socket_connection_factory_create_connection (data->current_socket);
-
- g_socket_client_proxy_connect (data);
-}
-
-static gboolean
-g_socket_client_socket_callback (GSocket *socket,
- GIOCondition condition,
- GSocketClientAsyncConnectData *data)
-{
- GError *error = NULL;
-
- if (g_cancellable_is_cancelled (data->cancellable))
- {
- /* Cancelled, return done with last error being cancelled */
- g_clear_error (&data->last_error);
- g_cancellable_set_error_if_cancelled (data->cancellable,
- &data->last_error);
-
- g_socket_client_async_connect_complete (data);
- return FALSE;
- }
- else
- {
- /* socket is ready for writing means connect done, did it succeed? */
- if (!g_socket_check_connect_result (data->current_socket, &error))
- {
- clarify_connect_error (error, data->connectable,
- data->current_addr);
- set_last_error (data, error);
-
- /* try next one */
- enumerator_next_async (data);
-
- return FALSE;
- }
- }
-
- g_socket_client_socket_connected (data);
- return FALSE;
-}
-
static void
g_socket_client_enumerator_callback (GObject *object,
GAsyncResult *result,
@@ -1409,44 +1384,20 @@ g_socket_client_enumerator_callback (GObject *object,
g_clear_error (&data->last_error);
socket = create_socket (data->client, address, &data->last_error);
- if (socket != NULL)
+ if (socket == NULL)
{
- g_socket_set_blocking (socket, FALSE);
- if (g_socket_connect (socket, address, data->cancellable, &tmp_error))
- {
- data->current_socket = socket;
- g_socket_client_socket_connected (data);
-
- g_object_unref (address);
- return;
- }
- else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
- {
- GSource *source;
-
- data->current_socket = socket;
- data->current_addr = address;
- g_error_free (tmp_error);
-
- source = g_socket_create_source (socket, G_IO_OUT,
- data->cancellable);
- g_source_set_callback (source,
- (GSourceFunc) g_socket_client_socket_callback,
- data, NULL);
- g_source_attach (source, g_main_context_get_thread_default ());
- g_source_unref (source);
- return;
- }
- else
- {
- clarify_connect_error (tmp_error, data->connectable, address);
- data->last_error = tmp_error;
- g_object_unref (socket);
- }
+ g_object_unref (address);
+ enumerator_next_async (data);
+ return;
}
- g_object_unref (address);
- enumerator_next_async (data);
+ data->current_socket = socket;
+ data->current_addr = address;
+ data->connection = (GIOStream *) g_socket_connection_factory_create_connection (socket);
+
+ g_socket_connection_connect_async (G_SOCKET_CONNECTION (data->connection),
+ address, data->cancellable,
+ g_socket_client_connected_callback, data);
}
/**
diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c
index 6f2f102a0..ee391ab18 100644
--- a/gio/gsocketconnection.c
+++ b/gio/gsocketconnection.c
@@ -113,6 +113,165 @@ g_socket_connection_get_output_stream (GIOStream *io_stream)
return connection->priv->output_stream;
}
+/**
+ * g_socket_connection_is_connected:
+ * @connection: a #GSocketConnection
+ *
+ * Checks if @connection is connected. This is equivalent to calling
+ * g_socket_is_connected() on @connection's underlying #GSocket.
+ *
+ * Returns: whether @connection is connected
+ *
+ * Since: 2.32
+ */
+gboolean
+g_socket_connection_is_connected (GSocketConnection *connection)
+{
+ return g_socket_is_connected (connection->priv->socket);
+}
+
+/**
+ * g_socket_connection_connect:
+ * @connection: a #GSocketConnection
+ * @address: a #GSocketAddress specifying the remote address.
+ * @cancellable: (allow-none): a %GCancellable or %NULL
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Connect @connection to the specified remote address.
+ *
+ * Returns: %TRUE if the connection succeeded, %FALSE on error
+ *
+ * Since: 2.32
+ */
+gboolean
+g_socket_connection_connect (GSocketConnection *connection,
+ GSocketAddress *address,
+ GCancellable *cancellable,
+ GError **error)
+{
+ g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), FALSE);
+
+ return g_socket_connect (connection->priv->socket, address,
+ cancellable, error);
+}
+
+static gboolean g_socket_connection_connect_callback (GSocket *socket,
+ GIOCondition condition,
+ gpointer user_data);
+
+/**
+ * g_socket_connection_connect_async:
+ * @connection: a #GSocketConnection
+ * @address: a #GSocketAddress specifying the remote address.
+ * @cancellable: (allow-none): a %GCancellable or %NULL
+ * @callback: (scope async): a #GAsyncReadyCallback
+ * @user_data: (closure): user data for the callback
+ *
+ * Asynchronously connect @connection to the specified remote address.
+ *
+ * This clears the #GSocket:blocking flag on @connection's underlying
+ * socket if it is currently set.
+ *
+ * Use g_socket_connection_connect_finish() to retrieve the result.
+ *
+ * Since: 2.32
+ */
+void
+g_socket_connection_connect_async (GSocketConnection *connection,
+ GSocketAddress *address,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple;
+ GError *tmp_error = NULL;
+
+ g_return_if_fail (G_IS_SOCKET_CONNECTION (connection));
+ g_return_if_fail (G_IS_SOCKET_ADDRESS (address));
+
+ simple = g_simple_async_result_new (G_OBJECT (connection),
+ callback, user_data,
+ g_socket_connection_connect_async);
+
+ g_socket_set_blocking (connection->priv->socket, FALSE);
+
+ if (g_socket_connect (connection->priv->socket, address,
+ cancellable, &tmp_error))
+ {
+ g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+ g_simple_async_result_complete_in_idle (simple);
+ }
+ else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
+ {
+ GSource *source;
+
+ g_error_free (tmp_error);
+ source = g_socket_create_source (connection->priv->socket,
+ G_IO_OUT, cancellable);
+ g_source_set_callback (source,
+ (GSourceFunc) g_socket_connection_connect_callback,
+ simple, NULL);
+ g_source_attach (source, g_main_context_get_thread_default ());
+ g_source_unref (source);
+ }
+ else
+ {
+ g_simple_async_result_take_error (simple, tmp_error);
+ g_simple_async_result_complete_in_idle (simple);
+ }
+}
+
+static gboolean
+g_socket_connection_connect_callback (GSocket *socket,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ GSimpleAsyncResult *simple = user_data;
+ GSocketConnection *connection;
+ GError *error = NULL;
+
+ connection = G_SOCKET_CONNECTION (g_async_result_get_source_object (G_ASYNC_RESULT (simple)));
+ g_object_unref (connection);
+
+ if (g_socket_check_connect_result (connection->priv->socket, &error))
+ g_simple_async_result_set_op_res_gboolean (simple, TRUE);
+ else
+ g_simple_async_result_take_error (simple, error);
+
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+ return FALSE;
+}
+
+/**
+ * g_socket_connection_connect_finish:
+ * @connection: a #GSocketConnection
+ * @result: the #GAsyncResult
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Gets the result of a g_socket_connection_connect_async() call.
+ *
+ * Returns: %TRUE if the connection succeeded, %FALSE on error
+ *
+ * Since: 2.32
+ */
+gboolean
+g_socket_connection_connect_finish (GSocketConnection *connection,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (connection), g_socket_connection_connect_async), FALSE);
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+ return TRUE;
+}
+
/**
* g_socket_connection_get_socket:
* @connection: a #GSocketConnection
diff --git a/gio/gsocketconnection.h b/gio/gsocketconnection.h
index 1edc2f44c..34a0cb184 100644
--- a/gio/gsocketconnection.h
+++ b/gio/gsocketconnection.h
@@ -72,11 +72,26 @@ struct _GSocketConnection
GType g_socket_connection_get_type (void) G_GNUC_CONST;
+gboolean g_socket_connection_is_connected (GSocketConnection *connection);
+gboolean g_socket_connection_connect (GSocketConnection *connection,
+ GSocketAddress *address,
+ GCancellable *cancellable,
+ GError **error);
+void g_socket_connection_connect_async (GSocketConnection *connection,
+ GSocketAddress *address,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+gboolean g_socket_connection_connect_finish (GSocketConnection *connection,
+ GAsyncResult *result,
+ GError **error);
+
GSocket *g_socket_connection_get_socket (GSocketConnection *connection);
GSocketAddress *g_socket_connection_get_local_address (GSocketConnection *connection,
GError **error);
GSocketAddress *g_socket_connection_get_remote_address (GSocketConnection *connection,
GError **error);
+
void g_socket_connection_factory_register_type (GType g_type,
GSocketFamily family,
GSocketType type,