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 _GSSDPClientPrivate {
93 GSSDPSocketSource *request_socket;
94 GSSDPSocketSource *multicast_socket;
95 GSSDPSocketSource *search_socket;
115 static guint signals[LAST_SIGNAL];
118 make_server_id (void);
120 request_socket_source_cb (GIOChannel *source,
121 GIOCondition condition,
124 multicast_socket_source_cb (GIOChannel *source,
125 GIOCondition condition,
128 search_socket_source_cb (GIOChannel *source,
129 GIOCondition condition,
133 init_network_info (GSSDPClient *client,
137 gssdp_client_initable_init (GInitable *initable,
138 GCancellable *cancellable,
142 gssdp_client_init (GSSDPClient *client)
144 client->priv = G_TYPE_INSTANCE_GET_PRIVATE
149 client->priv->active = TRUE;
151 /* Generate default server ID */
152 client->priv->server_id = make_server_id ();
156 gssdp_client_initable_iface_init (gpointer g_iface,
159 GInitableIface *iface = (GInitableIface *)g_iface;
160 iface->init = gssdp_client_initable_init;
164 gssdp_client_initable_init (GInitable *initable,
165 GCancellable *cancellable,
168 GSSDPClient *client = GSSDP_CLIENT (initable);
169 GError *internal_error = NULL;
171 WSADATA wsaData = {0};
172 if (WSAStartup (MAKEWORD (2,2), &wsaData) != 0) {
175 message = g_win32_error_message (WSAGetLastError ());
176 g_set_error_literal (error,
186 /* Make sure all network info is available to us */
187 if (!init_network_info (client, &internal_error))
190 /* Set up sockets (Will set errno if it failed) */
191 client->priv->request_socket =
192 gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_REQUEST,
193 gssdp_client_get_host_ip (client),
195 if (client->priv->request_socket != NULL) {
196 gssdp_socket_source_set_callback
197 (client->priv->request_socket,
198 (GSourceFunc) request_socket_source_cb,
204 client->priv->multicast_socket =
205 gssdp_socket_source_new (GSSDP_SOCKET_SOURCE_TYPE_MULTICAST,
206 gssdp_client_get_host_ip (client),
208 if (client->priv->multicast_socket != NULL) {
209 gssdp_socket_source_set_callback
210 (client->priv->multicast_socket,
211 (GSourceFunc) multicast_socket_source_cb,
217 /* Setup send socket. For security reasons, it is not recommended to
218 * send M-SEARCH with source port == SSDP_PORT */
219 client->priv->search_socket = gssdp_socket_source_new
220 (GSSDP_SOCKET_SOURCE_TYPE_SEARCH,
221 gssdp_client_get_host_ip (client),
223 if (client->priv->search_socket != NULL) {
224 gssdp_socket_source_set_callback
225 (client->priv->search_socket,
226 (GSourceFunc) search_socket_source_cb,
230 if (!client->priv->request_socket ||
231 !client->priv->multicast_socket ||
232 !client->priv->search_socket) {
233 g_propagate_error (error, internal_error);
235 if (client->priv->request_socket) {
236 g_object_unref (client->priv->request_socket);
238 client->priv->request_socket = NULL;
241 if (client->priv->multicast_socket) {
242 g_object_unref (client->priv->multicast_socket);
244 client->priv->multicast_socket = NULL;
247 if (client->priv->search_socket) {
248 g_object_unref (client->priv->search_socket);
250 client->priv->search_socket = NULL;
256 gssdp_socket_source_attach (client->priv->request_socket);
257 gssdp_socket_source_attach (client->priv->multicast_socket);
258 gssdp_socket_source_attach (client->priv->search_socket);
264 gssdp_client_get_property (GObject *object,
271 client = GSSDP_CLIENT (object);
273 switch (property_id) {
277 gssdp_client_get_server_id (client));
279 case PROP_MAIN_CONTEXT:
280 g_warning ("GSSDPClient:main-context is deprecated."
281 " Please use g_main_context_push_thread_default()");
285 g_main_context_get_thread_default ());
288 g_value_set_string (value,
289 gssdp_client_get_interface (client));
292 g_value_set_string (value,
293 gssdp_client_get_network (client));
296 g_value_set_string (value,
297 gssdp_client_get_host_ip (client));
300 g_value_set_boolean (value, client->priv->active);
303 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
309 gssdp_client_set_property (GObject *object,
316 client = GSSDP_CLIENT (object);
318 switch (property_id) {
320 gssdp_client_set_server_id (client,
321 g_value_get_string (value));
323 case PROP_MAIN_CONTEXT:
324 if (g_value_get_pointer (value) != NULL)
325 g_warning ("GSSDPClient:main-context is deprecated."
326 " Please use g_main_context_push_thread_default()");
329 client->priv->iface = g_value_dup_string (value);
332 client->priv->network = g_value_dup_string (value);
335 client->priv->active = g_value_get_boolean (value);
338 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
344 gssdp_client_dispose (GObject *object)
348 client = GSSDP_CLIENT (object);
350 /* Destroy the SocketSources */
351 if (client->priv->request_socket) {
352 g_object_unref (client->priv->request_socket);
353 client->priv->request_socket = NULL;
356 if (client->priv->multicast_socket) {
357 g_object_unref (client->priv->multicast_socket);
358 client->priv->multicast_socket = NULL;
361 if (client->priv->search_socket) {
362 g_object_unref (client->priv->search_socket);
363 client->priv->search_socket = NULL;
366 G_OBJECT_CLASS (gssdp_client_parent_class)->dispose (object);
370 gssdp_client_finalize (GObject *object)
374 client = GSSDP_CLIENT (object);
379 g_free (client->priv->server_id);
380 g_free (client->priv->iface);
381 g_free (client->priv->host_ip);
382 g_free (client->priv->network);
384 G_OBJECT_CLASS (gssdp_client_parent_class)->finalize (object);
388 gssdp_client_class_init (GSSDPClientClass *klass)
390 GObjectClass *object_class;
392 object_class = G_OBJECT_CLASS (klass);
394 object_class->set_property = gssdp_client_set_property;
395 object_class->get_property = gssdp_client_get_property;
396 object_class->dispose = gssdp_client_dispose;
397 object_class->finalize = gssdp_client_finalize;
399 g_type_class_add_private (klass, sizeof (GSSDPClientPrivate));
402 * GSSDPClient:server-id:
404 * The SSDP server's identifier.
406 g_object_class_install_property
412 "The SSDP server's identifier.",
415 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
416 G_PARAM_STATIC_BLURB));
419 * GSSDPClient:main-context: (skip)
421 * The #GMainContext to use. Set to NULL to use the default.
422 * Deprecated: 0.11.2: Use g_main_context_push_thread_default().
424 g_object_class_install_property
430 "The associated GMainContext.",
431 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
432 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
433 G_PARAM_STATIC_BLURB));
436 * GSSDPClient:interface:
438 * The name of the network interface this client is associated with.
439 * Set to NULL to autodetect.
441 g_object_class_install_property
447 "The name of the associated network interface.",
450 G_PARAM_CONSTRUCT_ONLY |
451 G_PARAM_STATIC_NAME |
452 G_PARAM_STATIC_NICK |
453 G_PARAM_STATIC_BLURB));
456 * GSSDPClient:network:
458 * The network this client is currently connected to. You could set this
459 * to anything you want to identify the network this client is
460 * associated with. If you are using #GUPnPContextManager and associated
461 * interface is a WiFi interface, this property is set to the ESSID of
462 * the network. Otherwise, expect this to be the network IP address by
465 g_object_class_install_property
471 "The network this client is currently connected to.",
475 G_PARAM_STATIC_NAME |
476 G_PARAM_STATIC_NICK |
477 G_PARAM_STATIC_BLURB));
480 * GSSDPClient:host-ip:
482 * The IP address of the assoicated network interface.
484 g_object_class_install_property
487 g_param_spec_string ("host-ip",
489 "The IP address of the associated"
493 G_PARAM_STATIC_NAME |
494 G_PARAM_STATIC_NICK |
495 G_PARAM_STATIC_BLURB));
498 * GSSDPClient:active:
500 * Whether this client is active or not (passive). When active
501 * (default), the client sends messages on the network, otherwise
502 * not. In most cases, you don't want to touch this property.
505 g_object_class_install_property
511 "TRUE if the client is active.",
514 G_PARAM_STATIC_NAME |
515 G_PARAM_STATIC_NICK |
516 G_PARAM_STATIC_BLURB));
519 * GSSDPClient::message-received: (skip)
525 signals[MESSAGE_RECEIVED] =
526 g_signal_new ("message-received",
531 gssdp_marshal_VOID__STRING_UINT_INT_POINTER,
534 G_TYPE_STRING | G_SIGNAL_TYPE_STATIC_SCOPE,
542 * @main_context: (allow-none): Deprecated: 0.11.2: Always set to NULL. If you want to
543 * specify a context use g_main_context_push_thread_default()
544 * @iface: The name of the network interface, or %NULL for auto-detection.
545 * @error: Location to store error, or NULL
547 * Return value: A new #GSSDPClient object.
550 gssdp_client_new (GMainContext *main_context,
555 g_warning ("GSSDPClient:main-context is deprecated."
556 " Please use g_main_context_push_thread_default()");
559 return g_initable_new (GSSDP_TYPE_CLIENT,
567 * gssdp_client_get_main_context: (skip)
568 * @client: A #GSSDPClient
570 * Returns: (transfer none): The #GMainContext @client is associated with, or NULL.
571 * Deprecated: 0.11.2: Returns g_main_context_get_thread_default()
574 gssdp_client_get_main_context (GSSDPClient *client)
576 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
578 return g_main_context_get_thread_default ();
582 * gssdp_client_set_server_id:
583 * @client: A #GSSDPClient
584 * @server_id: The server ID
586 * Sets the server ID of @client to @server_id.
589 gssdp_client_set_server_id (GSSDPClient *client,
590 const char *server_id)
592 g_return_if_fail (GSSDP_IS_CLIENT (client));
594 if (client->priv->server_id) {
595 g_free (client->priv->server_id);
596 client->priv->server_id = NULL;
600 client->priv->server_id = g_strdup (server_id);
602 g_object_notify (G_OBJECT (client), "server-id");
606 * gssdp_client_get_server_id:
607 * @client: A #GSSDPClient
609 * Return value: The server ID.
612 gssdp_client_get_server_id (GSSDPClient *client)
614 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
616 return client->priv->server_id;
620 * gssdp_client_get_interface:
621 * @client: A #GSSDPClient
623 * Get the name of the network interface associated to @client.
625 * Return value: The network interface name. This string should not be freed.
628 gssdp_client_get_interface (GSSDPClient *client)
630 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
632 return client->priv->iface;
636 * gssdp_client_get_host_ip:
637 * @client: A #GSSDPClient
639 * Get the IP address we advertise ourselves as using.
641 * Return value: The IP address. This string should not be freed.
644 gssdp_client_get_host_ip (GSSDPClient *client)
646 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
648 return client->priv->host_ip;
652 * gssdp_client_set_network:
653 * @client: A #GSSDPClient
654 * @network: The string identifying the network
656 * Sets the network identification of @client to @network.
659 gssdp_client_set_network (GSSDPClient *client,
662 g_return_if_fail (GSSDP_IS_CLIENT (client));
664 if (client->priv->network) {
665 g_free (client->priv->network);
666 client->priv->network = NULL;
670 client->priv->network = g_strdup (network);
672 g_object_notify (G_OBJECT (client), "network");
676 * gssdp_client_get_network:
677 * @client: A #GSSDPClient
679 * Get the network this client is associated with.
681 * Return value: The network identification. This string should not be freed.
684 gssdp_client_get_network (GSSDPClient *client)
686 g_return_val_if_fail (GSSDP_IS_CLIENT (client), NULL);
688 return client->priv->network;
692 * gssdp_client_get_active:
693 * @client: A #GSSDPClient
695 * Return value: %TRUE if @client is active, %FALSE otherwise.
698 gssdp_client_get_active (GSSDPClient *client)
700 g_return_val_if_fail (GSSDP_IS_CLIENT (client), FALSE);
702 return client->priv->active;
706 * _gssdp_client_send_message:
707 * @client: A #GSSDPClient
708 * @dest_ip: The destination IP address, or NULL to broadcast
709 * @dest_port: The destination port, or NULL for default
710 * @message: The message to send
712 * Sends @message to @dest_ip.
715 _gssdp_client_send_message (GSSDPClient *client,
719 _GSSDPMessageType type)
722 GError *error = NULL;
723 GInetAddress *inet_address = NULL;
724 GSocketAddress *address = NULL;
727 g_return_if_fail (GSSDP_IS_CLIENT (client));
728 g_return_if_fail (message != NULL);
730 if (!client->priv->active)
731 /* We don't send messages in passive mode */
734 /* Broadcast if @dest_ip is NULL */
738 /* Use default port if no port was explicitly specified */
740 dest_port = SSDP_PORT;
742 if (type == _GSSDP_DISCOVERY_REQUEST)
743 socket = gssdp_socket_source_get_socket
744 (client->priv->search_socket);
746 socket = gssdp_socket_source_get_socket
747 (client->priv->request_socket);
749 inet_address = g_inet_address_new_from_string (dest_ip);
750 address = g_inet_socket_address_new (inet_address, dest_port);
752 res = g_socket_send_to (socket,
760 g_warning ("Error sending SSDP packet to %s: %s",
763 g_error_free (error);
766 g_object_unref (address);
767 g_object_unref (inet_address);
771 * Generates the default server ID
774 make_server_id (void)
777 OSVERSIONINFO versioninfo;
778 versioninfo.dwOSVersionInfoSize = sizeof (OSVERSIONINFO);
779 if (GetVersionEx (&versioninfo)) {
780 return g_strdup_printf ("Microsoft Windows/%ld.%ld GSSDP/%s",
781 versioninfo.dwMajorVersion,
782 versioninfo.dwMinorVersion,
785 return g_strdup_printf ("Microsoft Windows GSSDP/%s",
789 struct utsname sysinfo;
793 return g_strdup_printf ("%s/%s GSSDP/%s",
801 parse_http_request (char *buf,
803 SoupMessageHeaders **headers,
806 char *req_method = NULL;
808 SoupHTTPVersion version;
810 *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_REQUEST);
812 if (soup_headers_parse_request (buf,
817 &version) == SOUP_STATUS_OK &&
818 version == SOUP_HTTP_1_1 &&
819 (path && g_ascii_strncasecmp (path, "*", 1) == 0)) {
820 if (g_ascii_strncasecmp (req_method,
822 strlen (SSDP_SEARCH_METHOD)) == 0)
823 *type = _GSSDP_DISCOVERY_REQUEST;
824 else if (g_ascii_strncasecmp (req_method,
826 strlen (GENA_NOTIFY_METHOD)) == 0)
827 *type = _GSSDP_ANNOUNCEMENT;
829 g_warning ("Unhandled method '%s'", req_method);
838 soup_message_headers_free (*headers);
852 parse_http_response (char *buf,
854 SoupMessageHeaders **headers,
859 *headers = soup_message_headers_new (SOUP_MESSAGE_HEADERS_RESPONSE);
861 if (soup_headers_parse_response (buf,
867 if (status_code == 200)
868 *type = _GSSDP_DISCOVERY_RESPONSE;
870 g_warning ("Unhandled status code '%d'", status_code);
874 soup_message_headers_free (*headers);
883 inet_netof (struct in_addr in) {
884 in_addr_t i = ntohl(in.s_addr);
887 return (((i) & IN_CLASSA_NET) >> IN_CLASSA_NSHIFT);
888 else if (IN_CLASSB (i))
889 return (((i) & IN_CLASSB_NET) >> IN_CLASSB_NSHIFT);
891 return (((i) & IN_CLASSC_NET) >> IN_CLASSC_NSHIFT);
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;
911 in_addr_t recv_network;
912 in_addr_t our_network;
913 struct in_addr our_addr;
914 struct sockaddr_in addr;
917 socket = gssdp_socket_source_get_socket (socket_source);
918 bytes = g_socket_receive_from (socket,
925 g_warning ("Failed to receive from socket: %s",
931 /* We need the following lines to make sure the right client received
932 * the packet. We won't need to do this if there was any way to tell
933 * Mr. Unix that we are only interested in receiving multicast packets
934 * on this socket from a particular interface but AFAIK that is not
935 * possible, at least not in a portable way.
938 if (!g_socket_address_to_native (address,
940 sizeof (struct sockaddr_in),
942 g_warning ("Could not convert address to native: %s",
948 recv_network = inet_netof (addr.sin_addr);
949 our_addr.s_addr = inet_addr (gssdp_client_get_host_ip (client));
950 our_network = inet_netof (our_addr);
951 if (recv_network != our_network)
954 if (bytes >= BUF_SIZE) {
955 g_warning ("Received packet of %u bytes, but the maximum "
956 "buffer size is %d. Packed dropped.",
957 (unsigned int) bytes, BUF_SIZE);
962 /* Add trailing \0 */
966 end = strstr (buf, "\r\n\r\n");
968 g_warning ("Received packet lacks \"\\r\\n\\r\\n\" sequence. "
980 if (!parse_http_request (buf,
984 if (!parse_http_response (buf,
988 g_warning ("Unhandled message '%s'", buf);
992 /* Emit signal if parsing succeeded */
993 inetaddr = g_inet_socket_address_get_address (
994 G_INET_SOCKET_ADDRESS (address));
995 ip_string = g_inet_address_to_string (inetaddr);
996 port = g_inet_socket_address_get_port (
997 G_INET_SOCKET_ADDRESS (address));
999 g_signal_emit (client,
1000 signals[MESSAGE_RECEIVED],
1010 g_error_free (error);
1016 soup_message_headers_free (headers);
1019 g_object_unref (address);
1025 request_socket_source_cb (GIOChannel *source,
1026 GIOCondition condition,
1029 GSSDPClient *client;
1031 client = GSSDP_CLIENT (user_data);
1033 return socket_source_cb (client->priv->request_socket, client);
1037 multicast_socket_source_cb (GIOChannel *source,
1038 GIOCondition condition,
1041 GSSDPClient *client;
1043 client = GSSDP_CLIENT (user_data);
1045 return socket_source_cb (client->priv->multicast_socket, client);
1049 search_socket_source_cb (GIOChannel *source,
1050 GIOCondition condition,
1053 GSSDPClient *client;
1055 client = GSSDP_CLIENT (user_data);
1057 return socket_source_cb (client->priv->search_socket, client);
1062 is_primary_adapter (PIP_ADAPTER_ADDRESSES adapter)
1065 adapter->FirstUnicastAddress->Address.lpSockaddr->sa_family;
1067 return !(adapter->IfType == IF_TYPE_SOFTWARE_LOOPBACK ||
1068 family == AF_INET6);
1072 extract_address_and_prefix (PIP_ADAPTER_UNICAST_ADDRESS adapter,
1073 PIP_ADAPTER_PREFIX prefix,
1077 DWORD len = INET6_ADDRSTRLEN;
1079 ret = WSAAddressToStringA (adapter->Address.lpSockaddr,
1080 adapter->Address.iSockaddrLength,
1088 ret = WSAAddressToStringA (prefix->Address.lpSockaddr,
1089 prefix->Address.iSockaddrLength,
1095 } else if (strcmp (iface, "127.0.0.1"))
1096 strcpy (network, "127.0.0.0");
1105 * Get the host IP for the specified interface. If no interface is specified,
1106 * it gets the IP of the first up & running interface and sets @interface
1111 get_host_ip (char **iface, char **network)
1115 GList *up_ifaces = NULL, *ifaceptr = NULL;
1116 ULONG flags = GAA_FLAG_INCLUDE_PREFIX |
1117 GAA_FLAG_SKIP_DNS_SERVER |
1118 GAA_FLAG_SKIP_MULTICAST;
1119 DWORD size = 15360; /* Use 15k buffer initially as documented in MSDN */
1121 PIP_ADAPTER_ADDRESSES adapters_addresses;
1122 PIP_ADAPTER_ADDRESSES adapter;
1125 adapters_addresses = (PIP_ADAPTER_ADDRESSES) g_malloc0 (size);
1126 ret = GetAdaptersAddresses (AF_UNSPEC,
1131 if (ret == ERROR_BUFFER_OVERFLOW)
1132 g_free (adapters_addresses);
1133 } while (ret == ERROR_BUFFER_OVERFLOW);
1135 if (ret == ERROR_SUCCESS)
1136 for (adapter = adapters_addresses;
1138 adapter = adapter->Next) {
1139 if (adapter->FirstUnicastAddress == NULL)
1141 if (adapter->OperStatus != IfOperStatusUp)
1143 /* skip Point-to-Point devices */
1144 if (adapter->IfType == IF_TYPE_PPP)
1147 if (*iface != NULL &&
1148 strcmp (*iface, adapter->AdapterName) != 0)
1151 /* I think that IPv6 is done via pseudo-adapters, so
1152 * that there are either IPv4 or IPv6 addresses defined
1154 * Loopback-Devices and IPv6 go to the end of the list,
1157 if (is_primary_adapter (adapter))
1158 up_ifaces = g_list_prepend (up_ifaces, adapter);
1160 up_ifaces = g_list_append (up_ifaces, adapter);
1163 for (ifaceptr = up_ifaces;
1165 ifaceptr = ifaceptr->next) {
1166 char ip[INET6_ADDRSTRLEN];
1167 char prefix[INET6_ADDRSTRLEN];
1169 PIP_ADAPTER_ADDRESSES adapter;
1170 PIP_ADAPTER_UNICAST_ADDRESS address;
1174 adapter = (PIP_ADAPTER_ADDRESSES) ifaceptr->data;
1175 address = adapter->FirstUnicastAddress;
1177 switch (address->Address.lpSockaddr->sa_family) {
1180 if (extract_address_and_prefix (
1182 adapter->FirstPrefix,
1194 addr = g_strdup (p);
1196 *iface = g_strdup (adapter->AdapterName);
1197 if (*network == NULL)
1198 *network = g_strdup (q);
1203 g_list_free (up_ifaces);
1204 g_free (adapters_addresses);
1208 struct ifaddrs *ifa_list, *ifa;
1210 GList *up_ifaces, *ifaceptr;
1215 if (getifaddrs (&ifa_list) != 0) {
1216 g_error ("Failed to retrieve list of network interfaces:\n%s\n",
1222 for (ifa = ifa_list; ifa != NULL; ifa = ifa->ifa_next) {
1223 if (ifa->ifa_addr == NULL)
1226 if (*iface && strcmp (*iface, ifa->ifa_name) != 0)
1228 else if (!(ifa->ifa_flags & IFF_UP))
1230 else if ((ifa->ifa_flags & IFF_POINTOPOINT))
1233 /* Loopback and IPv6 interfaces go at the bottom on the list */
1234 if (ifa->ifa_flags & IFF_LOOPBACK ||
1235 ifa->ifa_addr->sa_family == AF_INET6)
1236 up_ifaces = g_list_append (up_ifaces, ifa);
1238 up_ifaces = g_list_prepend (up_ifaces, ifa);
1241 for (ifaceptr = up_ifaces;
1243 ifaceptr = ifaceptr->next) {
1244 char ip[INET6_ADDRSTRLEN];
1245 char net[INET6_ADDRSTRLEN];
1248 struct sockaddr_in *s4, *s4_mask;
1249 struct sockaddr_in6 *s6, *s6_mask;
1250 struct in_addr net_addr;
1251 struct in6_addr net6_addr;
1255 ifa = ifaceptr->data;
1257 switch (ifa->ifa_addr->sa_family) {
1259 s4 = (struct sockaddr_in *) ifa->ifa_addr;
1260 p = inet_ntop (AF_INET,
1261 &s4->sin_addr, ip, sizeof (ip));
1262 s4_mask = (struct sockaddr_in *) ifa->ifa_netmask;
1263 net_addr.s_addr = (in_addr_t) s4->sin_addr.s_addr &
1264 (in_addr_t) s4_mask->sin_addr.s_addr;
1265 q = inet_ntop (AF_INET, &net_addr, net, sizeof (net));
1268 s6 = (struct sockaddr_in6 *) ifa->ifa_addr;
1269 p = inet_ntop (AF_INET6,
1270 &s6->sin6_addr, ip, sizeof (ip));
1271 s6_mask = (struct sockaddr_in6 *) ifa->ifa_netmask;
1272 /* FIXME: Is this the right way to calculate this? */
1273 /* FIXME: Does this work on big endian machines? */
1274 for (i = 0; i < 16; ++i) {
1275 net6_addr.s6_addr[i] =
1276 s6->sin6_addr.s6_addr[i] &
1277 s6_mask->sin6_addr.s6_addr[i];
1279 q = inet_ntop (AF_INET6, &net6_addr, net, sizeof (net));
1282 continue; /* Unknown: ignore */
1289 *iface = g_strdup (ifa->ifa_name);
1290 if (*network == NULL)
1291 *network = g_strdup (q);
1296 g_list_free (up_ifaces);
1297 freeifaddrs (ifa_list);
1304 init_network_info (GSSDPClient *client, GError **error)
1306 gboolean ret = TRUE;
1308 if (client->priv->iface == NULL || client->priv->host_ip == NULL)
1309 client->priv->host_ip =
1310 get_host_ip (&client->priv->iface,
1311 &client->priv->network);
1313 if (client->priv->iface == NULL) {
1314 g_set_error_literal (error,
1317 "No default route?");
1320 } else if (client->priv->host_ip == NULL) {
1323 GSSDP_ERROR_NO_IP_ADDRESS,
1324 "Failed to find IP of interface %s",
1325 client->priv->iface);