1 /* GIO - GLib Input, Output and Streaming Library
3 * Copyright © 2009 Codethink Limited
4 * Copyright © 2009 Red Hat, Inc
6 * SPDX-License-Identifier: LGPL-2.1-or-later
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General
19 * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
21 * Authors: Ryan Lortie <desrt@desrt.ca>
22 * Alexander Larsson <alexl@redhat.com>
26 * SECTION:gsocketservice
27 * @title: GSocketService
28 * @short_description: Make it easy to implement a network service
30 * @see_also: #GThreadedSocketService, #GSocketListener.
32 * A #GSocketService is an object that represents a service that
33 * is provided to the network or over local sockets. When a new
34 * connection is made to the service the #GSocketService::incoming
37 * A #GSocketService is a subclass of #GSocketListener and you need
38 * to add the addresses you want to accept connections on with the
39 * #GSocketListener APIs.
41 * There are two options for implementing a network service based on
42 * #GSocketService. The first is to create the service using
43 * g_socket_service_new() and to connect to the #GSocketService::incoming
44 * signal. The second is to subclass #GSocketService and override the
45 * default signal handler implementation.
47 * In either case, the handler must immediately return, or else it
48 * will block additional incoming connections from being serviced.
49 * If you are interested in writing connection handlers that contain
50 * blocking code then see #GThreadedSocketService.
52 * The socket service runs on the main loop of the
53 * [thread-default context][g-main-context-push-thread-default-context]
54 * of the thread it is created in, and is not
55 * threadsafe in general. However, the calls to start and stop the
56 * service are thread-safe so these can be used from threads that
57 * handle incoming clients.
63 #include "gsocketservice.h"
66 #include "gsocketlistener.h"
67 #include "gsocketconnection.h"
69 #include "gmarshal-internal.h"
71 struct _GSocketServicePrivate
73 GCancellable *cancellable;
75 guint outstanding_accept : 1;
78 static guint g_socket_service_incoming_signal;
80 G_LOCK_DEFINE_STATIC(active);
82 G_DEFINE_TYPE_WITH_PRIVATE (GSocketService, g_socket_service, G_TYPE_SOCKET_LISTENER)
90 static void g_socket_service_ready (GObject *object,
95 g_socket_service_real_incoming (GSocketService *service,
96 GSocketConnection *connection,
97 GObject *source_object)
103 g_socket_service_init (GSocketService *service)
105 service->priv = g_socket_service_get_instance_private (service);
106 service->priv->cancellable = g_cancellable_new ();
107 service->priv->active = TRUE;
111 g_socket_service_finalize (GObject *object)
113 GSocketService *service = G_SOCKET_SERVICE (object);
115 g_object_unref (service->priv->cancellable);
117 G_OBJECT_CLASS (g_socket_service_parent_class)
122 do_accept (GSocketService *service)
124 g_socket_listener_accept_async (G_SOCKET_LISTENER (service),
125 service->priv->cancellable,
126 g_socket_service_ready, NULL);
127 service->priv->outstanding_accept = TRUE;
131 get_active (GSocketService *service)
136 active = service->priv->active;
143 set_active (GSocketService *service, gboolean active)
145 gboolean notify = FALSE;
151 if (active != service->priv->active)
153 service->priv->active = active;
158 if (service->priv->outstanding_accept)
159 g_cancellable_cancel (service->priv->cancellable);
165 if (service->priv->outstanding_accept)
166 g_cancellable_cancel (service->priv->cancellable);
173 g_object_notify (G_OBJECT (service), "active");
177 g_socket_service_get_property (GObject *object,
182 GSocketService *service = G_SOCKET_SERVICE (object);
187 g_value_set_boolean (value, get_active (service));
190 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
196 g_socket_service_set_property (GObject *object,
201 GSocketService *service = G_SOCKET_SERVICE (object);
206 set_active (service, g_value_get_boolean (value));
209 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215 g_socket_service_changed (GSocketListener *listener)
217 GSocketService *service = G_SOCKET_SERVICE (listener);
221 if (service->priv->active)
223 if (service->priv->outstanding_accept)
224 g_cancellable_cancel (service->priv->cancellable);
233 * g_socket_service_is_active:
234 * @service: a #GSocketService
236 * Check whether the service is active or not. An active
237 * service will accept new clients that connect, while
238 * a non-active service will let connecting clients queue
239 * up until the service is started.
241 * Returns: %TRUE if the service is active, %FALSE otherwise
246 g_socket_service_is_active (GSocketService *service)
248 g_return_val_if_fail (G_IS_SOCKET_SERVICE (service), FALSE);
250 return get_active (service);
254 * g_socket_service_start:
255 * @service: a #GSocketService
257 * Restarts the service, i.e. start accepting connections
258 * from the added sockets when the mainloop runs. This only needs
259 * to be called after the service has been stopped from
260 * g_socket_service_stop().
262 * This call is thread-safe, so it may be called from a thread
263 * handling an incoming client request.
268 g_socket_service_start (GSocketService *service)
270 g_return_if_fail (G_IS_SOCKET_SERVICE (service));
272 set_active (service, TRUE);
276 * g_socket_service_stop:
277 * @service: a #GSocketService
279 * Stops the service, i.e. stops accepting connections
280 * from the added sockets when the mainloop runs.
282 * This call is thread-safe, so it may be called from a thread
283 * handling an incoming client request.
285 * Note that this only stops accepting new connections; it does not
286 * close the listening sockets, and you can call
287 * g_socket_service_start() again later to begin listening again. To
288 * close the listening sockets, call g_socket_listener_close(). (This
289 * will happen automatically when the #GSocketService is finalized.)
291 * This must be called before calling g_socket_listener_close() as
292 * the socket service will start accepting connections immediately
293 * when a new socket is added.
298 g_socket_service_stop (GSocketService *service)
300 g_return_if_fail (G_IS_SOCKET_SERVICE (service));
302 set_active (service, FALSE);
306 g_socket_service_incoming (GSocketService *service,
307 GSocketConnection *connection,
308 GObject *source_object)
312 g_signal_emit (service, g_socket_service_incoming_signal,
313 0, connection, source_object, &result);
318 g_socket_service_class_init (GSocketServiceClass *class)
320 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
321 GSocketListenerClass *listener_class = G_SOCKET_LISTENER_CLASS (class);
323 gobject_class->finalize = g_socket_service_finalize;
324 gobject_class->set_property = g_socket_service_set_property;
325 gobject_class->get_property = g_socket_service_get_property;
326 listener_class->changed = g_socket_service_changed;
327 class->incoming = g_socket_service_real_incoming;
330 * GSocketService::incoming:
331 * @service: the #GSocketService
332 * @connection: a new #GSocketConnection object
333 * @source_object: (nullable): the source_object passed to
334 * g_socket_listener_add_address()
336 * The ::incoming signal is emitted when a new incoming connection
337 * to @service needs to be handled. The handler must initiate the
338 * handling of @connection, but may not block; in essence,
339 * asynchronous operations must be used.
341 * @connection will be unreffed once the signal handler returns,
342 * so you need to ref it yourself if you are planning to use it.
344 * Returns: %TRUE to stop other handlers from being called
348 g_socket_service_incoming_signal =
349 g_signal_new (I_("incoming"), G_TYPE_FROM_CLASS (class), G_SIGNAL_RUN_LAST,
350 G_STRUCT_OFFSET (GSocketServiceClass, incoming),
351 g_signal_accumulator_true_handled, NULL,
352 _g_cclosure_marshal_BOOLEAN__OBJECT_OBJECT,
354 2, G_TYPE_SOCKET_CONNECTION, G_TYPE_OBJECT);
355 g_signal_set_va_marshaller (g_socket_service_incoming_signal,
356 G_TYPE_FROM_CLASS (class),
357 _g_cclosure_marshal_BOOLEAN__OBJECT_OBJECTv);
360 * GSocketService:active:
362 * Whether the service is currently accepting connections.
366 g_object_class_install_property (gobject_class, PROP_ACTIVE,
367 g_param_spec_boolean ("active",
369 P_("Whether the service is currently accepting connections"),
371 G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
375 g_socket_service_ready (GObject *object,
376 GAsyncResult *result,
379 GSocketListener *listener = G_SOCKET_LISTENER (object);
380 GSocketService *service = G_SOCKET_SERVICE (object);
381 GSocketConnection *connection;
382 GObject *source_object;
383 GError *error = NULL;
385 connection = g_socket_listener_accept_finish (listener, result, &source_object, &error);
388 if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
389 g_warning ("fail: %s", error->message);
390 g_error_free (error);
394 g_socket_service_incoming (service, connection, source_object);
395 g_object_unref (connection);
400 g_cancellable_reset (service->priv->cancellable);
403 service->priv->outstanding_accept = FALSE;
404 if (service->priv->active)
411 * g_socket_service_new:
413 * Creates a new #GSocketService with no sockets to listen for.
414 * New listeners can be added with e.g. g_socket_listener_add_address()
415 * or g_socket_listener_add_inet_port().
417 * New services are created active, there is no need to call
418 * g_socket_service_start(), unless g_socket_service_stop() has been
421 * Returns: a new #GSocketService.
426 g_socket_service_new (void)
428 return g_object_new (G_TYPE_SOCKET_SERVICE, NULL);