2 * Copyright (C) 2006, 2007, 2008 OpenedHand Ltd.
3 * Copyright (C) 2009 Nokia Corporation.
5 * Author: Jorn Baayen <jorn@openedhand.com>
6 * Zeeshan Ali (Khattak) <zeeshanak@gnome.org>
7 * <zeeshan.ali@nokia.com>
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.
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.
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.
26 * SECTION:gssdp-client
27 * @short_description: SSDP "bus" wrapper.
29 * #GSSDPClient wraps the SSDP "bus" as used by both #GSSDPResourceBrowser
30 * and #GSSDPResourceGroup.
34 #include <sys/types.h>
37 #include <sys/socket.h>
38 #include <sys/utsname.h>
39 #include <netinet/in.h>
40 #include <arpa/inet.h>
42 #define _WIN32_WINNT 0x502
46 typedef int socklen_t;
47 /* from the return value of inet_addr */
48 typedef unsigned long in_addr_t;
55 #include <arpa/inet.h>
59 #include <libsoup/soup-headers.h>
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"
68 #ifndef INET6_ADDRSTRLEN
69 #define INET6_ADDRSTRLEN 46
72 /* Size of the buffer used for reading from the socket */
73 #define BUF_SIZE 65536
76 gssdp_client_initable_iface_init (gpointer g_iface,
79 G_DEFINE_TYPE_EXTENDED (GSSDPClient,
85 gssdp_client_initable_iface_init));
87 struct _GSSDPNetworkDevice {
91 struct sockaddr_in mask;
93 typedef struct _GSSDPNetworkDevice GSSDPNetworkDevice;
95 struct _GSSDPClientPrivate {
99 GSSDPNetworkDevice device;
101 GSSDPSocketSource *request_socket;
102 GSSDPSocketSource *multicast_socket;
103 GSSDPSocketSource *search_socket;
106 gboolean initialized;
125 static guint signals[LAST_SIGNAL];
128 make_server_id (void);
130 request_socket_source_cb (GIOChannel *source,
131 GIOCondition condition,
134 multicast_socket_source_cb (GIOChannel *source,
135 GIOCondition condition,
138 search_socket_source_cb (GIOChannel *source,
139 GIOCondition condition,
143 init_network_info (GSSDPClient *client,
147 gssdp_client_initable_init (GInitable *initable,
148 GCancellable *cancellable,
152 gssdp_client_init (GSSDPClient *client)
154 client->priv = G_TYPE_INSTANCE_GET_PRIVATE
159 client->priv->active = TRUE;
161 /* Generate default server ID */
162 client->priv->server_id = make_server_id ();
166 gssdp_client_initable_iface_init (gpointer g_iface,
167 G_GNUC_UNUSED gpointer iface_data)
169 GInitableIface *iface = (GInitableIface *)g_iface;
170 iface->init = gssdp_client_initable_init;
174 gssdp_client_initable_init (GInitable *initable,
175 G_GNUC_UNUSED GCancellable *cancellable,
178 GSSDPClient *client = GSSDP_CLIENT (initable);
179 GError *internal_error = NULL;
181 if (client->priv->initialized)
185 WSADATA wsaData = {0};
186 if (WSAStartup (MAKEWORD (2,2), &wsaData) != 0) {
189 message = g_win32_error_message (WSAGetLastError ());
190 g_set_error_literal (error,
200 /* Make sure all network info is available to us */
201 if (!init_network_info (client, &internal_error))
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,
210 if (client->priv->request_socket != NULL) {
211 gssdp_socket_source_set_callback
212 (client->priv->request_socket,
213 (GSourceFunc) request_socket_source_cb,
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,
224 if (client->priv->multicast_socket != NULL) {
225 gssdp_socket_source_set_callback
226 (client->priv->multicast_socket,
227 (GSourceFunc) multicast_socket_source_cb,
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,
240 if (client->priv->search_socket != NULL) {
241 gssdp_socket_source_set_callback
242 (client->priv->search_socket,
243 (GSourceFunc) search_socket_source_cb,
247 if (!client->priv->request_socket ||
248 !client->priv->multicast_socket ||
249 !client->priv->search_socket) {
250 g_propagate_error (error, internal_error);
252 if (client->priv->request_socket) {
253 g_object_unref (client->priv->request_socket);
255 client->priv->request_socket = NULL;
258 if (client->priv->multicast_socket) {
259 g_object_unref (client->priv->multicast_socket);
261 client->priv->multicast_socket = NULL;
264 if (client->priv->search_socket) {
265 g_object_unref (client->priv->search_socket);
267 client->priv->search_socket = NULL;
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);
277 client->priv->initialized = TRUE;
283 gssdp_client_get_property (GObject *object,
290 client = GSSDP_CLIENT (object);
292 switch (property_id) {
296 gssdp_client_get_server_id (client));
298 case PROP_MAIN_CONTEXT:
299 g_warning ("GSSDPClient:main-context is deprecated."
300 " Please use g_main_context_push_thread_default()");
304 g_main_context_get_thread_default ());
307 g_value_set_string (value,
308 gssdp_client_get_interface (client));
311 g_value_set_string (value,
312 gssdp_client_get_network (client));
315 g_value_set_string (value,
316 gssdp_client_get_host_ip (client));
319 g_value_set_boolean (value, client->priv->active);
321 case PROP_SOCKET_TTL:
322 g_value_set_uint (value, client->priv->socket_ttl);
325 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
331 gssdp_client_set_property (GObject *object,
338 client = GSSDP_CLIENT (object);
340 switch (property_id) {
342 gssdp_client_set_server_id (client,
343 g_value_get_string (value));
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()");
351 client->priv->device.iface_name = g_value_dup_string (value);
354 client->priv->device.network = g_value_dup_string (value);
357 client->priv->active = g_value_get_boolean (value);
359 case PROP_SOCKET_TTL:
360 client->priv->socket_ttl = g_value_get_uint (value);
363 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
369 gssdp_client_dispose (GObject *object)
373 client = GSSDP_CLIENT (object);
375 /* Destroy the SocketSources */
376 if (client->priv->request_socket) {
377 g_object_unref (client->priv->request_socket);
378 client->priv->request_socket = NULL;
381 if (client->priv->multicast_socket) {
382 g_object_unref (client->priv->multicast_socket);
383 client->priv->multicast_socket = NULL;
386 if (client->priv->search_socket) {
387 g_object_unref (client->priv->search_socket);
388 client->priv->search_socket = NULL;
391 G_OBJECT_CLASS (gssdp_client_parent_class)->dispose (object);
395 gssdp_client_finalize (GObject *object)
399 client = GSSDP_CLIENT (object);
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);
409 G_OBJECT_CLASS (gssdp_client_parent_class)->finalize (object);
413 gssdp_client_class_init (GSSDPClientClass *klass)
415 GObjectClass *object_class;
417 object_class = G_OBJECT_CLASS (klass);
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;
424 g_type_class_add_private (klass, sizeof (GSSDPClientPrivate));
427 * GSSDPClient:server-id:
429 * The SSDP server's identifier.
431 g_object_class_install_property
437 "The SSDP server's identifier.",
440 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
441 G_PARAM_STATIC_BLURB));
444 * GSSDPClient:main-context: (skip)
446 * The #GMainContext to use. Set to NULL to use the default.
447 * Deprecated: 0.11.2: Use g_main_context_push_thread_default().
449 g_object_class_install_property
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));
461 * GSSDPClient:interface:
463 * The name of the network interface this client is associated with.
464 * Set to NULL to autodetect.
466 g_object_class_install_property
472 "The name of the associated network interface.",
475 G_PARAM_CONSTRUCT_ONLY |
476 G_PARAM_STATIC_NAME |
477 G_PARAM_STATIC_NICK |
478 G_PARAM_STATIC_BLURB));
481 * GSSDPClient:network:
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
490 g_object_class_install_property
496 "The network this client is currently connected to.",
500 G_PARAM_STATIC_NAME |
501 G_PARAM_STATIC_NICK |
502 G_PARAM_STATIC_BLURB));
505 * GSSDPClient:host-ip:
507 * The IP address of the assoicated network interface.
509 g_object_class_install_property
512 g_param_spec_string ("host-ip",
514 "The IP address of the associated"
518 G_PARAM_STATIC_NAME |
519 G_PARAM_STATIC_NICK |
520 G_PARAM_STATIC_BLURB));
523 * GSSDPClient:active:
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.
530 g_object_class_install_property
536 "TRUE if the client is active.",
539 G_PARAM_STATIC_NAME |
540 G_PARAM_STATIC_NICK |
541 G_PARAM_STATIC_BLURB));
544 * GSSDPClient:socket-ttl:
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.
550 g_object_class_install_property
556 "Time To Live for client's sockets",
559 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
560 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
561 G_PARAM_STATIC_BLURB));
564 * GSSDPClient::message-received: (skip)
570 signals[MESSAGE_RECEIVED] =
571 g_signal_new ("message-received",
576 gssdp_marshal_VOID__STRING_UINT_INT_POINTER,
579 G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
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
592 * Return value: A new #GSSDPClient object.
595 gssdp_client_new (GMainContext *main_context,
600 g_warning ("GSSDPClient:main-context is deprecated."
601 " Please use g_main_context_push_thread_default()");
604 return g_initable_new (GSSDP_TYPE_CLIENT,
612 * gssdp_client_get_main_context: (skip)
613 * @client: A #GSSDPClient
615 * Returns: (transfer none): The #GMainContext @client is associated with, or NULL.
616 * Deprecated: 0.11.2: Returns g_main_context_get_thread_default()
619 gssdp_client_get_main_context (GSSDPClient *client)
621 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
623 return g_main_context_get_thread_default ();
627 * gssdp_client_set_server_id:
628 * @client: A #GSSDPClient
629 * @server_id: The server ID
631 * Sets the server ID of @client to @server_id.
634 gssdp_client_set_server_id (GSSDPClient *client,
635 const char *server_id)
637 g_return_if_fail (GSSDP_IS_CLIENT (client));
639 if (client->priv->server_id) {
640 g_free (client->priv->server_id);
641 client->priv->server_id = NULL;
645 client->priv->server_id = g_strdup (server_id);
647 g_object_notify (G_OBJECT (client), "server-id");
651 * gssdp_client_get_server_id:
652 * @client: A #GSSDPClient
654 * Return value: The server ID.
657 gssdp_client_get_server_id (GSSDPClient *client)
659 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
661 return client->priv->server_id;
665 * gssdp_client_get_interface:
666 * @client: A #GSSDPClient
668 * Get the name of the network interface associated to @client.
670 * Return value: The network interface name. This string should not be freed.
673 gssdp_client_get_interface (GSSDPClient *client)
675 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
677 return client->priv->device.iface_name;
681 * gssdp_client_get_host_ip:
682 * @client: A #GSSDPClient
684 * Get the IP address we advertise ourselves as using.
686 * Return value: The IP address. This string should not be freed.
689 gssdp_client_get_host_ip (GSSDPClient *client)
691 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
693 return client->priv->device.host_ip;
697 * gssdp_client_set_network:
698 * @client: A #GSSDPClient
699 * @network: The string identifying the network
701 * Sets the network identification of @client to @network.
704 gssdp_client_set_network (GSSDPClient *client,
707 g_return_if_fail (GSSDP_IS_CLIENT (client));
709 if (client->priv->device.network) {
710 g_free (client->priv->device.network);
711 client->priv->device.network = NULL;
715 client->priv->device.network = g_strdup (network);
717 g_object_notify (G_OBJECT (client), "network");
721 * gssdp_client_get_network:
722 * @client: A #GSSDPClient
724 * Get the network this client is associated with.
726 * Return value: The network identification. This string should not be freed.
729 gssdp_client_get_network (GSSDPClient *client)
731 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
733 return client->priv->device.network;
737 * gssdp_client_get_active:
738 * @client: A #GSSDPClient
740 * Return value: %TRUE if @client is active, %FALSE otherwise.
743 gssdp_client_get_active (GSSDPClient *client)
745 g_return_val_if_fail (GSSDP_IS_CLIENT (client), FALSE);
747 return client->priv->active;
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
757 * Sends @message to @dest_ip.
760 _gssdp_client_send_message (GSSDPClient *client,
764 _GSSDPMessageType type)
767 GError *error = NULL;
768 GInetAddress *inet_address = NULL;
769 GSocketAddress *address = NULL;
772 g_return_if_fail (GSSDP_IS_CLIENT (client));
773 g_return_if_fail (message != NULL);
775 if (!client->priv->active)
776 /* We don't send messages in passive mode */
779 /* Broadcast if @dest_ip is NULL */
783 /* Use default port if no port was explicitly specified */
785 dest_port = SSDP_PORT;
787 if (type == _GSSDP_DISCOVERY_REQUEST)
788 socket = gssdp_socket_source_get_socket
789 (client->priv->search_socket);
791 socket = gssdp_socket_source_get_socket
792 (client->priv->request_socket);
794 inet_address = g_inet_address_new_from_string (dest_ip);
795 address = g_inet_socket_address_new (inet_address, dest_port);
797 res = g_socket_send_to (socket,
805 g_warning ("Error sending SSDP packet to %s: %s",
808 g_error_free (error);
811 g_object_unref (address);
812 g_object_unref (inet_address);
816 * Generates the default server ID
819 make_server_id (void)
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,
830 return g_strdup_printf ("Microsoft Windows GSSDP/%s",
834 struct utsname sysinfo;
838 return g_strdup_printf ("%s/%s GSSDP/%s",
846 parse_http_request (char *buf,
848 SoupMessageHeaders **headers,
851 char *req_method = NULL;
853 SoupHTTPVersion version;
855 *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
857 if (soup_headers_parse_request (buf,
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,
867 strlen (SSDP_SEARCH_METHOD)) == 0)
868 *type = _GSSDP_DISCOVERY_REQUEST;
869 else if (g_ascii_strncasecmp (req_method,
871 strlen (GENA_NOTIFY_METHOD)) == 0)
872 *type = _GSSDP_ANNOUNCEMENT;
874 g_warning ("Unhandled method '%s'", req_method);
883 soup_message_headers_free (*headers);
897 parse_http_response (char *buf,
899 SoupMessageHeaders **headers,
904 *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
906 if (soup_headers_parse_response (buf,
912 if (status_code == 200)
913 *type = _GSSDP_DISCOVERY_RESPONSE;
915 g_warning ("Unhandled status code '%d'", status_code);
919 soup_message_headers_free (*headers);
927 * Called when data can be read from the socket
930 socket_source_cb (GSSDPSocketSource *socket_source, GSSDPClient *client)
933 char buf[BUF_SIZE], *end;
934 SoupMessageHeaders *headers = NULL;
936 GSocketAddress *address = NULL;
938 GInetAddress *inetaddr;
939 char *ip_string = NULL;
941 GError *error = NULL;
944 struct sockaddr_in addr;
947 socket = gssdp_socket_source_get_socket (socket_source);
948 bytes = g_socket_receive_from (socket,
955 g_warning ("Failed to receive from socket: %s",
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.
968 if (!g_socket_address_to_native (address,
970 sizeof (struct sockaddr_in),
972 g_warning ("Could not convert address to native: %s",
978 mask = client->priv->device.mask.sin_addr.s_addr;
979 our_addr = inet_addr (gssdp_client_get_host_ip (client));
981 if ((addr.sin_addr.s_addr & mask) != (our_addr & mask))
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);
992 /* Add trailing \0 */
996 end = strstr (buf, "\r\n\r\n");
998 g_warning ("Received packet lacks \"\\r\\n\\r\\n\" sequence. "
1004 len = end - buf + 2;
1010 if (!parse_http_request (buf,
1014 if (!parse_http_response (buf,
1018 g_warning ("Unhandled message '%s'", buf);
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));
1029 g_signal_emit (client,
1030 signals[MESSAGE_RECEIVED],
1040 g_error_free (error);
1046 soup_message_headers_free (headers);
1049 g_object_unref (address);
1055 request_socket_source_cb (G_GNUC_UNUSED GIOChannel *source,
1056 G_GNUC_UNUSED GIOCondition condition,
1059 GSSDPClient *client;
1061 client = GSSDP_CLIENT (user_data);
1063 return socket_source_cb (client->priv->request_socket, client);
1067 multicast_socket_source_cb (G_GNUC_UNUSED GIOChannel *source,
1068 G_GNUC_UNUSED GIOCondition condition,
1071 GSSDPClient *client;
1073 client = GSSDP_CLIENT (user_data);
1075 return socket_source_cb (client->priv->multicast_socket, client);
1079 search_socket_source_cb (G_GNUC_UNUSED GIOChannel *source,
1080 G_GNUC_UNUSED GIOCondition condition,
1083 GSSDPClient *client;
1085 client = GSSDP_CLIENT (user_data);
1087 return socket_source_cb (client->priv->search_socket, client);
1092 is_primary_adapter (PIP_ADAPTER_ADDRESSES adapter)
1095 adapter->FirstUnicastAddress->Address.lpSockaddr->sa_family;
1097 return !(adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK ||
1098 family == AF_INET6);
1102 extract_address_and_prefix (PIP_ADAPTER_UNICAST_ADDRESS adapter,
1103 PIP_ADAPTER_PREFIX prefix,
1107 DWORD len = INET6_ADDRSTRLEN;
1109 ret = WSAAddressToStringA (adapter->Address.lpSockaddr,
1110 adapter->Address.iSockaddrLength,
1118 ret = WSAAddressToStringA (prefix->Address.lpSockaddr,
1119 prefix->Address.iSockaddrLength,
1125 } else if (strcmp (iface, "127.0.0.1"))
1126 strcpy (network, "127.0.0.0");
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
1141 get_host_ip (GSSDPNetworkDevice *device)
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 */
1150 PIP_ADAPTER_ADDRESSES adapters_addresses;
1151 PIP_ADAPTER_ADDRESSES adapter;
1154 adapters_addresses = (PIP_ADAPTER_ADDRESSES) g_malloc0 (size);
1155 ret = GetAdaptersAddresses (AF_UNSPEC,
1160 if (ret == ERROR_BUFFER_OVERFLOW)
1161 g_free (adapters_addresses);
1162 } while (ret == ERROR_BUFFER_OVERFLOW);
1164 if (ret == ERROR_SUCCESS)
1165 for (adapter = adapters_addresses;
1167 adapter = adapter->Next) {
1168 if (adapter->FirstUnicastAddress == NULL)
1170 if (adapter->OperStatus != IfOperStatusUp)
1172 /* skip Point-to-Point devices */
1173 if (adapter->IfType == IF_TYPE_PPP)
1176 if (device->iface_name != NULL &&
1177 strcmp (device->iface_name, adapter->AdapterName) != 0)
1180 /* I think that IPv6 is done via pseudo-adapters, so
1181 * that there are either IPv4 or IPv6 addresses defined
1183 * Loopback-Devices and IPv6 go to the end of the list,
1186 if (is_primary_adapter (adapter))
1187 up_ifaces = g_list_prepend (up_ifaces, adapter);
1189 up_ifaces = g_list_append (up_ifaces, adapter);
1192 for (ifaceptr = up_ifaces;
1194 ifaceptr = ifaceptr->next) {
1195 char ip[INET6_ADDRSTRLEN];
1196 char prefix[INET6_ADDRSTRLEN];
1198 PIP_ADAPTER_ADDRESSES adapter;
1199 PIP_ADAPTER_UNICAST_ADDRESS address;
1203 adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
1204 address = adapter->FirstUnicastAddress;
1206 if (address->Address.lpSockaddr->sa_family != AF_INET)
1209 if (extract_address_and_prefix (address,
1210 adapter->FirstPrefix,
1218 device->host_ip = g_strdup (p);
1219 /* This relies on the compiler doing an arithmetic
1223 if (adapter->FirstPrefix->PrefixLength > 0) {
1224 mask = (gint32) 0x80000000;
1225 mask >>= adapter->FirstPrefix->PrefixLength - 1;
1227 device->mask.sin_family = AF_INET;
1228 device->mask.sin_port = 0;
1229 device->mask.sin_addr.s_addr = htonl ((guint32) mask);
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);
1239 g_list_free (up_ifaces);
1240 g_free (adapters_addresses);
1244 struct ifaddrs *ifa_list, *ifa;
1245 GList *up_ifaces, *ifaceptr;
1249 if (getifaddrs (&ifa_list) != 0) {
1250 g_error ("Failed to retrieve list of network interfaces:\n%s\n",
1256 for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
1257 if (ifa->ifa_addr == NULL)
1260 if (device->iface_name &&
1261 strcmp (device->iface_name, ifa->ifa_name) != 0)
1263 else if (!(ifa->ifa_flags & IFF_UP))
1265 else if ((ifa->ifa_flags & IFF_POINTOPOINT))
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);
1273 up_ifaces = g_list_prepend (up_ifaces, ifa);
1276 for (ifaceptr = up_ifaces;
1278 ifaceptr = ifaceptr->next) {
1279 char ip[INET6_ADDRSTRLEN];
1280 char net[INET6_ADDRSTRLEN];
1282 struct sockaddr_in *s4, *s4_mask;
1283 struct in_addr net_addr;
1285 ifa = ifaceptr->data;
1287 if (ifa->ifa_addr->sa_family != AF_INET) {
1291 s4 = (struct sockaddr_in *) ifa->ifa_addr;
1292 p = inet_ntop (AF_INET,
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));
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);
1310 g_list_free (up_ifaces);
1311 freeifaddrs (ifa_list);
1318 init_network_info (GSSDPClient *client, GError **error)
1320 gboolean ret = TRUE;
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
1326 if (client->priv->device.iface_name == NULL ||
1327 client->priv->device.host_ip == NULL)
1328 get_host_ip (&(client->priv->device));
1330 if (client->priv->device.iface_name == NULL) {
1331 g_set_error_literal (error,
1334 "No default route?");
1337 } else if (client->priv->device.host_ip == NULL) {
1340 GSSDP_ERROR_NO_IP_ADDRESS,
1341 "Failed to find IP of interface %s",
1342 client->priv->device.iface_name);