mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-09 19:06:15 +01:00
Add g_socket_connection_connect(), etc
Previously it was more or less assumed that GSocketConnections were always connected, although this was not enforced. Make it explicit that they don't need to be, and add methods to connect them, and simplify GSocketClient by using those methods. https://bugzilla.gnome.org/show_bug.cgi?id=665805
This commit is contained in:
parent
e121d46b25
commit
57f279988c
@ -1885,6 +1885,11 @@ g_socket_client_get_type
|
||||
<FILE>gsocketconnection</FILE>
|
||||
<TITLE>GSocketConnection</TITLE>
|
||||
GSocketConnection
|
||||
g_socket_connection_connect
|
||||
g_socket_connection_connect_async
|
||||
g_socket_connection_connect_finish
|
||||
<SUBSECTION>
|
||||
g_socket_connection_is_connected
|
||||
g_socket_connection_get_local_address
|
||||
g_socket_connection_get_remote_address
|
||||
g_socket_connection_get_socket
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user