X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsocketconnection.c;h=9f490c84564c3bff82f08a2c81652b221b8348bd;hb=7fd6f07d498063470903a886b4805a13bd333908;hp=07a48a7881118135cfd3169456283203587ab54d;hpb=06144900ec87effb99c94e2d8369ca270d024bf1;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c index 07a48a7..9f490c8 100644 --- a/gio/gsocketconnection.c +++ b/gio/gsocketconnection.c @@ -15,9 +15,7 @@ * 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, write to the - * Free Software Foundation, Inc., 59 Temple Place, Suite 330, - * Boston, MA 02111-1307, USA. + * Public License along with this library; if not, see . * * Authors: Christian Kellner * Samuel Cormier-Iijima @@ -31,13 +29,13 @@ #include "gsocketoutputstream.h" #include "gsocketinputstream.h" +#include "gioprivate.h" #include -#include +#include #include "gunixconnection.h" #include "gtcpconnection.h" #include "glibintl.h" -#include "gioalias.h" /** * SECTION:gsocketconnection @@ -53,17 +51,18 @@ * depends on the type of the underlying socket that is in use. For * instance, for a TCP/IP connection it will be a #GTcpConnection. * - * Chosing what type of object to construct is done with the socket + * Choosing what type of object to construct is done with the socket * connection factory, and it is possible for 3rd parties to register * custom socket connection types for specific combination of socket * family/type/protocol using g_socket_connection_factory_register_type(). * + * To close a #GSocketConnection, use g_io_stream_close(). Closing both + * substreams of the #GIOStream separately will not close the underlying + * #GSocket. + * * Since: 2.22 */ -G_DEFINE_TYPE (GSocketConnection, - g_socket_connection, G_TYPE_IO_STREAM); - enum { PROP_NONE, @@ -75,6 +74,10 @@ struct _GSocketConnectionPrivate GSocket *socket; GInputStream *input_stream; GOutputStream *output_stream; + + GSocketAddress *cached_remote_address; + + gboolean in_dispose; }; static gboolean g_socket_connection_close (GIOStream *stream, @@ -89,6 +92,8 @@ static gboolean g_socket_connection_close_finish (GIOStream *stream, GAsyncResult *result, GError **error); +G_DEFINE_TYPE_WITH_PRIVATE (GSocketConnection, g_socket_connection, G_TYPE_IO_STREAM) + static GInputStream * g_socket_connection_get_input_stream (GIOStream *io_stream) { @@ -114,6 +119,152 @@ g_socket_connection_get_output_stream (GIOStream *io_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) +{ + GTask *task; + GError *tmp_error = NULL; + + g_return_if_fail (G_IS_SOCKET_CONNECTION (connection)); + g_return_if_fail (G_IS_SOCKET_ADDRESS (address)); + + task = g_task_new (connection, cancellable, callback, user_data); + + g_socket_set_blocking (connection->priv->socket, FALSE); + + if (g_socket_connect (connection->priv->socket, address, + cancellable, &tmp_error)) + { + g_task_return_boolean (task, TRUE); + g_object_unref (task); + } + 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_task_attach_source (task, source, + (GSourceFunc) g_socket_connection_connect_callback); + g_source_unref (source); + } + else + { + g_task_return_error (task, tmp_error); + g_object_unref (task); + } +} + +static gboolean +g_socket_connection_connect_callback (GSocket *socket, + GIOCondition condition, + gpointer user_data) +{ + GTask *task = user_data; + GSocketConnection *connection = g_task_get_source_object (task); + GError *error = NULL; + + if (g_socket_check_connect_result (connection->priv->socket, &error)) + g_task_return_boolean (task, TRUE); + else + g_task_return_error (task, error); + + g_object_unref (task); + 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) +{ + g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE); + g_return_val_if_fail (g_task_is_valid (result, connection), FALSE); + + return g_task_propagate_boolean (G_TASK (result), error); +} + +/** * g_socket_connection_get_socket: * @connection: a #GSocketConnection * @@ -121,7 +272,7 @@ g_socket_connection_get_output_stream (GIOStream *io_stream) * This can be useful if you want to do something unusual on it * not supported by the #GSocketConnection APIs. * - * Returns: a #GSocketAddress or %NULL on error. + * Returns: (transfer none): a #GSocketAddress or %NULL on error. * * Since: 2.22 */ @@ -140,7 +291,7 @@ g_socket_connection_get_socket (GSocketConnection *connection) * * Try to get the local address of a socket connection. * - * Returns: a #GSocketAddress or %NULL on error. + * Returns: (transfer full): a #GSocketAddress or %NULL on error. * Free the returned object with g_object_unref(). * * Since: 2.22 @@ -157,9 +308,16 @@ g_socket_connection_get_local_address (GSocketConnection *connection, * @connection: a #GSocketConnection * @error: #GError for error reporting, or %NULL to ignore. * - * Try to get the remove address of a socket connection. + * Try to get the remote address of a socket connection. + * + * Since GLib 2.40, when used with g_socket_client_connect() or + * g_socket_client_connect_async(), during emission of + * %G_SOCKET_CLIENT_CONNECTING, this function will return the remote + * address that will be used for the connection. This allows + * applications to print e.g. "Connecting to example.com + * (10.42.77.3)...". * - * Returns: a #GSocketAddress or %NULL on error. + * Returns: (transfer full): a #GSocketAddress or %NULL on error. * Free the returned object with g_object_unref(). * * Since: 2.22 @@ -168,9 +326,27 @@ GSocketAddress * g_socket_connection_get_remote_address (GSocketConnection *connection, GError **error) { + if (!g_socket_is_connected (connection->priv->socket)) + { + return connection->priv->cached_remote_address ? + g_object_ref (connection->priv->cached_remote_address) : NULL; + } return g_socket_get_remote_address (connection->priv->socket, error); } +/* Private API allowing applications to retrieve the resolved address + * now, before we start connecting. + * + * https://bugzilla.gnome.org/show_bug.cgi?id=712547 + */ +void +g_socket_connection_set_cached_remote_address (GSocketConnection *connection, + GSocketAddress *address) +{ + g_clear_object (&connection->priv->cached_remote_address); + connection->priv->cached_remote_address = address ? g_object_ref (address) : NULL; +} + static void g_socket_connection_get_property (GObject *object, guint prop_id, @@ -218,6 +394,21 @@ g_socket_connection_constructed (GObject *object) } static void +g_socket_connection_dispose (GObject *object) +{ + GSocketConnection *connection = G_SOCKET_CONNECTION (object); + + connection->priv->in_dispose = TRUE; + + g_clear_object (&connection->priv->cached_remote_address); + + G_OBJECT_CLASS (g_socket_connection_parent_class) + ->dispose (object); + + connection->priv->in_dispose = FALSE; +} + +static void g_socket_connection_finalize (GObject *object) { GSocketConnection *connection = G_SOCKET_CONNECTION (object); @@ -240,12 +431,11 @@ g_socket_connection_class_init (GSocketConnectionClass *klass) GObjectClass *gobject_class = G_OBJECT_CLASS (klass); GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass); - g_type_class_add_private (klass, sizeof (GSocketConnectionPrivate)); - gobject_class->set_property = g_socket_connection_set_property; gobject_class->get_property = g_socket_connection_get_property; gobject_class->constructed = g_socket_connection_constructed; gobject_class->finalize = g_socket_connection_finalize; + gobject_class->dispose = g_socket_connection_dispose; stream_class->get_input_stream = g_socket_connection_get_input_stream; stream_class->get_output_stream = g_socket_connection_get_output_stream; @@ -267,9 +457,7 @@ g_socket_connection_class_init (GSocketConnectionClass *klass) static void g_socket_connection_init (GSocketConnection *connection) { - connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection, - G_TYPE_SOCKET_CONNECTION, - GSocketConnectionPrivate); + connection->priv = g_socket_connection_get_instance_private (connection); } static gboolean @@ -286,6 +474,15 @@ g_socket_connection_close (GIOStream *stream, g_input_stream_close (connection->priv->input_stream, cancellable, NULL); + /* Don't close the underlying socket if this is being called + * as part of dispose(); when destroying the GSocketConnection, + * we only want to close the socket if we're holding the last + * reference on it, and in that case it will close itself when + * we unref it in finalize(). + */ + if (connection->priv->in_dispose) + return TRUE; + return g_socket_close (connection->priv->socket, error); } @@ -297,30 +494,23 @@ g_socket_connection_close_async (GIOStream *stream, GAsyncReadyCallback callback, gpointer user_data) { - GSimpleAsyncResult *res; + GTask *task; GIOStreamClass *class; GError *error; class = G_IO_STREAM_GET_CLASS (stream); + task = g_task_new (stream, cancellable, callback, user_data); + /* socket close is not blocked, just do it! */ error = NULL; if (class->close_fn && !class->close_fn (stream, cancellable, &error)) - { - g_simple_async_report_gerror_in_idle (G_OBJECT (stream), - callback, user_data, - error); - g_error_free (error); - return; - } + g_task_return_error (task, error); + else + g_task_return_boolean (task, TRUE); - res = g_simple_async_result_new (G_OBJECT (stream), - callback, - user_data, - g_socket_connection_close_async); - g_simple_async_result_complete_in_idle (res); - g_object_unref (res); + g_object_unref (task); } static gboolean @@ -328,7 +518,7 @@ g_socket_connection_close_finish (GIOStream *stream, GAsyncResult *result, GError **error) { - return TRUE; + return g_task_propagate_boolean (G_TASK (result), error); } typedef struct { @@ -382,7 +572,7 @@ G_LOCK_DEFINE_STATIC(connection_factories); * @protocol: a protocol id * * Looks up the #GType to be used when creating socket connections on - * sockets with the specified @family,@type and @protocol. + * sockets with the specified @family, @type and @protocol. * * If no type is registered, the #GSocketConnection base type is returned. * @@ -421,11 +611,10 @@ g_socket_connection_factory_register_type (GType g_type, static void init_builtin_types (void) { - volatile GType a_type; #ifndef G_OS_WIN32 - a_type = g_unix_connection_get_type (); + g_type_ensure (G_TYPE_UNIX_CONNECTION); #endif - a_type = g_tcp_connection_get_type (); + g_type_ensure (G_TYPE_TCP_CONNECTION); } /** @@ -435,7 +624,7 @@ init_builtin_types (void) * @protocol_id: a protocol id * * Looks up the #GType to be used when creating socket connections on - * sockets with the specified @family,@type and @protocol_id. + * sockets with the specified @family, @type and @protocol_id. * * If no type is registered, the #GSocketConnection base type is returned. * @@ -480,7 +669,7 @@ g_socket_connection_factory_lookup_type (GSocketFamily family, * Creates a #GSocketConnection subclass of the right type for * @socket. * - * Returns: a #GSocketConnection + * Returns: (transfer full): a #GSocketConnection * * Since: 2.22 */ @@ -494,6 +683,3 @@ g_socket_connection_factory_create_connection (GSocket *socket) g_socket_get_protocol (socket)); return g_object_new (type, "socket", socket, NULL); } - -#define __G_SOCKET_CONNECTION_C__ -#include "gioaliasdef.c"