Branch data Line data Source code
1 : : /* GIO - GLib Input, Output and Streaming Library
2 : : *
3 : : * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
4 : : * © 2008 codethink
5 : : * Copyright © 2009 Red Hat, Inc
6 : : *
7 : : * SPDX-License-Identifier: LGPL-2.1-or-later
8 : : *
9 : : * This library is free software; you can redistribute it and/or
10 : : * modify it under the terms of the GNU Lesser General Public
11 : : * License as published by the Free Software Foundation; either
12 : : * version 2.1 of the License, or (at your option) any later version.
13 : : *
14 : : * This library is distributed in the hope that it will be useful,
15 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 : : * Lesser General Public License for more details.
18 : : *
19 : : * You should have received a copy of the GNU Lesser General
20 : : * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 : : *
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>
26 : : */
27 : :
28 : : #include "config.h"
29 : :
30 : : #include "gsocketconnection.h"
31 : :
32 : : #include "gsocketoutputstream.h"
33 : : #include "gsocketinputstream.h"
34 : : #include "gioprivate.h"
35 : : #include <gio/giostream.h>
36 : : #include <gio/gtask.h>
37 : : #include "gunixconnection.h"
38 : : #include "gtcpconnection.h"
39 : : #include "glibintl.h"
40 : :
41 : :
42 : : /**
43 : : * GSocketConnection:
44 : : *
45 : : * `GSocketConnection` is a [class@Gio.IOStream] for a connected socket. They
46 : : * can be created either by [class@Gio.SocketClient] when connecting to a host,
47 : : * or by [class@Gio.SocketListener] when accepting a new client.
48 : : *
49 : : * The type of the `GSocketConnection` object returned from these calls
50 : : * depends on the type of the underlying socket that is in use. For
51 : : * instance, for a TCP/IP connection it will be a [class@Gio.TcpConnection].
52 : : *
53 : : * Choosing what type of object to construct is done with the socket
54 : : * connection factory, and it is possible for third parties to register
55 : : * custom socket connection types for specific combination of socket
56 : : * family/type/protocol using [func@Gio.SocketConnection.factory_register_type].
57 : : *
58 : : * To close a `GSocketConnection`, use [method@Gio.IOStream.close]. Closing both
59 : : * substreams of the [class@Gio.IOStream] separately will not close the
60 : : * underlying [class@Gio.Socket].
61 : : *
62 : : * Since: 2.22
63 : : */
64 : :
65 : : enum
66 : : {
67 : : PROP_NONE,
68 : : PROP_SOCKET,
69 : : };
70 : :
71 : : struct _GSocketConnectionPrivate
72 : : {
73 : : GSocket *socket;
74 : : GInputStream *input_stream;
75 : : GOutputStream *output_stream;
76 : :
77 : : GSocketAddress *cached_remote_address;
78 : :
79 : : gboolean in_dispose;
80 : : };
81 : :
82 : : static gboolean g_socket_connection_close (GIOStream *stream,
83 : : GCancellable *cancellable,
84 : : GError **error);
85 : : static void g_socket_connection_close_async (GIOStream *stream,
86 : : int io_priority,
87 : : GCancellable *cancellable,
88 : : GAsyncReadyCallback callback,
89 : : gpointer user_data);
90 : : static gboolean g_socket_connection_close_finish (GIOStream *stream,
91 : : GAsyncResult *result,
92 : : GError **error);
93 : :
94 : 77832 : G_DEFINE_TYPE_WITH_PRIVATE (GSocketConnection, g_socket_connection, G_TYPE_IO_STREAM)
95 : :
96 : : static GInputStream *
97 : 6001 : g_socket_connection_get_input_stream (GIOStream *io_stream)
98 : : {
99 : 6001 : GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
100 : :
101 : 6001 : if (connection->priv->input_stream == NULL)
102 : 2752 : connection->priv->input_stream = (GInputStream *)
103 : 2752 : _g_socket_input_stream_new (connection->priv->socket);
104 : :
105 : 6001 : return connection->priv->input_stream;
106 : : }
107 : :
108 : : static GOutputStream *
109 : 20004 : g_socket_connection_get_output_stream (GIOStream *io_stream)
110 : : {
111 : 20004 : GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
112 : :
113 : 20004 : if (connection->priv->output_stream == NULL)
114 : 2750 : connection->priv->output_stream = (GOutputStream *)
115 : 2750 : _g_socket_output_stream_new (connection->priv->socket);
116 : :
117 : 20004 : return connection->priv->output_stream;
118 : : }
119 : :
120 : : /**
121 : : * g_socket_connection_is_connected:
122 : : * @connection: a #GSocketConnection
123 : : *
124 : : * Checks if @connection is connected. This is equivalent to calling
125 : : * g_socket_is_connected() on @connection's underlying #GSocket.
126 : : *
127 : : * Returns: whether @connection is connected
128 : : *
129 : : * Since: 2.32
130 : : */
131 : : gboolean
132 : 2 : g_socket_connection_is_connected (GSocketConnection *connection)
133 : : {
134 : 2 : return g_socket_is_connected (connection->priv->socket);
135 : : }
136 : :
137 : : /**
138 : : * g_socket_connection_connect:
139 : : * @connection: a #GSocketConnection
140 : : * @address: a #GSocketAddress specifying the remote address.
141 : : * @cancellable: (nullable): a %GCancellable or %NULL
142 : : * @error: #GError for error reporting, or %NULL to ignore.
143 : : *
144 : : * Connect @connection to the specified remote address.
145 : : *
146 : : * Returns: %TRUE if the connection succeeded, %FALSE on error
147 : : *
148 : : * Since: 2.32
149 : : */
150 : : gboolean
151 : 2548 : g_socket_connection_connect (GSocketConnection *connection,
152 : : GSocketAddress *address,
153 : : GCancellable *cancellable,
154 : : GError **error)
155 : : {
156 : 2548 : g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
157 : 2548 : g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), FALSE);
158 : :
159 : 2548 : return g_socket_connect (connection->priv->socket, address,
160 : : cancellable, error);
161 : : }
162 : :
163 : : static gboolean g_socket_connection_connect_callback (GSocket *socket,
164 : : GIOCondition condition,
165 : : gpointer user_data);
166 : :
167 : : /**
168 : : * g_socket_connection_connect_async:
169 : : * @connection: a #GSocketConnection
170 : : * @address: a #GSocketAddress specifying the remote address.
171 : : * @cancellable: (nullable): a %GCancellable or %NULL
172 : : * @callback: (scope async): a #GAsyncReadyCallback
173 : : * @user_data: user data for the callback
174 : : *
175 : : * Asynchronously connect @connection to the specified remote address.
176 : : *
177 : : * This clears the #GSocket:blocking flag on @connection's underlying
178 : : * socket if it is currently set.
179 : : *
180 : : * If #GSocket:timeout is set, the operation will time out and return
181 : : * %G_IO_ERROR_TIMED_OUT after that period. Otherwise, it will continue
182 : : * indefinitely until operating system timeouts (if any) are hit.
183 : : *
184 : : * Use g_socket_connection_connect_finish() to retrieve the result.
185 : : *
186 : : * Since: 2.32
187 : : */
188 : : void
189 : 26 : g_socket_connection_connect_async (GSocketConnection *connection,
190 : : GSocketAddress *address,
191 : : GCancellable *cancellable,
192 : : GAsyncReadyCallback callback,
193 : : gpointer user_data)
194 : : {
195 : : GTask *task;
196 : 26 : GError *tmp_error = NULL;
197 : :
198 : 26 : g_return_if_fail (G_IS_SOCKET_CONNECTION (connection));
199 : 26 : g_return_if_fail (G_IS_SOCKET_ADDRESS (address));
200 : :
201 : 26 : task = g_task_new (connection, cancellable, callback, user_data);
202 : 26 : g_task_set_source_tag (task, g_socket_connection_connect_async);
203 : :
204 : 26 : g_socket_set_blocking (connection->priv->socket, FALSE);
205 : :
206 : 26 : if (g_socket_connect (connection->priv->socket, address,
207 : : cancellable, &tmp_error))
208 : : {
209 : 0 : g_task_return_boolean (task, TRUE);
210 : 0 : g_object_unref (task);
211 : : }
212 : 26 : else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
213 : : {
214 : : GSource *source;
215 : :
216 : 26 : g_error_free (tmp_error);
217 : 26 : source = g_socket_create_source (connection->priv->socket,
218 : : G_IO_OUT, cancellable);
219 : 26 : g_task_attach_source (task, source,
220 : : (GSourceFunc) g_socket_connection_connect_callback);
221 : 26 : g_source_unref (source);
222 : : }
223 : : else
224 : : {
225 : 0 : g_task_return_error (task, tmp_error);
226 : 0 : g_object_unref (task);
227 : : }
228 : : }
229 : :
230 : : static gboolean
231 : 26 : g_socket_connection_connect_callback (GSocket *socket,
232 : : GIOCondition condition,
233 : : gpointer user_data)
234 : : {
235 : 26 : GTask *task = user_data;
236 : 26 : GSocketConnection *connection = g_task_get_source_object (task);
237 : 26 : GError *error = NULL;
238 : :
239 : 26 : if (g_socket_check_connect_result (connection->priv->socket, &error))
240 : 24 : g_task_return_boolean (task, TRUE);
241 : : else
242 : 2 : g_task_return_error (task, error);
243 : :
244 : 26 : g_object_unref (task);
245 : 26 : return FALSE;
246 : : }
247 : :
248 : : /**
249 : : * g_socket_connection_connect_finish:
250 : : * @connection: a #GSocketConnection
251 : : * @result: the #GAsyncResult
252 : : * @error: #GError for error reporting, or %NULL to ignore.
253 : : *
254 : : * Gets the result of a g_socket_connection_connect_async() call.
255 : : *
256 : : * Returns: %TRUE if the connection succeeded, %FALSE on error
257 : : *
258 : : * Since: 2.32
259 : : */
260 : : gboolean
261 : 26 : g_socket_connection_connect_finish (GSocketConnection *connection,
262 : : GAsyncResult *result,
263 : : GError **error)
264 : : {
265 : 26 : g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
266 : 26 : g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
267 : :
268 : 26 : return g_task_propagate_boolean (G_TASK (result), error);
269 : : }
270 : :
271 : : /**
272 : : * g_socket_connection_get_socket:
273 : : * @connection: a #GSocketConnection
274 : : *
275 : : * Gets the underlying #GSocket object of the connection.
276 : : * This can be useful if you want to do something unusual on it
277 : : * not supported by the #GSocketConnection APIs.
278 : : *
279 : : * Returns: (transfer none) (not nullable): the underlying socket
280 : : *
281 : : * Since: 2.22
282 : : */
283 : : GSocket *
284 : 5714 : g_socket_connection_get_socket (GSocketConnection *connection)
285 : : {
286 : 5714 : g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), NULL);
287 : :
288 : 5714 : return connection->priv->socket;
289 : : }
290 : :
291 : : /**
292 : : * g_socket_connection_get_local_address:
293 : : * @connection: a #GSocketConnection
294 : : * @error: #GError for error reporting, or %NULL to ignore.
295 : : *
296 : : * Try to get the local address of a socket connection.
297 : : *
298 : : * Returns: (transfer full): a #GSocketAddress or %NULL on error.
299 : : * Free the returned object with g_object_unref().
300 : : *
301 : : * Since: 2.22
302 : : */
303 : : GSocketAddress *
304 : 2 : g_socket_connection_get_local_address (GSocketConnection *connection,
305 : : GError **error)
306 : : {
307 : 2 : return g_socket_get_local_address (connection->priv->socket, error);
308 : : }
309 : :
310 : : /**
311 : : * g_socket_connection_get_remote_address:
312 : : * @connection: a #GSocketConnection
313 : : * @error: #GError for error reporting, or %NULL to ignore.
314 : : *
315 : : * Try to get the remote address of a socket connection.
316 : : *
317 : : * Since GLib 2.40, when used with g_socket_client_connect() or
318 : : * g_socket_client_connect_async(), during emission of
319 : : * %G_SOCKET_CLIENT_CONNECTING, this function will return the remote
320 : : * address that will be used for the connection. This allows
321 : : * applications to print e.g. "Connecting to example.com
322 : : * (10.42.77.3)...".
323 : : *
324 : : * Returns: (transfer full): a #GSocketAddress or %NULL on error.
325 : : * Free the returned object with g_object_unref().
326 : : *
327 : : * Since: 2.22
328 : : */
329 : : GSocketAddress *
330 : 6 : g_socket_connection_get_remote_address (GSocketConnection *connection,
331 : : GError **error)
332 : : {
333 : 6 : if (!g_socket_is_connected (connection->priv->socket))
334 : : {
335 : 0 : if (connection->priv->cached_remote_address)
336 : : {
337 : 0 : return g_object_ref (connection->priv->cached_remote_address);
338 : : }
339 : : else
340 : : {
341 : 0 : g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_CONNECTED,
342 : : _("Socket connection not connected"));
343 : 0 : return NULL;
344 : : }
345 : : }
346 : 6 : return g_socket_get_remote_address (connection->priv->socket, error);
347 : : }
348 : :
349 : : /* Private API allowing applications to retrieve the resolved address
350 : : * now, before we start connecting.
351 : : *
352 : : * https://bugzilla.gnome.org/show_bug.cgi?id=712547
353 : : */
354 : : void
355 : 5119 : g_socket_connection_set_cached_remote_address (GSocketConnection *connection,
356 : : GSocketAddress *address)
357 : : {
358 : 5119 : g_clear_object (&connection->priv->cached_remote_address);
359 : 5119 : connection->priv->cached_remote_address = address ? g_object_ref (address) : NULL;
360 : 5119 : }
361 : :
362 : : static void
363 : 2506 : g_socket_connection_get_property (GObject *object,
364 : : guint prop_id,
365 : : GValue *value,
366 : : GParamSpec *pspec)
367 : : {
368 : 2506 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
369 : :
370 : 2506 : switch (prop_id)
371 : : {
372 : 2506 : case PROP_SOCKET:
373 : 2506 : g_value_set_object (value, connection->priv->socket);
374 : 2506 : break;
375 : :
376 : 0 : default:
377 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
378 : : }
379 : 2506 : }
380 : :
381 : : static void
382 : 2821 : g_socket_connection_set_property (GObject *object,
383 : : guint prop_id,
384 : : const GValue *value,
385 : : GParamSpec *pspec)
386 : : {
387 : 2821 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
388 : :
389 : 2821 : switch (prop_id)
390 : : {
391 : 2821 : case PROP_SOCKET:
392 : 2821 : connection->priv->socket = G_SOCKET (g_value_dup_object (value));
393 : 2821 : break;
394 : :
395 : 0 : default:
396 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
397 : : }
398 : 2821 : }
399 : :
400 : : static void
401 : 2821 : g_socket_connection_constructed (GObject *object)
402 : : {
403 : : #ifndef G_DISABLE_ASSERT
404 : 2821 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
405 : : #endif
406 : :
407 : 2821 : g_assert (connection->priv->socket != NULL);
408 : 2821 : }
409 : :
410 : : static void
411 : 2557 : g_socket_connection_dispose (GObject *object)
412 : : {
413 : 2557 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
414 : :
415 : 2557 : connection->priv->in_dispose = TRUE;
416 : :
417 : 2557 : g_clear_object (&connection->priv->cached_remote_address);
418 : :
419 : 2557 : G_OBJECT_CLASS (g_socket_connection_parent_class)
420 : 2557 : ->dispose (object);
421 : :
422 : 2557 : connection->priv->in_dispose = FALSE;
423 : 2557 : }
424 : :
425 : : static void
426 : 2557 : g_socket_connection_finalize (GObject *object)
427 : : {
428 : 2557 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
429 : :
430 : 2557 : if (connection->priv->input_stream)
431 : 2488 : g_object_unref (connection->priv->input_stream);
432 : :
433 : 2557 : if (connection->priv->output_stream)
434 : 2486 : g_object_unref (connection->priv->output_stream);
435 : :
436 : 2557 : g_object_unref (connection->priv->socket);
437 : :
438 : 2557 : G_OBJECT_CLASS (g_socket_connection_parent_class)
439 : 2557 : ->finalize (object);
440 : 2557 : }
441 : :
442 : : static void
443 : 130 : g_socket_connection_class_init (GSocketConnectionClass *klass)
444 : : {
445 : 130 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
446 : 130 : GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
447 : :
448 : 130 : gobject_class->set_property = g_socket_connection_set_property;
449 : 130 : gobject_class->get_property = g_socket_connection_get_property;
450 : 130 : gobject_class->constructed = g_socket_connection_constructed;
451 : 130 : gobject_class->finalize = g_socket_connection_finalize;
452 : 130 : gobject_class->dispose = g_socket_connection_dispose;
453 : :
454 : 130 : stream_class->get_input_stream = g_socket_connection_get_input_stream;
455 : 130 : stream_class->get_output_stream = g_socket_connection_get_output_stream;
456 : 130 : stream_class->close_fn = g_socket_connection_close;
457 : 130 : stream_class->close_async = g_socket_connection_close_async;
458 : 130 : stream_class->close_finish = g_socket_connection_close_finish;
459 : :
460 : : /**
461 : : * GSocketConnection:socket:
462 : : *
463 : : * The underlying [class@Gio.Socket].
464 : : *
465 : : * Since: 2.22
466 : : */
467 : 130 : g_object_class_install_property (gobject_class,
468 : : PROP_SOCKET,
469 : : g_param_spec_object ("socket", NULL, NULL,
470 : : G_TYPE_SOCKET,
471 : : G_PARAM_CONSTRUCT_ONLY |
472 : : G_PARAM_READWRITE |
473 : : G_PARAM_STATIC_STRINGS));
474 : 130 : }
475 : :
476 : : static void
477 : 2821 : g_socket_connection_init (GSocketConnection *connection)
478 : : {
479 : 2821 : connection->priv = g_socket_connection_get_instance_private (connection);
480 : 2821 : }
481 : :
482 : : static gboolean
483 : 2557 : g_socket_connection_close (GIOStream *stream,
484 : : GCancellable *cancellable,
485 : : GError **error)
486 : : {
487 : 2557 : GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
488 : :
489 : 2557 : if (connection->priv->output_stream)
490 : 2486 : g_output_stream_close (connection->priv->output_stream,
491 : : cancellable, NULL);
492 : 2557 : if (connection->priv->input_stream)
493 : 2488 : g_input_stream_close (connection->priv->input_stream,
494 : : cancellable, NULL);
495 : :
496 : : /* Don't close the underlying socket if this is being called
497 : : * as part of dispose(); when destroying the GSocketConnection,
498 : : * we only want to close the socket if we're holding the last
499 : : * reference on it, and in that case it will close itself when
500 : : * we unref it in finalize().
501 : : */
502 : 2557 : if (connection->priv->in_dispose)
503 : 96 : return TRUE;
504 : :
505 : 2461 : return g_socket_close (connection->priv->socket, error);
506 : : }
507 : :
508 : :
509 : : static void
510 : 2451 : g_socket_connection_close_async (GIOStream *stream,
511 : : int io_priority,
512 : : GCancellable *cancellable,
513 : : GAsyncReadyCallback callback,
514 : : gpointer user_data)
515 : : {
516 : : GTask *task;
517 : : GIOStreamClass *class;
518 : : GError *error;
519 : :
520 : 2451 : class = G_IO_STREAM_GET_CLASS (stream);
521 : :
522 : 2451 : task = g_task_new (stream, cancellable, callback, user_data);
523 : 2451 : g_task_set_source_tag (task, g_socket_connection_close_async);
524 : :
525 : : /* socket close is not blocked, just do it! */
526 : 2451 : error = NULL;
527 : 4902 : if (class->close_fn &&
528 : 2451 : !class->close_fn (stream, cancellable, &error))
529 : 0 : g_task_return_error (task, error);
530 : : else
531 : 2451 : g_task_return_boolean (task, TRUE);
532 : :
533 : 2451 : g_object_unref (task);
534 : 2451 : }
535 : :
536 : : static gboolean
537 : 2451 : g_socket_connection_close_finish (GIOStream *stream,
538 : : GAsyncResult *result,
539 : : GError **error)
540 : : {
541 : 2451 : return g_task_propagate_boolean (G_TASK (result), error);
542 : : }
543 : :
544 : : typedef struct {
545 : : GSocketFamily socket_family;
546 : : GSocketType socket_type;
547 : : int protocol;
548 : : GType implementation;
549 : : } ConnectionFactory;
550 : :
551 : : static guint
552 : 3479 : connection_factory_hash (gconstpointer key)
553 : : {
554 : 3479 : const ConnectionFactory *factory = key;
555 : : guint h;
556 : :
557 : 3479 : h = factory->socket_family ^ (factory->socket_type << 4) ^ (factory->protocol << 8);
558 : : /* This is likely to be small, so spread over whole
559 : : hash space to get some distribution */
560 : 3479 : h = h ^ (h << 8) ^ (h << 16) ^ (h << 24);
561 : :
562 : 3479 : return h;
563 : : }
564 : :
565 : : static gboolean
566 : 2821 : connection_factory_equal (gconstpointer _a,
567 : : gconstpointer _b)
568 : : {
569 : 2821 : const ConnectionFactory *a = _a;
570 : 2821 : const ConnectionFactory *b = _b;
571 : :
572 : 2821 : if (a->socket_family != b->socket_family)
573 : 0 : return FALSE;
574 : :
575 : 2821 : if (a->socket_type != b->socket_type)
576 : 0 : return FALSE;
577 : :
578 : 2821 : if (a->protocol != b->protocol)
579 : 0 : return FALSE;
580 : :
581 : 2821 : return TRUE;
582 : : }
583 : :
584 : : static GHashTable *connection_factories = NULL;
585 : : G_LOCK_DEFINE_STATIC(connection_factories);
586 : :
587 : : /**
588 : : * g_socket_connection_factory_register_type:
589 : : * @g_type: a #GType, inheriting from %G_TYPE_SOCKET_CONNECTION
590 : : * @family: a #GSocketFamily
591 : : * @type: a #GSocketType
592 : : * @protocol: a protocol id
593 : : *
594 : : * Looks up the #GType to be used when creating socket connections on
595 : : * sockets with the specified @family, @type and @protocol.
596 : : *
597 : : * If no type is registered, the #GSocketConnection base type is returned.
598 : : *
599 : : * Since: 2.22
600 : : */
601 : : void
602 : 658 : g_socket_connection_factory_register_type (GType g_type,
603 : : GSocketFamily family,
604 : : GSocketType type,
605 : : gint protocol)
606 : : {
607 : : ConnectionFactory *factory;
608 : :
609 : 658 : g_return_if_fail (g_type_is_a (g_type, G_TYPE_SOCKET_CONNECTION));
610 : :
611 : 658 : G_LOCK (connection_factories);
612 : :
613 : 658 : if (connection_factories == NULL)
614 : 134 : connection_factories = g_hash_table_new_full (connection_factory_hash,
615 : : connection_factory_equal,
616 : : (GDestroyNotify)g_free,
617 : : NULL);
618 : :
619 : 658 : factory = g_new0 (ConnectionFactory, 1);
620 : 658 : factory->socket_family = family;
621 : 658 : factory->socket_type = type;
622 : 658 : factory->protocol = protocol;
623 : 658 : factory->implementation = g_type;
624 : :
625 : 658 : g_hash_table_insert (connection_factories,
626 : : factory, factory);
627 : :
628 : 658 : G_UNLOCK (connection_factories);
629 : : }
630 : :
631 : : static void
632 : 2821 : init_builtin_types (void)
633 : : {
634 : 2821 : g_type_ensure (G_TYPE_UNIX_CONNECTION);
635 : 2821 : g_type_ensure (G_TYPE_TCP_CONNECTION);
636 : 2821 : }
637 : :
638 : : /**
639 : : * g_socket_connection_factory_lookup_type:
640 : : * @family: a #GSocketFamily
641 : : * @type: a #GSocketType
642 : : * @protocol_id: a protocol id
643 : : *
644 : : * Looks up the #GType to be used when creating socket connections on
645 : : * sockets with the specified @family, @type and @protocol_id.
646 : : *
647 : : * If no type is registered, the #GSocketConnection base type is returned.
648 : : *
649 : : * Returns: a #GType
650 : : *
651 : : * Since: 2.22
652 : : */
653 : : GType
654 : 2821 : g_socket_connection_factory_lookup_type (GSocketFamily family,
655 : : GSocketType type,
656 : : gint protocol_id)
657 : : {
658 : : ConnectionFactory *factory, key;
659 : : GType g_type;
660 : :
661 : 2821 : init_builtin_types ();
662 : :
663 : 2821 : G_LOCK (connection_factories);
664 : :
665 : 2821 : g_type = G_TYPE_SOCKET_CONNECTION;
666 : :
667 : 2821 : if (connection_factories)
668 : : {
669 : 2821 : key.socket_family = family;
670 : 2821 : key.socket_type = type;
671 : 2821 : key.protocol = protocol_id;
672 : :
673 : 2821 : factory = g_hash_table_lookup (connection_factories, &key);
674 : 2821 : if (factory)
675 : 2821 : g_type = factory->implementation;
676 : : }
677 : :
678 : 2821 : G_UNLOCK (connection_factories);
679 : :
680 : 2821 : return g_type;
681 : : }
682 : :
683 : : /**
684 : : * g_socket_connection_factory_create_connection:
685 : : * @socket: a #GSocket
686 : : *
687 : : * Creates a #GSocketConnection subclass of the right type for
688 : : * @socket.
689 : : *
690 : : * Returns: (transfer full): a #GSocketConnection
691 : : *
692 : : * Since: 2.22
693 : : */
694 : : GSocketConnection *
695 : 2821 : g_socket_connection_factory_create_connection (GSocket *socket)
696 : : {
697 : : GType type;
698 : :
699 : 2821 : type = g_socket_connection_factory_lookup_type (g_socket_get_family (socket),
700 : : g_socket_get_socket_type (socket),
701 : 2821 : g_socket_get_protocol (socket));
702 : 2821 : return g_object_new (type, "socket", socket, NULL);
703 : : }
|