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 {
98 GSSDPNetworkDevice device;
100 GSSDPSocketSource *request_socket;
101 GSSDPSocketSource *multicast_socket;
102 GSSDPSocketSource *search_socket;
105 gboolean initialized;
123 static guint signals[LAST_SIGNAL];
126 make_server_id (void);
128 request_socket_source_cb (GIOChannel *source,
129 GIOCondition condition,
132 multicast_socket_source_cb (GIOChannel *source,
133 GIOCondition condition,
136 search_socket_source_cb (GIOChannel *source,
137 GIOCondition condition,
141 init_network_info (GSSDPClient *client,
145 gssdp_client_initable_init (GInitable *initable,
146 GCancellable *cancellable,
150 gssdp_client_init (GSSDPClient *client)
152 client->priv = G_TYPE_INSTANCE_GET_PRIVATE
157 client->priv->active = TRUE;
159 /* Generate default server ID */
160 client->priv->server_id = make_server_id ();
164 gssdp_client_initable_iface_init (gpointer g_iface,
167 GInitableIface *iface = (GInitableIface *)g_iface;
168 iface->init = gssdp_client_initable_init;
172 gssdp_client_initable_init (GInitable *initable,
173 GCancellable *cancellable,
176 GSSDPClient *client = GSSDP_CLIENT (initable);
177 GError *internal_error = NULL;
179 if (client->priv->initialized)
183 WSADATA wsaData = {0};
184 if (WSAStartup (MAKEWORD (2,2), &wsaData) != 0) {
187 message = g_win32_error_message (WSAGetLastError ());
188 g_set_error_literal (error,
198 /* Make sure all network info is available to us */
199 if (!init_network_info (client, &internal_error))
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),
207 if (client->priv->request_socket != NULL) {
208 gssdp_socket_source_set_callback
209 (client->priv->request_socket,
210 (GSourceFunc) request_socket_source_cb,
216 client->priv->multicast_socket =
217 gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_MULTICAST,
218 gssdp_client_get_host_ip (client),
220 if (client->priv->multicast_socket != NULL) {
221 gssdp_socket_source_set_callback
222 (client->priv->multicast_socket,
223 (GSourceFunc) multicast_socket_source_cb,
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),
235 if (client->priv->search_socket != NULL) {
236 gssdp_socket_source_set_callback
237 (client->priv->search_socket,
238 (GSourceFunc) search_socket_source_cb,
242 if (!client->priv->request_socket ||
243 !client->priv->multicast_socket ||
244 !client->priv->search_socket) {
245 g_propagate_error (error, internal_error);
247 if (client->priv->request_socket) {
248 g_object_unref (client->priv->request_socket);
250 client->priv->request_socket = NULL;
253 if (client->priv->multicast_socket) {
254 g_object_unref (client->priv->multicast_socket);
256 client->priv->multicast_socket = NULL;
259 if (client->priv->search_socket) {
260 g_object_unref (client->priv->search_socket);
262 client->priv->search_socket = NULL;
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);
272 client->priv->initialized = TRUE;
278 gssdp_client_get_property (GObject *object,
285 client = GSSDP_CLIENT (object);
287 switch (property_id) {
291 gssdp_client_get_server_id (client));
293 case PROP_MAIN_CONTEXT:
294 g_warning ("GSSDPClient:main-context is deprecated."
295 " Please use g_main_context_push_thread_default()");
299 g_main_context_get_thread_default ());
302 g_value_set_string (value,
303 gssdp_client_get_interface (client));
306 g_value_set_string (value,
307 gssdp_client_get_network (client));
310 g_value_set_string (value,
311 gssdp_client_get_host_ip (client));
314 g_value_set_boolean (value, client->priv->active);
317 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
323 gssdp_client_set_property (GObject *object,
330 client = GSSDP_CLIENT (object);
332 switch (property_id) {
334 gssdp_client_set_server_id (client,
335 g_value_get_string (value));
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()");
343 client->priv->device.iface_name = g_value_dup_string (value);
346 client->priv->device.network = g_value_dup_string (value);
349 client->priv->active = g_value_get_boolean (value);
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
358 gssdp_client_dispose (GObject *object)
362 client = GSSDP_CLIENT (object);
364 /* Destroy the SocketSources */
365 if (client->priv->request_socket) {
366 g_object_unref (client->priv->request_socket);
367 client->priv->request_socket = NULL;
370 if (client->priv->multicast_socket) {
371 g_object_unref (client->priv->multicast_socket);
372 client->priv->multicast_socket = NULL;
375 if (client->priv->search_socket) {
376 g_object_unref (client->priv->search_socket);
377 client->priv->search_socket = NULL;
380 G_OBJECT_CLASS (gssdp_client_parent_class)->dispose (object);
384 gssdp_client_finalize (GObject *object)
388 client = GSSDP_CLIENT (object);
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);
398 G_OBJECT_CLASS (gssdp_client_parent_class)->finalize (object);
402 gssdp_client_class_init (GSSDPClientClass *klass)
404 GObjectClass *object_class;
406 object_class = G_OBJECT_CLASS (klass);
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;
413 g_type_class_add_private (klass, sizeof (GSSDPClientPrivate));
416 * GSSDPClient:server-id:
418 * The SSDP server's identifier.
420 g_object_class_install_property
426 "The SSDP server's identifier.",
429 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
430 G_PARAM_STATIC_BLURB));
433 * GSSDPClient:main-context: (skip)
435 * The #GMainContext to use. Set to NULL to use the default.
436 * Deprecated: 0.11.2: Use g_main_context_push_thread_default().
438 g_object_class_install_property
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));
450 * GSSDPClient:interface:
452 * The name of the network interface this client is associated with.
453 * Set to NULL to autodetect.
455 g_object_class_install_property
461 "The name of the associated network interface.",
464 G_PARAM_CONSTRUCT_ONLY |
465 G_PARAM_STATIC_NAME |
466 G_PARAM_STATIC_NICK |
467 G_PARAM_STATIC_BLURB));
470 * GSSDPClient:network:
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
479 g_object_class_install_property
485 "The network this client is currently connected to.",
489 G_PARAM_STATIC_NAME |
490 G_PARAM_STATIC_NICK |
491 G_PARAM_STATIC_BLURB));
494 * GSSDPClient:host-ip:
496 * The IP address of the assoicated network interface.
498 g_object_class_install_property
501 g_param_spec_string ("host-ip",
503 "The IP address of the associated"
507 G_PARAM_STATIC_NAME |
508 G_PARAM_STATIC_NICK |
509 G_PARAM_STATIC_BLURB));
512 * GSSDPClient:active:
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.
519 g_object_class_install_property
525 "TRUE if the client is active.",
528 G_PARAM_STATIC_NAME |
529 G_PARAM_STATIC_NICK |
530 G_PARAM_STATIC_BLURB));
533 * GSSDPClient::message-received: (skip)
539 signals[MESSAGE_RECEIVED] =
540 g_signal_new ("message-received",
545 gssdp_marshal_VOID__STRING_UINT_INT_POINTER,
548 G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
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
561 * Return value: A new #GSSDPClient object.
564 gssdp_client_new (GMainContext *main_context,
569 g_warning ("GSSDPClient:main-context is deprecated."
570 " Please use g_main_context_push_thread_default()");
573 return g_initable_new (GSSDP_TYPE_CLIENT,
581 * gssdp_client_get_main_context: (skip)
582 * @client: A #GSSDPClient
584 * Returns: (transfer none): The #GMainContext @client is associated with, or NULL.
585 * Deprecated: 0.11.2: Returns g_main_context_get_thread_default()
588 gssdp_client_get_main_context (GSSDPClient *client)
590 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
592 return g_main_context_get_thread_default ();
596 * gssdp_client_set_server_id:
597 * @client: A #GSSDPClient
598 * @server_id: The server ID
600 * Sets the server ID of @client to @server_id.
603 gssdp_client_set_server_id (GSSDPClient *client,
604 const char *server_id)
606 g_return_if_fail (GSSDP_IS_CLIENT (client));
608 if (client->priv->server_id) {
609 g_free (client->priv->server_id);
610 client->priv->server_id = NULL;
614 client->priv->server_id = g_strdup (server_id);
616 g_object_notify (G_OBJECT (client), "server-id");
620 * gssdp_client_get_server_id:
621 * @client: A #GSSDPClient
623 * Return value: The server ID.
626 gssdp_client_get_server_id (GSSDPClient *client)
628 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
630 return client->priv->server_id;
634 * gssdp_client_get_interface:
635 * @client: A #GSSDPClient
637 * Get the name of the network interface associated to @client.
639 * Return value: The network interface name. This string should not be freed.
642 gssdp_client_get_interface (GSSDPClient *client)
644 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
646 return client->priv->device.iface_name;
650 * gssdp_client_get_host_ip:
651 * @client: A #GSSDPClient
653 * Get the IP address we advertise ourselves as using.
655 * Return value: The IP address. This string should not be freed.
658 gssdp_client_get_host_ip (GSSDPClient *client)
660 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
662 return client->priv->device.host_ip;
666 * gssdp_client_set_network:
667 * @client: A #GSSDPClient
668 * @network: The string identifying the network
670 * Sets the network identification of @client to @network.
673 gssdp_client_set_network (GSSDPClient *client,
676 g_return_if_fail (GSSDP_IS_CLIENT (client));
678 if (client->priv->device.network) {
679 g_free (client->priv->device.network);
680 client->priv->device.network = NULL;
684 client->priv->device.network = g_strdup (network);
686 g_object_notify (G_OBJECT (client), "network");
690 * gssdp_client_get_network:
691 * @client: A #GSSDPClient
693 * Get the network this client is associated with.
695 * Return value: The network identification. This string should not be freed.
698 gssdp_client_get_network (GSSDPClient *client)
700 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
702 return client->priv->device.network;
706 * gssdp_client_get_active:
707 * @client: A #GSSDPClient
709 * Return value: %TRUE if @client is active, %FALSE otherwise.
712 gssdp_client_get_active (GSSDPClient *client)
714 g_return_val_if_fail (GSSDP_IS_CLIENT (client), FALSE);
716 return client->priv->active;
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
726 * Sends @message to @dest_ip.
729 _gssdp_client_send_message (GSSDPClient *client,
733 _GSSDPMessageType type)
736 GError *error = NULL;
737 GInetAddress *inet_address = NULL;
738 GSocketAddress *address = NULL;
741 g_return_if_fail (GSSDP_IS_CLIENT (client));
742 g_return_if_fail (message != NULL);
744 if (!client->priv->active)
745 /* We don't send messages in passive mode */
748 /* Broadcast if @dest_ip is NULL */
752 /* Use default port if no port was explicitly specified */
754 dest_port = SSDP_PORT;
756 if (type == _GSSDP_DISCOVERY_REQUEST)
757 socket = gssdp_socket_source_get_socket
758 (client->priv->search_socket);
760 socket = gssdp_socket_source_get_socket
761 (client->priv->request_socket);
763 inet_address = g_inet_address_new_from_string (dest_ip);
764 address = g_inet_socket_address_new (inet_address, dest_port);
766 res = g_socket_send_to (socket,
774 g_warning ("Error sending SSDP packet to %s: %s",
777 g_error_free (error);
780 g_object_unref (address);
781 g_object_unref (inet_address);
785 * Generates the default server ID
788 make_server_id (void)
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,
799 return g_strdup_printf ("Microsoft Windows GSSDP/%s",
803 struct utsname sysinfo;
807 return g_strdup_printf ("%s/%s GSSDP/%s",
815 parse_http_request (char *buf,
817 SoupMessageHeaders **headers,
820 char *req_method = NULL;
822 SoupHTTPVersion version;
824 *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
826 if (soup_headers_parse_request (buf,
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,
836 strlen (SSDP_SEARCH_METHOD)) == 0)
837 *type = _GSSDP_DISCOVERY_REQUEST;
838 else if (g_ascii_strncasecmp (req_method,
840 strlen (GENA_NOTIFY_METHOD)) == 0)
841 *type = _GSSDP_ANNOUNCEMENT;
843 g_warning ("Unhandled method '%s'", req_method);
852 soup_message_headers_free (*headers);
866 parse_http_response (char *buf,
868 SoupMessageHeaders **headers,
873 *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
875 if (soup_headers_parse_response (buf,
881 if (status_code == 200)
882 *type = _GSSDP_DISCOVERY_RESPONSE;
884 g_warning ("Unhandled status code '%d'", status_code);
888 soup_message_headers_free (*headers);
896 * Called when data can be read from the socket
899 socket_source_cb (GSSDPSocketSource *socket_source, GSSDPClient *client)
902 char buf[BUF_SIZE], *end;
903 SoupMessageHeaders *headers = NULL;
905 GSocketAddress *address = NULL;
907 GInetAddress *inetaddr;
908 char *ip_string = NULL;
910 GError *error = NULL;
913 struct sockaddr_in addr;
916 socket = gssdp_socket_source_get_socket (socket_source);
917 bytes = g_socket_receive_from (socket,
924 g_warning ("Failed to receive from socket: %s",
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.
937 if (!g_socket_address_to_native (address,
939 sizeof (struct sockaddr_in),
941 g_warning ("Could not convert address to native: %s",
947 mask = client->priv->device.mask.sin_addr.s_addr;
948 our_addr = inet_addr (gssdp_client_get_host_ip (client));
950 if ((addr.sin_addr.s_addr & mask) != (our_addr & mask))
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);
961 /* Add trailing \0 */
965 end = strstr (buf, "\r\n\r\n");
967 g_warning ("Received packet lacks \"\\r\\n\\r\\n\" sequence. "
979 if (!parse_http_request (buf,
983 if (!parse_http_response (buf,
987 g_warning ("Unhandled message '%s'", buf);
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));
998 g_signal_emit (client,
999 signals[MESSAGE_RECEIVED],
1009 g_error_free (error);
1015 soup_message_headers_free (headers);
1018 g_object_unref (address);
1024 request_socket_source_cb (GIOChannel *source,
1025 GIOCondition condition,
1028 GSSDPClient *client;
1030 client = GSSDP_CLIENT (user_data);
1032 return socket_source_cb (client->priv->request_socket, client);
1036 multicast_socket_source_cb (GIOChannel *source,
1037 GIOCondition condition,
1040 GSSDPClient *client;
1042 client = GSSDP_CLIENT (user_data);
1044 return socket_source_cb (client->priv->multicast_socket, client);
1048 search_socket_source_cb (GIOChannel *source,
1049 GIOCondition condition,
1052 GSSDPClient *client;
1054 client = GSSDP_CLIENT (user_data);
1056 return socket_source_cb (client->priv->search_socket, client);
1061 is_primary_adapter (PIP_ADAPTER_ADDRESSES adapter)
1064 adapter->FirstUnicastAddress->Address.lpSockaddr->sa_family;
1066 return !(adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK ||
1067 family == AF_INET6);
1071 extract_address_and_prefix (PIP_ADAPTER_UNICAST_ADDRESS adapter,
1072 PIP_ADAPTER_PREFIX prefix,
1076 DWORD len = INET6_ADDRSTRLEN;
1078 ret = WSAAddressToStringA (adapter->Address.lpSockaddr,
1079 adapter->Address.iSockaddrLength,
1087 ret = WSAAddressToStringA (prefix->Address.lpSockaddr,
1088 prefix->Address.iSockaddrLength,
1094 } else if (strcmp (iface, "127.0.0.1"))
1095 strcpy (network, "127.0.0.0");
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
1110 get_host_ip (GSSDPNetworkDevice *device)
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 */
1119 PIP_ADAPTER_ADDRESSES adapters_addresses;
1120 PIP_ADAPTER_ADDRESSES adapter;
1123 adapters_addresses = (PIP_ADAPTER_ADDRESSES) g_malloc0 (size);
1124 ret = GetAdaptersAddresses (AF_UNSPEC,
1129 if (ret == ERROR_BUFFER_OVERFLOW)
1130 g_free (adapters_addresses);
1131 } while (ret == ERROR_BUFFER_OVERFLOW);
1133 if (ret == ERROR_SUCCESS)
1134 for (adapter = adapters_addresses;
1136 adapter = adapter->Next) {
1137 if (adapter->FirstUnicastAddress == NULL)
1139 if (adapter->OperStatus != IfOperStatusUp)
1141 /* skip Point-to-Point devices */
1142 if (adapter->IfType == IF_TYPE_PPP)
1145 if (device->iface_name != NULL &&
1146 strcmp (device->iface_name, adapter->AdapterName) != 0)
1149 /* I think that IPv6 is done via pseudo-adapters, so
1150 * that there are either IPv4 or IPv6 addresses defined
1152 * Loopback-Devices and IPv6 go to the end of the list,
1155 if (is_primary_adapter (adapter))
1156 up_ifaces = g_list_prepend (up_ifaces, adapter);
1158 up_ifaces = g_list_append (up_ifaces, adapter);
1161 for (ifaceptr = up_ifaces;
1163 ifaceptr = ifaceptr->next) {
1164 char ip[INET6_ADDRSTRLEN];
1165 char prefix[INET6_ADDRSTRLEN];
1167 PIP_ADAPTER_ADDRESSES adapter;
1168 PIP_ADAPTER_UNICAST_ADDRESS address;
1172 adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
1173 address = adapter->FirstUnicastAddress;
1175 if (address->Address.lpSockaddr->sa_family != AF_INET)
1178 if (extract_address_and_prefix (address,
1179 adapter->FirstPrefix,
1187 device->host_ip = g_strdup (p);
1188 /* This relies on the compiler doing an arithmetic
1192 if (adapter->FirstPrefix->PrefixLength > 0) {
1193 mask = (gint32) 0x80000000;
1194 mask >>= adapter->FirstPrefix->PrefixLength - 1;
1196 device->mask.sin_family = AF_INET;
1197 device->mask.sin_port = 0;
1198 device->mask.sin_addr.s_addr = htonl ((guint32) mask);
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);
1208 g_list_free (up_ifaces);
1209 g_free (adapters_addresses);
1213 struct ifaddrs *ifa_list, *ifa;
1214 GList *up_ifaces, *ifaceptr;
1218 if (getifaddrs (&ifa_list) != 0) {
1219 g_error ("Failed to retrieve list of network interfaces:\n%s\n",
1225 for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
1226 if (ifa->ifa_addr == NULL)
1229 if (device->iface_name &&
1230 strcmp (device->iface_name, ifa->ifa_name) != 0)
1232 else if (!(ifa->ifa_flags & IFF_UP))
1234 else if ((ifa->ifa_flags & IFF_POINTOPOINT))
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);
1242 up_ifaces = g_list_prepend (up_ifaces, ifa);
1245 for (ifaceptr = up_ifaces;
1247 ifaceptr = ifaceptr->next) {
1248 char ip[INET6_ADDRSTRLEN];
1249 char net[INET6_ADDRSTRLEN];
1251 struct sockaddr_in *s4, *s4_mask;
1252 struct in_addr net_addr;
1254 ifa = ifaceptr->data;
1256 if (ifa->ifa_addr->sa_family != AF_INET) {
1260 s4 = (struct sockaddr_in *) ifa->ifa_addr;
1261 p = inet_ntop (AF_INET,
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));
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);
1278 g_list_free (up_ifaces);
1279 freeifaddrs (ifa_list);
1286 init_network_info (GSSDPClient *client, GError **error)
1288 gboolean ret = TRUE;
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
1294 if (client->priv->device.iface_name == NULL ||
1295 client->priv->device.host_ip == NULL)
1296 get_host_ip (&(client->priv->device));
1298 if (client->priv->device.iface_name == NULL) {
1299 g_set_error_literal (error,
1302 "No default route?");
1305 } else if (client->priv->device.host_ip == NULL) {
1308 GSSDP_ERROR_NO_IP_ADDRESS,
1309 "Failed to find IP of interface %s",
1310 client->priv->device.iface_name);