Change LGPL-2.1+ to LGPL-2.1-or-later
[platform/upstream/glib.git] / gio / gsocketservice.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2009 Codethink Limited
4  * Copyright © 2009 Red Hat, Inc
5  *
6  * SPDX-License-Identifier: LGPL-2.1-or-later
7  *
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.
12  *
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.
17  *
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/>.
20  *
21  * Authors: Ryan Lortie <desrt@desrt.ca>
22  *          Alexander Larsson <alexl@redhat.com>
23  */
24
25 /**
26  * SECTION:gsocketservice
27  * @title: GSocketService
28  * @short_description: Make it easy to implement a network service
29  * @include: gio/gio.h
30  * @see_also: #GThreadedSocketService, #GSocketListener.
31  *
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
35  * signal is emitted.
36  *
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.
40  *
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.
46  *
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.
51  *
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.
58  *
59  * Since: 2.22
60  */
61
62 #include "config.h"
63 #include "gsocketservice.h"
64
65 #include <gio/gio.h>
66 #include "gsocketlistener.h"
67 #include "gsocketconnection.h"
68 #include "glibintl.h"
69 #include "gmarshal-internal.h"
70
71 struct _GSocketServicePrivate
72 {
73   GCancellable *cancellable;
74   guint active : 1;
75   guint outstanding_accept : 1;
76 };
77
78 static guint g_socket_service_incoming_signal;
79
80 G_LOCK_DEFINE_STATIC(active);
81
82 G_DEFINE_TYPE_WITH_PRIVATE (GSocketService, g_socket_service, G_TYPE_SOCKET_LISTENER)
83
84 enum
85 {
86   PROP_0,
87   PROP_ACTIVE
88 };
89
90 static void g_socket_service_ready (GObject      *object,
91                                     GAsyncResult *result,
92                                     gpointer      user_data);
93
94 static gboolean
95 g_socket_service_real_incoming (GSocketService    *service,
96                                 GSocketConnection *connection,
97                                 GObject           *source_object)
98 {
99   return FALSE;
100 }
101
102 static void
103 g_socket_service_init (GSocketService *service)
104 {
105   service->priv = g_socket_service_get_instance_private (service);
106   service->priv->cancellable = g_cancellable_new ();
107   service->priv->active = TRUE;
108 }
109
110 static void
111 g_socket_service_finalize (GObject *object)
112 {
113   GSocketService *service = G_SOCKET_SERVICE (object);
114
115   g_object_unref (service->priv->cancellable);
116
117   G_OBJECT_CLASS (g_socket_service_parent_class)
118     ->finalize (object);
119 }
120
121 static void
122 do_accept (GSocketService  *service)
123 {
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;
128 }
129
130 static gboolean
131 get_active (GSocketService *service)
132 {
133   gboolean active;
134
135   G_LOCK (active);
136   active = service->priv->active;
137   G_UNLOCK (active);
138
139   return active;
140 }
141
142 static void
143 set_active (GSocketService *service, gboolean active)
144 {
145   gboolean notify = FALSE;
146
147   active = !!active;
148
149   G_LOCK (active);
150
151   if (active != service->priv->active)
152     {
153       service->priv->active = active;
154       notify = TRUE;
155
156       if (active)
157         {
158           if (service->priv->outstanding_accept)
159             g_cancellable_cancel (service->priv->cancellable);
160           else
161             do_accept (service);
162         }
163       else
164         {
165           if (service->priv->outstanding_accept)
166             g_cancellable_cancel (service->priv->cancellable);
167         }
168     }
169
170   G_UNLOCK (active);
171
172   if (notify)
173     g_object_notify (G_OBJECT (service), "active");
174 }
175
176 static void
177 g_socket_service_get_property (GObject    *object,
178                                guint       prop_id,
179                                GValue     *value,
180                                GParamSpec *pspec)
181 {
182   GSocketService *service = G_SOCKET_SERVICE (object);
183
184   switch (prop_id)
185     {
186     case PROP_ACTIVE:
187       g_value_set_boolean (value, get_active (service));
188       break;
189     default:
190       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
191       break;
192     }
193 }
194
195 static void
196 g_socket_service_set_property (GObject      *object,
197                                guint         prop_id,
198                                const GValue *value,
199                                GParamSpec   *pspec)
200 {
201   GSocketService *service = G_SOCKET_SERVICE (object);
202
203   switch (prop_id)
204     {
205     case PROP_ACTIVE:
206       set_active (service, g_value_get_boolean (value));
207       break;
208     default:
209       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
210       break;
211     }
212 }
213
214 static void
215 g_socket_service_changed (GSocketListener *listener)
216 {
217   GSocketService  *service = G_SOCKET_SERVICE (listener);
218
219   G_LOCK (active);
220
221   if (service->priv->active)
222     {
223       if (service->priv->outstanding_accept)
224         g_cancellable_cancel (service->priv->cancellable);
225       else
226         do_accept (service);
227     }
228
229   G_UNLOCK (active);
230 }
231
232 /**
233  * g_socket_service_is_active:
234  * @service: a #GSocketService
235  *
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.
240  *
241  * Returns: %TRUE if the service is active, %FALSE otherwise
242  *
243  * Since: 2.22
244  */
245 gboolean
246 g_socket_service_is_active (GSocketService *service)
247 {
248   g_return_val_if_fail (G_IS_SOCKET_SERVICE (service), FALSE);
249
250   return get_active (service);
251 }
252
253 /**
254  * g_socket_service_start:
255  * @service: a #GSocketService
256  *
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().
261  *
262  * This call is thread-safe, so it may be called from a thread
263  * handling an incoming client request.
264  *
265  * Since: 2.22
266  */
267 void
268 g_socket_service_start (GSocketService *service)
269 {
270   g_return_if_fail (G_IS_SOCKET_SERVICE (service));
271
272   set_active (service, TRUE);
273 }
274
275 /**
276  * g_socket_service_stop:
277  * @service: a #GSocketService
278  *
279  * Stops the service, i.e. stops accepting connections
280  * from the added sockets when the mainloop runs.
281  *
282  * This call is thread-safe, so it may be called from a thread
283  * handling an incoming client request.
284  *
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.)
290  *
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.
294  *
295  * Since: 2.22
296  */
297 void
298 g_socket_service_stop (GSocketService *service)
299 {
300   g_return_if_fail (G_IS_SOCKET_SERVICE (service));
301
302   set_active (service, FALSE);
303 }
304
305 static gboolean
306 g_socket_service_incoming (GSocketService    *service,
307                            GSocketConnection *connection,
308                            GObject           *source_object)
309 {
310   gboolean result;
311
312   g_signal_emit (service, g_socket_service_incoming_signal,
313                  0, connection, source_object, &result);
314   return result;
315 }
316
317 static void
318 g_socket_service_class_init (GSocketServiceClass *class)
319 {
320   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
321   GSocketListenerClass *listener_class = G_SOCKET_LISTENER_CLASS (class);
322
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;
328
329   /**
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()
335    *
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.
340    *
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.
343    *
344    * Returns: %TRUE to stop other handlers from being called
345    *
346    * Since: 2.22
347    */
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,
353                   G_TYPE_BOOLEAN,
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);
358
359   /**
360    * GSocketService:active:
361    *
362    * Whether the service is currently accepting connections.
363    *
364    * Since: 2.46
365    */
366   g_object_class_install_property (gobject_class, PROP_ACTIVE,
367                                    g_param_spec_boolean ("active",
368                                                          P_("Active"),
369                                                          P_("Whether the service is currently accepting connections"),
370                                                          TRUE,
371                                                          G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
372 }
373
374 static void
375 g_socket_service_ready (GObject      *object,
376                         GAsyncResult *result,
377                         gpointer      user_data)
378 {
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;
384
385   connection = g_socket_listener_accept_finish (listener, result, &source_object, &error);
386   if (error)
387     {
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);
391     }
392   else
393     {
394       g_socket_service_incoming (service, connection, source_object);
395       g_object_unref (connection);
396     }
397
398   G_LOCK (active);
399
400   g_cancellable_reset (service->priv->cancellable);
401
402   /* requeue */
403   service->priv->outstanding_accept = FALSE;
404   if (service->priv->active)
405     do_accept (service);
406
407   G_UNLOCK (active);
408 }
409
410 /**
411  * g_socket_service_new:
412  *
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().
416  *
417  * New services are created active, there is no need to call
418  * g_socket_service_start(), unless g_socket_service_stop() has been
419  * called before.
420  *
421  * Returns: a new #GSocketService.
422  *
423  * Since: 2.22
424  */
425 GSocketService *
426 g_socket_service_new (void)
427 {
428   return g_object_new (G_TYPE_SOCKET_SERVICE, NULL);
429 }