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