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 : 56429 : G_DEFINE_TYPE_WITH_PRIVATE (GSocketConnection, g_socket_connection, G_TYPE_IO_STREAM)
95 : :
96 : : static GInputStream *
97 : 4198 : g_socket_connection_get_input_stream (GIOStream *io_stream)
98 : : {
99 : 4198 : GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
100 : :
101 : 4198 : if (connection->priv->input_stream == NULL)
102 : 1846 : connection->priv->input_stream = (GInputStream *)
103 : 1846 : _g_socket_input_stream_new (connection->priv->socket);
104 : :
105 : 4198 : return connection->priv->input_stream;
106 : : }
107 : :
108 : : static GOutputStream *
109 : 16906 : g_socket_connection_get_output_stream (GIOStream *io_stream)
110 : : {
111 : 16906 : GSocketConnection *connection = G_SOCKET_CONNECTION (io_stream);
112 : :
113 : 16906 : if (connection->priv->output_stream == NULL)
114 : 1845 : connection->priv->output_stream = (GOutputStream *)
115 : 1845 : _g_socket_output_stream_new (connection->priv->socket);
116 : :
117 : 16906 : 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 : 1642 : g_socket_connection_connect (GSocketConnection *connection,
152 : : GSocketAddress *address,
153 : : GCancellable *cancellable,
154 : : GError **error)
155 : : {
156 : 1642 : g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
157 : 1642 : g_return_val_if_fail (G_IS_SOCKET_ADDRESS (address), FALSE);
158 : :
159 : 1642 : 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 : 21 : 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 : 21 : GError *tmp_error = NULL;
197 : :
198 : 21 : g_return_if_fail (G_IS_SOCKET_CONNECTION (connection));
199 : 21 : g_return_if_fail (G_IS_SOCKET_ADDRESS (address));
200 : :
201 : 21 : task = g_task_new (connection, cancellable, callback, user_data);
202 : 21 : g_task_set_source_tag (task, g_socket_connection_connect_async);
203 : :
204 : 21 : g_socket_set_blocking (connection->priv->socket, FALSE);
205 : :
206 : 21 : 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 : 21 : else if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_PENDING))
213 : : {
214 : : GSource *source;
215 : :
216 : 21 : g_error_free (tmp_error);
217 : 21 : source = g_socket_create_source (connection->priv->socket,
218 : : G_IO_OUT, cancellable);
219 : 21 : g_task_attach_source (task, source,
220 : : (GSourceFunc) g_socket_connection_connect_callback);
221 : 21 : 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 : 21 : g_socket_connection_connect_callback (GSocket *socket,
232 : : GIOCondition condition,
233 : : gpointer user_data)
234 : : {
235 : 21 : GTask *task = user_data;
236 : 21 : GSocketConnection *connection = g_task_get_source_object (task);
237 : 21 : GError *error = NULL;
238 : :
239 : 21 : if (g_socket_check_connect_result (connection->priv->socket, &error))
240 : 19 : g_task_return_boolean (task, TRUE);
241 : : else
242 : 2 : g_task_return_error (task, error);
243 : :
244 : 21 : g_object_unref (task);
245 : 21 : 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 : 21 : g_socket_connection_connect_finish (GSocketConnection *connection,
262 : : GAsyncResult *result,
263 : : GError **error)
264 : : {
265 : 21 : g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), FALSE);
266 : 21 : g_return_val_if_fail (g_task_is_valid (result, connection), FALSE);
267 : :
268 : 21 : 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): a #GSocket or %NULL on error.
280 : : *
281 : : * Since: 2.22
282 : : */
283 : : GSocket *
284 : 3890 : g_socket_connection_get_socket (GSocketConnection *connection)
285 : : {
286 : 3890 : g_return_val_if_fail (G_IS_SOCKET_CONNECTION (connection), NULL);
287 : :
288 : 3890 : 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 : return connection->priv->cached_remote_address ?
336 : 0 : g_object_ref (connection->priv->cached_remote_address) : NULL;
337 : : }
338 : 6 : return g_socket_get_remote_address (connection->priv->socket, error);
339 : : }
340 : :
341 : : /* Private API allowing applications to retrieve the resolved address
342 : : * now, before we start connecting.
343 : : *
344 : : * https://bugzilla.gnome.org/show_bug.cgi?id=712547
345 : : */
346 : : void
347 : 3298 : g_socket_connection_set_cached_remote_address (GSocketConnection *connection,
348 : : GSocketAddress *address)
349 : : {
350 : 3298 : g_clear_object (&connection->priv->cached_remote_address);
351 : 3298 : connection->priv->cached_remote_address = address ? g_object_ref (address) : NULL;
352 : 3298 : }
353 : :
354 : : static void
355 : 1601 : g_socket_connection_get_property (GObject *object,
356 : : guint prop_id,
357 : : GValue *value,
358 : : GParamSpec *pspec)
359 : : {
360 : 1601 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
361 : :
362 : 1601 : switch (prop_id)
363 : : {
364 : 1601 : case PROP_SOCKET:
365 : 1601 : g_value_set_object (value, connection->priv->socket);
366 : 1601 : break;
367 : :
368 : 0 : default:
369 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
370 : : }
371 : 1601 : }
372 : :
373 : : static void
374 : 1903 : g_socket_connection_set_property (GObject *object,
375 : : guint prop_id,
376 : : const GValue *value,
377 : : GParamSpec *pspec)
378 : : {
379 : 1903 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
380 : :
381 : 1903 : switch (prop_id)
382 : : {
383 : 1903 : case PROP_SOCKET:
384 : 1903 : connection->priv->socket = G_SOCKET (g_value_dup_object (value));
385 : 1903 : break;
386 : :
387 : 0 : default:
388 : 0 : G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
389 : : }
390 : 1903 : }
391 : :
392 : : static void
393 : 1903 : g_socket_connection_constructed (GObject *object)
394 : : {
395 : : #ifndef G_DISABLE_ASSERT
396 : 1903 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
397 : : #endif
398 : :
399 : 1903 : g_assert (connection->priv->socket != NULL);
400 : 1903 : }
401 : :
402 : : static void
403 : 1648 : g_socket_connection_dispose (GObject *object)
404 : : {
405 : 1648 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
406 : :
407 : 1648 : connection->priv->in_dispose = TRUE;
408 : :
409 : 1648 : g_clear_object (&connection->priv->cached_remote_address);
410 : :
411 : 1648 : G_OBJECT_CLASS (g_socket_connection_parent_class)
412 : 1648 : ->dispose (object);
413 : :
414 : 1648 : connection->priv->in_dispose = FALSE;
415 : 1648 : }
416 : :
417 : : static void
418 : 1648 : g_socket_connection_finalize (GObject *object)
419 : : {
420 : 1648 : GSocketConnection *connection = G_SOCKET_CONNECTION (object);
421 : :
422 : 1648 : if (connection->priv->input_stream)
423 : 1591 : g_object_unref (connection->priv->input_stream);
424 : :
425 : 1648 : if (connection->priv->output_stream)
426 : 1590 : g_object_unref (connection->priv->output_stream);
427 : :
428 : 1648 : g_object_unref (connection->priv->socket);
429 : :
430 : 1648 : G_OBJECT_CLASS (g_socket_connection_parent_class)
431 : 1648 : ->finalize (object);
432 : 1648 : }
433 : :
434 : : static void
435 : 124 : g_socket_connection_class_init (GSocketConnectionClass *klass)
436 : : {
437 : 124 : GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
438 : 124 : GIOStreamClass *stream_class = G_IO_STREAM_CLASS (klass);
439 : :
440 : 124 : gobject_class->set_property = g_socket_connection_set_property;
441 : 124 : gobject_class->get_property = g_socket_connection_get_property;
442 : 124 : gobject_class->constructed = g_socket_connection_constructed;
443 : 124 : gobject_class->finalize = g_socket_connection_finalize;
444 : 124 : gobject_class->dispose = g_socket_connection_dispose;
445 : :
446 : 124 : stream_class->get_input_stream = g_socket_connection_get_input_stream;
447 : 124 : stream_class->get_output_stream = g_socket_connection_get_output_stream;
448 : 124 : stream_class->close_fn = g_socket_connection_close;
449 : 124 : stream_class->close_async = g_socket_connection_close_async;
450 : 124 : stream_class->close_finish = g_socket_connection_close_finish;
451 : :
452 : : /**
453 : : * GSocketConnection:socket:
454 : : *
455 : : * The underlying [class@Gio.Socket].
456 : : *
457 : : * Since: 2.22
458 : : */
459 : 124 : g_object_class_install_property (gobject_class,
460 : : PROP_SOCKET,
461 : : g_param_spec_object ("socket", NULL, NULL,
462 : : G_TYPE_SOCKET,
463 : : G_PARAM_CONSTRUCT_ONLY |
464 : : G_PARAM_READWRITE |
465 : : G_PARAM_STATIC_STRINGS));
466 : 124 : }
467 : :
468 : : static void
469 : 1903 : g_socket_connection_init (GSocketConnection *connection)
470 : : {
471 : 1903 : connection->priv = g_socket_connection_get_instance_private (connection);
472 : 1903 : }
473 : :
474 : : static gboolean
475 : 1648 : g_socket_connection_close (GIOStream *stream,
476 : : GCancellable *cancellable,
477 : : GError **error)
478 : : {
479 : 1648 : GSocketConnection *connection = G_SOCKET_CONNECTION (stream);
480 : :
481 : 1648 : if (connection->priv->output_stream)
482 : 1590 : g_output_stream_close (connection->priv->output_stream,
483 : : cancellable, NULL);
484 : 1648 : if (connection->priv->input_stream)
485 : 1591 : g_input_stream_close (connection->priv->input_stream,
486 : : cancellable, NULL);
487 : :
488 : : /* Don't close the underlying socket if this is being called
489 : : * as part of dispose(); when destroying the GSocketConnection,
490 : : * we only want to close the socket if we're holding the last
491 : : * reference on it, and in that case it will close itself when
492 : : * we unref it in finalize().
493 : : */
494 : 1648 : if (connection->priv->in_dispose)
495 : 94 : return TRUE;
496 : :
497 : 1554 : return g_socket_close (connection->priv->socket, error);
498 : : }
499 : :
500 : :
501 : : static void
502 : 1554 : g_socket_connection_close_async (GIOStream *stream,
503 : : int io_priority,
504 : : GCancellable *cancellable,
505 : : GAsyncReadyCallback callback,
506 : : gpointer user_data)
507 : : {
508 : : GTask *task;
509 : : GIOStreamClass *class;
510 : : GError *error;
511 : :
512 : 1554 : class = G_IO_STREAM_GET_CLASS (stream);
513 : :
514 : 1554 : task = g_task_new (stream, cancellable, callback, user_data);
515 : 1554 : g_task_set_source_tag (task, g_socket_connection_close_async);
516 : :
517 : : /* socket close is not blocked, just do it! */
518 : 1554 : error = NULL;
519 : 3108 : if (class->close_fn &&
520 : 1554 : !class->close_fn (stream, cancellable, &error))
521 : 0 : g_task_return_error (task, error);
522 : : else
523 : 1554 : g_task_return_boolean (task, TRUE);
524 : :
525 : 1554 : g_object_unref (task);
526 : 1554 : }
527 : :
528 : : static gboolean
529 : 1554 : g_socket_connection_close_finish (GIOStream *stream,
530 : : GAsyncResult *result,
531 : : GError **error)
532 : : {
533 : 1554 : return g_task_propagate_boolean (G_TASK (result), error);
534 : : }
535 : :
536 : : typedef struct {
537 : : GSocketFamily socket_family;
538 : : GSocketType socket_type;
539 : : int protocol;
540 : : GType implementation;
541 : : } ConnectionFactory;
542 : :
543 : : static guint
544 : 2531 : connection_factory_hash (gconstpointer key)
545 : : {
546 : 2531 : const ConnectionFactory *factory = key;
547 : : guint h;
548 : :
549 : 2531 : h = factory->socket_family ^ (factory->socket_type << 4) ^ (factory->protocol << 8);
550 : : /* This is likely to be small, so spread over whole
551 : : hash space to get some distribution */
552 : 2531 : h = h ^ (h << 8) ^ (h << 16) ^ (h << 24);
553 : :
554 : 2531 : return h;
555 : : }
556 : :
557 : : static gboolean
558 : 1903 : connection_factory_equal (gconstpointer _a,
559 : : gconstpointer _b)
560 : : {
561 : 1903 : const ConnectionFactory *a = _a;
562 : 1903 : const ConnectionFactory *b = _b;
563 : :
564 : 1903 : if (a->socket_family != b->socket_family)
565 : 0 : return FALSE;
566 : :
567 : 1903 : if (a->socket_type != b->socket_type)
568 : 0 : return FALSE;
569 : :
570 : 1903 : if (a->protocol != b->protocol)
571 : 0 : return FALSE;
572 : :
573 : 1903 : return TRUE;
574 : : }
575 : :
576 : : static GHashTable *connection_factories = NULL;
577 : : G_LOCK_DEFINE_STATIC(connection_factories);
578 : :
579 : : /**
580 : : * g_socket_connection_factory_register_type:
581 : : * @g_type: a #GType, inheriting from %G_TYPE_SOCKET_CONNECTION
582 : : * @family: a #GSocketFamily
583 : : * @type: a #GSocketType
584 : : * @protocol: a protocol id
585 : : *
586 : : * Looks up the #GType to be used when creating socket connections on
587 : : * sockets with the specified @family, @type and @protocol.
588 : : *
589 : : * If no type is registered, the #GSocketConnection base type is returned.
590 : : *
591 : : * Since: 2.22
592 : : */
593 : : void
594 : 628 : g_socket_connection_factory_register_type (GType g_type,
595 : : GSocketFamily family,
596 : : GSocketType type,
597 : : gint protocol)
598 : : {
599 : : ConnectionFactory *factory;
600 : :
601 : 628 : g_return_if_fail (g_type_is_a (g_type, G_TYPE_SOCKET_CONNECTION));
602 : :
603 : 628 : G_LOCK (connection_factories);
604 : :
605 : 628 : if (connection_factories == NULL)
606 : 128 : connection_factories = g_hash_table_new_full (connection_factory_hash,
607 : : connection_factory_equal,
608 : : (GDestroyNotify)g_free,
609 : : NULL);
610 : :
611 : 628 : factory = g_new0 (ConnectionFactory, 1);
612 : 628 : factory->socket_family = family;
613 : 628 : factory->socket_type = type;
614 : 628 : factory->protocol = protocol;
615 : 628 : factory->implementation = g_type;
616 : :
617 : 628 : g_hash_table_insert (connection_factories,
618 : : factory, factory);
619 : :
620 : 628 : G_UNLOCK (connection_factories);
621 : : }
622 : :
623 : : static void
624 : 1903 : init_builtin_types (void)
625 : : {
626 : 1903 : g_type_ensure (G_TYPE_UNIX_CONNECTION);
627 : 1903 : g_type_ensure (G_TYPE_TCP_CONNECTION);
628 : 1903 : }
629 : :
630 : : /**
631 : : * g_socket_connection_factory_lookup_type:
632 : : * @family: a #GSocketFamily
633 : : * @type: a #GSocketType
634 : : * @protocol_id: a protocol id
635 : : *
636 : : * Looks up the #GType to be used when creating socket connections on
637 : : * sockets with the specified @family, @type and @protocol_id.
638 : : *
639 : : * If no type is registered, the #GSocketConnection base type is returned.
640 : : *
641 : : * Returns: a #GType
642 : : *
643 : : * Since: 2.22
644 : : */
645 : : GType
646 : 1903 : g_socket_connection_factory_lookup_type (GSocketFamily family,
647 : : GSocketType type,
648 : : gint protocol_id)
649 : : {
650 : : ConnectionFactory *factory, key;
651 : : GType g_type;
652 : :
653 : 1903 : init_builtin_types ();
654 : :
655 : 1903 : G_LOCK (connection_factories);
656 : :
657 : 1903 : g_type = G_TYPE_SOCKET_CONNECTION;
658 : :
659 : 1903 : if (connection_factories)
660 : : {
661 : 1903 : key.socket_family = family;
662 : 1903 : key.socket_type = type;
663 : 1903 : key.protocol = protocol_id;
664 : :
665 : 1903 : factory = g_hash_table_lookup (connection_factories, &key);
666 : 1903 : if (factory)
667 : 1903 : g_type = factory->implementation;
668 : : }
669 : :
670 : 1903 : G_UNLOCK (connection_factories);
671 : :
672 : 1903 : return g_type;
673 : : }
674 : :
675 : : /**
676 : : * g_socket_connection_factory_create_connection:
677 : : * @socket: a #GSocket
678 : : *
679 : : * Creates a #GSocketConnection subclass of the right type for
680 : : * @socket.
681 : : *
682 : : * Returns: (transfer full): a #GSocketConnection
683 : : *
684 : : * Since: 2.22
685 : : */
686 : : GSocketConnection *
687 : 1903 : g_socket_connection_factory_create_connection (GSocket *socket)
688 : : {
689 : : GType type;
690 : :
691 : 1903 : type = g_socket_connection_factory_lookup_type (g_socket_get_family (socket),
692 : : g_socket_get_socket_type (socket),
693 : 1903 : g_socket_get_protocol (socket));
694 : 1903 : return g_object_new (type, "socket", socket, NULL);
695 : : }
|