Fix the lib path
[external/gssdp.git] / libgssdp / gssdp-client.c
1 /* 
2  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
3  * Copyright (C) 2009 Nokia Corporation, all rights reserved.
4  *
5  * Author: Jorn Baayen <jorn@openedhand.com>
6  *         Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
7  *                               <zeeshan.ali@nokia.com>
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24
25 /**
26  * SECTION:gssdp-client
27  * @short_description: SSDP "bus" wrapper.
28  *
29  * #GSSDPClient wraps the SSDP "bus" as used by both #GSSDPResourceBrowser
30  * and #GSSDPResourceGroup.
31  */
32
33 #include <config.h>
34 #include <sys/socket.h>
35 #include <sys/types.h>
36 #include <sys/utsname.h>
37 #include <netinet/in.h>
38 #include <arpa/inet.h>
39 #include <string.h>
40 #include <stdio.h>
41 #include <errno.h>
42 #include <unistd.h>
43 #include <arpa/inet.h>
44 #include <net/if.h>
45 #include <ifaddrs.h>
46 #include <libsoup/soup-headers.h>
47
48 #include "gssdp-client.h"
49 #include "gssdp-client-private.h"
50 #include "gssdp-error.h"
51 #include "gssdp-socket-source.h"
52 #include "gssdp-marshal.h"
53 #include "gssdp-protocol.h"
54
55 /* Size of the buffer used for reading from the socket */
56 #define BUF_SIZE 1024
57
58 G_DEFINE_TYPE (GSSDPClient,
59                gssdp_client,
60                G_TYPE_OBJECT);
61
62 struct _GSSDPClientPrivate {
63         GMainContext      *main_context;
64
65         char              *server_id;
66         char              *interface;
67         char              *host_ip;
68
69         GError            **error;
70
71         GSSDPSocketSource *request_socket;
72         GSSDPSocketSource *multicast_socket;
73
74         gboolean           active;
75 };
76
77 enum {
78         PROP_0,
79         PROP_MAIN_CONTEXT,
80         PROP_SERVER_ID,
81         PROP_IFACE,
82         PROP_HOST_IP,
83         PROP_ACTIVE,
84         PROP_ERROR
85 };
86
87 enum {
88         MESSAGE_RECEIVED,
89         LAST_SIGNAL
90 };
91
92 static guint signals[LAST_SIGNAL];
93
94 /* Function prototypes */
95 static void
96 gssdp_client_set_main_context (GSSDPClient  *client,
97                                GMainContext *context);
98 static char *
99 make_server_id                (void);
100 static gboolean
101 request_socket_source_cb      (gpointer      user_data);
102 static gboolean
103 multicast_socket_source_cb    (gpointer      user_data);
104 static gboolean
105 init_network_info             (GSSDPClient  *client);
106
107 static void
108 gssdp_client_init (GSSDPClient *client)
109 {
110         client->priv = G_TYPE_INSTANCE_GET_PRIVATE
111                                         (client,
112                                          GSSDP_TYPE_CLIENT,
113                                          GSSDPClientPrivate);
114
115         client->priv->active = TRUE;
116
117         /* Generate default server ID */
118         client->priv->server_id = make_server_id ();
119 }
120
121 static void
122 gssdp_client_constructed (GObject *object)
123 {
124         GSSDPClient *client = GSSDP_CLIENT (object);
125
126         /* Make sure all network info is available to us */
127         if (!init_network_info (client))
128                 return;
129
130         /* Set up sockets (Will set errno if it failed) */
131         client->priv->request_socket =
132                 gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_REQUEST,
133                                          gssdp_client_get_host_ip (client));
134         if (client->priv->request_socket != NULL) {
135                 g_source_set_callback
136                         ((GSource *) client->priv->request_socket,
137                          request_socket_source_cb,
138                          client,
139                          NULL);
140         } else {
141                 goto errors;
142         }
143
144         client->priv->multicast_socket =
145                 gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_MULTICAST,
146                                          gssdp_client_get_host_ip (client));
147         if (client->priv->multicast_socket != NULL) {
148                 g_source_set_callback
149                         ((GSource *) client->priv->multicast_socket,
150                          multicast_socket_source_cb,
151                          client,
152                          NULL);
153         }
154
155  errors:
156         if (!client->priv->request_socket || !client->priv->multicast_socket) {
157                 if (client->priv->error)
158                         g_set_error_literal (client->priv->error,
159                                              GSSDP_ERROR,
160                                              GSSDP_ERROR_FAILED,
161                                              g_strerror (errno));
162
163                 return;
164         }
165
166         g_source_attach ((GSource *) client->priv->request_socket,
167                          client->priv->main_context);
168         g_source_unref ((GSource *) client->priv->request_socket);
169
170         g_source_attach ((GSource *) client->priv->multicast_socket,
171                          client->priv->main_context);
172         g_source_unref ((GSource *) client->priv->multicast_socket);
173 }
174
175 static void
176 gssdp_client_get_property (GObject    *object,
177                            guint       property_id,
178                            GValue     *value,
179                            GParamSpec *pspec)
180 {
181         GSSDPClient *client;
182
183         client = GSSDP_CLIENT (object);
184
185         switch (property_id) {
186         case PROP_SERVER_ID:
187                 g_value_set_string
188                         (value,
189                          gssdp_client_get_server_id (client));
190                 break;
191         case PROP_MAIN_CONTEXT:
192                 g_value_set_pointer
193                         (value,
194                          (gpointer)
195                           gssdp_client_get_main_context (client));
196                 break;
197         case PROP_IFACE:
198                 g_value_set_string (value,
199                                     gssdp_client_get_interface (client));
200                 break;
201         case PROP_HOST_IP:
202                 g_value_set_string (value,
203                                     gssdp_client_get_host_ip (client));
204                 break;
205         case PROP_ACTIVE:
206                 g_value_set_boolean (value, client->priv->active);
207                 break;
208         default:
209                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
210                 break;
211         }
212 }
213
214 static void
215 gssdp_client_set_property (GObject      *object,
216                            guint         property_id,
217                            const GValue *value,
218                            GParamSpec   *pspec)
219 {
220         GSSDPClient *client;
221
222         client = GSSDP_CLIENT (object);
223
224         switch (property_id) {
225         case PROP_SERVER_ID:
226                 gssdp_client_set_server_id (client,
227                                             g_value_get_string (value));
228                 break;
229         case PROP_MAIN_CONTEXT:
230                 gssdp_client_set_main_context (client,
231                                                g_value_get_pointer (value));
232                 break;
233         case PROP_ERROR:
234                 client->priv->error = g_value_get_pointer (value);
235                 break;
236         case PROP_IFACE:
237                 client->priv->interface = g_value_dup_string (value);
238                 break;
239         case PROP_ACTIVE:
240                 client->priv->active = g_value_get_boolean (value);
241                 break;
242         default:
243                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
244                 break;
245         }
246 }
247
248 static void
249 gssdp_client_dispose (GObject *object)
250 {
251         GSSDPClient *client;
252
253         client = GSSDP_CLIENT (object);
254
255         /* Destroy the SocketSources */
256         if (client->priv->request_socket) {
257                 g_source_destroy ((GSource *) client->priv->request_socket);
258                 client->priv->request_socket = NULL;
259         }
260
261         if (client->priv->multicast_socket) {
262                 g_source_destroy ((GSource *) client->priv->multicast_socket);
263                 client->priv->multicast_socket = NULL;
264         }
265
266         /* Unref the context */
267         if (client->priv->main_context) {
268                 g_main_context_unref (client->priv->main_context);
269                 client->priv->main_context = NULL;
270         }
271
272         G_OBJECT_CLASS (gssdp_client_parent_class)->dispose (object);
273 }
274
275 static void
276 gssdp_client_finalize (GObject *object)
277 {
278         GSSDPClient *client;
279
280         client = GSSDP_CLIENT (object);
281
282         g_free (client->priv->server_id);
283         g_free (client->priv->interface);
284         g_free (client->priv->host_ip);
285
286         G_OBJECT_CLASS (gssdp_client_parent_class)->finalize (object);
287 }
288
289 static void
290 gssdp_client_class_init (GSSDPClientClass *klass)
291 {
292         GObjectClass *object_class;
293
294         object_class = G_OBJECT_CLASS (klass);
295
296         object_class->constructed = gssdp_client_constructed;
297         object_class->set_property = gssdp_client_set_property;
298         object_class->get_property = gssdp_client_get_property;
299         object_class->dispose      = gssdp_client_dispose;
300         object_class->finalize     = gssdp_client_finalize;
301
302         g_type_class_add_private (klass, sizeof (GSSDPClientPrivate));
303
304         /**
305          * GSSDPClient:server-id
306          *
307          * The SSDP server's identifier.
308          **/
309         g_object_class_install_property
310                 (object_class,
311                  PROP_SERVER_ID,
312                  g_param_spec_string
313                          ("server-id",
314                           "Server ID",
315                           "The SSDP server's identifier.",
316                           NULL,
317                           G_PARAM_READWRITE |
318                           G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
319                           G_PARAM_STATIC_BLURB));
320
321         /**
322          * GSSDPClient:main-context
323          *
324          * The #GMainContext to use. Set to NULL to use the default.
325          **/
326         g_object_class_install_property
327                 (object_class,
328                  PROP_MAIN_CONTEXT,
329                  g_param_spec_pointer
330                          ("main-context",
331                           "Main context",
332                           "The associated GMainContext.",
333                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
334                           G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
335                           G_PARAM_STATIC_BLURB));
336
337         /**
338          * GSSDPClient:error
339          *
340          * Internal property.
341          *
342          * Stability: Private
343          **/
344         g_object_class_install_property
345                 (object_class,
346                  PROP_ERROR,
347                  g_param_spec_pointer
348                          ("error",
349                           "Error",
350                           "Location where to store the constructor GError, "
351                           "if any.",
352                           G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY |
353                           G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
354                           G_PARAM_STATIC_BLURB));
355
356         /**
357          * GSSDPClient:interface
358          *
359          * The name of the network interface this client is associated with.
360          * Set to NULL to autodetect.
361          **/
362         g_object_class_install_property
363                 (object_class,
364                  PROP_IFACE,
365                  g_param_spec_string
366                          ("interface",
367                           "Network interface",
368                           "The name of the associated network interface.",
369                           NULL,
370                           G_PARAM_READWRITE |
371                           G_PARAM_CONSTRUCT_ONLY |
372                           G_PARAM_STATIC_NAME |
373                           G_PARAM_STATIC_NICK |
374                           G_PARAM_STATIC_BLURB));
375
376         /**
377          * GSSDPClient:host-ip
378          *
379          * The IP address of the assoicated network interface.
380          **/
381         g_object_class_install_property
382                 (object_class,
383                  PROP_HOST_IP,
384                  g_param_spec_string ("host-ip",
385                                       "Host IP",
386                                       "The IP address of the associated"
387                                       "network interface",
388                                       NULL,
389                                       G_PARAM_READABLE |
390                                       G_PARAM_STATIC_NAME |
391                                       G_PARAM_STATIC_NICK |
392                                       G_PARAM_STATIC_BLURB));
393
394         /**
395          * GSSDPClient:active
396          *
397          * Whether this client is active or not (passive). When active
398          * (default), the client sends messages on the network, otherwise
399          * not. In most cases, you don't want to touch this property.
400          *
401          **/
402         g_object_class_install_property
403                 (object_class,
404                  PROP_ACTIVE,
405                  g_param_spec_boolean
406                          ("active",
407                           "Active",
408                           "TRUE if the client is active.",
409                           TRUE,
410                           G_PARAM_READWRITE |
411                           G_PARAM_STATIC_NAME |
412                           G_PARAM_STATIC_NICK |
413                           G_PARAM_STATIC_BLURB));
414
415         /**
416          * GSSDPClient::message-received
417          *
418          * Internal signal.
419          *
420          * Stability: Private
421          **/
422         signals[MESSAGE_RECEIVED] =
423                 g_signal_new ("message-received",
424                               GSSDP_TYPE_CLIENT,
425                               G_SIGNAL_RUN_LAST,
426                               0,
427                               NULL, NULL,
428                               gssdp_marshal_VOID__STRING_UINT_INT_POINTER,
429                               G_TYPE_NONE,
430                               4,
431                               G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
432                               G_TYPE_UINT,
433                               G_TYPE_INT,
434                               G_TYPE_POINTER);
435 }
436
437 /**
438  * gssdp_client_new
439  * @main_context: The #GMainContext to associate with, or NULL
440  * @interface: The name of the network interface, or %NULL for auto-detection.
441  * @error: Location to store error, or NULL
442  *
443  * Return value: A new #GSSDPClient object.
444  **/
445 GSSDPClient *
446 gssdp_client_new (GMainContext *main_context,
447                   const char   *interface,
448                   GError      **error)
449 {
450         return g_object_new (GSSDP_TYPE_CLIENT,
451                              "main-context", main_context,
452                              "interface", interface,
453                              "error", error,
454                              NULL);
455 }
456
457 /**
458  * Sets the GMainContext @client is associated with to @main_context
459  **/
460 static void
461 gssdp_client_set_main_context (GSSDPClient  *client,
462                                GMainContext *main_context)
463 {
464         g_return_if_fail (GSSDP_IS_CLIENT (client));
465
466         /* A NULL main_context is fine */
467         if (main_context)
468                 client->priv->main_context = g_main_context_ref (main_context);
469
470         g_object_notify (G_OBJECT (client), "main-context");
471 }
472
473 /**
474  * gssdp_client_get_main_context
475  * @client: A #GSSDPClient
476  *
477  * Return value: The #GMainContext @client is associated with, or NULL.
478  **/
479 GMainContext *
480 gssdp_client_get_main_context (GSSDPClient *client)
481 {
482         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
483
484         return client->priv->main_context;
485 }
486
487 /**
488  * gssdp_client_set_server_id
489  * @client: A #GSSDPClient
490  * @server_id: The server ID
491  *
492  * Sets the server ID of @client to @server_id.
493  **/
494 void
495 gssdp_client_set_server_id (GSSDPClient *client,
496                             const char  *server_id)
497 {
498         g_return_if_fail (GSSDP_IS_CLIENT (client));
499
500         if (client->priv->server_id) {
501                 g_free (client->priv->server_id);
502                 client->priv->server_id = NULL;
503         }
504
505         if (server_id)
506                 client->priv->server_id = g_strdup (server_id);
507
508         g_object_notify (G_OBJECT (client), "server-id");
509 }
510
511 /**
512  * gssdp_client_get_server_id
513  * @client: A #GSSDPClient
514  *
515  * Return value: The server ID.
516  **/
517 const char *
518 gssdp_client_get_server_id (GSSDPClient *client)
519 {
520         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
521
522         return client->priv->server_id;
523 }
524
525 /**
526  * gssdp_client_get_interface
527  * @client: A #GSSDPClient
528  *
529  * Get the name of the network interface associated to @client.
530  *
531  * Return value: The network interface name. This string should not be freed.
532  **/
533 const char *
534 gssdp_client_get_interface (GSSDPClient *client)
535 {
536         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
537
538         return client->priv->interface;
539 }
540
541 /**
542  * gssdp_client_get_host_ip
543  * @client: A #GSSDPClient
544  *
545  * Get the IP address we advertise ourselves as using.
546  *
547  * Return value: The IP address. This string should not be freed.
548  **/
549 const char *
550 gssdp_client_get_host_ip (GSSDPClient *client)
551 {
552         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
553
554         return client->priv->host_ip;
555 }
556
557 /**
558  * gssdp_client_get_active
559  * @client: A #GSSDPClient
560  *
561  * Return value: %TRUE if @client is active, %FALSE otherwise.
562  **/
563 gboolean
564 gssdp_client_get_active (GSSDPClient *client)
565 {
566         g_return_val_if_fail (GSSDP_IS_CLIENT (client), FALSE);
567
568         return client->priv->active;
569 }
570
571 /**
572  * _gssdp_client_send_message
573  * @client: A #GSSDPClient
574  * @dest_ip: The destination IP address, or NULL to broadcast
575  * @dest_port: The destination port, or NULL for default
576  * @message: The message to send
577  *
578  * Sends @message to @dest_ip.
579  **/
580 void
581 _gssdp_client_send_message (GSSDPClient *client,
582                             const char  *dest_ip,
583                             gushort      dest_port,
584                             const char  *message)
585 {
586         struct sockaddr_in addr;
587         int socket_fd, res;
588
589         g_return_if_fail (GSSDP_IS_CLIENT (client));
590         g_return_if_fail (message != NULL);
591
592         if (!client->priv->active)
593                 /* We don't send messages in passive mode */
594                 return;
595
596         /* Broadcast if @dest_ip is NULL */
597         if (dest_ip == NULL)
598                 dest_ip = SSDP_ADDR;
599
600         /* Use default port if no port was explicitly specified */
601         if (dest_port == 0)
602                 dest_port = SSDP_PORT;
603
604         socket_fd = gssdp_socket_source_get_fd (client->priv->request_socket);
605
606         memset (&addr, 0, sizeof (addr));
607
608         addr.sin_family      = AF_INET;
609         addr.sin_port        = htons (dest_port);
610         addr.sin_addr.s_addr = inet_addr (dest_ip);
611
612         res = sendto (socket_fd,
613                       message,
614                       strlen (message),
615                       0,
616                       (struct sockaddr *) &addr,
617                       sizeof (addr));
618
619         if (res == -1) {
620                 g_warning ("sendto: Error %d sending message: %s",
621                            errno, strerror (errno));
622         }
623 }
624
625 /**
626  * Generates the default server ID
627  **/
628 static char *
629 make_server_id (void)
630 {
631         struct utsname sysinfo;
632
633         uname (&sysinfo);
634         
635         return g_strdup_printf ("%s/%s GSSDP/%s",
636                                 sysinfo.sysname,
637                                 sysinfo.version,
638                                 VERSION);
639 }
640
641 static gboolean
642 parse_http_request (char                *buf,
643                     int                  len,
644                     SoupMessageHeaders **headers,
645                     int                 *type)
646 {
647         char *req_method;
648
649         *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
650
651         if (soup_headers_parse_request (buf,
652                                         len,
653                                         *headers,
654                                         &req_method,
655                                         NULL,
656                                         NULL) == SOUP_STATUS_OK) {
657                 if (g_ascii_strncasecmp (req_method,
658                                          SSDP_SEARCH_METHOD,
659                                          strlen (SSDP_SEARCH_METHOD)) == 0)
660                         *type = _GSSDP_DISCOVERY_REQUEST;
661                 else if (g_ascii_strncasecmp (req_method,
662                                               GENA_NOTIFY_METHOD,
663                                               strlen (GENA_NOTIFY_METHOD)) == 0)
664                         *type = _GSSDP_ANNOUNCEMENT;
665                 else
666                         g_warning ("Unhandled method '%s'", req_method);
667
668                 g_free (req_method);
669
670                 return TRUE;
671         } else {
672                 soup_message_headers_free (*headers);
673                 *headers = NULL;
674
675                 return FALSE;
676         }
677 }
678
679 static gboolean
680 parse_http_response (char                *buf,
681                     int                  len,
682                     SoupMessageHeaders **headers,
683                     int                 *type)
684 {
685         guint status_code;
686
687         *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
688
689         if (soup_headers_parse_response (buf,
690                                          len,
691                                          *headers,
692                                          NULL,
693                                          &status_code,
694                                          NULL)) {
695                 if (status_code == 200)
696                         *type = _GSSDP_DISCOVERY_RESPONSE;
697                 else
698                         g_warning ("Unhandled status code '%d'", status_code);
699
700                 return TRUE;
701         } else {
702                 soup_message_headers_free (*headers);
703                 *headers = NULL;
704
705                 return FALSE;
706         }
707 }
708
709 /**
710  * Called when data can be read from the socket
711  **/
712 static gboolean
713 socket_source_cb (GSSDPSocketSource *socket, GSSDPClient *client)
714 {
715         int fd, type, len;
716         ssize_t bytes;
717         char buf[BUF_SIZE], *end;
718         struct sockaddr_in addr;
719         socklen_t addr_size;
720         SoupMessageHeaders *headers;
721         struct in_addr our_addr;
722         in_addr_t our_network;
723         in_addr_t recv_network;
724
725         /* Get FD */
726         fd = gssdp_socket_source_get_fd (socket);
727
728         /* Read data */
729         addr_size = sizeof (addr);
730         
731         bytes = recvfrom (fd,
732                           buf,
733                           BUF_SIZE - 1, /* Leave space for trailing \0 */
734                           MSG_TRUNC,
735                           (struct sockaddr *) &addr,
736                           &addr_size);
737         if (bytes == -1) {
738                 g_warning ("Failed to read from socket: %d (%s)",
739                            errno,
740                            strerror (errno));
741
742                 return TRUE;
743         }
744
745         /* We need the following lines to make sure the right client received
746          * the packet. We won't need to do this if there was any way to tell
747          * Mr. Unix that we are only interested in receiving multicast packets
748          * on this socket from a particular interface but AFAIK that is not
749          * possible, at least not in a portable way.
750          */
751         recv_network = inet_netof (addr.sin_addr);
752         our_addr.s_addr = inet_addr (gssdp_client_get_host_ip (client));
753         our_network = inet_netof (our_addr);
754         if (recv_network != our_network)
755                 return TRUE;
756
757         if (bytes >= BUF_SIZE) {
758                 g_warning ("Received packet of %u bytes, but the maximum "
759                            "buffer size is %d. Packed dropped.",
760                            (unsigned int) bytes, BUF_SIZE);
761
762                 return TRUE;
763         }
764
765         /* Add trailing \0 */
766         buf[bytes] = '\0';
767
768         /* Find length */
769         end = strstr (buf, "\r\n\r\n");
770         if (!end) {
771                 g_warning ("Received packet lacks \"\\r\\n\\r\\n\" sequence. "
772                            "Packed dropped.");
773
774                 return TRUE;
775         }
776
777         len = end - buf + 2;
778         
779         /* Parse message */
780         type = -1;
781         headers = NULL;
782
783         if (!parse_http_request (buf,
784                                  len,
785                                  &headers,
786                                  &type)) {
787                 if (!parse_http_response (buf,
788                                           len,
789                                           &headers,
790                                           &type)) {
791                         g_warning ("Unhandled message '%s'", buf);
792                 }
793         }
794         
795         /* Emit signal if parsing succeeded */
796         if (type >= 0) {
797                 g_signal_emit (client,
798                                signals[MESSAGE_RECEIVED],
799                                0,
800                                inet_ntoa (addr.sin_addr),
801                                ntohs (addr.sin_port),
802                                type,
803                                headers);
804         }
805
806         if (headers)
807                 soup_message_headers_free (headers);
808
809         return TRUE;
810 }
811
812 static gboolean
813 request_socket_source_cb (gpointer user_data)
814 {
815         GSSDPClient *client;
816
817         client = GSSDP_CLIENT (user_data);
818
819         return socket_source_cb (client->priv->request_socket, client);
820 }
821
822 static gboolean
823 multicast_socket_source_cb (gpointer user_data)
824 {
825         GSSDPClient *client;
826
827         client = GSSDP_CLIENT (user_data);
828
829         return socket_source_cb (client->priv->multicast_socket, client);
830 }
831
832 /*
833  * Get the host IP for the specified interface. If no interface is specified,
834  * it gets the IP of the first up & running interface and sets @interface
835  * appropriately.
836  */
837 static char *
838 get_host_ip (char **interface)
839 {
840         struct ifaddrs *ifa_list, *ifa;
841         char *ret;
842         GList *up_ifaces, *iface;
843
844         ret = NULL;
845         up_ifaces = NULL;
846
847         if (getifaddrs (&ifa_list) != 0) {
848                 g_error ("Failed to retrieve list of network interfaces:\n%s\n",
849                          strerror (errno));
850
851                 return NULL;
852         }
853
854         for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
855                 if (ifa->ifa_addr == NULL)
856                         continue;
857
858                 if (*interface && strcmp (*interface, ifa->ifa_name) != 0)
859                         continue;
860                 else if (!(ifa->ifa_flags & IFF_UP))
861                         continue;
862                 else if ((ifa->ifa_flags & IFF_POINTOPOINT))
863                         continue;
864
865                 /* Loopback and IPv6 interfaces go at the bottom on the list */
866                 if (ifa->ifa_flags & IFF_LOOPBACK ||
867                     ifa->ifa_addr->sa_family == AF_INET6)
868                         up_ifaces = g_list_append (up_ifaces, ifa);
869                 else
870                         up_ifaces = g_list_prepend (up_ifaces, ifa);
871         }
872
873         for (iface = up_ifaces; iface != NULL; iface = iface->next) {
874                 char ip[INET6_ADDRSTRLEN];
875                 const char *p;
876                 struct sockaddr_in *s4;
877                 struct sockaddr_in6 *s6;
878
879                 p = NULL;
880
881                 ifa = iface->data;
882
883                 switch (ifa->ifa_addr->sa_family) {
884                 case AF_INET:
885                         s4 = (struct sockaddr_in *) ifa->ifa_addr;
886                         p = inet_ntop (AF_INET,
887                                        &s4->sin_addr, ip, sizeof (ip));
888                         break;
889                 case AF_INET6:
890                         s6 = (struct sockaddr_in6 *) ifa->ifa_addr;
891                         p = inet_ntop (AF_INET6,
892                                        &s6->sin6_addr, ip, sizeof (ip));
893                         break;
894                 default:
895                         continue; /* Unknown: ignore */
896                 }
897
898                 if (p != NULL) {
899                         ret = g_strdup (p);
900
901                         if (*interface == NULL)
902                                 *interface = g_strdup (ifa->ifa_name);
903                         break;
904                 }
905         }
906
907         g_list_free (up_ifaces);
908         freeifaddrs (ifa_list);
909
910         return ret;
911 }
912
913 static gboolean
914 init_network_info (GSSDPClient *client)
915 {
916         gboolean ret = TRUE;
917
918         if (client->priv->interface == NULL || client->priv->host_ip == NULL)
919                 client->priv->host_ip =
920                         get_host_ip (&client->priv->interface);
921
922         if (client->priv->interface == NULL) {
923                 if (client->priv->error)
924                         g_set_error (client->priv->error,
925                                      GSSDP_ERROR,
926                                      GSSDP_ERROR_FAILED,
927                                      "No default route?");
928
929                 ret = FALSE;
930         } else if (client->priv->host_ip == NULL) {
931                 if (client->priv->error)
932                         g_set_error (client->priv->error,
933                                      GSSDP_ERROR,
934                                      GSSDP_ERROR_NO_IP_ADDRESS,
935                                      "Failed to find IP of interface %s",
936                                      client->priv->interface);
937
938                 ret = FALSE;
939         }
940
941         return ret;
942 }
943