Set the listen backlog before calling listen.
[platform/upstream/glib.git] / gio / gsocketlistener.c
1 /* GIO - GLib Input, Output and Streaming Library
2  *
3  * Copyright © 2008 Christian Kellner, Samuel Cormier-Iijima
4  * Copyright © 2009 codethink
5  * Copyright © 2009 Red Hat, Inc
6  *
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.
11  *
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.
16  *
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.
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 #include "gsocketlistener.h"
30
31 #include <gio/gsimpleasyncresult.h>
32 #include <gio/gcancellable.h>
33 #include <gio/gsocketaddress.h>
34 #include <gio/ginetaddress.h>
35 #include <gio/gioerror.h>
36 #include <gio/gsocket.h>
37 #include <gio/gsocketconnection.h>
38 #include <gio/ginetsocketaddress.h>
39 #include "glibintl.h"
40
41 #include "gioalias.h"
42
43 /**
44  * SECTION: gsocketlistener
45  * @title: GSocketListener
46  * @short_description: Helper for accepting network client connections
47  * @see_also: #GThreadedSocketService, #GSocketService.
48  *
49  * A #GSocketListener is an object that keeps track of a set
50  * of server sockets and helps you accept sockets from any of the
51  * socket, either sync or async.
52  *
53  * If you want to implement a network server, also look at #GSocketService
54  * and #GThreadedSocketService which are subclass of #GSocketListener
55  * that makes this even easier.
56  *
57  * Since: 2.22
58  */
59
60 G_DEFINE_TYPE (GSocketListener, g_socket_listener, G_TYPE_OBJECT);
61
62 enum
63 {
64   PROP_0,
65   PROP_LISTEN_BACKLOG
66 };
67
68
69 static GQuark source_quark = 0;
70
71 struct _GSocketListenerPrivate
72 {
73   GPtrArray           *sockets;
74   GMainContext        *main_context;
75   int                 listen_backlog;
76   guint               closed : 1;
77 };
78
79 static void
80 g_socket_listener_finalize (GObject *object)
81 {
82   GSocketListener *listener = G_SOCKET_LISTENER (object);
83
84   if (listener->priv->main_context)
85     g_main_context_unref (listener->priv->main_context);
86
87   if (!listener->priv->closed)
88     g_socket_listener_close (listener);
89
90   g_ptr_array_free (listener->priv->sockets, TRUE);
91
92   G_OBJECT_CLASS (g_socket_listener_parent_class)
93     ->finalize (object);
94 }
95
96 static void
97 g_socket_listener_get_property (GObject    *object,
98                                 guint       prop_id,
99                                 GValue     *value,
100                                 GParamSpec *pspec)
101 {
102   GSocketListener *listener = G_SOCKET_LISTENER (object);
103
104   switch (prop_id)
105     {
106       case PROP_LISTEN_BACKLOG:
107         g_value_set_int (value, listener->priv->listen_backlog);
108         break;
109
110       default:
111         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
112     }
113 }
114
115 static void
116 g_socket_listener_set_property (GObject      *object,
117                                 guint         prop_id,
118                                 const GValue *value,
119                                 GParamSpec   *pspec)
120 {
121   GSocketListener *listener = G_SOCKET_LISTENER (object);
122
123   switch (prop_id)
124     {
125       case PROP_LISTEN_BACKLOG:
126         g_socket_listener_set_backlog (listener, g_value_get_int (value));
127         break;
128
129       default:
130         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
131     }
132 }
133
134
135 static void
136 g_socket_listener_class_init (GSocketListenerClass *klass)
137 {
138   GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass);
139
140   g_type_class_add_private (klass, sizeof (GSocketListenerPrivate));
141
142   gobject_class->finalize = g_socket_listener_finalize;
143   gobject_class->set_property = g_socket_listener_set_property;
144   gobject_class->get_property = g_socket_listener_get_property;
145   g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG,
146                                    g_param_spec_int ("listen-backlog",
147                                                      P_("Listen backlog"),
148                                                      P_("outstanding connections in the listen queue"),
149                                                      0,
150                                                      2000,
151                                                      10,
152                                                      G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
153
154   source_quark = g_quark_from_static_string ("g-socket-listener-source");
155 }
156
157 static void
158 g_socket_listener_init (GSocketListener *listener)
159 {
160   listener->priv = G_TYPE_INSTANCE_GET_PRIVATE (listener,
161                                                 G_TYPE_SOCKET_LISTENER,
162                                                 GSocketListenerPrivate);
163   listener->priv->sockets =
164     g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
165   listener->priv->listen_backlog = 10;
166 }
167
168 /**
169  * g_socket_listener_new:
170  *
171  * Creates a new #GSocketListener with no sockets to listen for.
172  * New listeners can be added with e.g. g_socket_listener_add_address()
173  * or g_socket_listener_add_inet_port().
174  *
175  * Returns: a new #GSocketListener.
176  *
177  * Since: 2.22
178  **/
179 GSocketListener *
180 g_socket_listener_new (void)
181 {
182   return g_object_new (G_TYPE_SOCKET_LISTENER, NULL);
183 }
184
185 static gboolean
186 check_listener (GSocketListener *listener,
187                 GError **error)
188 {
189   if (listener->priv->closed)
190     {
191       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED,
192                            _("Listener is already closed"));
193       return FALSE;
194     }
195
196   return TRUE;
197 }
198
199 /**
200  * g_socket_listener_add_socket:
201  * @listener: a #GSocketListener
202  * @socket: a listening #GSocket
203  * @source_object: Optional #GObject identifying this source
204  * @error: #GError for error reporting, or %NULL to ignore.
205  *
206  * Adds @socket to the set of sockets that we try to accept
207  * new clients from. The socket must be bound to a local
208  * address and listened to.
209  *
210  * @source_object will be passed out in the various calls
211  * to accept to identify this particular source, which is
212  * useful if you're listening on multiple addresses and do
213  * different things depending on what address is connected to.
214  *
215  * Returns: %TRUE on success, %FALSE on error.
216  *
217  * Since: 2.22
218  **/
219 gboolean
220 g_socket_listener_add_socket (GSocketListener *listener,
221                               GSocket *socket,
222                               GObject *source_object,
223                               GError **error)
224 {
225   if (!check_listener (listener, error))
226     return FALSE;
227
228   /* TODO: Check that socket it is bound & not closed? */
229
230   if (g_socket_is_closed (socket))
231     {
232       g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED,
233                            _("Added socket is closed"));
234       return FALSE;
235     }
236
237   g_ptr_array_add (listener->priv->sockets, socket);
238
239   if (source_object)
240     g_object_set_qdata_full (G_OBJECT (socket), source_quark,
241                              g_object_ref (source_object), g_object_unref);
242
243   return TRUE;
244 }
245
246 /**
247  * g_socket_listener_add_address:
248  * @listener: a #GSocketListener
249  * @address: a #GSocketAddres
250  * @type: a #GSocketType
251  * @protocol: a protocol name, or %NULL
252  * @source_object: Optional #GObject identifying this source
253  * @error: #GError for error reporting, or %NULL to ignore.
254  *
255  * Creates a socket of type @type and protocol @protocol, binds
256  * it to @address and adds it to the set of sockets we're accepting
257  * sockets from.
258  *
259  * @source_object will be passed out in the various calls
260  * to accept to identify this particular source, which is
261  * useful if you're listening on multiple addresses and do
262  * different things depending on what address is connected to.
263  *
264  * Returns: %TRUE on success, %FALSE on error.
265  *
266  * Since: 2.22
267  **/
268 gboolean
269 g_socket_listener_add_address (GSocketListener *listener,
270                                GSocketAddress *address,
271                                GSocketType type,
272                                const char *protocol,
273                                GObject *source_object,
274                                GError **error)
275 {
276   GSocketFamily family;
277   GSocket *socket;
278
279   if (!check_listener (listener, error))
280     return FALSE;
281
282   family = g_socket_address_get_family (address);
283   socket = g_socket_new (family, type,
284                          g_socket_protocol_id_lookup_by_name (protocol), error);
285   if (socket == NULL)
286     return FALSE;
287
288   g_socket_set_listen_backlog (socket, listener->priv->listen_backlog);
289
290   if (!g_socket_bind (socket, address, TRUE, error) ||
291       !g_socket_listen (socket, error) ||
292       !g_socket_listener_add_socket (listener, socket,
293                                      source_object,
294                                      error))
295     {
296       g_object_unref (socket);
297       return FALSE;
298     }
299
300   if (G_SOCKET_LISTENER_GET_CLASS (listener)->changed)
301     G_SOCKET_LISTENER_GET_CLASS (listener)->changed (listener);
302
303   return TRUE;
304 }
305
306 /**
307  * g_socket_listener_add_inet_port:
308  * @listener: a #GSocketListener
309  * @port: an ip port number
310  * @source_object: Optional #GObject identifying this source
311  * @error: #GError for error reporting, or %NULL to ignore.
312  *
313  * Helper function for g_socket_listener_add_address() that
314  * creates a TCP/IP socket listening on IPv4 and IPv6 (if
315  * supported) on the specified port on all interfaces.
316  *
317  * @source_object will be passed out in the various calls
318  * to accept to identify this particular source, which is
319  * useful if you're listening on multiple addresses and do
320  * different things depending on what address is connected to.
321  *
322  * Returns: %TRUE on success, %FALSE on error.
323  *
324  * Since: 2.22
325  **/
326 gboolean
327 g_socket_listener_add_inet_port (GSocketListener *listener,
328                                  int port,
329                                  GObject *source_object,
330                                  GError **error)
331 {
332   GSocketAddress *address4, *address6;
333   GInetAddress *inet_address;
334   gboolean res;
335
336   if (!check_listener (listener, error))
337     return FALSE;
338
339   inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4);
340   address4 = g_inet_socket_address_new (inet_address, port);
341   g_object_unref (inet_address);
342
343   inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6);
344   address6 = g_inet_socket_address_new (inet_address, port);
345   g_object_unref (inet_address);
346
347   if (!g_socket_listener_add_address (listener,
348                                       address6,
349                                       G_SOCKET_TYPE_STREAM,
350                                       NULL,
351                                       source_object,
352                                       NULL))
353     {
354       /* Failed, to create ipv6, socket, just use ipv4,
355          return any error */
356       res = g_socket_listener_add_address (listener,
357                                            address4,
358                                            G_SOCKET_TYPE_STREAM,
359                                            NULL,
360                                            source_object,
361                                            error);
362     }
363   else
364     {
365       /* Succeeded with ipv6, also try ipv4 in case its ipv6 only,
366          but ignore errors here */
367       res = TRUE;
368       g_socket_listener_add_address (listener,
369                                      address4,
370                                      G_SOCKET_TYPE_STREAM,
371                                      NULL,
372                                      source_object,
373                                      NULL);
374     }
375
376   g_object_unref (address4);
377   g_object_unref (address6);
378
379   return res;
380 }
381
382 static GList *
383 add_sources (GSocketListener *listener,
384              GSocketSourceFunc callback,
385              gpointer callback_data,
386              GCancellable *cancellable,
387              GMainContext *context)
388 {
389   GSocket *socket;
390   GSource *source;
391   GList *sources;
392   int i;
393
394   sources = NULL;
395   for (i = 0; i < listener->priv->sockets->len; i++)
396     {
397       socket = listener->priv->sockets->pdata[i];
398
399       source = g_socket_create_source (socket, G_IO_IN, cancellable);
400       g_source_set_callback (source,
401                              (GSourceFunc) callback,
402                              callback_data, NULL);
403       g_source_attach (source, context);
404
405       sources = g_list_prepend (sources, source);
406     }
407
408   return sources;
409 }
410
411 static void
412 free_sources (GList *sources)
413 {
414   GSource *source;
415   while (sources != NULL)
416     {
417       source = sources->data;
418       sources = g_list_delete_link (sources, sources);
419       g_source_destroy (source);
420       g_source_unref (source);
421     }
422 }
423
424 struct AcceptData {
425   GMainLoop *loop;
426   GSocket *socket;
427 };
428
429 static gboolean
430 accept_callback (GSocket *socket,
431                  GIOCondition condition,
432                  gpointer user_data)
433 {
434   struct AcceptData *data = user_data;
435
436   data->socket = socket;
437   g_main_loop_quit (data->loop);
438
439   return TRUE;
440 }
441
442 /**
443  * g_socket_listener_accept_socket:
444  * @listener: a #GSocketListener
445  * @source_object: location where #GObject pointer will be stored, or %NULL
446  * @cancellable: optional #GCancellable object, %NULL to ignore.
447  * @error: #GError for error reporting, or %NULL to ignore.
448  *
449  * Blocks waiting for a client to connect to any of the sockets added
450  * to the listener. Returns the #GSocket that was accepted.
451  *
452  * If you want to accept the high-level #GSocketConnection, not a #GSocket,
453  * which is often the case, then you should use g_socket_listener_accept()
454  * instead.
455  *
456  * If @source_object is not %NULL it will be filled out with the source
457  * object specified when the corresponding socket or address was added
458  * to the listener.
459  *
460  * If @cancellable is not NULL, then the operation can be cancelled by
461  * triggering the cancellable object from another thread. If the operation
462  * was cancelled, the error G_IO_ERROR_CANCELLED will be returned.
463  *
464  * Returns: a #GSocket on success, %NULL on error.
465  *
466  * Since: 2.22
467  **/
468 GSocket *
469 g_socket_listener_accept_socket (GSocketListener  *listener,
470                                  GObject         **source_object,
471                                  GCancellable     *cancellable,
472                                  GError          **error)
473 {
474   GSocket *accept_socket, *socket;
475
476   g_return_val_if_fail (G_IS_SOCKET_LISTENER (listener), NULL);
477
478   if (!check_listener (listener, error))
479     return NULL;
480
481   if (listener->priv->sockets->len == 1)
482     {
483       accept_socket = listener->priv->sockets->pdata[0];
484       if (!g_socket_condition_wait (accept_socket, G_IO_IN,
485                                     cancellable, error))
486         return NULL;
487     }
488   else
489     {
490       GList *sources;
491       struct AcceptData data;
492       GMainLoop *loop;
493
494       if (listener->priv->main_context == NULL)
495         listener->priv->main_context = g_main_context_new ();
496
497       loop = g_main_loop_new (listener->priv->main_context, FALSE);
498       data.loop = loop;
499       sources = add_sources (listener,
500                              accept_callback,
501                              &data,
502                              cancellable,
503                              listener->priv->main_context);
504       g_main_loop_run (loop);
505       accept_socket = data.socket;
506       free_sources (sources);
507       g_main_loop_unref (loop);
508     }
509
510   if (!(socket = g_socket_accept (accept_socket, error)))
511     return NULL;
512
513   if (source_object)
514     *source_object = g_object_get_qdata (G_OBJECT (accept_socket), source_quark);
515
516   return socket;
517 }
518
519 /**
520  * g_socket_listener_accept:
521  * @listener: a #GSocketListener
522  * @source_object: location where #GObject pointer will be stored, or %NULL
523  * @cancellable: optional #GCancellable object, %NULL to ignore.
524  * @error: #GError for error reporting, or %NULL to ignore.
525  *
526  * Blocks waiting for a client to connect to any of the sockets added
527  * to the listener. Returns a #GSocketConnection for the socket that was
528  * accepted.
529  *
530  * If @source_object is not %NULL it will be filled out with the source
531  * object specified when the corresponding socket or address was added
532  * to the listener.
533  *
534  * If @cancellable is not NULL, then the operation can be cancelled by
535  * triggering the cancellable object from another thread. If the operation
536  * was cancelled, the error G_IO_ERROR_CANCELLED will be returned.
537  *
538  * Returns: a #GSocketConnection on success, %NULL on error.
539  *
540  * Since: 2.22
541  **/
542 GSocketConnection *
543 g_socket_listener_accept (GSocketListener  *listener,
544                           GObject         **source_object,
545                           GCancellable     *cancellable,
546                           GError          **error)
547 {
548   GSocketConnection *connection;
549   GSocket *socket;
550
551   socket = g_socket_listener_accept_socket (listener,
552                                             source_object,
553                                             cancellable,
554                                             error);
555   if (socket == NULL)
556     return NULL;
557
558   connection = g_socket_connection_factory_create_connection (socket);
559   g_object_unref (socket);
560
561   return connection;
562 }
563
564 struct AcceptAsyncData {
565   GSimpleAsyncResult *simple;
566   GCancellable *cancellable;
567   GList *sources;
568 };
569
570 static gboolean
571 accept_ready (GSocket *accept_socket,
572               GIOCondition condition,
573               gpointer _data)
574 {
575   struct AcceptAsyncData *data = _data;
576   GError *error = NULL;
577
578   if (!g_cancellable_set_error_if_cancelled (data->cancellable,
579                                              &error))
580     {
581       GSocket *socket;
582       GObject *source_object;
583
584       socket = g_socket_accept (accept_socket, &error);
585       if (socket)
586         {
587           g_simple_async_result_set_op_res_gpointer (data->simple, socket,
588                                                      g_object_unref);
589           source_object = g_object_get_qdata (G_OBJECT (accept_socket), source_quark);
590           if (source_object)
591             g_object_set_qdata_full (G_OBJECT (data->simple),
592                                      source_quark,
593                                      g_object_ref (source_object), g_object_unref);
594         }
595     }
596
597   if (error)
598     {
599       g_simple_async_result_set_from_error (data->simple, error);
600       g_error_free (error);
601     }
602
603   g_simple_async_result_complete_in_idle (data->simple);
604   g_object_unref (data->simple);
605   free_sources (data->sources);
606   g_free (data);
607
608   return FALSE;
609 }
610
611 /**
612  * g_socket_listener_accept_socket_async:
613  * @listener: a #GSocketListener
614  * @cancellable: a #GCancellable, or %NULL
615  * @callback: a #GAsyncReadyCallback
616  * @user_data: user data for the callback
617  *
618  * This is the asynchronous version of g_socket_listener_accept_socket().
619  *
620  * When the operation is finished @callback will be
621  * called. You can then call g_socket_listener_accept_socket_finish() to get
622  * the result of the operation.
623  *
624  * Since: 2.22
625  **/
626 void
627 g_socket_listener_accept_socket_async (GSocketListener      *listener,
628                                        GCancellable         *cancellable,
629                                        GAsyncReadyCallback   callback,
630                                        gpointer              user_data)
631 {
632   struct AcceptAsyncData *data;
633   GError *error = NULL;
634
635   if (!check_listener (listener, &error))
636     {
637       g_simple_async_report_gerror_in_idle (G_OBJECT (listener),
638                                             callback, user_data,
639                                             error);
640       g_error_free (error);
641       return;
642     }
643
644   data = g_new0 (struct AcceptAsyncData, 1);
645   data->simple = g_simple_async_result_new (G_OBJECT (listener),
646                                             callback, user_data,
647                                             g_socket_listener_accept_socket_async);
648   data->cancellable = cancellable;
649   data->sources = add_sources (listener,
650                                accept_ready,
651                                data,
652                                cancellable,
653                                NULL);
654 }
655
656 /**
657  * g_socket_listener_accept_socket_finish:
658  * @listener: a #GSocketListener
659  * @result: a #GAsyncResult.
660  * @source_object: Optional #GObject identifying this source
661  * @error: a #GError location to store the error occuring, or %NULL to
662  * ignore.
663  *
664  * Finishes an async accept operation. See g_socket_listener_accept_socket_async()
665  *
666  * Returns: a #GSocket on success, %NULL on error.
667  *
668  * Since: 2.22
669  **/
670 GSocket *
671 g_socket_listener_accept_socket_finish (GSocketListener   *listener,
672                                         GAsyncResult      *result,
673                                         GObject          **source_object,
674                                         GError           **error)
675 {
676   GSocket *socket;
677   GSimpleAsyncResult *simple;
678
679   g_return_val_if_fail (G_IS_SOCKET_LISTENER (listener), FALSE);
680
681   simple = G_SIMPLE_ASYNC_RESULT (result);
682
683   if (g_simple_async_result_propagate_error (simple, error))
684     return NULL;
685
686   g_warn_if_fail (g_simple_async_result_get_source_tag (simple) == g_socket_listener_accept_socket_async);
687
688   socket = g_simple_async_result_get_op_res_gpointer (simple);
689
690   if (source_object)
691     *source_object = g_object_get_qdata (G_OBJECT (result), source_quark);
692
693   return g_object_ref (socket);
694 }
695
696 /**
697  * g_socket_listener_accept_async:
698  * @listener: a #GSocketListener
699  * @cancellable: a #GCancellable, or %NULL
700  * @callback: a #GAsyncReadyCallback
701  * @user_data: user data for the callback
702  *
703  * This is the asynchronous version of g_socket_listener_accept().
704  *
705  * When the operation is finished @callback will be
706  * called. You can then call g_socket_listener_accept_socket() to get
707  * the result of the operation.
708  *
709  * Since: 2.22
710  **/
711 void
712 g_socket_listener_accept_async (GSocketListener     *listener,
713                                 GCancellable        *cancellable,
714                                 GAsyncReadyCallback  callback,
715                                 gpointer             user_data)
716 {
717   g_socket_listener_accept_socket_async (listener,
718                                          cancellable,
719                                          callback,
720                                          user_data);
721 }
722
723 /**
724  * g_socket_listener_accept_finish:
725  * @listener: a #GSocketListener
726  * @result: a #GAsyncResult.
727  * @source_object: Optional #GObject identifying this source
728  * @error: a #GError location to store the error occuring, or %NULL to
729  * ignore.
730  *
731  * Finishes an async accept operation. See g_socket_listener_accept_async()
732  *
733  * Returns: a #GSocketConnection on success, %NULL on error.
734  *
735  * Since: 2.22
736  **/
737 GSocketConnection *
738 g_socket_listener_accept_finish (GSocketListener *listener,
739                                  GAsyncResult *result,
740                                  GObject **source_object,
741                                  GError **error)
742 {
743   GSocket *socket;
744   GSocketConnection *connection;
745
746   socket = g_socket_listener_accept_socket_finish (listener,
747                                                    result,
748                                                    source_object,
749                                                    error);
750   if (socket == NULL)
751     return NULL;
752
753   connection = g_socket_connection_factory_create_connection (socket);
754   g_object_unref (socket);
755   return connection;
756 }
757
758 /**
759  * g_socket_listener_set_backlog:
760  * @listener: a #GSocketListener
761  * @listen_backlog: an integer
762  *
763  * Sets the listen backlog on the sockets in the listener.
764  *
765  * See g_socket_set_listen_backlog() for details
766  *
767  * Since: 2.22
768  **/
769 void
770 g_socket_listener_set_backlog (GSocketListener *listener,
771                                int listen_backlog)
772 {
773   GSocket *socket;
774   int i;
775
776   if (listener->priv->closed)
777     return;
778
779   listener->priv->listen_backlog = listen_backlog;
780
781   for (i = 0; i < listener->priv->sockets->len; i++)
782     {
783       socket = listener->priv->sockets->pdata[i];
784       g_socket_set_listen_backlog (socket, listen_backlog);
785     }
786 }
787
788 /**
789  * g_socket_listener_close:
790  * @listener: a #GSocketListener
791  *
792  * Closes all the sockets in the listener.
793  *
794  * Since: 2.22
795  **/
796 void
797 g_socket_listener_close (GSocketListener *listener)
798 {
799   GSocket *socket;
800   int i;
801
802   g_return_if_fail (G_IS_SOCKET_LISTENER (listener));
803
804   if (listener->priv->closed)
805     return;
806
807   for (i = 0; i < listener->priv->sockets->len; i++)
808     {
809       socket = listener->priv->sockets->pdata[i];
810       g_socket_close (socket, NULL);
811     }
812   listener->priv->closed = TRUE;
813 }
814
815 #define __G_SOCKET_LISTENER_C__
816 #include "gioaliasdef.c"