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