Add a test for the previous fix
[glib.git] / gio / gsocketconnection.c
blobd60f1989635a532dc32babac839d373ce36ee645
1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
4 * © 2008 codethink
5 * Copyright © 2009 Red Hat, Inc
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General
18 * Public License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
20 * Boston, MA 02111-1307, USA.
22 * Authors: Christian Kellner <gicmo@gnome.org>
23 * Samuel Cormier-Iijima <sciyoshi@gmail.com>
24 * Ryan Lortie <desrt@desrt.ca>
25 * Alexander Larsson <alexl@redhat.com>
28 #include "config.h"
30 #include "gsocketconnection.h"
32 #include "gsocketoutputstream.h"
33 #include "gsocketinputstream.h"
34 #include <gio/giostream.h>
35 #include <gio/gtask.h>
36 #include "gunixconnection.h"
37 #include "gtcpconnection.h"
38 #include "glibintl.h"
41 /**
42 * SECTION:gsocketconnection
43 * @short_description: A socket connection
44 * @include: gio/gio.h
45 * @see_also: #GIOStream, #GSocketClient, #GSocketListener
47 * #GSocketConnection is a #GIOStream for a connected socket. They
48 * can be created either by #GSocketClient when connecting to a host,
49 * or by #GSocketListener when accepting a new client.
51 * The type of the #GSocketConnection object returned from these calls
52 * depends on the type of the underlying socket that is in use. For
53 * instance, for a TCP/IP connection it will be a #GTcpConnection.
55 * Choosing what type of object to construct is done with the socket
56 * connection factory, and it is possible for 3rd parties to register
57 * custom socket connection types for specific combination of socket
58 * family/type/protocol using g_socket_connection_factory_register_type().
60 * Since: 2.22
63 G_DEFINE_TYPE (GSocketConnection, g_socket_connection, G_TYPE_IO_STREAM);
65 enum
67 PROP_NONE,
68 PROP_SOCKET,
71 struct _GSocketConnectionPrivate
73 GSocket *socket;
74 GInputStream *input_stream;
75 GOutputStream *output_stream;
77 gboolean in_dispose;
80 static gboolean g_socket_connection_close (GIOStream *stream,
81 GCancellable *cancellable,
82 GError **error);
83 static void g_socket_connection_close_async (GIOStream *stream,
84 int io_priority,
85 GCancellable *cancellable,
86 GAsyncReadyCallback callback,
87 gpointer user_data);
88 static gboolean g_socket_connection_close_finish (GIOStream *stream,
89 GAsyncResult *result,
90 GError **error);
92 static GInputStream *
93 g_socket_connection_get_input_stream (GIOStream *io_stream)
95 GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
97 if (connection->priv->input_stream == NULL)
98 connection->priv->input_stream = (GInputStream *)
99 _g_socket_input_stream_new (connection->priv->socket);
101 return connection->priv->input_stream;
104 static GOutputStream *
105 g_socket_connection_get_output_stream (GIOStream *io_stream)
107 GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
109 if (connection->priv->output_stream == NULL)
110 connection->priv->output_stream = (GOutputStream *)
111 _g_socket_output_stream_new (connection->priv->socket);
113 return connection->priv->output_stream;
117 * g_socket_connection_is_connected:
118 * @connection: a #GSocketConnection
120 * Checks if @connection is connected. This is equivalent to calling
121 * g_socket_is_connected() on @connection's underlying #GSocket.
123 * Returns: whether @connection is connected
125 * Since: 2.32
127 gboolean
128 g_socket_connection_is_connected (GSocketConnection *connection)
130 return g_socket_is_connected (connection->priv->socket);
134 * g_socket_connection_connect:
135 * @connection: a #GSocketConnection
136 * @address: a #GSocketAddress specifying the remote address.
137 * @cancellable: (allow-none): a %GCancellable or %NULL
138 * @error: #GError for error reporting, or %NULL to ignore.
140 * Connect @connection to the specified remote address.
142 * Returns: %TRUE if the connection succeeded, %FALSE on error
144 * Since: 2.32
146 gboolean
147 g_socket_connection_connect (GSocketConnection *connection,
148 GSocketAddress *address,
149 GCancellable *cancellable,
150 GError **error)
152 g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
153 g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), FALSE);
155 return g_socket_connect (connection->priv->socket, address,
156 cancellable, error);
159 static gboolean g_socket_connection_connect_callback (GSocket *socket,
160 GIOCondition condition,
161 gpointer user_data);
164 * g_socket_connection_connect_async:
165 * @connection: a #GSocketConnection
166 * @address: a #GSocketAddress specifying the remote address.
167 * @cancellable: (allow-none): a %GCancellable or %NULL
168 * @callback: (scope async): a #GAsyncReadyCallback
169 * @user_data: (closure): user data for the callback
171 * Asynchronously connect @connection to the specified remote address.
173 * This clears the #GSocket:blocking flag on @connection's underlying
174 * socket if it is currently set.
176 * Use g_socket_connection_connect_finish() to retrieve the result.
178 * Since: 2.32
180 void
181 g_socket_connection_connect_async (GSocketConnection *connection,
182 GSocketAddress *address,
183 GCancellable *cancellable,
184 GAsyncReadyCallback callback,
185 gpointer user_data)
187 GTask *task;
188 GError *tmp_error = NULL;
190 g_return_if_fail (G_IS_SOCKET_CONNECTION (connection));
191 g_return_if_fail (G_IS_SOCKET_ADDRESS (address));
193 task = g_task_new (connection, cancellable, callback, user_data);
195 g_socket_set_blocking (connection->priv->socket, FALSE);
197 if (g_socket_connect (connection->priv->socket, address,
198 cancellable, &tmp_error))
200 g_task_return_boolean (task, TRUE);
201 g_object_unref (task);
203 else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
205 GSource *source;
207 g_error_free (tmp_error);
208 source = g_socket_create_source (connection->priv->socket,
209 G_IO_OUT, cancellable);
210 g_task_attach_source (task, source,
211 (GSourceFunc) g_socket_connection_connect_callback);
212 g_source_unref (source);
214 else
216 g_task_return_error (task, tmp_error);
217 g_object_unref (task);
221 static gboolean
222 g_socket_connection_connect_callback (GSocket *socket,
223 GIOCondition condition,
224 gpointer user_data)
226 GTask *task = user_data;
227 GSocketConnection *connection = g_task_get_source_object (task);
228 GError *error = NULL;
230 if (g_socket_check_connect_result (connection->priv->socket, &error))
231 g_task_return_boolean (task, TRUE);
232 else
233 g_task_return_error (task, error);
235 g_object_unref (task);
236 return FALSE;
240 * g_socket_connection_connect_finish:
241 * @connection: a #GSocketConnection
242 * @result: the #GAsyncResult
243 * @error: #GError for error reporting, or %NULL to ignore.
245 * Gets the result of a g_socket_connection_connect_async() call.
247 * Returns: %TRUE if the connection succeeded, %FALSE on error
249 * Since: 2.32
251 gboolean
252 g_socket_connection_connect_finish (GSocketConnection *connection,
253 GAsyncResult *result,
254 GError **error)
256 g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
257 g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
259 return g_task_propagate_boolean (G_TASK (result), error);
263 * g_socket_connection_get_socket:
264 * @connection: a #GSocketConnection
266 * Gets the underlying #GSocket object of the connection.
267 * This can be useful if you want to do something unusual on it
268 * not supported by the #GSocketConnection APIs.
270 * Returns: (transfer none): a #GSocketAddress or %NULL on error.
272 * Since: 2.22
274 GSocket *
275 g_socket_connection_get_socket (GSocketConnection *connection)
277 g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), NULL);
279 return connection->priv->socket;
283 * g_socket_connection_get_local_address:
284 * @connection: a #GSocketConnection
285 * @error: #GError for error reporting, or %NULL to ignore.
287 * Try to get the local address of a socket connection.
289 * Returns: (transfer full): a #GSocketAddress or %NULL on error.
290 * Free the returned object with g_object_unref().
292 * Since: 2.22
294 GSocketAddress *
295 g_socket_connection_get_local_address (GSocketConnection *connection,
296 GError **error)
298 return g_socket_get_local_address (connection->priv->socket, error);
302 * g_socket_connection_get_remote_address:
303 * @connection: a #GSocketConnection
304 * @error: #GError for error reporting, or %NULL to ignore.
306 * Try to get the remote address of a socket connection.
308 * Returns: (transfer full): a #GSocketAddress or %NULL on error.
309 * Free the returned object with g_object_unref().
311 * Since: 2.22
313 GSocketAddress *
314 g_socket_connection_get_remote_address (GSocketConnection *connection,
315 GError **error)
317 return g_socket_get_remote_address (connection->priv->socket, error);
320 static void
321 g_socket_connection_get_property (GObject *object,
322 guint prop_id,
323 GValue *value,
324 GParamSpec *pspec)
326 GSocketConnection *connection = G_SOCKET_CONNECTION (object);
328 switch (prop_id)
330 case PROP_SOCKET:
331 g_value_set_object (value, connection->priv->socket);
332 break;
334 default:
335 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
339 static void
340 g_socket_connection_set_property (GObject *object,
341 guint prop_id,
342 const GValue *value,
343 GParamSpec *pspec)
345 GSocketConnection *connection = G_SOCKET_CONNECTION (object);
347 switch (prop_id)
349 case PROP_SOCKET:
350 connection->priv->socket = G_SOCKET (g_value_dup_object (value));
351 break;
353 default:
354 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
358 static void
359 g_socket_connection_constructed (GObject *object)
361 GSocketConnection *connection = G_SOCKET_CONNECTION (object);
363 g_assert (connection->priv->socket != NULL);
366 static void
367 g_socket_connection_dispose (GObject *object)
369 GSocketConnection *connection = G_SOCKET_CONNECTION (object);
371 connection->priv->in_dispose = TRUE;
373 G_OBJECT_CLASS (g_socket_connection_parent_class)
374 ->dispose (object);
376 connection->priv->in_dispose = FALSE;
379 static void
380 g_socket_connection_finalize (GObject *object)
382 GSocketConnection *connection = G_SOCKET_CONNECTION (object);
384 if (connection->priv->input_stream)
385 g_object_unref (connection->priv->input_stream);
387 if (connection->priv->output_stream)
388 g_object_unref (connection->priv->output_stream);
390 g_object_unref (connection->priv->socket);
392 G_OBJECT_CLASS (g_socket_connection_parent_class)
393 ->finalize (object);
396 static void
397 g_socket_connection_class_init (GSocketConnectionClass *klass)
399 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
400 GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
402 g_type_class_add_private (klass, sizeof (GSocketConnectionPrivate));
404 gobject_class->set_property = g_socket_connection_set_property;
405 gobject_class->get_property = g_socket_connection_get_property;
406 gobject_class->constructed = g_socket_connection_constructed;
407 gobject_class->finalize = g_socket_connection_finalize;
408 gobject_class->dispose = g_socket_connection_dispose;
410 stream_class->get_input_stream = g_socket_connection_get_input_stream;
411 stream_class->get_output_stream = g_socket_connection_get_output_stream;
412 stream_class->close_fn = g_socket_connection_close;
413 stream_class->close_async = g_socket_connection_close_async;
414 stream_class->close_finish = g_socket_connection_close_finish;
416 g_object_class_install_property (gobject_class,
417 PROP_SOCKET,
418 g_param_spec_object ("socket",
419 P_("Socket"),
420 P_("The underlying GSocket"),
421 G_TYPE_SOCKET,
422 G_PARAM_CONSTRUCT_ONLY |
423 G_PARAM_READWRITE |
424 G_PARAM_STATIC_STRINGS));
427 static void
428 g_socket_connection_init (GSocketConnection *connection)
430 connection->priv = G_TYPE_INSTANCE_GET_PRIVATE (connection,
431 G_TYPE_SOCKET_CONNECTION,
432 GSocketConnectionPrivate);
435 static gboolean
436 g_socket_connection_close (GIOStream *stream,
437 GCancellable *cancellable,
438 GError **error)
440 GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
442 if (connection->priv->output_stream)
443 g_output_stream_close (connection->priv->output_stream,
444 cancellable, NULL);
445 if (connection->priv->input_stream)
446 g_input_stream_close (connection->priv->input_stream,
447 cancellable, NULL);
449 /* Don't close the underlying socket if this is being called
450 * as part of dispose(); when destroying the GSocketConnection,
451 * we only want to close the socket if we're holding the last
452 * reference on it, and in that case it will close itself when
453 * we unref it in finalize().
455 if (connection->priv->in_dispose)
456 return TRUE;
458 return g_socket_close (connection->priv->socket, error);
462 static void
463 g_socket_connection_close_async (GIOStream *stream,
464 int io_priority,
465 GCancellable *cancellable,
466 GAsyncReadyCallback callback,
467 gpointer user_data)
469 GTask *task;
470 GIOStreamClass *class;
471 GError *error;
473 class = G_IO_STREAM_GET_CLASS (stream);
475 task = g_task_new (stream, cancellable, callback, user_data);
477 /* socket close is not blocked, just do it! */
478 error = NULL;
479 if (class->close_fn &&
480 !class->close_fn (stream, cancellable, &error))
481 g_task_return_error (task, error);
482 else
483 g_task_return_boolean (task, TRUE);
485 g_object_unref (task);
488 static gboolean
489 g_socket_connection_close_finish (GIOStream *stream,
490 GAsyncResult *result,
491 GError **error)
493 return g_task_propagate_boolean (G_TASK (result), error);
496 typedef struct {
497 GSocketFamily socket_family;
498 GSocketType socket_type;
499 int protocol;
500 GType implementation;
501 } ConnectionFactory;
503 static guint
504 connection_factory_hash (gconstpointer key)
506 const ConnectionFactory *factory = key;
507 guint h;
509 h = factory->socket_family ^ (factory->socket_type << 4) ^ (factory->protocol << 8);
510 /* This is likely to be small, so spread over whole
511 hash space to get some distribution */
512 h = h ^ (h << 8) ^ (h << 16) ^ (h << 24);
514 return h;
517 static gboolean
518 connection_factory_equal (gconstpointer _a,
519 gconstpointer _b)
521 const ConnectionFactory *a = _a;
522 const ConnectionFactory *b = _b;
524 if (a->socket_family != b->socket_family)
525 return FALSE;
527 if (a->socket_type != b->socket_type)
528 return FALSE;
530 if (a->protocol != b->protocol)
531 return FALSE;
533 return TRUE;
536 static GHashTable *connection_factories = NULL;
537 G_LOCK_DEFINE_STATIC(connection_factories);
540 * g_socket_connection_factory_register_type:
541 * @g_type: a #GType, inheriting from %G_TYPE_SOCKET_CONNECTION
542 * @family: a #GSocketFamily
543 * @type: a #GSocketType
544 * @protocol: a protocol id
546 * Looks up the #GType to be used when creating socket connections on
547 * sockets with the specified @family, @type and @protocol.
549 * If no type is registered, the #GSocketConnection base type is returned.
551 * Since: 2.22
553 void
554 g_socket_connection_factory_register_type (GType g_type,
555 GSocketFamily family,
556 GSocketType type,
557 gint protocol)
559 ConnectionFactory *factory;
561 g_return_if_fail (g_type_is_a (g_type, G_TYPE_SOCKET_CONNECTION));
563 G_LOCK (connection_factories);
565 if (connection_factories == NULL)
566 connection_factories = g_hash_table_new_full (connection_factory_hash,
567 connection_factory_equal,
568 (GDestroyNotify)g_free,
569 NULL);
571 factory = g_new0 (ConnectionFactory, 1);
572 factory->socket_family = family;
573 factory->socket_type = type;
574 factory->protocol = protocol;
575 factory->implementation = g_type;
577 g_hash_table_insert (connection_factories,
578 factory, factory);
580 G_UNLOCK (connection_factories);
583 static void
584 init_builtin_types (void)
586 #ifndef G_OS_WIN32
587 g_type_ensure (G_TYPE_UNIX_CONNECTION);
588 #endif
589 g_type_ensure (G_TYPE_TCP_CONNECTION);
593 * g_socket_connection_factory_lookup_type:
594 * @family: a #GSocketFamily
595 * @type: a #GSocketType
596 * @protocol_id: a protocol id
598 * Looks up the #GType to be used when creating socket connections on
599 * sockets with the specified @family, @type and @protocol_id.
601 * If no type is registered, the #GSocketConnection base type is returned.
603 * Returns: a #GType
605 * Since: 2.22
607 GType
608 g_socket_connection_factory_lookup_type (GSocketFamily family,
609 GSocketType type,
610 gint protocol_id)
612 ConnectionFactory *factory, key;
613 GType g_type;
615 init_builtin_types ();
617 G_LOCK (connection_factories);
619 g_type = G_TYPE_SOCKET_CONNECTION;
621 if (connection_factories)
623 key.socket_family = family;
624 key.socket_type = type;
625 key.protocol = protocol_id;
627 factory = g_hash_table_lookup (connection_factories, &key);
628 if (factory)
629 g_type = factory->implementation;
632 G_UNLOCK (connection_factories);
634 return g_type;
638 * g_socket_connection_factory_create_connection:
639 * @socket: a #GSocket
641 * Creates a #GSocketConnection subclass of the right type for
642 * @socket.
644 * Returns: (transfer full): a #GSocketConnection
646 * Since: 2.22
648 GSocketConnection *
649 g_socket_connection_factory_create_connection (GSocket *socket)
651 GType type;
653 type = g_socket_connection_factory_lookup_type (g_socket_get_family (socket),
654 g_socket_get_socket_type (socket),
655 g_socket_get_protocol (socket));
656 return g_object_new (type, "socket", socket, NULL);