Make it possible to call _init multiple times
[profile/ivi/GSSDP.git] / libgssdp / gssdp-client.c
1 /* 
2  * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
3  * Copyright (C) 2009 Nokia Corporation.
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., 51 Franklin Street, Fifth Floor,
22  * Boston, MA 02110-1301, 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/types.h>
35 #include <glib.h>
36 #ifndef G_OS_WIN32
37 #include <sys/socket.h>
38 #include <sys/utsname.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
41 #else
42 #define _WIN32_WINNT 0x502
43 #include <winsock2.h>
44 #include <ws2tcpip.h>
45 #include <iphlpapi.h>
46 typedef int socklen_t;
47 /* from the return value of inet_addr */
48 typedef unsigned long in_addr_t;
49 #endif
50 #include <string.h>
51 #include <stdio.h>
52 #include <errno.h>
53 #include <unistd.h>
54 #ifndef G_OS_WIN32
55 #include <arpa/inet.h>
56 #include <net/if.h>
57 #include <ifaddrs.h>
58 #endif
59 #include <libsoup/soup-headers.h>
60
61 #include "gssdp-client.h"
62 #include "gssdp-client-private.h"
63 #include "gssdp-error.h"
64 #include "gssdp-socket-source.h"
65 #include "gssdp-marshal.h"
66 #include "gssdp-protocol.h"
67
68 #ifndef INET6_ADDRSTRLEN
69 #define INET6_ADDRSTRLEN 46
70 #endif
71
72 /* Size of the buffer used for reading from the socket */
73 #define BUF_SIZE 65536
74
75 static void
76 gssdp_client_initable_iface_init (gpointer g_iface,
77                                   gpointer iface_data);
78
79 G_DEFINE_TYPE_EXTENDED (GSSDPClient,
80                         gssdp_client,
81                         G_TYPE_OBJECT,
82                         0,
83                         G_IMPLEMENT_INTERFACE
84                                 (G_TYPE_INITABLE,
85                                  gssdp_client_initable_iface_init));
86
87 struct _GSSDPClientPrivate {
88         char              *server_id;
89         char              *iface;
90         char              *host_ip;
91         char              *network;
92
93         GSSDPSocketSource *request_socket;
94         GSSDPSocketSource *multicast_socket;
95         GSSDPSocketSource *search_socket;
96
97         gboolean           active;
98         gboolean           initialized;
99 };
100
101 enum {
102         PROP_0,
103         PROP_MAIN_CONTEXT,
104         PROP_SERVER_ID,
105         PROP_IFACE,
106         PROP_NETWORK,
107         PROP_HOST_IP,
108         PROP_ACTIVE
109 };
110
111 enum {
112         MESSAGE_RECEIVED,
113         LAST_SIGNAL
114 };
115
116 static guint signals[LAST_SIGNAL];
117
118 static char *
119 make_server_id                (void);
120 static gboolean
121 request_socket_source_cb      (GIOChannel   *source,
122                                GIOCondition  condition,
123                                gpointer      user_data);
124 static gboolean
125 multicast_socket_source_cb    (GIOChannel   *source,
126                                GIOCondition  condition,
127                                gpointer      user_data);
128 static gboolean
129 search_socket_source_cb       (GIOChannel   *source,
130                                GIOCondition  condition,
131                                gpointer      user_data);
132
133 static gboolean
134 init_network_info             (GSSDPClient  *client,
135                                GError      **error);
136
137 static gboolean
138 gssdp_client_initable_init    (GInitable     *initable,
139                                GCancellable  *cancellable,
140                                GError       **error);
141
142 static void
143 gssdp_client_init (GSSDPClient *client)
144 {
145         client->priv = G_TYPE_INSTANCE_GET_PRIVATE
146                                         (client,
147                                          GSSDP_TYPE_CLIENT,
148                                          GSSDPClientPrivate);
149
150         client->priv->active = TRUE;
151
152         /* Generate default server ID */
153         client->priv->server_id = make_server_id ();
154 }
155
156 static void
157 gssdp_client_initable_iface_init (gpointer g_iface,
158                                   gpointer iface_data)
159 {
160         GInitableIface *iface = (GInitableIface *)g_iface;
161         iface->init = gssdp_client_initable_init;
162 }
163
164 static gboolean
165 gssdp_client_initable_init (GInitable     *initable,
166                             GCancellable  *cancellable,
167                             GError       **error)
168 {
169         GSSDPClient *client = GSSDP_CLIENT (initable);
170         GError *internal_error = NULL;
171
172         if (client->priv->initialized)
173                 return TRUE;
174
175 #ifdef G_OS_WIN32
176         WSADATA wsaData = {0};
177         if (WSAStartup (MAKEWORD (2,2), &wsaData) != 0) {
178                 gchar *message;
179
180                 message = g_win32_error_message (WSAGetLastError ());
181                 g_set_error_literal (error,
182                                      GSSDP_ERROR,
183                                      GSSDP_ERROR_FAILED,
184                                      message);
185                 g_free (message);
186
187                 return FALSE;
188         }
189 #endif
190
191         /* Make sure all network info is available to us */
192         if (!init_network_info (client, &internal_error))
193                 goto errors;
194
195         /* Set up sockets (Will set errno if it failed) */
196         client->priv->request_socket =
197                 gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_REQUEST,
198                                          gssdp_client_get_host_ip (client),
199                                          &internal_error);
200         if (client->priv->request_socket != NULL) {
201                 gssdp_socket_source_set_callback
202                         (client->priv->request_socket,
203                         (GSourceFunc) request_socket_source_cb,
204                         client);
205         } else {
206                 goto errors;
207         }
208
209         client->priv->multicast_socket =
210                 gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_MULTICAST,
211                                          gssdp_client_get_host_ip (client),
212                                          &internal_error);
213         if (client->priv->multicast_socket != NULL) {
214                 gssdp_socket_source_set_callback
215                         (client->priv->multicast_socket,
216                          (GSourceFunc) multicast_socket_source_cb,
217                          client);
218         } else {
219                 goto errors;
220         }
221
222         /* Setup send socket. For security reasons, it is not recommended to
223          * send M-SEARCH with source port == SSDP_PORT */
224         client->priv->search_socket = gssdp_socket_source_new
225                                         (GSSDP_SOCKET_SOURCE_TYPE_SEARCH,
226                                          gssdp_client_get_host_ip (client),
227                                          &internal_error);
228         if (client->priv->search_socket != NULL) {
229                 gssdp_socket_source_set_callback
230                                         (client->priv->search_socket,
231                                          (GSourceFunc) search_socket_source_cb,
232                                          client);
233         }
234  errors:
235         if (!client->priv->request_socket ||
236             !client->priv->multicast_socket ||
237             !client->priv->search_socket) {
238                 g_propagate_error (error, internal_error);
239
240                 if (client->priv->request_socket) {
241                         g_object_unref (client->priv->request_socket);
242
243                         client->priv->request_socket = NULL;
244                 }
245
246                 if (client->priv->multicast_socket) {
247                         g_object_unref (client->priv->multicast_socket);
248
249                         client->priv->multicast_socket = NULL;
250                 }
251
252                 if (client->priv->search_socket) {
253                         g_object_unref (client->priv->search_socket);
254
255                         client->priv->search_socket = NULL;
256                 }
257
258                 return FALSE;
259         }
260
261         gssdp_socket_source_attach (client->priv->request_socket);
262         gssdp_socket_source_attach (client->priv->multicast_socket);
263         gssdp_socket_source_attach (client->priv->search_socket);
264
265         client->priv->initialized = TRUE;
266
267         return TRUE;
268 }
269
270 static void
271 gssdp_client_get_property (GObject    *object,
272                            guint       property_id,
273                            GValue     *value,
274                            GParamSpec *pspec)
275 {
276         GSSDPClient *client;
277
278         client = GSSDP_CLIENT (object);
279
280         switch (property_id) {
281         case PROP_SERVER_ID:
282                 g_value_set_string
283                         (value,
284                          gssdp_client_get_server_id (client));
285                 break;
286         case PROP_MAIN_CONTEXT:
287                 g_warning ("GSSDPClient:main-context is deprecated."
288                            " Please use g_main_context_push_thread_default()");
289                 g_value_set_pointer
290                         (value,
291                          (gpointer)
292                           g_main_context_get_thread_default ());
293                 break;
294         case PROP_IFACE:
295                 g_value_set_string (value,
296                                     gssdp_client_get_interface (client));
297                 break;
298         case PROP_NETWORK:
299                 g_value_set_string (value,
300                                     gssdp_client_get_network (client));
301                 break;
302         case PROP_HOST_IP:
303                 g_value_set_string (value,
304                                     gssdp_client_get_host_ip (client));
305                 break;
306         case PROP_ACTIVE:
307                 g_value_set_boolean (value, client->priv->active);
308                 break;
309         default:
310                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
311                 break;
312         }
313 }
314
315 static void
316 gssdp_client_set_property (GObject      *object,
317                            guint         property_id,
318                            const GValue *value,
319                            GParamSpec   *pspec)
320 {
321         GSSDPClient *client;
322
323         client = GSSDP_CLIENT (object);
324
325         switch (property_id) {
326         case PROP_SERVER_ID:
327                 gssdp_client_set_server_id (client,
328                                             g_value_get_string (value));
329                 break;
330         case PROP_MAIN_CONTEXT:
331                 if (g_value_get_pointer (value) != NULL)
332                         g_warning ("GSSDPClient:main-context is deprecated."
333                                    " Please use g_main_context_push_thread_default()");
334                 break;
335         case PROP_IFACE:
336                 client->priv->iface = g_value_dup_string (value);
337                 break;
338         case PROP_NETWORK:
339                 client->priv->network = g_value_dup_string (value);
340                 break;
341         case PROP_ACTIVE:
342                 client->priv->active = g_value_get_boolean (value);
343                 break;
344         default:
345                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
346                 break;
347         }
348 }
349
350 static void
351 gssdp_client_dispose (GObject *object)
352 {
353         GSSDPClient *client;
354
355         client = GSSDP_CLIENT (object);
356
357         /* Destroy the SocketSources */
358         if (client->priv->request_socket) {
359                 g_object_unref (client->priv->request_socket);
360                 client->priv->request_socket = NULL;
361         }
362
363         if (client->priv->multicast_socket) {
364                 g_object_unref (client->priv->multicast_socket);
365                 client->priv->multicast_socket = NULL;
366         }
367
368         if (client->priv->search_socket) {
369                 g_object_unref (client->priv->search_socket);
370                 client->priv->search_socket = NULL;
371         }
372
373         G_OBJECT_CLASS (gssdp_client_parent_class)->dispose (object);
374 }
375
376 static void
377 gssdp_client_finalize (GObject *object)
378 {
379         GSSDPClient *client;
380
381         client = GSSDP_CLIENT (object);
382 #ifdef G_OS_WIN32
383         WSACleanup ();
384 #endif
385
386         g_free (client->priv->server_id);
387         g_free (client->priv->iface);
388         g_free (client->priv->host_ip);
389         g_free (client->priv->network);
390
391         G_OBJECT_CLASS (gssdp_client_parent_class)->finalize (object);
392 }
393
394 static void
395 gssdp_client_class_init (GSSDPClientClass *klass)
396 {
397         GObjectClass *object_class;
398
399         object_class = G_OBJECT_CLASS (klass);
400
401         object_class->set_property = gssdp_client_set_property;
402         object_class->get_property = gssdp_client_get_property;
403         object_class->dispose      = gssdp_client_dispose;
404         object_class->finalize     = gssdp_client_finalize;
405
406         g_type_class_add_private (klass, sizeof (GSSDPClientPrivate));
407
408         /**
409          * GSSDPClient:server-id:
410          *
411          * The SSDP server's identifier.
412          **/
413         g_object_class_install_property
414                 (object_class,
415                  PROP_SERVER_ID,
416                  g_param_spec_string
417                          ("server-id",
418                           "Server ID",
419                           "The SSDP server's identifier.",
420                           NULL,
421                           G_PARAM_READWRITE |
422                           G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
423                           G_PARAM_STATIC_BLURB));
424
425         /**
426          * GSSDPClient:main-context: (skip)
427          *
428          * The #GMainContext to use. Set to NULL to use the default.
429          * Deprecated: 0.11.2: Use g_main_context_push_thread_default().
430          **/
431         g_object_class_install_property
432                 (object_class,
433                  PROP_MAIN_CONTEXT,
434                  g_param_spec_pointer
435                          ("main-context",
436                           "Main context",
437                           "The associated GMainContext.",
438                           G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
439                           G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
440                           G_PARAM_STATIC_BLURB));
441
442         /**
443          * GSSDPClient:interface:
444          *
445          * The name of the network interface this client is associated with.
446          * Set to NULL to autodetect.
447          **/
448         g_object_class_install_property
449                 (object_class,
450                  PROP_IFACE,
451                  g_param_spec_string
452                          ("interface",
453                           "Network interface",
454                           "The name of the associated network interface.",
455                           NULL,
456                           G_PARAM_READWRITE |
457                           G_PARAM_CONSTRUCT_ONLY |
458                           G_PARAM_STATIC_NAME |
459                           G_PARAM_STATIC_NICK |
460                           G_PARAM_STATIC_BLURB));
461
462         /**
463          * GSSDPClient:network:
464          *
465          * The network this client is currently connected to. You could set this
466          * to anything you want to identify the network this client is
467          * associated with. If you are using #GUPnPContextManager and associated
468          * interface is a WiFi interface, this property is set to the ESSID of
469          * the network. Otherwise, expect this to be the network IP address by
470          * default.
471          **/
472         g_object_class_install_property
473                 (object_class,
474                  PROP_NETWORK,
475                  g_param_spec_string
476                          ("network",
477                           "Network ID",
478                           "The network this client is currently connected to.",
479                           NULL,
480                           G_PARAM_READWRITE |
481                           G_PARAM_CONSTRUCT |
482                           G_PARAM_STATIC_NAME |
483                           G_PARAM_STATIC_NICK |
484                           G_PARAM_STATIC_BLURB));
485
486         /**
487          * GSSDPClient:host-ip:
488          *
489          * The IP address of the assoicated network interface.
490          **/
491         g_object_class_install_property
492                 (object_class,
493                  PROP_HOST_IP,
494                  g_param_spec_string ("host-ip",
495                                       "Host IP",
496                                       "The IP address of the associated"
497                                       "network interface",
498                                       NULL,
499                                       G_PARAM_READABLE |
500                                       G_PARAM_STATIC_NAME |
501                                       G_PARAM_STATIC_NICK |
502                                       G_PARAM_STATIC_BLURB));
503
504         /**
505          * GSSDPClient:active:
506          *
507          * Whether this client is active or not (passive). When active
508          * (default), the client sends messages on the network, otherwise
509          * not. In most cases, you don't want to touch this property.
510          *
511          **/
512         g_object_class_install_property
513                 (object_class,
514                  PROP_ACTIVE,
515                  g_param_spec_boolean
516                          ("active",
517                           "Active",
518                           "TRUE if the client is active.",
519                           TRUE,
520                           G_PARAM_READWRITE |
521                           G_PARAM_STATIC_NAME |
522                           G_PARAM_STATIC_NICK |
523                           G_PARAM_STATIC_BLURB));
524
525         /**
526          * GSSDPClient::message-received: (skip)
527          *
528          * Internal signal.
529          *
530          * Stability: Private
531          **/
532         signals[MESSAGE_RECEIVED] =
533                 g_signal_new ("message-received",
534                               GSSDP_TYPE_CLIENT,
535                               G_SIGNAL_RUN_LAST,
536                               0,
537                               NULL, NULL,
538                               gssdp_marshal_VOID__STRING_UINT_INT_POINTER,
539                               G_TYPE_NONE,
540                               4,
541                               G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
542                               G_TYPE_UINT,
543                               G_TYPE_INT,
544                               G_TYPE_POINTER);
545 }
546
547 /**
548  * gssdp_client_new:
549  * @main_context: (allow-none): Deprecated: 0.11.2: Always set to NULL. If you want to
550  *                specify a context use g_main_context_push_thread_default()
551  * @iface: The name of the network interface, or %NULL for auto-detection.
552  * @error: Location to store error, or NULL
553  *
554  * Return value: A new #GSSDPClient object.
555  **/
556 GSSDPClient *
557 gssdp_client_new (GMainContext *main_context,
558                   const char   *iface,
559                   GError      **error)
560 {
561         if (main_context) {
562                 g_warning ("GSSDPClient:main-context is deprecated."
563                            " Please use g_main_context_push_thread_default()");
564         }
565
566         return g_initable_new (GSSDP_TYPE_CLIENT,
567                                NULL,
568                                error,
569                                "interface", iface,
570                                NULL);
571 }
572
573 /*
574  * gssdp_client_get_main_context: (skip)
575  * @client: A #GSSDPClient
576  *
577  * Returns: (transfer none): The #GMainContext @client is associated with, or NULL.
578  * Deprecated: 0.11.2: Returns g_main_context_get_thread_default()
579  **/
580 GMainContext *
581 gssdp_client_get_main_context (GSSDPClient *client)
582 {
583         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
584
585         return g_main_context_get_thread_default ();
586 }
587
588 /**
589  * gssdp_client_set_server_id:
590  * @client: A #GSSDPClient
591  * @server_id: The server ID
592  *
593  * Sets the server ID of @client to @server_id.
594  **/
595 void
596 gssdp_client_set_server_id (GSSDPClient *client,
597                             const char  *server_id)
598 {
599         g_return_if_fail (GSSDP_IS_CLIENT (client));
600
601         if (client->priv->server_id) {
602                 g_free (client->priv->server_id);
603                 client->priv->server_id = NULL;
604         }
605
606         if (server_id)
607                 client->priv->server_id = g_strdup (server_id);
608
609         g_object_notify (G_OBJECT (client), "server-id");
610 }
611
612 /**
613  * gssdp_client_get_server_id:
614  * @client: A #GSSDPClient
615  *
616  * Return value: The server ID.
617  **/
618 const char *
619 gssdp_client_get_server_id (GSSDPClient *client)
620 {
621         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
622
623         return client->priv->server_id;
624 }
625
626 /**
627  * gssdp_client_get_interface:
628  * @client: A #GSSDPClient
629  *
630  * Get the name of the network interface associated to @client.
631  *
632  * Return value: The network interface name. This string should not be freed.
633  **/
634 const char *
635 gssdp_client_get_interface (GSSDPClient *client)
636 {
637         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
638
639         return client->priv->iface;
640 }
641
642 /**
643  * gssdp_client_get_host_ip:
644  * @client: A #GSSDPClient
645  *
646  * Get the IP address we advertise ourselves as using.
647  *
648  * Return value: The IP address. This string should not be freed.
649  **/
650 const char *
651 gssdp_client_get_host_ip (GSSDPClient *client)
652 {
653         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
654
655         return client->priv->host_ip;
656 }
657
658 /**
659  * gssdp_client_set_network:
660  * @client: A #GSSDPClient
661  * @network: The string identifying the network
662  *
663  * Sets the network identification of @client to @network.
664  **/
665 void
666 gssdp_client_set_network (GSSDPClient *client,
667                           const char  *network)
668 {
669         g_return_if_fail (GSSDP_IS_CLIENT (client));
670
671         if (client->priv->network) {
672                 g_free (client->priv->network);
673                 client->priv->network = NULL;
674         }
675
676         if (network)
677                 client->priv->network = g_strdup (network);
678
679         g_object_notify (G_OBJECT (client), "network");
680 }
681
682 /**
683  * gssdp_client_get_network:
684  * @client: A #GSSDPClient
685  *
686  * Get the network this client is associated with.
687  *
688  * Return value: The network identification. This string should not be freed.
689  **/
690 const char *
691 gssdp_client_get_network (GSSDPClient *client)
692 {
693         g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
694
695         return client->priv->network;
696 }
697
698 /**
699  * gssdp_client_get_active:
700  * @client: A #GSSDPClient
701  *
702  * Return value: %TRUE if @client is active, %FALSE otherwise.
703  **/
704 gboolean
705 gssdp_client_get_active (GSSDPClient *client)
706 {
707         g_return_val_if_fail (GSSDP_IS_CLIENT (client), FALSE);
708
709         return client->priv->active;
710 }
711
712 /**
713  * _gssdp_client_send_message:
714  * @client: A #GSSDPClient
715  * @dest_ip: The destination IP address, or NULL to broadcast
716  * @dest_port: The destination port, or NULL for default
717  * @message: The message to send
718  *
719  * Sends @message to @dest_ip.
720  **/
721 void
722 _gssdp_client_send_message (GSSDPClient      *client,
723                             const char       *dest_ip,
724                             gushort           dest_port,
725                             const char       *message,
726                             _GSSDPMessageType type)
727 {
728         gssize res;
729         GError *error = NULL;
730         GInetAddress *inet_address = NULL;
731         GSocketAddress *address = NULL;
732         GSocket *socket;
733
734         g_return_if_fail (GSSDP_IS_CLIENT (client));
735         g_return_if_fail (message != NULL);
736
737         if (!client->priv->active)
738                 /* We don't send messages in passive mode */
739                 return;
740
741         /* Broadcast if @dest_ip is NULL */
742         if (dest_ip == NULL)
743                 dest_ip = SSDP_ADDR;
744
745         /* Use default port if no port was explicitly specified */
746         if (dest_port == 0)
747                 dest_port = SSDP_PORT;
748
749         if (type == _GSSDP_DISCOVERY_REQUEST)
750                 socket = gssdp_socket_source_get_socket
751                                         (client->priv->search_socket);
752         else
753                 socket = gssdp_socket_source_get_socket
754                                         (client->priv->request_socket);
755
756         inet_address = g_inet_address_new_from_string (dest_ip);
757         address = g_inet_socket_address_new (inet_address, dest_port);
758
759         res = g_socket_send_to (socket,
760                                 address,
761                                 message,
762                                 strlen (message),
763                                 NULL,
764                                 &error);
765
766         if (res == -1) {
767                 g_warning ("Error sending SSDP packet to %s: %s",
768                            dest_ip,
769                            error->message);
770                 g_error_free (error);
771         }
772
773         g_object_unref (address);
774         g_object_unref (inet_address);
775 }
776
777 /*
778  * Generates the default server ID
779  */
780 static char *
781 make_server_id (void)
782 {
783 #ifdef G_OS_WIN32
784         OSVERSIONINFO versioninfo;
785         versioninfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
786         if (GetVersionEx (&versioninfo)) {
787                 return g_strdup_printf ("Microsoft Windows/%ld.%ld GSSDP/%s",
788                                         versioninfo.dwMajorVersion,
789                                         versioninfo.dwMinorVersion,
790                                         VERSION);
791         } else {
792                 return g_strdup_printf ("Microsoft Windows GSSDP/%s",
793                                         VERSION);
794         }
795 #else
796         struct utsname sysinfo;
797
798         uname (&sysinfo);
799         
800         return g_strdup_printf ("%s/%s GSSDP/%s",
801                                 sysinfo.sysname,
802                                 sysinfo.version,
803                                 VERSION);
804 #endif
805 }
806
807 static gboolean
808 parse_http_request (char                *buf,
809                     int                  len,
810                     SoupMessageHeaders **headers,
811                     int                 *type)
812 {
813         char *req_method = NULL;
814         char *path = NULL;
815         SoupHTTPVersion version;
816
817         *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
818
819         if (soup_headers_parse_request (buf,
820                                         len,
821                                         *headers,
822                                         &req_method,
823                                         &path,
824                                         &version) == SOUP_STATUS_OK &&
825             version == SOUP_HTTP_1_1 &&
826             (path && g_ascii_strncasecmp (path, "*", 1) == 0)) {
827                 if (g_ascii_strncasecmp (req_method,
828                                          SSDP_SEARCH_METHOD,
829                                          strlen (SSDP_SEARCH_METHOD)) == 0)
830                         *type = _GSSDP_DISCOVERY_REQUEST;
831                 else if (g_ascii_strncasecmp (req_method,
832                                               GENA_NOTIFY_METHOD,
833                                               strlen (GENA_NOTIFY_METHOD)) == 0)
834                         *type = _GSSDP_ANNOUNCEMENT;
835                 else
836                         g_warning ("Unhandled method '%s'", req_method);
837
838                 g_free (req_method);
839
840                 if (path)
841                         g_free (path);
842
843                 return TRUE;
844         } else {
845                 soup_message_headers_free (*headers);
846                 *headers = NULL;
847
848                 if (path)
849                         g_free (path);
850
851                 if (req_method)
852                         g_free (req_method);
853
854                 return FALSE;
855         }
856 }
857
858 static gboolean
859 parse_http_response (char                *buf,
860                     int                  len,
861                     SoupMessageHeaders **headers,
862                     int                 *type)
863 {
864         guint status_code;
865
866         *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
867
868         if (soup_headers_parse_response (buf,
869                                          len,
870                                          *headers,
871                                          NULL,
872                                          &status_code,
873                                          NULL)) {
874                 if (status_code == 200)
875                         *type = _GSSDP_DISCOVERY_RESPONSE;
876                 else
877                         g_warning ("Unhandled status code '%d'", status_code);
878
879                 return TRUE;
880         } else {
881                 soup_message_headers_free (*headers);
882                 *headers = NULL;
883
884                 return FALSE;
885         }
886 }
887
888 #ifdef G_OS_WIN32
889 static in_addr_t
890 inet_netof (struct in_addr in) {
891         in_addr_t i = ntohl(in.s_addr);
892
893         if (IN_CLASSA (i))
894             return (((i) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
895         else if (IN_CLASSB (i))
896             return (((i) & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
897         else
898             return (((i) & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
899 }
900 #endif
901
902 /*
903  * Called when data can be read from the socket
904  */
905 static gboolean
906 socket_source_cb (GSSDPSocketSource *socket_source, GSSDPClient *client)
907 {
908         int type, len;
909         char buf[BUF_SIZE], *end;
910         SoupMessageHeaders *headers = NULL;
911         GSocket *socket;
912         GSocketAddress *address = NULL;
913         gssize bytes;
914         GInetAddress *inetaddr;
915         char *ip_string = NULL;
916         guint16 port;
917         GError *error = NULL;
918         in_addr_t recv_network;
919         in_addr_t our_network;
920         struct in_addr our_addr;
921         struct sockaddr_in addr;
922
923         /* Get Socket */
924         socket = gssdp_socket_source_get_socket (socket_source);
925         bytes = g_socket_receive_from (socket,
926                                        &address,
927                                        buf,
928                                        BUF_SIZE - 1,
929                                        NULL,
930                                        &error);
931         if (bytes == -1) {
932                 g_warning ("Failed to receive from socket: %s",
933                            error->message);
934
935                 goto out;
936         }
937
938         /* We need the following lines to make sure the right client received
939          * the packet. We won't need to do this if there was any way to tell
940          * Mr. Unix that we are only interested in receiving multicast packets
941          * on this socket from a particular interface but AFAIK that is not
942          * possible, at least not in a portable way.
943          */
944
945         if (!g_socket_address_to_native (address,
946                                          &addr,
947                                          sizeof (struct sockaddr_in),
948                                          &error)) {
949                 g_warning ("Could not convert address to native: %s",
950                            error->message);
951
952                 goto out;
953         }
954
955         recv_network = inet_netof (addr.sin_addr);
956         our_addr.s_addr = inet_addr (gssdp_client_get_host_ip (client));
957         our_network = inet_netof (our_addr);
958         if (recv_network != our_network)
959                 goto out;
960
961         if (bytes >= BUF_SIZE) {
962                 g_warning ("Received packet of %u bytes, but the maximum "
963                            "buffer size is %d. Packed dropped.",
964                            (unsigned int) bytes, BUF_SIZE);
965
966                 goto out;
967         }
968
969         /* Add trailing \0 */
970         buf[bytes] = '\0';
971
972         /* Find length */
973         end = strstr (buf, "\r\n\r\n");
974         if (!end) {
975                 g_warning ("Received packet lacks \"\\r\\n\\r\\n\" sequence. "
976                            "Packed dropped.");
977
978                 goto out;
979         }
980
981         len = end - buf + 2;
982         
983         /* Parse message */
984         type = -1;
985         headers = NULL;
986
987         if (!parse_http_request (buf,
988                                  len,
989                                  &headers,
990                                  &type)) {
991                 if (!parse_http_response (buf,
992                                           len,
993                                           &headers,
994                                           &type)) {
995                         g_warning ("Unhandled message '%s'", buf);
996                 }
997         }
998         
999         /* Emit signal if parsing succeeded */
1000         inetaddr = g_inet_socket_address_get_address (
1001                                         G_INET_SOCKET_ADDRESS (address));
1002         ip_string = g_inet_address_to_string (inetaddr);
1003         port = g_inet_socket_address_get_port (
1004                                         G_INET_SOCKET_ADDRESS (address));
1005         if (type >= 0) {
1006                 g_signal_emit (client,
1007                                signals[MESSAGE_RECEIVED],
1008                                0,
1009                                ip_string,
1010                                port,
1011                                type,
1012                                headers);
1013         }
1014
1015 out:
1016         if (error)
1017                 g_error_free (error);
1018
1019         if (ip_string)
1020                 g_free (ip_string);
1021
1022         if (headers)
1023                 soup_message_headers_free (headers);
1024
1025         if (address)
1026                 g_object_unref (address);
1027
1028         return TRUE;
1029 }
1030
1031 static gboolean
1032 request_socket_source_cb (GIOChannel  *source,
1033                           GIOCondition condition,
1034                           gpointer     user_data)
1035 {
1036         GSSDPClient *client;
1037
1038         client = GSSDP_CLIENT (user_data);
1039
1040         return socket_source_cb (client->priv->request_socket, client);
1041 }
1042
1043 static gboolean
1044 multicast_socket_source_cb (GIOChannel  *source,
1045                             GIOCondition condition,
1046                             gpointer     user_data)
1047 {
1048         GSSDPClient *client;
1049
1050         client = GSSDP_CLIENT (user_data);
1051
1052         return socket_source_cb (client->priv->multicast_socket, client);
1053 }
1054
1055 static gboolean
1056 search_socket_source_cb (GIOChannel  *source,
1057                          GIOCondition condition,
1058                          gpointer     user_data)
1059 {
1060         GSSDPClient *client;
1061
1062         client = GSSDP_CLIENT (user_data);
1063
1064         return socket_source_cb (client->priv->search_socket, client);
1065 }
1066
1067 #ifdef G_OS_WIN32
1068 static gboolean
1069 is_primary_adapter (PIP_ADAPTER_ADDRESSES adapter)
1070 {
1071         int family =
1072                 adapter->FirstUnicastAddress->Address.lpSockaddr->sa_family;
1073
1074         return !(adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK ||
1075                  family == AF_INET6);
1076 }
1077
1078 static gboolean
1079 extract_address_and_prefix (PIP_ADAPTER_UNICAST_ADDRESS  adapter,
1080                             PIP_ADAPTER_PREFIX           prefix,
1081                             char                        *iface,
1082                             char                        *network) {
1083         DWORD ret = 0;
1084         DWORD len = INET6_ADDRSTRLEN;
1085
1086         ret = WSAAddressToStringA (adapter->Address.lpSockaddr,
1087                                    adapter->Address.iSockaddrLength,
1088                                    NULL,
1089                                    iface,
1090                                    &len);
1091         if (ret != 0)
1092                 return FALSE;
1093
1094         if (prefix) {
1095                 ret = WSAAddressToStringA (prefix->Address.lpSockaddr,
1096                                            prefix->Address.iSockaddrLength,
1097                                            NULL,
1098                                            network,
1099                                            &len);
1100                 if (ret != 0)
1101                         return FALSE;
1102         } else if (strcmp (iface, "127.0.0.1"))
1103                 strcpy (network, "127.0.0.0");
1104         else
1105                 return FALSE;
1106
1107         return TRUE;
1108 }
1109 #endif
1110
1111 /*
1112  * Get the host IP for the specified interface. If no interface is specified,
1113  * it gets the IP of the first up & running interface and sets @interface
1114  * appropriately.
1115  */
1116
1117 static char *
1118 get_host_ip (char **iface, char **network)
1119 {
1120 #ifdef G_OS_WIN32
1121         char *addr = NULL;
1122         GList *up_ifaces = NULL, *ifaceptr = NULL;
1123         ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
1124                       GAA_FLAG_SKIP_DNS_SERVER |
1125                       GAA_FLAG_SKIP_MULTICAST;
1126         DWORD size = 15360; /* Use 15k buffer initially as documented in MSDN */
1127         DWORD ret;
1128         PIP_ADAPTER_ADDRESSES adapters_addresses;
1129         PIP_ADAPTER_ADDRESSES adapter;
1130
1131         do {
1132                 adapters_addresses = (PIP_ADAPTER_ADDRESSES) g_malloc0 (size);
1133                 ret = GetAdaptersAddresses (AF_UNSPEC,
1134                                             flags,
1135                                             NULL,
1136                                             adapters_addresses,
1137                                             &size);
1138                 if (ret == ERROR_BUFFER_OVERFLOW)
1139                         g_free (adapters_addresses);
1140         } while (ret == ERROR_BUFFER_OVERFLOW);
1141
1142         if (ret == ERROR_SUCCESS)
1143                 for (adapter = adapters_addresses;
1144                      adapter != NULL;
1145                      adapter = adapter->Next) {
1146                         if (adapter->FirstUnicastAddress == NULL)
1147                                 continue;
1148                         if (adapter->OperStatus != IfOperStatusUp)
1149                                 continue;
1150                         /* skip Point-to-Point devices */
1151                         if (adapter->IfType == IF_TYPE_PPP)
1152                                 continue;
1153
1154                         if (*iface != NULL &&
1155                             strcmp (*iface, adapter->AdapterName) != 0)
1156                                 continue;
1157
1158                         /* I think that IPv6 is done via pseudo-adapters, so
1159                          * that there are either IPv4 or IPv6 addresses defined
1160                          * on the adapter.
1161                          * Loopback-Devices and IPv6 go to the end of the list,
1162                          * IPv4 to the front
1163                          */
1164                         if (is_primary_adapter (adapter))
1165                                 up_ifaces = g_list_prepend (up_ifaces, adapter);
1166                         else
1167                                 up_ifaces = g_list_append (up_ifaces, adapter);
1168                 }
1169
1170         for (ifaceptr = up_ifaces;
1171              ifaceptr != NULL;
1172              ifaceptr = ifaceptr->next) {
1173                 char ip[INET6_ADDRSTRLEN];
1174                 char prefix[INET6_ADDRSTRLEN];
1175                 const char *p, *q;
1176                 PIP_ADAPTER_ADDRESSES adapter;
1177                 PIP_ADAPTER_UNICAST_ADDRESS address;
1178
1179                 p = NULL;
1180
1181                 adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
1182                 address = adapter->FirstUnicastAddress;
1183
1184                 switch (address->Address.lpSockaddr->sa_family) {
1185                         case AF_INET:
1186                         case AF_INET6:
1187                                 if (extract_address_and_prefix (
1188                                          address,
1189                                          adapter->FirstPrefix,
1190                                          ip,
1191                                          prefix)) {
1192                                         p = ip;
1193                                         q = prefix;
1194                                 }
1195                                 break;
1196                         default:
1197                                 continue;
1198                 }
1199
1200                 if (p != NULL) {
1201                         addr = g_strdup (p);
1202                         if (*iface == NULL)
1203                                 *iface = g_strdup (adapter->AdapterName);
1204                         if (*network == NULL)
1205                                 *network = g_strdup (q);
1206                         break;
1207                 }
1208
1209         }
1210         g_list_free (up_ifaces);
1211         g_free (adapters_addresses);
1212
1213         return addr;
1214 #else
1215         struct ifaddrs *ifa_list, *ifa;
1216         char *ret;
1217         GList *up_ifaces, *ifaceptr;
1218
1219         ret = NULL;
1220         up_ifaces = NULL;
1221
1222         if (getifaddrs (&ifa_list) != 0) {
1223                 g_error ("Failed to retrieve list of network interfaces:\n%s\n",
1224                          strerror (errno));
1225
1226                 return NULL;
1227         }
1228
1229         for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
1230                 if (ifa->ifa_addr == NULL)
1231                         continue;
1232
1233                 if (*iface && strcmp (*iface, ifa->ifa_name) != 0)
1234                         continue;
1235                 else if (!(ifa->ifa_flags & IFF_UP))
1236                         continue;
1237                 else if ((ifa->ifa_flags & IFF_POINTOPOINT))
1238                         continue;
1239
1240                 /* Loopback and IPv6 interfaces go at the bottom on the list */
1241                 if (ifa->ifa_flags & IFF_LOOPBACK ||
1242                     ifa->ifa_addr->sa_family == AF_INET6)
1243                         up_ifaces = g_list_append (up_ifaces, ifa);
1244                 else
1245                         up_ifaces = g_list_prepend (up_ifaces, ifa);
1246         }
1247
1248         for (ifaceptr = up_ifaces;
1249              ifaceptr != NULL;
1250              ifaceptr = ifaceptr->next) {
1251                 char ip[INET6_ADDRSTRLEN];
1252                 char net[INET6_ADDRSTRLEN];
1253                 const char *p, *q;
1254                 int i = 0;
1255                 struct sockaddr_in *s4, *s4_mask;
1256                 struct sockaddr_in6 *s6, *s6_mask;
1257                 struct in_addr net_addr;
1258                 struct in6_addr net6_addr;
1259
1260                 p = NULL;
1261
1262                 ifa = ifaceptr->data;
1263
1264                 switch (ifa->ifa_addr->sa_family) {
1265                 case AF_INET:
1266                         s4 = (struct sockaddr_in *) ifa->ifa_addr;
1267                         p = inet_ntop (AF_INET,
1268                                        &s4->sin_addr, ip, sizeof (ip));
1269                         s4_mask = (struct sockaddr_in *) ifa->ifa_netmask;
1270                         net_addr.s_addr = (in_addr_t) s4->sin_addr.s_addr &
1271                                           (in_addr_t) s4_mask->sin_addr.s_addr;
1272                         q = inet_ntop (AF_INET, &net_addr, net, sizeof (net));
1273                         break;
1274                 case AF_INET6:
1275                         s6 = (struct sockaddr_in6 *) ifa->ifa_addr;
1276                         p = inet_ntop (AF_INET6,
1277                                        &s6->sin6_addr, ip, sizeof (ip));
1278                         s6_mask = (struct sockaddr_in6 *) ifa->ifa_netmask;
1279                         /* FIXME: Is this the right way to calculate this? */
1280                         /* FIXME: Does this work on big endian machines? */
1281                         for (i = 0; i < 16; ++i) {
1282                                 net6_addr.s6_addr[i] =
1283                                         s6->sin6_addr.s6_addr[i] &
1284                                         s6_mask->sin6_addr.s6_addr[i];
1285                         }
1286                         q = inet_ntop (AF_INET6, &net6_addr, net, sizeof (net));
1287                         break;
1288                 default:
1289                         continue; /* Unknown: ignore */
1290                 }
1291
1292                 if (p != NULL) {
1293                         ret = g_strdup (p);
1294
1295                         if (*iface == NULL)
1296                                 *iface = g_strdup (ifa->ifa_name);
1297                         if (*network == NULL)
1298                                 *network = g_strdup (q);
1299                         break;
1300                 }
1301         }
1302
1303         g_list_free (up_ifaces);
1304         freeifaddrs (ifa_list);
1305
1306         return ret;
1307 #endif
1308 }
1309
1310 static gboolean
1311 init_network_info (GSSDPClient *client, GError **error)
1312 {
1313         gboolean ret = TRUE;
1314
1315         if (client->priv->iface == NULL || client->priv->host_ip == NULL)
1316                 client->priv->host_ip =
1317                         get_host_ip (&client->priv->iface,
1318                                      &client->priv->network);
1319
1320         if (client->priv->iface == NULL) {
1321                 g_set_error_literal (error,
1322                                      GSSDP_ERROR,
1323                                      GSSDP_ERROR_FAILED,
1324                                      "No default route?");
1325
1326                 ret = FALSE;
1327         } else if (client->priv->host_ip == NULL) {
1328                         g_set_error (error,
1329                                      GSSDP_ERROR,
1330                                      GSSDP_ERROR_NO_IP_ADDRESS,
1331                                      "Failed to find IP of interface %s",
1332                                      client->priv->iface);
1333
1334                 ret = FALSE;
1335         }
1336
1337         return ret;
1338 }
1339