nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 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, see <http://www.gnu.org/licenses/>. |
||
19 | * |
||
20 | * Authors: Christian Kellner <gicmo@gnome.org> |
||
21 | * Samuel Cormier-Iijima <sciyoshi@gmail.com> |
||
22 | * Ryan Lortie <desrt@desrt.ca> |
||
23 | * Alexander Larsson <alexl@redhat.com> |
||
24 | */ |
||
25 | |||
26 | #include "config.h" |
||
27 | #include "gsocketlistener.h" |
||
28 | |||
29 | #include <gio/gioenumtypes.h> |
||
30 | #include <gio/gtask.h> |
||
31 | #include <gio/gcancellable.h> |
||
32 | #include <gio/gsocketaddress.h> |
||
33 | #include <gio/ginetaddress.h> |
||
34 | #include <gio/gioerror.h> |
||
35 | #include <gio/gsocket.h> |
||
36 | #include <gio/gsocketconnection.h> |
||
37 | #include <gio/ginetsocketaddress.h> |
||
38 | #include "glibintl.h" |
||
39 | |||
40 | |||
41 | /** |
||
42 | * SECTION:gsocketlistener |
||
43 | * @title: GSocketListener |
||
44 | * @short_description: Helper for accepting network client connections |
||
45 | * @include: gio/gio.h |
||
46 | * @see_also: #GThreadedSocketService, #GSocketService. |
||
47 | * |
||
48 | * A #GSocketListener is an object that keeps track of a set |
||
49 | * of server sockets and helps you accept sockets from any of the |
||
50 | * socket, either sync or async. |
||
51 | * |
||
52 | * If you want to implement a network server, also look at #GSocketService |
||
53 | * and #GThreadedSocketService which are subclass of #GSocketListener |
||
54 | * that makes this even easier. |
||
55 | * |
||
56 | * Since: 2.22 |
||
57 | */ |
||
58 | |||
59 | enum |
||
60 | { |
||
61 | PROP_0, |
||
62 | PROP_LISTEN_BACKLOG |
||
63 | }; |
||
64 | |||
65 | enum |
||
66 | { |
||
67 | EVENT, |
||
68 | LAST_SIGNAL |
||
69 | }; |
||
70 | |||
71 | static guint signals[LAST_SIGNAL] = { 0 }; |
||
72 | |||
73 | static GQuark source_quark = 0; |
||
74 | |||
75 | struct _GSocketListenerPrivate |
||
76 | { |
||
77 | GPtrArray *sockets; |
||
78 | GMainContext *main_context; |
||
79 | int listen_backlog; |
||
80 | guint closed : 1; |
||
81 | }; |
||
82 | |||
83 | G_DEFINE_TYPE_WITH_PRIVATE (GSocketListener, g_socket_listener, G_TYPE_OBJECT) |
||
84 | |||
85 | static void |
||
86 | g_socket_listener_finalize (GObject *object) |
||
87 | { |
||
88 | GSocketListener *listener = G_SOCKET_LISTENER (object); |
||
89 | |||
90 | if (listener->priv->main_context) |
||
91 | g_main_context_unref (listener->priv->main_context); |
||
92 | |||
93 | /* Do not explicitly close the sockets. Instead, let them close themselves if |
||
94 | * their final reference is dropped, but keep them open if a reference is |
||
95 | * held externally to the GSocketListener (which is possible if |
||
96 | * g_socket_listener_add_socket() was used). |
||
97 | */ |
||
98 | g_ptr_array_free (listener->priv->sockets, TRUE); |
||
99 | |||
100 | G_OBJECT_CLASS (g_socket_listener_parent_class) |
||
101 | ->finalize (object); |
||
102 | } |
||
103 | |||
104 | static void |
||
105 | g_socket_listener_get_property (GObject *object, |
||
106 | guint prop_id, |
||
107 | GValue *value, |
||
108 | GParamSpec *pspec) |
||
109 | { |
||
110 | GSocketListener *listener = G_SOCKET_LISTENER (object); |
||
111 | |||
112 | switch (prop_id) |
||
113 | { |
||
114 | case PROP_LISTEN_BACKLOG: |
||
115 | g_value_set_int (value, listener->priv->listen_backlog); |
||
116 | break; |
||
117 | |||
118 | default: |
||
119 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
||
120 | } |
||
121 | } |
||
122 | |||
123 | static void |
||
124 | g_socket_listener_set_property (GObject *object, |
||
125 | guint prop_id, |
||
126 | const GValue *value, |
||
127 | GParamSpec *pspec) |
||
128 | { |
||
129 | GSocketListener *listener = G_SOCKET_LISTENER (object); |
||
130 | |||
131 | switch (prop_id) |
||
132 | { |
||
133 | case PROP_LISTEN_BACKLOG: |
||
134 | g_socket_listener_set_backlog (listener, g_value_get_int (value)); |
||
135 | break; |
||
136 | |||
137 | default: |
||
138 | G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); |
||
139 | } |
||
140 | } |
||
141 | |||
142 | static void |
||
143 | g_socket_listener_class_init (GSocketListenerClass *klass) |
||
144 | { |
||
145 | GObjectClass *gobject_class G_GNUC_UNUSED = G_OBJECT_CLASS (klass); |
||
146 | |||
147 | gobject_class->finalize = g_socket_listener_finalize; |
||
148 | gobject_class->set_property = g_socket_listener_set_property; |
||
149 | gobject_class->get_property = g_socket_listener_get_property; |
||
150 | g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG, |
||
151 | g_param_spec_int ("listen-backlog", |
||
152 | P_("Listen backlog"), |
||
153 | P_("outstanding connections in the listen queue"), |
||
154 | 0, |
||
155 | 2000, |
||
156 | 10, |
||
157 | G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); |
||
158 | |||
159 | /** |
||
160 | * GSocketListener::event: |
||
161 | * @listener: the #GSocketListener |
||
162 | * @event: the event that is occurring |
||
163 | * @socket: the #GSocket the event is occurring on |
||
164 | * |
||
165 | * Emitted when @listener's activity on @socket changes state. |
||
166 | * Note that when @listener is used to listen on both IPv4 and |
||
167 | * IPv6, a separate set of signals will be emitted for each, and |
||
168 | * the order they happen in is undefined. |
||
169 | * |
||
170 | * Since: 2.46 |
||
171 | */ |
||
172 | signals[EVENT] = |
||
173 | g_signal_new (I_("event"), |
||
174 | G_TYPE_FROM_CLASS (gobject_class), |
||
175 | G_SIGNAL_RUN_LAST, |
||
176 | G_STRUCT_OFFSET (GSocketListenerClass, event), |
||
177 | NULL, NULL, NULL, |
||
178 | G_TYPE_NONE, 2, |
||
179 | G_TYPE_SOCKET_LISTENER_EVENT, |
||
180 | G_TYPE_SOCKET); |
||
181 | |||
182 | source_quark = g_quark_from_static_string ("g-socket-listener-source"); |
||
183 | } |
||
184 | |||
185 | static void |
||
186 | g_socket_listener_init (GSocketListener *listener) |
||
187 | { |
||
188 | listener->priv = g_socket_listener_get_instance_private (listener); |
||
189 | listener->priv->sockets = |
||
190 | g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref); |
||
191 | listener->priv->listen_backlog = 10; |
||
192 | } |
||
193 | |||
194 | /** |
||
195 | * g_socket_listener_new: |
||
196 | * |
||
197 | * Creates a new #GSocketListener with no sockets to listen for. |
||
198 | * New listeners can be added with e.g. g_socket_listener_add_address() |
||
199 | * or g_socket_listener_add_inet_port(). |
||
200 | * |
||
201 | * Returns: a new #GSocketListener. |
||
202 | * |
||
203 | * Since: 2.22 |
||
204 | */ |
||
205 | GSocketListener * |
||
206 | g_socket_listener_new (void) |
||
207 | { |
||
208 | return g_object_new (G_TYPE_SOCKET_LISTENER, NULL); |
||
209 | } |
||
210 | |||
211 | static gboolean |
||
212 | check_listener (GSocketListener *listener, |
||
213 | GError **error) |
||
214 | { |
||
215 | if (listener->priv->closed) |
||
216 | { |
||
217 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CLOSED, |
||
218 | _("Listener is already closed")); |
||
219 | return FALSE; |
||
220 | } |
||
221 | |||
222 | return TRUE; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * g_socket_listener_add_socket: |
||
227 | * @listener: a #GSocketListener |
||
228 | * @socket: a listening #GSocket |
||
229 | * @source_object: (allow-none): Optional #GObject identifying this source |
||
230 | * @error: #GError for error reporting, or %NULL to ignore. |
||
231 | * |
||
232 | * Adds @socket to the set of sockets that we try to accept |
||
233 | * new clients from. The socket must be bound to a local |
||
234 | * address and listened to. |
||
235 | * |
||
236 | * @source_object will be passed out in the various calls |
||
237 | * to accept to identify this particular source, which is |
||
238 | * useful if you're listening on multiple addresses and do |
||
239 | * different things depending on what address is connected to. |
||
240 | * |
||
241 | * The @socket will not be automatically closed when the @listener is finalized |
||
242 | * unless the listener held the final reference to the socket. Before GLib 2.42, |
||
243 | * the @socket was automatically closed on finalization of the @listener, even |
||
244 | * if references to it were held elsewhere. |
||
245 | * |
||
246 | * Returns: %TRUE on success, %FALSE on error. |
||
247 | * |
||
248 | * Since: 2.22 |
||
249 | */ |
||
250 | gboolean |
||
251 | g_socket_listener_add_socket (GSocketListener *listener, |
||
252 | GSocket *socket, |
||
253 | GObject *source_object, |
||
254 | GError **error) |
||
255 | { |
||
256 | if (!check_listener (listener, error)) |
||
257 | return FALSE; |
||
258 | |||
259 | /* TODO: Check that socket it is bound & not closed? */ |
||
260 | |||
261 | if (g_socket_is_closed (socket)) |
||
262 | { |
||
263 | g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, |
||
264 | _("Added socket is closed")); |
||
265 | return FALSE; |
||
266 | } |
||
267 | |||
268 | g_object_ref (socket); |
||
269 | g_ptr_array_add (listener->priv->sockets, socket); |
||
270 | |||
271 | if (source_object) |
||
272 | g_object_set_qdata_full (G_OBJECT (socket), source_quark, |
||
273 | g_object_ref (source_object), g_object_unref); |
||
274 | |||
275 | |||
276 | if (G_SOCKET_LISTENER_GET_CLASS (listener)->changed) |
||
277 | G_SOCKET_LISTENER_GET_CLASS (listener)->changed (listener); |
||
278 | |||
279 | return TRUE; |
||
280 | } |
||
281 | |||
282 | /** |
||
283 | * g_socket_listener_add_address: |
||
284 | * @listener: a #GSocketListener |
||
285 | * @address: a #GSocketAddress |
||
286 | * @type: a #GSocketType |
||
287 | * @protocol: a #GSocketProtocol |
||
288 | * @source_object: (allow-none): Optional #GObject identifying this source |
||
289 | * @effective_address: (out) (allow-none): location to store the address that was bound to, or %NULL. |
||
290 | * @error: #GError for error reporting, or %NULL to ignore. |
||
291 | * |
||
292 | * Creates a socket of type @type and protocol @protocol, binds |
||
293 | * it to @address and adds it to the set of sockets we're accepting |
||
294 | * sockets from. |
||
295 | * |
||
296 | * Note that adding an IPv6 address, depending on the platform, |
||
297 | * may or may not result in a listener that also accepts IPv4 |
||
298 | * connections. For more deterministic behavior, see |
||
299 | * g_socket_listener_add_inet_port(). |
||
300 | * |
||
301 | * @source_object will be passed out in the various calls |
||
302 | * to accept to identify this particular source, which is |
||
303 | * useful if you're listening on multiple addresses and do |
||
304 | * different things depending on what address is connected to. |
||
305 | * |
||
306 | * If successful and @effective_address is non-%NULL then it will |
||
307 | * be set to the address that the binding actually occurred at. This |
||
308 | * is helpful for determining the port number that was used for when |
||
309 | * requesting a binding to port 0 (ie: "any port"). This address, if |
||
310 | * requested, belongs to the caller and must be freed. |
||
311 | * |
||
312 | * Returns: %TRUE on success, %FALSE on error. |
||
313 | * |
||
314 | * Since: 2.22 |
||
315 | */ |
||
316 | gboolean |
||
317 | g_socket_listener_add_address (GSocketListener *listener, |
||
318 | GSocketAddress *address, |
||
319 | GSocketType type, |
||
320 | GSocketProtocol protocol, |
||
321 | GObject *source_object, |
||
322 | GSocketAddress **effective_address, |
||
323 | GError **error) |
||
324 | { |
||
325 | GSocketAddress *local_address; |
||
326 | GSocketFamily family; |
||
327 | GSocket *socket; |
||
328 | |||
329 | if (!check_listener (listener, error)) |
||
330 | return FALSE; |
||
331 | |||
332 | family = g_socket_address_get_family (address); |
||
333 | socket = g_socket_new (family, type, protocol, error); |
||
334 | if (socket == NULL) |
||
335 | return FALSE; |
||
336 | |||
337 | g_socket_set_listen_backlog (socket, listener->priv->listen_backlog); |
||
338 | |||
339 | g_signal_emit (listener, signals[EVENT], 0, |
||
340 | G_SOCKET_LISTENER_BINDING, socket); |
||
341 | |||
342 | if (!g_socket_bind (socket, address, TRUE, error)) |
||
343 | { |
||
344 | g_object_unref (socket); |
||
345 | return FALSE; |
||
346 | } |
||
347 | |||
348 | g_signal_emit (listener, signals[EVENT], 0, |
||
349 | G_SOCKET_LISTENER_BOUND, socket); |
||
350 | g_signal_emit (listener, signals[EVENT], 0, |
||
351 | G_SOCKET_LISTENER_LISTENING, socket); |
||
352 | |||
353 | if (!g_socket_listen (socket, error)) |
||
354 | { |
||
355 | g_object_unref (socket); |
||
356 | return FALSE; |
||
357 | } |
||
358 | |||
359 | g_signal_emit (listener, signals[EVENT], 0, |
||
360 | G_SOCKET_LISTENER_LISTENED, socket); |
||
361 | |||
362 | local_address = NULL; |
||
363 | if (effective_address) |
||
364 | { |
||
365 | local_address = g_socket_get_local_address (socket, error); |
||
366 | if (local_address == NULL) |
||
367 | { |
||
368 | g_object_unref (socket); |
||
369 | return FALSE; |
||
370 | } |
||
371 | } |
||
372 | |||
373 | if (!g_socket_listener_add_socket (listener, socket, |
||
374 | source_object, |
||
375 | error)) |
||
376 | { |
||
377 | if (local_address) |
||
378 | g_object_unref (local_address); |
||
379 | g_object_unref (socket); |
||
380 | return FALSE; |
||
381 | } |
||
382 | |||
383 | if (effective_address) |
||
384 | *effective_address = local_address; |
||
385 | |||
386 | g_object_unref (socket); /* add_socket refs this */ |
||
387 | |||
388 | return TRUE; |
||
389 | } |
||
390 | |||
391 | /** |
||
392 | * g_socket_listener_add_inet_port: |
||
393 | * @listener: a #GSocketListener |
||
394 | * @port: an IP port number (non-zero) |
||
395 | * @source_object: (allow-none): Optional #GObject identifying this source |
||
396 | * @error: #GError for error reporting, or %NULL to ignore. |
||
397 | * |
||
398 | * Helper function for g_socket_listener_add_address() that |
||
399 | * creates a TCP/IP socket listening on IPv4 and IPv6 (if |
||
400 | * supported) on the specified port on all interfaces. |
||
401 | * |
||
402 | * @source_object will be passed out in the various calls |
||
403 | * to accept to identify this particular source, which is |
||
404 | * useful if you're listening on multiple addresses and do |
||
405 | * different things depending on what address is connected to. |
||
406 | * |
||
407 | * Returns: %TRUE on success, %FALSE on error. |
||
408 | * |
||
409 | * Since: 2.22 |
||
410 | */ |
||
411 | gboolean |
||
412 | g_socket_listener_add_inet_port (GSocketListener *listener, |
||
413 | guint16 port, |
||
414 | GObject *source_object, |
||
415 | GError **error) |
||
416 | { |
||
417 | gboolean need_ipv4_socket = TRUE; |
||
418 | GSocket *socket4 = NULL; |
||
419 | GSocket *socket6; |
||
420 | |||
421 | g_return_val_if_fail (listener != NULL, FALSE); |
||
422 | g_return_val_if_fail (port != 0, FALSE); |
||
423 | |||
424 | if (!check_listener (listener, error)) |
||
425 | return FALSE; |
||
426 | |||
427 | /* first try to create an IPv6 socket */ |
||
428 | socket6 = g_socket_new (G_SOCKET_FAMILY_IPV6, |
||
429 | G_SOCKET_TYPE_STREAM, |
||
430 | G_SOCKET_PROTOCOL_DEFAULT, |
||
431 | NULL); |
||
432 | |||
433 | if (socket6 != NULL) |
||
434 | /* IPv6 is supported on this platform, so if we fail now it is |
||
435 | * a result of being unable to bind to our port. Don't fail |
||
436 | * silently as a result of this! |
||
437 | */ |
||
438 | { |
||
439 | GInetAddress *inet_address; |
||
440 | GSocketAddress *address; |
||
441 | |||
442 | inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6); |
||
443 | address = g_inet_socket_address_new (inet_address, port); |
||
444 | g_object_unref (inet_address); |
||
445 | |||
446 | g_socket_set_listen_backlog (socket6, listener->priv->listen_backlog); |
||
447 | |||
448 | g_signal_emit (listener, signals[EVENT], 0, |
||
449 | G_SOCKET_LISTENER_BINDING, socket6); |
||
450 | |||
451 | if (!g_socket_bind (socket6, address, TRUE, error)) |
||
452 | { |
||
453 | g_object_unref (address); |
||
454 | g_object_unref (socket6); |
||
455 | return FALSE; |
||
456 | } |
||
457 | |||
458 | g_object_unref (address); |
||
459 | |||
460 | g_signal_emit (listener, signals[EVENT], 0, |
||
461 | G_SOCKET_LISTENER_BOUND, socket6); |
||
462 | g_signal_emit (listener, signals[EVENT], 0, |
||
463 | G_SOCKET_LISTENER_LISTENING, socket6); |
||
464 | |||
465 | if (!g_socket_listen (socket6, error)) |
||
466 | { |
||
467 | g_object_unref (socket6); |
||
468 | return FALSE; |
||
469 | } |
||
470 | |||
471 | g_signal_emit (listener, signals[EVENT], 0, |
||
472 | G_SOCKET_LISTENER_LISTENED, socket6); |
||
473 | |||
474 | if (source_object) |
||
475 | g_object_set_qdata_full (G_OBJECT (socket6), source_quark, |
||
476 | g_object_ref (source_object), |
||
477 | g_object_unref); |
||
478 | |||
479 | /* If this socket already speaks IPv4 then we are done. */ |
||
480 | if (g_socket_speaks_ipv4 (socket6)) |
||
481 | need_ipv4_socket = FALSE; |
||
482 | } |
||
483 | |||
484 | if (need_ipv4_socket) |
||
485 | /* We are here for exactly one of the following reasons: |
||
486 | * |
||
487 | * - our platform doesn't support IPv6 |
||
488 | * - we successfully created an IPv6 socket but it's V6ONLY |
||
489 | * |
||
490 | * In either case, we need to go ahead and create an IPv4 socket |
||
491 | * and fail the call if we can't bind to it. |
||
492 | */ |
||
493 | { |
||
494 | socket4 = g_socket_new (G_SOCKET_FAMILY_IPV4, |
||
495 | G_SOCKET_TYPE_STREAM, |
||
496 | G_SOCKET_PROTOCOL_DEFAULT, |
||
497 | error); |
||
498 | |||
499 | if (socket4 != NULL) |
||
500 | /* IPv4 is supported on this platform, so if we fail now it is |
||
501 | * a result of being unable to bind to our port. Don't fail |
||
502 | * silently as a result of this! |
||
503 | */ |
||
504 | { |
||
505 | GInetAddress *inet_address; |
||
506 | GSocketAddress *address; |
||
507 | |||
508 | inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); |
||
509 | address = g_inet_socket_address_new (inet_address, port); |
||
510 | g_object_unref (inet_address); |
||
511 | |||
512 | g_socket_set_listen_backlog (socket4, |
||
513 | listener->priv->listen_backlog); |
||
514 | |||
515 | g_signal_emit (listener, signals[EVENT], 0, |
||
516 | G_SOCKET_LISTENER_BINDING, socket4); |
||
517 | |||
518 | if (!g_socket_bind (socket4, address, TRUE, error)) |
||
519 | { |
||
520 | g_object_unref (address); |
||
521 | g_object_unref (socket4); |
||
522 | if (socket6 != NULL) |
||
523 | g_object_unref (socket6); |
||
524 | |||
525 | return FALSE; |
||
526 | } |
||
527 | |||
528 | g_object_unref (address); |
||
529 | |||
530 | g_signal_emit (listener, signals[EVENT], 0, |
||
531 | G_SOCKET_LISTENER_BOUND, socket4); |
||
532 | g_signal_emit (listener, signals[EVENT], 0, |
||
533 | G_SOCKET_LISTENER_LISTENING, socket4); |
||
534 | |||
535 | if (!g_socket_listen (socket4, error)) |
||
536 | { |
||
537 | g_object_unref (socket4); |
||
538 | if (socket6 != NULL) |
||
539 | g_object_unref (socket6); |
||
540 | |||
541 | return FALSE; |
||
542 | } |
||
543 | |||
544 | g_signal_emit (listener, signals[EVENT], 0, |
||
545 | G_SOCKET_LISTENER_LISTENED, socket4); |
||
546 | |||
547 | if (source_object) |
||
548 | g_object_set_qdata_full (G_OBJECT (socket4), source_quark, |
||
549 | g_object_ref (source_object), |
||
550 | g_object_unref); |
||
551 | } |
||
552 | else |
||
553 | /* Ok. So IPv4 is not supported on this platform. If we |
||
554 | * succeeded at creating an IPv6 socket then that's OK, but |
||
555 | * otherwise we need to tell the user we failed. |
||
556 | */ |
||
557 | { |
||
558 | if (socket6 != NULL) |
||
559 | g_clear_error (error); |
||
560 | else |
||
561 | return FALSE; |
||
562 | } |
||
563 | } |
||
564 | |||
565 | g_assert (socket6 != NULL || socket4 != NULL); |
||
566 | |||
567 | if (socket6 != NULL) |
||
568 | g_ptr_array_add (listener->priv->sockets, socket6); |
||
569 | |||
570 | if (socket4 != NULL) |
||
571 | g_ptr_array_add (listener->priv->sockets, socket4); |
||
572 | |||
573 | if (G_SOCKET_LISTENER_GET_CLASS (listener)->changed) |
||
574 | G_SOCKET_LISTENER_GET_CLASS (listener)->changed (listener); |
||
575 | |||
576 | return TRUE; |
||
577 | } |
||
578 | |||
579 | static GList * |
||
580 | add_sources (GSocketListener *listener, |
||
581 | GSocketSourceFunc callback, |
||
582 | gpointer callback_data, |
||
583 | GCancellable *cancellable, |
||
584 | GMainContext *context) |
||
585 | { |
||
586 | GSocket *socket; |
||
587 | GSource *source; |
||
588 | GList *sources; |
||
589 | int i; |
||
590 | |||
591 | sources = NULL; |
||
592 | for (i = 0; i < listener->priv->sockets->len; i++) |
||
593 | { |
||
594 | socket = listener->priv->sockets->pdata[i]; |
||
595 | |||
596 | source = g_socket_create_source (socket, G_IO_IN, cancellable); |
||
597 | g_source_set_callback (source, |
||
598 | (GSourceFunc) callback, |
||
599 | callback_data, NULL); |
||
600 | g_source_attach (source, context); |
||
601 | |||
602 | sources = g_list_prepend (sources, source); |
||
603 | } |
||
604 | |||
605 | return sources; |
||
606 | } |
||
607 | |||
608 | static void |
||
609 | free_sources (GList *sources) |
||
610 | { |
||
611 | GSource *source; |
||
612 | while (sources != NULL) |
||
613 | { |
||
614 | source = sources->data; |
||
615 | sources = g_list_delete_link (sources, sources); |
||
616 | g_source_destroy (source); |
||
617 | g_source_unref (source); |
||
618 | } |
||
619 | } |
||
620 | |||
621 | struct AcceptData { |
||
622 | GMainLoop *loop; |
||
623 | GSocket *socket; |
||
624 | }; |
||
625 | |||
626 | static gboolean |
||
627 | accept_callback (GSocket *socket, |
||
628 | GIOCondition condition, |
||
629 | gpointer user_data) |
||
630 | { |
||
631 | struct AcceptData *data = user_data; |
||
632 | |||
633 | data->socket = socket; |
||
634 | g_main_loop_quit (data->loop); |
||
635 | |||
636 | return TRUE; |
||
637 | } |
||
638 | |||
639 | /** |
||
640 | * g_socket_listener_accept_socket: |
||
641 | * @listener: a #GSocketListener |
||
642 | * @source_object: (out) (transfer none) (allow-none): location where #GObject pointer will be stored, or %NULL. |
||
643 | * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. |
||
644 | * @error: #GError for error reporting, or %NULL to ignore. |
||
645 | * |
||
646 | * Blocks waiting for a client to connect to any of the sockets added |
||
647 | * to the listener. Returns the #GSocket that was accepted. |
||
648 | * |
||
649 | * If you want to accept the high-level #GSocketConnection, not a #GSocket, |
||
650 | * which is often the case, then you should use g_socket_listener_accept() |
||
651 | * instead. |
||
652 | * |
||
653 | * If @source_object is not %NULL it will be filled out with the source |
||
654 | * object specified when the corresponding socket or address was added |
||
655 | * to the listener. |
||
656 | * |
||
657 | * If @cancellable is not %NULL, then the operation can be cancelled by |
||
658 | * triggering the cancellable object from another thread. If the operation |
||
659 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
||
660 | * |
||
661 | * Returns: (transfer full): a #GSocket on success, %NULL on error. |
||
662 | * |
||
663 | * Since: 2.22 |
||
664 | */ |
||
665 | GSocket * |
||
666 | g_socket_listener_accept_socket (GSocketListener *listener, |
||
667 | GObject **source_object, |
||
668 | GCancellable *cancellable, |
||
669 | GError **error) |
||
670 | { |
||
671 | GSocket *accept_socket, *socket; |
||
672 | |||
673 | g_return_val_if_fail (G_IS_SOCKET_LISTENER (listener), NULL); |
||
674 | |||
675 | if (!check_listener (listener, error)) |
||
676 | return NULL; |
||
677 | |||
678 | if (listener->priv->sockets->len == 1) |
||
679 | { |
||
680 | accept_socket = listener->priv->sockets->pdata[0]; |
||
681 | if (!g_socket_condition_wait (accept_socket, G_IO_IN, |
||
682 | cancellable, error)) |
||
683 | return NULL; |
||
684 | } |
||
685 | else |
||
686 | { |
||
687 | GList *sources; |
||
688 | struct AcceptData data; |
||
689 | GMainLoop *loop; |
||
690 | |||
691 | if (listener->priv->main_context == NULL) |
||
692 | listener->priv->main_context = g_main_context_new (); |
||
693 | |||
694 | loop = g_main_loop_new (listener->priv->main_context, FALSE); |
||
695 | data.loop = loop; |
||
696 | sources = add_sources (listener, |
||
697 | accept_callback, |
||
698 | &data, |
||
699 | cancellable, |
||
700 | listener->priv->main_context); |
||
701 | g_main_loop_run (loop); |
||
702 | accept_socket = data.socket; |
||
703 | free_sources (sources); |
||
704 | g_main_loop_unref (loop); |
||
705 | } |
||
706 | |||
707 | if (!(socket = g_socket_accept (accept_socket, cancellable, error))) |
||
708 | return NULL; |
||
709 | |||
710 | if (source_object) |
||
711 | *source_object = g_object_get_qdata (G_OBJECT (accept_socket), source_quark); |
||
712 | |||
713 | return socket; |
||
714 | } |
||
715 | |||
716 | /** |
||
717 | * g_socket_listener_accept: |
||
718 | * @listener: a #GSocketListener |
||
719 | * @source_object: (out) (transfer none) (allow-none): location where #GObject pointer will be stored, or %NULL |
||
720 | * @cancellable: (allow-none): optional #GCancellable object, %NULL to ignore. |
||
721 | * @error: #GError for error reporting, or %NULL to ignore. |
||
722 | * |
||
723 | * Blocks waiting for a client to connect to any of the sockets added |
||
724 | * to the listener. Returns a #GSocketConnection for the socket that was |
||
725 | * accepted. |
||
726 | * |
||
727 | * If @source_object is not %NULL it will be filled out with the source |
||
728 | * object specified when the corresponding socket or address was added |
||
729 | * to the listener. |
||
730 | * |
||
731 | * If @cancellable is not %NULL, then the operation can be cancelled by |
||
732 | * triggering the cancellable object from another thread. If the operation |
||
733 | * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. |
||
734 | * |
||
735 | * Returns: (transfer full): a #GSocketConnection on success, %NULL on error. |
||
736 | * |
||
737 | * Since: 2.22 |
||
738 | */ |
||
739 | GSocketConnection * |
||
740 | g_socket_listener_accept (GSocketListener *listener, |
||
741 | GObject **source_object, |
||
742 | GCancellable *cancellable, |
||
743 | GError **error) |
||
744 | { |
||
745 | GSocketConnection *connection; |
||
746 | GSocket *socket; |
||
747 | |||
748 | socket = g_socket_listener_accept_socket (listener, |
||
749 | source_object, |
||
750 | cancellable, |
||
751 | error); |
||
752 | if (socket == NULL) |
||
753 | return NULL; |
||
754 | |||
755 | connection = g_socket_connection_factory_create_connection (socket); |
||
756 | g_object_unref (socket); |
||
757 | |||
758 | return connection; |
||
759 | } |
||
760 | |||
761 | static gboolean |
||
762 | accept_ready (GSocket *accept_socket, |
||
763 | GIOCondition condition, |
||
764 | gpointer user_data) |
||
765 | { |
||
766 | GTask *task = user_data; |
||
767 | GError *error = NULL; |
||
768 | GSocket *socket; |
||
769 | GObject *source_object; |
||
770 | |||
771 | socket = g_socket_accept (accept_socket, g_task_get_cancellable (task), &error); |
||
772 | if (socket) |
||
773 | { |
||
774 | source_object = g_object_get_qdata (G_OBJECT (accept_socket), source_quark); |
||
775 | if (source_object) |
||
776 | g_object_set_qdata_full (G_OBJECT (task), |
||
777 | source_quark, |
||
778 | g_object_ref (source_object), g_object_unref); |
||
779 | g_task_return_pointer (task, socket, g_object_unref); |
||
780 | } |
||
781 | else |
||
782 | { |
||
783 | g_task_return_error (task, error); |
||
784 | } |
||
785 | |||
786 | g_object_unref (task); |
||
787 | return FALSE; |
||
788 | } |
||
789 | |||
790 | /** |
||
791 | * g_socket_listener_accept_socket_async: |
||
792 | * @listener: a #GSocketListener |
||
793 | * @cancellable: (allow-none): a #GCancellable, or %NULL |
||
794 | * @callback: (scope async): a #GAsyncReadyCallback |
||
795 | * @user_data: (closure): user data for the callback |
||
796 | * |
||
797 | * This is the asynchronous version of g_socket_listener_accept_socket(). |
||
798 | * |
||
799 | * When the operation is finished @callback will be |
||
800 | * called. You can then call g_socket_listener_accept_socket_finish() |
||
801 | * to get the result of the operation. |
||
802 | * |
||
803 | * Since: 2.22 |
||
804 | */ |
||
805 | void |
||
806 | g_socket_listener_accept_socket_async (GSocketListener *listener, |
||
807 | GCancellable *cancellable, |
||
808 | GAsyncReadyCallback callback, |
||
809 | gpointer user_data) |
||
810 | { |
||
811 | GTask *task; |
||
812 | GList *sources; |
||
813 | GError *error = NULL; |
||
814 | |||
815 | task = g_task_new (listener, cancellable, callback, user_data); |
||
816 | |||
817 | if (!check_listener (listener, &error)) |
||
818 | { |
||
819 | g_task_return_error (task, error); |
||
820 | g_object_unref (task); |
||
821 | return; |
||
822 | } |
||
823 | |||
824 | sources = add_sources (listener, |
||
825 | accept_ready, |
||
826 | task, |
||
827 | cancellable, |
||
828 | g_main_context_get_thread_default ()); |
||
829 | g_task_set_task_data (task, sources, (GDestroyNotify) free_sources); |
||
830 | } |
||
831 | |||
832 | /** |
||
833 | * g_socket_listener_accept_socket_finish: |
||
834 | * @listener: a #GSocketListener |
||
835 | * @result: a #GAsyncResult. |
||
836 | * @source_object: (out) (transfer none) (allow-none): Optional #GObject identifying this source |
||
837 | * @error: a #GError location to store the error occurring, or %NULL to |
||
838 | * ignore. |
||
839 | * |
||
840 | * Finishes an async accept operation. See g_socket_listener_accept_socket_async() |
||
841 | * |
||
842 | * Returns: (transfer full): a #GSocket on success, %NULL on error. |
||
843 | * |
||
844 | * Since: 2.22 |
||
845 | */ |
||
846 | GSocket * |
||
847 | g_socket_listener_accept_socket_finish (GSocketListener *listener, |
||
848 | GAsyncResult *result, |
||
849 | GObject **source_object, |
||
850 | GError **error) |
||
851 | { |
||
852 | g_return_val_if_fail (G_IS_SOCKET_LISTENER (listener), NULL); |
||
853 | g_return_val_if_fail (g_task_is_valid (result, listener), NULL); |
||
854 | |||
855 | if (source_object) |
||
856 | *source_object = g_object_get_qdata (G_OBJECT (result), source_quark); |
||
857 | |||
858 | return g_task_propagate_pointer (G_TASK (result), error); |
||
859 | } |
||
860 | |||
861 | /** |
||
862 | * g_socket_listener_accept_async: |
||
863 | * @listener: a #GSocketListener |
||
864 | * @cancellable: (allow-none): a #GCancellable, or %NULL |
||
865 | * @callback: (scope async): a #GAsyncReadyCallback |
||
866 | * @user_data: (closure): user data for the callback |
||
867 | * |
||
868 | * This is the asynchronous version of g_socket_listener_accept(). |
||
869 | * |
||
870 | * When the operation is finished @callback will be |
||
871 | * called. You can then call g_socket_listener_accept_socket() |
||
872 | * to get the result of the operation. |
||
873 | * |
||
874 | * Since: 2.22 |
||
875 | */ |
||
876 | void |
||
877 | g_socket_listener_accept_async (GSocketListener *listener, |
||
878 | GCancellable *cancellable, |
||
879 | GAsyncReadyCallback callback, |
||
880 | gpointer user_data) |
||
881 | { |
||
882 | g_socket_listener_accept_socket_async (listener, |
||
883 | cancellable, |
||
884 | callback, |
||
885 | user_data); |
||
886 | } |
||
887 | |||
888 | /** |
||
889 | * g_socket_listener_accept_finish: |
||
890 | * @listener: a #GSocketListener |
||
891 | * @result: a #GAsyncResult. |
||
892 | * @source_object: (out) (transfer none) (allow-none): Optional #GObject identifying this source |
||
893 | * @error: a #GError location to store the error occurring, or %NULL to |
||
894 | * ignore. |
||
895 | * |
||
896 | * Finishes an async accept operation. See g_socket_listener_accept_async() |
||
897 | * |
||
898 | * Returns: (transfer full): a #GSocketConnection on success, %NULL on error. |
||
899 | * |
||
900 | * Since: 2.22 |
||
901 | */ |
||
902 | GSocketConnection * |
||
903 | g_socket_listener_accept_finish (GSocketListener *listener, |
||
904 | GAsyncResult *result, |
||
905 | GObject **source_object, |
||
906 | GError **error) |
||
907 | { |
||
908 | GSocket *socket; |
||
909 | GSocketConnection *connection; |
||
910 | |||
911 | socket = g_socket_listener_accept_socket_finish (listener, |
||
912 | result, |
||
913 | source_object, |
||
914 | error); |
||
915 | if (socket == NULL) |
||
916 | return NULL; |
||
917 | |||
918 | connection = g_socket_connection_factory_create_connection (socket); |
||
919 | g_object_unref (socket); |
||
920 | return connection; |
||
921 | } |
||
922 | |||
923 | /** |
||
924 | * g_socket_listener_set_backlog: |
||
925 | * @listener: a #GSocketListener |
||
926 | * @listen_backlog: an integer |
||
927 | * |
||
928 | * Sets the listen backlog on the sockets in the listener. |
||
929 | * |
||
930 | * See g_socket_set_listen_backlog() for details |
||
931 | * |
||
932 | * Since: 2.22 |
||
933 | */ |
||
934 | void |
||
935 | g_socket_listener_set_backlog (GSocketListener *listener, |
||
936 | int listen_backlog) |
||
937 | { |
||
938 | GSocket *socket; |
||
939 | int i; |
||
940 | |||
941 | if (listener->priv->closed) |
||
942 | return; |
||
943 | |||
944 | listener->priv->listen_backlog = listen_backlog; |
||
945 | |||
946 | for (i = 0; i < listener->priv->sockets->len; i++) |
||
947 | { |
||
948 | socket = listener->priv->sockets->pdata[i]; |
||
949 | g_socket_set_listen_backlog (socket, listen_backlog); |
||
950 | } |
||
951 | } |
||
952 | |||
953 | /** |
||
954 | * g_socket_listener_close: |
||
955 | * @listener: a #GSocketListener |
||
956 | * |
||
957 | * Closes all the sockets in the listener. |
||
958 | * |
||
959 | * Since: 2.22 |
||
960 | */ |
||
961 | void |
||
962 | g_socket_listener_close (GSocketListener *listener) |
||
963 | { |
||
964 | GSocket *socket; |
||
965 | int i; |
||
966 | |||
967 | g_return_if_fail (G_IS_SOCKET_LISTENER (listener)); |
||
968 | |||
969 | if (listener->priv->closed) |
||
970 | return; |
||
971 | |||
972 | for (i = 0; i < listener->priv->sockets->len; i++) |
||
973 | { |
||
974 | socket = listener->priv->sockets->pdata[i]; |
||
975 | g_socket_close (socket, NULL); |
||
976 | } |
||
977 | listener->priv->closed = TRUE; |
||
978 | } |
||
979 | |||
980 | /** |
||
981 | * g_socket_listener_add_any_inet_port: |
||
982 | * @listener: a #GSocketListener |
||
983 | * @source_object: (allow-none): Optional #GObject identifying this source |
||
984 | * @error: a #GError location to store the error occurring, or %NULL to |
||
985 | * ignore. |
||
986 | * |
||
987 | * Listens for TCP connections on any available port number for both |
||
988 | * IPv6 and IPv4 (if each is available). |
||
989 | * |
||
990 | * This is useful if you need to have a socket for incoming connections |
||
991 | * but don't care about the specific port number. |
||
992 | * |
||
993 | * @source_object will be passed out in the various calls |
||
994 | * to accept to identify this particular source, which is |
||
995 | * useful if you're listening on multiple addresses and do |
||
996 | * different things depending on what address is connected to. |
||
997 | * |
||
998 | * Returns: the port number, or 0 in case of failure. |
||
999 | * |
||
1000 | * Since: 2.24 |
||
1001 | **/ |
||
1002 | guint16 |
||
1003 | g_socket_listener_add_any_inet_port (GSocketListener *listener, |
||
1004 | GObject *source_object, |
||
1005 | GError **error) |
||
1006 | { |
||
1007 | GSList *sockets_to_close = NULL; |
||
1008 | guint16 candidate_port = 0; |
||
1009 | GSocket *socket6 = NULL; |
||
1010 | GSocket *socket4 = NULL; |
||
1011 | gint attempts = 37; |
||
1012 | |||
1013 | /* |
||
1014 | * multi-step process: |
||
1015 | * - first, create an IPv6 socket. |
||
1016 | * - if that fails, create an IPv4 socket and bind it to port 0 and |
||
1017 | * that's it. no retries if that fails (why would it?). |
||
1018 | * - if our IPv6 socket also speaks IPv4 then we are done. |
||
1019 | * - if not, then we need to create a IPv4 socket with the same port |
||
1020 | * number. this might fail, of course. so we try this a bunch of |
||
1021 | * times -- leaving the old IPv6 sockets open so that we get a |
||
1022 | * different port number to try each time. |
||
1023 | * - if all that fails then just give up. |
||
1024 | */ |
||
1025 | |||
1026 | while (attempts--) |
||
1027 | { |
||
1028 | GInetAddress *inet_address; |
||
1029 | GSocketAddress *address; |
||
1030 | gboolean result; |
||
1031 | |||
1032 | g_assert (socket6 == NULL); |
||
1033 | socket6 = g_socket_new (G_SOCKET_FAMILY_IPV6, |
||
1034 | G_SOCKET_TYPE_STREAM, |
||
1035 | G_SOCKET_PROTOCOL_DEFAULT, |
||
1036 | NULL); |
||
1037 | |||
1038 | if (socket6 != NULL) |
||
1039 | { |
||
1040 | inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV6); |
||
1041 | address = g_inet_socket_address_new (inet_address, 0); |
||
1042 | g_object_unref (inet_address); |
||
1043 | |||
1044 | g_signal_emit (listener, signals[EVENT], 0, |
||
1045 | G_SOCKET_LISTENER_BINDING, socket6); |
||
1046 | |||
1047 | result = g_socket_bind (socket6, address, TRUE, error); |
||
1048 | g_object_unref (address); |
||
1049 | |||
1050 | if (!result || |
||
1051 | !(address = g_socket_get_local_address (socket6, error))) |
||
1052 | { |
||
1053 | g_object_unref (socket6); |
||
1054 | socket6 = NULL; |
||
1055 | break; |
||
1056 | } |
||
1057 | |||
1058 | g_signal_emit (listener, signals[EVENT], 0, |
||
1059 | G_SOCKET_LISTENER_BOUND, socket6); |
||
1060 | |||
1061 | g_assert (G_IS_INET_SOCKET_ADDRESS (address)); |
||
1062 | candidate_port = |
||
1063 | g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address)); |
||
1064 | g_assert (candidate_port != 0); |
||
1065 | g_object_unref (address); |
||
1066 | |||
1067 | if (g_socket_speaks_ipv4 (socket6)) |
||
1068 | break; |
||
1069 | } |
||
1070 | |||
1071 | g_assert (socket4 == NULL); |
||
1072 | socket4 = g_socket_new (G_SOCKET_FAMILY_IPV4, |
||
1073 | G_SOCKET_TYPE_STREAM, |
||
1074 | G_SOCKET_PROTOCOL_DEFAULT, |
||
1075 | socket6 ? NULL : error); |
||
1076 | |||
1077 | if (socket4 == NULL) |
||
1078 | /* IPv4 not supported. |
||
1079 | * if IPv6 is supported then candidate_port will be non-zero |
||
1080 | * (and the error parameter above will have been NULL) |
||
1081 | * if IPv6 is unsupported then candidate_port will be zero |
||
1082 | * (and error will have been set by the above call) |
||
1083 | */ |
||
1084 | break; |
||
1085 | |||
1086 | inet_address = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); |
||
1087 | address = g_inet_socket_address_new (inet_address, candidate_port); |
||
1088 | g_object_unref (inet_address); |
||
1089 | |||
1090 | g_signal_emit (listener, signals[EVENT], 0, |
||
1091 | G_SOCKET_LISTENER_BINDING, socket4); |
||
1092 | |||
1093 | /* a note on the 'error' clause below: |
||
1094 | * |
||
1095 | * if candidate_port is 0 then we report the error right away |
||
1096 | * since it is strange that this binding would fail at all. |
||
1097 | * otherwise, we ignore the error message (ie: NULL). |
||
1098 | * |
||
1099 | * the exception to this rule is the last time through the loop |
||
1100 | * (ie: attempts == 0) in which case we want to set the error |
||
1101 | * because failure here means that the entire call will fail and |
||
1102 | * we need something to show to the user. |
||
1103 | * |
||
1104 | * an english summary of the situation: "if we gave a candidate |
||
1105 | * port number AND we have more attempts to try, then ignore the |
||
1106 | * error for now". |
||
1107 | */ |
||
1108 | result = g_socket_bind (socket4, address, TRUE, |
||
1109 | (candidate_port && attempts) ? NULL : error); |
||
1110 | g_object_unref (address); |
||
1111 | |||
1112 | if (candidate_port) |
||
1113 | { |
||
1114 | g_assert (socket6 != NULL); |
||
1115 | |||
1116 | if (result) |
||
1117 | /* got our candidate port successfully */ |
||
1118 | { |
||
1119 | g_signal_emit (listener, signals[EVENT], 0, |
||
1120 | G_SOCKET_LISTENER_BOUND, socket4); |
||
1121 | break; |
||
1122 | } |
||
1123 | else |
||
1124 | /* we failed to bind to the specified port. try again. */ |
||
1125 | { |
||
1126 | g_object_unref (socket4); |
||
1127 | socket4 = NULL; |
||
1128 | |||
1129 | /* keep this open so we get a different port number */ |
||
1130 | sockets_to_close = g_slist_prepend (sockets_to_close, |
||
1131 | socket6); |
||
1132 | candidate_port = 0; |
||
1133 | socket6 = NULL; |
||
1134 | } |
||
1135 | } |
||
1136 | else |
||
1137 | /* we didn't tell it a port. this means two things. |
||
1138 | * - if we failed, then something really bad happened. |
||
1139 | * - if we succeeded, then we need to find out the port number. |
||
1140 | */ |
||
1141 | { |
||
1142 | g_assert (socket6 == NULL); |
||
1143 | |||
1144 | if (!result || |
||
1145 | !(address = g_socket_get_local_address (socket4, error))) |
||
1146 | { |
||
1147 | g_object_unref (socket4); |
||
1148 | socket4 = NULL; |
||
1149 | break; |
||
1150 | } |
||
1151 | |||
1152 | g_signal_emit (listener, signals[EVENT], 0, |
||
1153 | G_SOCKET_LISTENER_BOUND, socket4); |
||
1154 | |||
1155 | g_assert (G_IS_INET_SOCKET_ADDRESS (address)); |
||
1156 | candidate_port = |
||
1157 | g_inet_socket_address_get_port (G_INET_SOCKET_ADDRESS (address)); |
||
1158 | g_assert (candidate_port != 0); |
||
1159 | g_object_unref (address); |
||
1160 | break; |
||
1161 | } |
||
1162 | } |
||
1163 | |||
1164 | /* should only be non-zero if we have a socket */ |
||
1165 | g_assert ((candidate_port != 0) == (socket4 || socket6)); |
||
1166 | |||
1167 | while (sockets_to_close) |
||
1168 | { |
||
1169 | g_object_unref (sockets_to_close->data); |
||
1170 | sockets_to_close = g_slist_delete_link (sockets_to_close, |
||
1171 | sockets_to_close); |
||
1172 | } |
||
1173 | |||
1174 | /* now we actually listen() the sockets and add them to the listener */ |
||
1175 | if (socket6 != NULL) |
||
1176 | { |
||
1177 | g_socket_set_listen_backlog (socket6, listener->priv->listen_backlog); |
||
1178 | |||
1179 | g_signal_emit (listener, signals[EVENT], 0, |
||
1180 | G_SOCKET_LISTENER_LISTENING, socket6); |
||
1181 | |||
1182 | if (!g_socket_listen (socket6, error)) |
||
1183 | { |
||
1184 | g_object_unref (socket6); |
||
1185 | if (socket4) |
||
1186 | g_object_unref (socket4); |
||
1187 | |||
1188 | return 0; |
||
1189 | } |
||
1190 | |||
1191 | g_signal_emit (listener, signals[EVENT], 0, |
||
1192 | G_SOCKET_LISTENER_LISTENED, socket6); |
||
1193 | |||
1194 | if (source_object) |
||
1195 | g_object_set_qdata_full (G_OBJECT (socket6), source_quark, |
||
1196 | g_object_ref (source_object), |
||
1197 | g_object_unref); |
||
1198 | |||
1199 | g_ptr_array_add (listener->priv->sockets, socket6); |
||
1200 | } |
||
1201 | |||
1202 | if (socket4 != NULL) |
||
1203 | { |
||
1204 | g_socket_set_listen_backlog (socket4, listener->priv->listen_backlog); |
||
1205 | |||
1206 | g_signal_emit (listener, signals[EVENT], 0, |
||
1207 | G_SOCKET_LISTENER_LISTENING, socket4); |
||
1208 | |||
1209 | if (!g_socket_listen (socket4, error)) |
||
1210 | { |
||
1211 | g_object_unref (socket4); |
||
1212 | if (socket6) |
||
1213 | g_object_unref (socket6); |
||
1214 | |||
1215 | return 0; |
||
1216 | } |
||
1217 | |||
1218 | g_signal_emit (listener, signals[EVENT], 0, |
||
1219 | G_SOCKET_LISTENER_LISTENED, socket4); |
||
1220 | |||
1221 | if (source_object) |
||
1222 | g_object_set_qdata_full (G_OBJECT (socket4), source_quark, |
||
1223 | g_object_ref (source_object), |
||
1224 | g_object_unref); |
||
1225 | |||
1226 | g_ptr_array_add (listener->priv->sockets, socket4); |
||
1227 | } |
||
1228 | |||
1229 | if ((socket4 != NULL || socket6 != NULL) && |
||
1230 | G_SOCKET_LISTENER_GET_CLASS (listener)->changed) |
||
1231 | G_SOCKET_LISTENER_GET_CLASS (listener)->changed (listener); |
||
1232 | |||
1233 | return candidate_port; |
||
1234 | } |