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