X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=gio%2Fgsocketconnection.c;h=9f490c84564c3bff82f08a2c81652b221b8348bd;hb=c8d10470939847069b1a346d4c44f2adde3469f6;hp=a1b42bba665349f9fd8320e55978ca1ad21e7fd8;hpb=69130db81a0b174bb072f458e8c1b1cd6bc1a0c9;p=platform%2Fupstream%2Fglib.git diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c index a1b42bb..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 @@ -49,20 +47,21 @@ * can be created either by #GSocketClient when connecting to a host, * or by #GSocketListener when accepting a new client. * - * The type of the #GSocketConnection object returned from these calls depends - * on the type of the underlying socket that is in use. For instance, for a - * TCP/IP connection it will be a #GTcpConnection. + * The type of the #GSocketConnection object returned from these calls + * 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 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(). + * 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 { @@ -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,17 +119,163 @@ 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. + * @connection: a #GSocketConnection * * Gets the underlying #GSocket object of the connection. * 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 - **/ + */ GSocket * g_socket_connection_get_socket (GSocketConnection *connection) { @@ -135,45 +286,72 @@ g_socket_connection_get_socket (GSocketConnection *connection) /** * g_socket_connection_get_local_address: - * @connection: a #GSocketConnection. + * @connection: a #GSocketConnection * @error: #GError for error reporting, or %NULL to ignore. * * 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 - **/ + */ GSocketAddress * g_socket_connection_get_local_address (GSocketConnection *connection, - GError **error) + GError **error) { return g_socket_get_local_address (connection->priv->socket, error); } /** * g_socket_connection_get_remote_address: - * @connection: a #GSocketConnection. + * @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. * - * Returns: a #GSocketAddress or %NULL on error. + * 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: (transfer full): a #GSocketAddress or %NULL on error. * Free the returned object with g_object_unref(). * * Since: 2.22 - **/ + */ GSocketAddress * g_socket_connection_get_remote_address (GSocketConnection *connection, - GError **error) + 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, - GValue *value, GParamSpec *pspec) +g_socket_connection_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) { GSocketConnection *connection = G_SOCKET_CONNECTION (object); @@ -189,8 +367,10 @@ g_socket_connection_get_property (GObject *object, guint prop_id, } static void -g_socket_connection_set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) +g_socket_connection_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) { GSocketConnection *connection = G_SOCKET_CONNECTION (object); @@ -214,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); @@ -236,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; @@ -249,26 +443,27 @@ g_socket_connection_class_init (GSocketConnectionClass *klass) stream_class->close_async = g_socket_connection_close_async; stream_class->close_finish = g_socket_connection_close_finish; - g_object_class_install_property (gobject_class, PROP_SOCKET, - g_param_spec_object ("socket", - P_("Socket"), - P_("The underlying GSocket"), - G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY | - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + g_object_class_install_property (gobject_class, + PROP_SOCKET, + g_param_spec_object ("socket", + P_("Socket"), + P_("The underlying GSocket"), + G_TYPE_SOCKET, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); } 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 -g_socket_connection_close (GIOStream *stream, - GCancellable *cancellable, - GError **error) +g_socket_connection_close (GIOStream *stream, + GCancellable *cancellable, + GError **error) { GSocketConnection *connection = G_SOCKET_CONNECTION (stream); @@ -279,45 +474,51 @@ 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); } static void -g_socket_connection_close_async (GIOStream *stream, - int io_priority, - GCancellable *cancellable, - GAsyncReadyCallback callback, - gpointer user_data) +g_socket_connection_close_async (GIOStream *stream, + int io_priority, + GCancellable *cancellable, + 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 (!g_io_stream_close (stream, cancellable, &error)) - { - g_simple_async_report_gerror_in_idle (G_OBJECT (stream), - callback, user_data, - error); - g_error_free (error); - return; - } + if (class->close_fn && + !class->close_fn (stream, cancellable, &error)) + 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 -g_socket_connection_close_finish (GIOStream *stream, +g_socket_connection_close_finish (GIOStream *stream, GAsyncResult *result, GError **error) { - return TRUE; + return g_task_propagate_boolean (G_TASK (result), error); } typedef struct { @@ -365,23 +566,23 @@ G_LOCK_DEFINE_STATIC(connection_factories); /** * g_socket_connection_factory_register_type: - * @g_type: a #GType, inheriting from G_SOCKET_CONNECTION - * @family: a #GSocketFamily. + * @g_type: a #GType, inheriting from %G_TYPE_SOCKET_CONNECTION + * @family: a #GSocketFamily * @type: a #GSocketType * @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. * * Since: 2.22 - **/ + */ void -g_socket_connection_factory_register_type (GType g_type, +g_socket_connection_factory_register_type (GType g_type, GSocketFamily family, - GSocketType type, - gint protocol) + GSocketType type, + gint protocol) { ConnectionFactory *factory; @@ -410,31 +611,31 @@ 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); } /** * g_socket_connection_factory_lookup_type: - * @family: a #GSocketFamily. + * @family: a #GSocketFamily * @type: a #GSocketType * @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. * * Returns: a #GType + * * Since: 2.22 - **/ + */ GType g_socket_connection_factory_lookup_type (GSocketFamily family, - GSocketType type, - gint protocol_id) + GSocketType type, + gint protocol_id) { ConnectionFactory *factory, key; GType g_type; @@ -463,15 +664,15 @@ g_socket_connection_factory_lookup_type (GSocketFamily family, /** * g_socket_connection_factory_create_connection: - * @socket: a #GSocket. + * @socket: a #GSocket * * Creates a #GSocketConnection subclass of the right type for * @socket. * - * Returns: a #GSocketConnection + * Returns: (transfer full): a #GSocketConnection * * Since: 2.22 - **/ + */ GSocketConnection * g_socket_connection_factory_create_connection (GSocket *socket) { @@ -479,9 +680,6 @@ g_socket_connection_factory_create_connection (GSocket *socket) type = g_socket_connection_factory_lookup_type (g_socket_get_family (socket), g_socket_get_socket_type (socket), - g_socket_get_protocol_id (socket)); + g_socket_get_protocol (socket)); return g_object_new (type, "socket", socket, NULL); } - -#define __G_SOCKET_CONNECTION_C__ -#include "gioaliasdef.c"