#include "glibintl.h"
#include "gnetworkingprivate.h"
+#ifdef G_OS_WIN32
+/* Ensure Windows XP runtime compatibility, while using
+ * inet_pton() and inet_ntop() if available
+ */
+#include "gwin32networking.h"
+#endif
+
struct _GInetAddressPrivate
{
GSocketFamily family;
address->priv = g_inet_address_get_instance_private (address);
}
+/* These are provided so that we can use inet_pton() and inet_ntop() on Windows
+ * if they are available (i.e. Vista and later), and use the existing code path
+ * on Windows XP/Server 2003. We can drop this portion when we drop support for
+ * XP/Server 2003.
+ */
+#if defined(G_OS_WIN32) && _WIN32_WINNT < 0x0600
+static gint
+inet_pton (gint family,
+ const gchar *addr_string,
+ gpointer addr)
+{
+ /* For Vista/Server 2008 and later, there is native inet_pton() in Winsock2 */
+ if (ws2funcs.pInetPton != NULL)
+ return ws2funcs.pInetPton (family, addr_string, addr);
+ else
+ {
+ /* Fallback codepath for XP/Server 2003 */
+ struct sockaddr_storage sa;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
+ gint len = sizeof (sa);
+
+ /* We need to make sure to not pass a string of the form
+ * "IPv4addr:port" or "[IPv6addr]:port" to WSAStringToAddress(),
+ * since it would accept them (returning both the address and the
+ * port), but we only want to accept standalone IP addresses. (In
+ * the IPv6 case, WINE actually only checks for the ']', not the
+ * '[', which is why we do the same here.)
+ */
+ if (family != AF_INET && family != AF_INET6)
+ {
+ WSASetLastError (WSAEAFNOSUPPORT);
+ return -1;
+ }
+ if (!strchr (addr_string, ':'))
+ {
+ if (WSAStringToAddress ((LPTSTR) addr_string, AF_INET, NULL, (LPSOCKADDR) &sa, &len) == 0)
+ {
+ /* XXX: Figure out when WSAStringToAddress() accepts a IPv4 address but the
+ numbers-and-dots address is actually not complete. This code will be
+ removed once XP/Server 2003 support is dropped... */
+ addr = &sin->sin_addr;
+ return 1;
+ }
+ }
+ if (!strchr (addr_string, ']'))
+ {
+ if (WSAStringToAddress ((LPTSTR) addr_string, AF_INET6, NULL, (LPSOCKADDR) &sa, &len) == 0)
+ {
+ addr = &sin6->sin6_addr;
+ return 1;
+ }
+ }
+ return 0;
+ }
+}
+
+static const gchar *
+inet_ntop (gint family,
+ const gpointer addr,
+ gchar *addr_str,
+ socklen_t size)
+{
+ /* On Vista/Server 2008 and later, there is native inet_ntop() in Winsock2 */
+ if (ws2funcs.pInetNtop != NULL)
+ return ws2funcs.pInetNtop (family, addr, addr_str, size);
+ else
+ {
+ /* Fallback codepath for XP/Server 2003 */
+ DWORD buflen = sizeof (addr_str), addrlen;
+ struct sockaddr_storage sa;
+ struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
+
+ memset (&sa, 0, sizeof (sa));
+ sa.ss_family = family;
+ if (sa.ss_family == AF_INET)
+ {
+ struct in_addr *addrv4 = (struct in_addr *) addr;
+
+ addrlen = sizeof (*sin);
+ memcpy (&sin->sin_addr, addrv4, sizeof (sin->sin_addr));
+ }
+ else if (sa.ss_family == AF_INET6)
+ {
+ struct in6_addr *addrv6 = (struct in6_addr *) addr;
+
+ addrlen = sizeof (*sin6);
+ memcpy (&sin6->sin6_addr, addrv6, sizeof (sin6->sin6_addr));
+ }
+ else
+ {
+ WSASetLastError (WSAEAFNOSUPPORT);
+ return NULL;
+ }
+ if (WSAAddressToString ((LPSOCKADDR) &sa, addrlen, NULL, addr_str, &buflen) == 0)
+ return addr_str;
+ else
+ return NULL;
+ }
+}
+#endif
+
/**
* g_inet_address_new_from_string:
* @string: a string representation of an IP address
GInetAddress *
g_inet_address_new_from_string (const gchar *string)
{
-#ifdef G_OS_WIN32
- struct sockaddr_storage sa;
- struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
- gint len;
-#else /* !G_OS_WIN32 */
struct in_addr in_addr;
struct in6_addr in6_addr;
-#endif
g_return_val_if_fail (string != NULL, NULL);
*/
g_networking_init ();
-#ifdef G_OS_WIN32
- /* We need to make sure to not pass a string of the form
- * "IPv4addr:port" or "[IPv6addr]:port" to WSAStringToAddress(),
- * since it would accept them (returning both the address and the
- * port), but we only want to accept standalone IP addresses. (In
- * the IPv6 case, WINE actually only checks for the ']', not the
- * '[', which is why we do the same here.)
- */
- if (!strchr (string, ':'))
- {
- len = sizeof (sa);
- if (WSAStringToAddress ((LPTSTR) string, AF_INET, NULL, (LPSOCKADDR) &sa, &len) == 0)
- return g_inet_address_new_from_bytes ((guint8 *)&sin->sin_addr, AF_INET);
- }
-
- if (!strchr (string, ']'))
- {
- len = sizeof (sa);
- if (WSAStringToAddress ((LPTSTR) string, AF_INET6, NULL, (LPSOCKADDR) &sa, &len) == 0)
- return g_inet_address_new_from_bytes ((guint8 *)&sin6->sin6_addr, AF_INET6);
- }
-
-#else /* !G_OS_WIN32 */
-
if (inet_pton (AF_INET, string, &in_addr) > 0)
return g_inet_address_new_from_bytes ((guint8 *)&in_addr, AF_INET);
else if (inet_pton (AF_INET6, string, &in6_addr) > 0)
return g_inet_address_new_from_bytes ((guint8 *)&in6_addr, AF_INET6);
-#endif
return NULL;
}
g_inet_address_to_string (GInetAddress *address)
{
gchar buffer[INET6_ADDRSTRLEN];
-#ifdef G_OS_WIN32
- DWORD buflen = sizeof (buffer), addrlen;
- struct sockaddr_storage sa;
- struct sockaddr_in *sin = (struct sockaddr_in *)&sa;
- struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&sa;
-#endif
g_return_val_if_fail (G_IS_INET_ADDRESS (address), NULL);
-#ifdef G_OS_WIN32
- memset (&sa, 0, sizeof (sa));
- sa.ss_family = address->priv->family;
- if (address->priv->family == AF_INET)
- {
- addrlen = sizeof (*sin);
- memcpy (&sin->sin_addr, &address->priv->addr.ipv4,
- sizeof (sin->sin_addr));
- }
- else
- {
- addrlen = sizeof (*sin6);
- memcpy (&sin6->sin6_addr, &address->priv->addr.ipv6,
- sizeof (sin6->sin6_addr));
- }
- if (WSAAddressToString ((LPSOCKADDR) &sa, addrlen, NULL, buffer, &buflen) != 0)
- return NULL;
-
-#else /* !G_OS_WIN32 */
-
if (address->priv->family == AF_INET)
inet_ntop (AF_INET, &address->priv->addr.ipv4, buffer, sizeof (buffer));
else
inet_ntop (AF_INET6, &address->priv->addr.ipv6, buffer, sizeof (buffer));
-#endif
return g_strdup (buffer);
}
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2015 Chun-wei Fan
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_WIN32_NETWORKING_H__
+#define __G_WIN32_NETWORKING_H__
+
+G_BEGIN_DECLS
+
+/* Check if more ANSI-compliant Winsock2 functions are provided */
+/* For run-time compatibility with Windows XP, remove when XP support dropped */
+
+typedef INT (WSAAPI *PFN_InetPton) (INT, PCTSTR, PVOID);
+typedef PCTSTR (WSAAPI *PFN_InetNtop) (INT, PVOID, PTSTR, size_t);
+typedef NET_IFINDEX (WINAPI *PFN_IfNameToIndex) (PCSTR);
+
+typedef struct _GWin32WinsockFuncs
+{
+ PFN_InetPton pInetPton;
+ PFN_InetNtop pInetNtop;
+ PFN_IfNameToIndex pIfNameToIndex;
+} GWin32WinsockFuncs;
+
+extern GWin32WinsockFuncs ws2funcs;
+
+G_END_DECLS /* __G_WIN32_NETWORKING_H__ */
+
+#endif