1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
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>
30 #include "gsocketconnection.h"
32 #include "gsocketoutputstream.h"
33 #include "gsocketinputstream.h"
34 #include <gio/giostream.h>
35 #include <gio/gsimpleasyncresult.h>
36 #include "gunixconnection.h"
37 #include "gtcpconnection.h"
42 * SECTION:gsocketconnection
43 * @short_description: A socket connection
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 * Chosing 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().
63 G_DEFINE_TYPE (GSocketConnection
,
64 g_socket_connection
, G_TYPE_IO_STREAM
);
72 struct _GSocketConnectionPrivate
75 GInputStream
*input_stream
;
76 GOutputStream
*output_stream
;
81 static gboolean
g_socket_connection_close (GIOStream
*stream
,
82 GCancellable
*cancellable
,
84 static void g_socket_connection_close_async (GIOStream
*stream
,
86 GCancellable
*cancellable
,
87 GAsyncReadyCallback callback
,
89 static gboolean
g_socket_connection_close_finish (GIOStream
*stream
,
94 g_socket_connection_get_input_stream (GIOStream
*io_stream
)
96 GSocketConnection
*connection
= G_SOCKET_CONNECTION (io_stream
);
98 if (connection
->priv
->input_stream
== NULL
)
99 connection
->priv
->input_stream
= (GInputStream
*)
100 _g_socket_input_stream_new (connection
->priv
->socket
);
102 return connection
->priv
->input_stream
;
105 static GOutputStream
*
106 g_socket_connection_get_output_stream (GIOStream
*io_stream
)
108 GSocketConnection
*connection
= G_SOCKET_CONNECTION (io_stream
);
110 if (connection
->priv
->output_stream
== NULL
)
111 connection
->priv
->output_stream
= (GOutputStream
*)
112 _g_socket_output_stream_new (connection
->priv
->socket
);
114 return connection
->priv
->output_stream
;
118 * g_socket_connection_get_socket:
119 * @connection: a #GSocketConnection
121 * Gets the underlying #GSocket object of the connection.
122 * This can be useful if you want to do something unusual on it
123 * not supported by the #GSocketConnection APIs.
125 * Returns: (transfer none): a #GSocketAddress or %NULL on error.
130 g_socket_connection_get_socket (GSocketConnection
*connection
)
132 g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection
), NULL
);
134 return connection
->priv
->socket
;
138 * g_socket_connection_get_local_address:
139 * @connection: a #GSocketConnection
140 * @error: #GError for error reporting, or %NULL to ignore.
142 * Try to get the local address of a socket connection.
144 * Returns: a #GSocketAddress or %NULL on error.
145 * Free the returned object with g_object_unref().
150 g_socket_connection_get_local_address (GSocketConnection
*connection
,
153 return g_socket_get_local_address (connection
->priv
->socket
, error
);
157 * g_socket_connection_get_remote_address:
158 * @connection: a #GSocketConnection
159 * @error: #GError for error reporting, or %NULL to ignore.
161 * Try to get the remote address of a socket connection.
163 * Returns: a #GSocketAddress or %NULL on error.
164 * Free the returned object with g_object_unref().
169 g_socket_connection_get_remote_address (GSocketConnection
*connection
,
172 return g_socket_get_remote_address (connection
->priv
->socket
, error
);
176 g_socket_connection_get_property (GObject
*object
,
181 GSocketConnection
*connection
= G_SOCKET_CONNECTION (object
);
186 g_value_set_object (value
, connection
->priv
->socket
);
190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
195 g_socket_connection_set_property (GObject
*object
,
200 GSocketConnection
*connection
= G_SOCKET_CONNECTION (object
);
205 connection
->priv
->socket
= G_SOCKET (g_value_dup_object (value
));
209 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
214 g_socket_connection_constructed (GObject
*object
)
216 GSocketConnection
*connection
= G_SOCKET_CONNECTION (object
);
218 g_assert (connection
->priv
->socket
!= NULL
);
222 g_socket_connection_dispose (GObject
*object
)
224 GSocketConnection
*connection
= G_SOCKET_CONNECTION (object
);
226 connection
->priv
->in_dispose
= TRUE
;
228 G_OBJECT_CLASS (g_socket_connection_parent_class
)
231 connection
->priv
->in_dispose
= FALSE
;
235 g_socket_connection_finalize (GObject
*object
)
237 GSocketConnection
*connection
= G_SOCKET_CONNECTION (object
);
239 if (connection
->priv
->input_stream
)
240 g_object_unref (connection
->priv
->input_stream
);
242 if (connection
->priv
->output_stream
)
243 g_object_unref (connection
->priv
->output_stream
);
245 g_object_unref (connection
->priv
->socket
);
247 G_OBJECT_CLASS (g_socket_connection_parent_class
)
252 g_socket_connection_class_init (GSocketConnectionClass
*klass
)
254 GObjectClass
*gobject_class
= G_OBJECT_CLASS (klass
);
255 GIOStreamClass
*stream_class
= G_IO_STREAM_CLASS (klass
);
257 g_type_class_add_private (klass
, sizeof (GSocketConnectionPrivate
));
259 gobject_class
->set_property
= g_socket_connection_set_property
;
260 gobject_class
->get_property
= g_socket_connection_get_property
;
261 gobject_class
->constructed
= g_socket_connection_constructed
;
262 gobject_class
->finalize
= g_socket_connection_finalize
;
263 gobject_class
->dispose
= g_socket_connection_dispose
;
265 stream_class
->get_input_stream
= g_socket_connection_get_input_stream
;
266 stream_class
->get_output_stream
= g_socket_connection_get_output_stream
;
267 stream_class
->close_fn
= g_socket_connection_close
;
268 stream_class
->close_async
= g_socket_connection_close_async
;
269 stream_class
->close_finish
= g_socket_connection_close_finish
;
271 g_object_class_install_property (gobject_class
,
273 g_param_spec_object ("socket",
275 P_("The underlying GSocket"),
277 G_PARAM_CONSTRUCT_ONLY
|
279 G_PARAM_STATIC_STRINGS
));
283 g_socket_connection_init (GSocketConnection
*connection
)
285 connection
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (connection
,
286 G_TYPE_SOCKET_CONNECTION
,
287 GSocketConnectionPrivate
);
291 g_socket_connection_close (GIOStream
*stream
,
292 GCancellable
*cancellable
,
295 GSocketConnection
*connection
= G_SOCKET_CONNECTION (stream
);
297 if (connection
->priv
->output_stream
)
298 g_output_stream_close (connection
->priv
->output_stream
,
300 if (connection
->priv
->input_stream
)
301 g_input_stream_close (connection
->priv
->input_stream
,
304 /* Don't close the underlying socket if this is being called
305 * as part of dispose(); when destroying the GSocketConnection,
306 * we only want to close the socket if we're holding the last
307 * reference on it, and in that case it will close itself when
308 * we unref it in finalize().
310 if (connection
->priv
->in_dispose
)
313 return g_socket_close (connection
->priv
->socket
, error
);
318 g_socket_connection_close_async (GIOStream
*stream
,
320 GCancellable
*cancellable
,
321 GAsyncReadyCallback callback
,
324 GSimpleAsyncResult
*res
;
325 GIOStreamClass
*class;
328 class = G_IO_STREAM_GET_CLASS (stream
);
330 /* socket close is not blocked, just do it! */
332 if (class->close_fn
&&
333 !class->close_fn (stream
, cancellable
, &error
))
335 g_simple_async_report_gerror_in_idle (G_OBJECT (stream
),
338 g_error_free (error
);
342 res
= g_simple_async_result_new (G_OBJECT (stream
),
345 g_socket_connection_close_async
);
346 g_simple_async_result_complete_in_idle (res
);
347 g_object_unref (res
);
351 g_socket_connection_close_finish (GIOStream
*stream
,
352 GAsyncResult
*result
,
359 GSocketFamily socket_family
;
360 GSocketType socket_type
;
362 GType implementation
;
366 connection_factory_hash (gconstpointer key
)
368 const ConnectionFactory
*factory
= key
;
371 h
= factory
->socket_family
^ (factory
->socket_type
<< 4) ^ (factory
->protocol
<< 8);
372 /* This is likely to be small, so spread over whole
373 hash space to get some distribution */
374 h
= h
^ (h
<< 8) ^ (h
<< 16) ^ (h
<< 24);
380 connection_factory_equal (gconstpointer _a
,
383 const ConnectionFactory
*a
= _a
;
384 const ConnectionFactory
*b
= _b
;
386 if (a
->socket_family
!= b
->socket_family
)
389 if (a
->socket_type
!= b
->socket_type
)
392 if (a
->protocol
!= b
->protocol
)
398 static GHashTable
*connection_factories
= NULL
;
399 G_LOCK_DEFINE_STATIC(connection_factories
);
402 * g_socket_connection_factory_register_type:
403 * @g_type: a #GType, inheriting from %G_TYPE_SOCKET_CONNECTION
404 * @family: a #GSocketFamily
405 * @type: a #GSocketType
406 * @protocol: a protocol id
408 * Looks up the #GType to be used when creating socket connections on
409 * sockets with the specified @family,@type and @protocol.
411 * If no type is registered, the #GSocketConnection base type is returned.
416 g_socket_connection_factory_register_type (GType g_type
,
417 GSocketFamily family
,
421 ConnectionFactory
*factory
;
423 g_return_if_fail (g_type_is_a (g_type
, G_TYPE_SOCKET_CONNECTION
));
425 G_LOCK (connection_factories
);
427 if (connection_factories
== NULL
)
428 connection_factories
= g_hash_table_new_full (connection_factory_hash
,
429 connection_factory_equal
,
430 (GDestroyNotify
)g_free
,
433 factory
= g_new0 (ConnectionFactory
, 1);
434 factory
->socket_family
= family
;
435 factory
->socket_type
= type
;
436 factory
->protocol
= protocol
;
437 factory
->implementation
= g_type
;
439 g_hash_table_insert (connection_factories
,
442 G_UNLOCK (connection_factories
);
446 init_builtin_types (void)
448 volatile GType a_type
;
450 a_type
= g_unix_connection_get_type ();
452 a_type
= g_tcp_connection_get_type ();
456 * g_socket_connection_factory_lookup_type:
457 * @family: a #GSocketFamily
458 * @type: a #GSocketType
459 * @protocol_id: a protocol id
461 * Looks up the #GType to be used when creating socket connections on
462 * sockets with the specified @family,@type and @protocol_id.
464 * If no type is registered, the #GSocketConnection base type is returned.
471 g_socket_connection_factory_lookup_type (GSocketFamily family
,
475 ConnectionFactory
*factory
, key
;
478 init_builtin_types ();
480 G_LOCK (connection_factories
);
482 g_type
= G_TYPE_SOCKET_CONNECTION
;
484 if (connection_factories
)
486 key
.socket_family
= family
;
487 key
.socket_type
= type
;
488 key
.protocol
= protocol_id
;
490 factory
= g_hash_table_lookup (connection_factories
, &key
);
492 g_type
= factory
->implementation
;
495 G_UNLOCK (connection_factories
);
501 * g_socket_connection_factory_create_connection:
502 * @socket: a #GSocket
504 * Creates a #GSocketConnection subclass of the right type for
507 * Returns: a #GSocketConnection
512 g_socket_connection_factory_create_connection (GSocket
*socket
)
516 type
= g_socket_connection_factory_lookup_type (g_socket_get_family (socket
),
517 g_socket_get_socket_type (socket
),
518 g_socket_get_protocol (socket
));
519 return g_object_new (type
, "socket", socket
, NULL
);