aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2011-06-29 09:54:23 +0000
committerhiro <hiro@ee746299-78ed-0310-b773-934348b2243d>2011-06-29 09:54:23 +0000
commit99c8a36557261ae7148b30acebbbba7090d86210 (patch)
treefc578e3131284a5d03ef308832e322071de40195
parentb3428b720c8c4ba59a4539542a0bf3e3a131bde8 (diff)
win32: supported IPv6 with fallback implementation for Windows 2000.
git-svn-id: svn://sylpheed.sraoss.jp/sylpheed/trunk@2919 ee746299-78ed-0310-b773-934348b2243d
-rw-r--r--ChangeLog6
-rw-r--r--libsylph/socket.c142
-rwxr-xr-xmakewin32.sh2
3 files changed, 147 insertions, 3 deletions
diff --git a/ChangeLog b/ChangeLog
index aa41ae94..6856e047 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,9 @@
+2011-06-29
+
+ * libsylph/socket.c: win32: supported IPv6 with fallback implementation
+ for Windows 2000.
+ * makewin32.sh: enabled IPv6.
+
2011-06-28
* src/foldersel.c: removed alloca() calls.
diff --git a/libsylph/socket.c b/libsylph/socket.c
index da6d9fdc..d2b55c13 100644
--- a/libsylph/socket.c
+++ b/libsylph/socket.c
@@ -1,6 +1,6 @@
/*
* LibSylph -- E-Mail client library
- * Copyright (C) 1999-2009 Hiroyuki Yamamoto
+ * Copyright (C) 1999-2011 Hiroyuki Yamamoto
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -150,6 +150,22 @@ static gint sock_connect_by_hostname (gint sock,
const gchar *hostname,
gushort port);
#else
+#ifdef G_OS_WIN32
+typedef int (*GetAddrInfoFunc) (const char *node,
+ const char *service,
+ const struct addrinfo *hints,
+ struct addrinfo **res);
+typedef void (*FreeAddrInfoFunc) (struct addrinfo *res);
+
+static GetAddrInfoFunc getaddrinfo_func = NULL;
+static FreeAddrInfoFunc freeaddrinfo_func = NULL;
+
+#undef getaddrinfo
+#define getaddrinfo my_getaddrinfo
+#undef freeaddrinfo
+#define freeaddrinfo my_freeaddrinfo
+#endif
+
static SockDesc sock_connect_by_getaddrinfo (const gchar *hostname,
gushort port);
#endif
@@ -777,7 +793,7 @@ static void sock_set_buffer_size(gint sock)
#endif
}
-#ifndef INET6
+#if !defined(INET6) || defined(G_OS_WIN32)
static gint my_inet_aton(const gchar *hostname, struct in_addr *inp)
{
#if HAVE_INET_ATON
@@ -797,7 +813,9 @@ static gint my_inet_aton(const gchar *hostname, struct in_addr *inp)
#endif
#endif /* HAVE_INET_ATON */
}
+#endif /* !defined(INET6) || defined(G_OS_WIN32) */
+#ifndef INET6
static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
gushort port)
{
@@ -833,6 +851,126 @@ static gint sock_connect_by_hostname(gint sock, const gchar *hostname,
#else /* INET6 */
#ifdef G_OS_WIN32
+static gboolean win32_ipv6_supported(void)
+{
+ static gboolean ipv6_checked = FALSE;
+ HMODULE hmodule;
+
+ if (ipv6_checked)
+ return getaddrinfo_func != NULL;
+
+ hmodule = GetModuleHandleA("ws2_32");
+ if (hmodule) {
+ getaddrinfo_func =
+ (GetAddrInfoFunc)GetProcAddress(hmodule, "getaddrinfo");
+ freeaddrinfo_func =
+ (FreeAddrInfoFunc)GetProcAddress(hmodule, "freeaddrinfo");
+ if (!getaddrinfo_func || !freeaddrinfo_func) {
+ getaddrinfo_func = NULL;
+ freeaddrinfo_func = NULL;
+ }
+ }
+
+ if (getaddrinfo_func)
+ debug_print("ws2_32 has IPv6 functions.\n");
+ else
+ debug_print("ws2_32 does not have IPv6 functions.\n");
+
+ ipv6_checked = TRUE;
+ return getaddrinfo_func != NULL;
+}
+
+/* subset of getaddrinfo() */
+static int my_getaddrinfo(const char *node, const char *service,
+ const struct addrinfo *hintp,
+ struct addrinfo **res)
+{
+ struct addrinfo *ai;
+ struct sockaddr_in addr, *paddr;
+ struct addrinfo hints;
+ gint port = 0;
+
+ if (win32_ipv6_supported())
+ return getaddrinfo_func(node, service, hintp, res);
+
+ if (!hintp) {
+ memset(&hints, 0, sizeof(hints));
+ hints.ai_family = AF_INET;
+ hints.ai_socktype = SOCK_STREAM;
+ } else
+ memcpy(&hints, hintp, sizeof(hints));
+
+ if (hints.ai_family != AF_UNSPEC && hints.ai_family != AF_INET)
+ return EAI_FAMILY;
+ if (hints.ai_socktype == 0)
+ hints.ai_socktype = SOCK_STREAM;
+ if (hints.ai_protocol == 0)
+ hints.ai_protocol = IPPROTO_TCP;
+ if (hints.ai_socktype != SOCK_STREAM)
+ return EAI_SOCKTYPE;
+ if (hints.ai_protocol != IPPROTO_TCP)
+ return EAI_SOCKTYPE;
+#if 0
+ if (!node && !service)
+ return EAI_NONAME;
+#endif
+ if (!node || !service)
+ return EAI_NONAME;
+
+ port = atoi(service);
+
+ memset(&addr, 0, sizeof(addr));
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(port);
+
+ if (!my_inet_aton(node, &addr.sin_addr)) {
+ struct hostent *hp;
+
+ if ((hp = my_gethostbyname(node)) == NULL) {
+ fprintf(stderr, "%s: unknown host.\n", node);
+ errno = 0;
+ return EAI_NONAME;
+ }
+ if (hp->h_length != 4 && hp->h_length != 8) {
+ fprintf(stderr, "illegal address length received for host %s\n", node);
+ errno = 0;
+ return EAI_FAIL;
+ }
+
+ memcpy(&addr.sin_addr, hp->h_addr, hp->h_length);
+ }
+
+ ai = g_malloc0(sizeof(struct addrinfo));
+ paddr = g_malloc0(sizeof(struct sockaddr_in));
+ memcpy(paddr, &addr, sizeof(struct sockaddr_in));
+
+ ai->ai_flags = 0;
+ ai->ai_family = AF_INET;
+ ai->ai_socktype = hints.ai_socktype;
+ ai->ai_protocol = hints.ai_protocol;
+ ai->ai_addrlen = sizeof(struct sockaddr_in);
+ ai->ai_addr = (struct sockaddr *)paddr;
+ ai->ai_canonname = NULL;
+ ai->ai_next = NULL;
+
+ *res = ai;
+
+ return 0;
+}
+
+static void my_freeaddrinfo(struct addrinfo *res)
+{
+ if (win32_ipv6_supported()) {
+ freeaddrinfo_func(res);
+ return;
+ }
+
+ if (res) {
+ g_free(res->ai_addr);
+ g_free(res);
+ }
+}
+
/* MinGW defines gai_strerror() in ws2tcpip.h, but it is not implemented. */
#undef gai_strerror
const gchar *gai_strerror(gint errcode)
diff --git a/makewin32.sh b/makewin32.sh
index 7d8b35d5..efa2eb0b 100755
--- a/makewin32.sh
+++ b/makewin32.sh
@@ -4,7 +4,7 @@ export LIBRARY_PATH=$LIBRARY_PATH:/usr/local/lib
export C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/include
./configure --prefix=$HOME/dist --with-localedir=lib/locale \
- --enable-oniguruma --enable-threads --disable-ipv6 \
+ --enable-oniguruma --enable-threads \
'CC=gcc -mtune=pentium3' CFLAGS=-O3 \
&& make \
&& make install-strip \