git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 0/2] Add support for IPv6 on MinGW
@ 2009-11-23 22:54 Martin Storsjö
  2009-11-23 22:55 ` [PATCH 1/2] Refactor winsock initialization into a separate function Martin Storsjö
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Martin Storsjö @ 2009-11-23 22:54 UTC (permalink / raw)
  To: git; +Cc: gitster

[-- Attachment #1: Type: TEXT/PLAIN, Size: 555 bytes --]

Hi,

This is a short patch series that adds support for IPv6 on MinGW. These 
patches have been in use in msysgit for a few months (but the code was 
accidentally removed recently in a merge). For consistency, it would be 
good to add them upstream, too.

Martin Storsjö (2):
  Refactor winsock initialization into a separate function
  Enable support for IPv6 on MinGW

 Makefile       |    1 -
 compat/mingw.c |  184 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 compat/mingw.h |   13 ++++
 3 files changed, 193 insertions(+), 5 deletions(-)

^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH 1/2] Refactor winsock initialization into a separate function
  2009-11-23 22:54 [PATCH 0/2] Add support for IPv6 on MinGW Martin Storsjö
@ 2009-11-23 22:55 ` Martin Storsjö
  2009-11-24  7:36   ` Johannes Sixt
  2009-11-23 22:55 ` [PATCH 2/2] Enable support for IPv6 on MinGW Martin Storsjö
  2009-11-24  0:58 ` [PATCH 0/2] Add " Junio C Hamano
  2 siblings, 1 reply; 7+ messages in thread
From: Martin Storsjö @ 2009-11-23 22:55 UTC (permalink / raw)
  To: git; +Cc: gitster

Signed-off-by: Martin Storsjo <martin@martin.st>
---
 compat/mingw.c |   15 ++++++++++++---
 1 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/compat/mingw.c b/compat/mingw.c
index 15fe33e..f9d82ff 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -903,16 +903,25 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
-/* this is the first function to call into WS_32; initialize it */
-#undef gethostbyname
-struct hostent *mingw_gethostbyname(const char *host)
+static void ensure_socket_initialization(void)
 {
 	WSADATA wsa;
+	static int initialized = 0;
+
+	if (initialized)
+		return;
 
 	if (WSAStartup(MAKEWORD(2,2), &wsa))
 		die("unable to initialize winsock subsystem, error %d",
 			WSAGetLastError());
 	atexit((void(*)(void)) WSACleanup);
+	initialized = 1;
+}
+
+#undef gethostbyname
+struct hostent *mingw_gethostbyname(const char *host)
+{
+	ensure_socket_initialization();
 	return gethostbyname(host);
 }
 
-- 
1.6.4.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH 2/2] Enable support for IPv6 on MinGW
  2009-11-23 22:54 [PATCH 0/2] Add support for IPv6 on MinGW Martin Storsjö
  2009-11-23 22:55 ` [PATCH 1/2] Refactor winsock initialization into a separate function Martin Storsjö
@ 2009-11-23 22:55 ` Martin Storsjö
  2009-11-24  7:41   ` Johannes Sixt
  2009-11-24  0:58 ` [PATCH 0/2] Add " Junio C Hamano
  2 siblings, 1 reply; 7+ messages in thread
From: Martin Storsjö @ 2009-11-23 22:55 UTC (permalink / raw)
  To: git; +Cc: gitster

The IPv6 support functions are loaded dynamically, to maintain backwards
compatibility with versions of Windows prior to XP, and fallback wrappers
are provided, implemented in terms of gethostbyname and gethostbyaddr.

Signed-off-by: Martin Storsjo <martin@martin.st>
---
 Makefile       |    1 -
 compat/mingw.c |  169 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 compat/mingw.h |   13 ++++
 3 files changed, 181 insertions(+), 2 deletions(-)

diff --git a/Makefile b/Makefile
index 25a9771..31db29d 100644
--- a/Makefile
+++ b/Makefile
@@ -982,7 +982,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
 	NEEDS_CRYPTO_WITH_SSL = YesPlease
 	NO_LIBGEN_H = YesPlease
 	NO_SYMLINK_HEAD = YesPlease
-	NO_IPV6 = YesPlease
 	NO_SETENV = YesPlease
 	NO_UNSETENV = YesPlease
 	NO_STRCASESTR = YesPlease
diff --git a/compat/mingw.c b/compat/mingw.c
index f9d82ff..0d73f15 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -903,10 +903,129 @@ char **make_augmented_environ(const char *const *vars)
 	return env;
 }
 
+/*
+ * Note, this isn't a complete replacement for getaddrinfo. It assumes
+ * that service contains a numerical port, or that it it is null. It
+ * does a simple search using gethostbyname, and returns one IPv4 host
+ * if one was found.
+ */
+static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
+				   const struct addrinfo *hints,
+				   struct addrinfo **res)
+{
+	struct hostent *h = gethostbyname(node);
+	struct addrinfo *ai;
+	struct sockaddr_in *sin;
+
+	if (!h)
+		return WSAGetLastError();
+
+	ai = xmalloc(sizeof(struct addrinfo));
+	*res = ai;
+	ai->ai_flags = 0;
+	ai->ai_family = AF_INET;
+	ai->ai_socktype = hints->ai_socktype;
+	switch (hints->ai_socktype) {
+	case SOCK_STREAM:
+		ai->ai_protocol = IPPROTO_TCP;
+		break;
+	case SOCK_DGRAM:
+		ai->ai_protocol = IPPROTO_UDP;
+		break;
+	default:
+		ai->ai_protocol = 0;
+		break;
+	}
+	ai->ai_addrlen = sizeof(struct sockaddr_in);
+	ai->ai_canonname = strdup(h->h_name);
+
+	sin = xmalloc(ai->ai_addrlen);
+	memset(sin, 0, ai->ai_addrlen);
+	sin->sin_family = AF_INET;
+	if (service)
+		sin->sin_port = htons(atoi(service));
+	sin->sin_addr = *(struct in_addr *)h->h_addr;
+	ai->ai_addr = (struct sockaddr *)sin;
+	ai->ai_next = 0;
+	return 0;
+}
+
+static void WSAAPI freeaddrinfo_stub(struct addrinfo *res)
+{
+	free(res->ai_canonname);
+	free(res->ai_addr);
+	free(res);
+}
+
+static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen,
+				   char *host, DWORD hostlen,
+				   char *serv, DWORD servlen, int flags)
+{
+	const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
+	if (sa->sa_family != AF_INET)
+		return EAI_FAMILY;
+	if (!host && !serv)
+		return EAI_NONAME;
+
+	if (host && hostlen > 0) {
+		struct hostent *ent = NULL;
+		if (!(flags & NI_NUMERICHOST))
+			ent = gethostbyaddr((const char *)&sin->sin_addr,
+					    sizeof(sin->sin_addr), AF_INET);
+
+		if (ent)
+			snprintf(host, hostlen, "%s", ent->h_name);
+		else if (flags & NI_NAMEREQD)
+			return EAI_NONAME;
+		else
+			snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
+	}
+
+	if (serv && servlen > 0) {
+		struct servent *ent = NULL;
+		if (!(flags & NI_NUMERICSERV))
+			ent = getservbyport(sin->sin_port,
+					    flags & NI_DGRAM ? "udp" : "tcp");
+
+		if (ent)
+			snprintf(serv, servlen, "%s", ent->s_name);
+		else
+			snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
+	}
+
+	return 0;
+}
+
+static HMODULE ipv6_dll = NULL;
+static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res);
+static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service,
+				      const struct addrinfo *hints,
+				      struct addrinfo **res);
+static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen,
+				      char *host, DWORD hostlen,
+				      char *serv, DWORD servlen, int flags);
+/*
+ * gai_strerror is an inline function in the ws2tcpip.h header, so we
+ * don't need to try to load that one dynamically.
+ */
+
+static void socket_cleanup(void)
+{
+	WSACleanup();
+	if (ipv6_dll)
+		FreeLibrary(ipv6_dll);
+	ipv6_dll = NULL;
+	ipv6_freeaddrinfo = freeaddrinfo_stub;
+	ipv6_getaddrinfo = getaddrinfo_stub;
+	ipv6_getnameinfo = getnameinfo_stub;
+}
+
 static void ensure_socket_initialization(void)
 {
 	WSADATA wsa;
 	static int initialized = 0;
+	const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL };
+	const char **name;
 
 	if (initialized)
 		return;
@@ -914,7 +1033,35 @@ static void ensure_socket_initialization(void)
 	if (WSAStartup(MAKEWORD(2,2), &wsa))
 		die("unable to initialize winsock subsystem, error %d",
 			WSAGetLastError());
-	atexit((void(*)(void)) WSACleanup);
+
+	for (name = libraries; *name; name++) {
+		ipv6_dll = LoadLibrary(*name);
+		if (!ipv6_dll)
+			continue;
+
+		ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *))
+			GetProcAddress(ipv6_dll, "freeaddrinfo");
+		ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *,
+						   const struct addrinfo *,
+						   struct addrinfo **))
+			GetProcAddress(ipv6_dll, "getaddrinfo");
+		ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *,
+						   socklen_t, char *, DWORD,
+						   char *, DWORD, int))
+			GetProcAddress(ipv6_dll, "getnameinfo");
+		if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
+			FreeLibrary(ipv6_dll);
+			ipv6_dll = NULL;
+		} else
+			break;
+	}
+	if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
+		ipv6_freeaddrinfo = freeaddrinfo_stub;
+		ipv6_getaddrinfo = getaddrinfo_stub;
+		ipv6_getnameinfo = getnameinfo_stub;
+	}
+
+	atexit(socket_cleanup);
 	initialized = 1;
 }
 
@@ -925,6 +1072,26 @@ struct hostent *mingw_gethostbyname(const char *host)
 	return gethostbyname(host);
 }
 
+void mingw_freeaddrinfo(struct addrinfo *res)
+{
+	ipv6_freeaddrinfo(res);
+}
+
+int mingw_getaddrinfo(const char *node, const char *service,
+		      const struct addrinfo *hints, struct addrinfo **res)
+{
+	ensure_socket_initialization();
+	return ipv6_getaddrinfo(node, service, hints, res);
+}
+
+int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+		      char *host, DWORD hostlen, char *serv, DWORD servlen,
+		      int flags)
+{
+	ensure_socket_initialization();
+	return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
+}
+
 int mingw_socket(int domain, int type, int protocol)
 {
 	int sockfd;
diff --git a/compat/mingw.h b/compat/mingw.h
index 51993ef..b3d299f 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -1,4 +1,5 @@
 #include <winsock2.h>
+#include <ws2tcpip.h>
 
 /*
  * things that are not available in header files
@@ -178,6 +179,18 @@ char *mingw_getenv(const char *name);
 struct hostent *mingw_gethostbyname(const char *host);
 #define gethostbyname mingw_gethostbyname
 
+void mingw_freeaddrinfo(struct addrinfo *res);
+#define freeaddrinfo mingw_freeaddrinfo
+
+int mingw_getaddrinfo(const char *node, const char *service,
+		      const struct addrinfo *hints, struct addrinfo **res);
+#define getaddrinfo mingw_getaddrinfo
+
+int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
+		      char *host, DWORD hostlen, char *serv, DWORD servlen,
+		      int flags);
+#define getnameinfo mingw_getnameinfo
+
 int mingw_socket(int domain, int type, int protocol);
 #define socket mingw_socket
 
-- 
1.6.4.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] Add support for IPv6 on MinGW
  2009-11-23 22:54 [PATCH 0/2] Add support for IPv6 on MinGW Martin Storsjö
  2009-11-23 22:55 ` [PATCH 1/2] Refactor winsock initialization into a separate function Martin Storsjö
  2009-11-23 22:55 ` [PATCH 2/2] Enable support for IPv6 on MinGW Martin Storsjö
@ 2009-11-24  0:58 ` Junio C Hamano
  2009-11-24 11:41   ` Martin Storsjö
  2 siblings, 1 reply; 7+ messages in thread
From: Junio C Hamano @ 2009-11-24  0:58 UTC (permalink / raw)
  To: Martin Storsjö; +Cc: git

Martin Storsjö <martin@martin.st> writes:

> This is a short patch series that adds support for IPv6 on MinGW. These 
> patches have been in use in msysgit for a few months (but the code was 
> accidentally removed recently in a merge). For consistency, it would be 
> good to add them upstream, too.

I am aware of the exchange between you and J6t on msysgit@googlegroups
where he suggested you to send them here.  Giving better visibility to
these patches for public review is good.

But you didn't have to Cc: me; in Windows API issues I have no clue so I
won't be a good reviewer.  I do not even compile git on Windows myself,
let alone testing nor using.

As hinted by J6t, he will be saying Ack or something else, so I'll act on
these patches when it happens.

Preferrably, I'd like somebody reasonably high in msysgit foodchain to
volunteer to be a coordinator and send me a pull-request whenever a set of
changes that has been:

 (1) cooking in msysgit tree without issues; and

 (2) reviewed favorably here on this list

is ready for git.git.  That way, I do not even have to remember whose
patches in the msysgit area I should blindly trust and apply, or keep
track of which patches are still under discussion in general.

Thanks.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 1/2] Refactor winsock initialization into a separate  function
  2009-11-23 22:55 ` [PATCH 1/2] Refactor winsock initialization into a separate function Martin Storsjö
@ 2009-11-24  7:36   ` Johannes Sixt
  0 siblings, 0 replies; 7+ messages in thread
From: Johannes Sixt @ 2009-11-24  7:36 UTC (permalink / raw)
  To: Martin Storsjö; +Cc: git, gitster

Martin Storsjö schrieb:
> Signed-off-by: Martin Storsjo <martin@martin.st>

I have used this series in my tree for 6 weeks without negative
sideffects. I haven't tested IPv6, though.

Here's an updated commit message with my ACK:

--- >8 ---
Refactor winsock initialization into a separate function

The winsock library must be initialized. Since gethostbyname() is the
first function that calls into winsock, it was overridden to do the
initialization. This refactoring helps the next patch, where other
functions can be called earlier.

Signed-off-by: Martin Storsjo <martin@martin.st>
Acked-by: Johannes Sixt <j6t@kdbg.org>
--- >8 ---


> ---
>  compat/mingw.c |   15 ++++++++++++---
>  1 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/compat/mingw.c b/compat/mingw.c
> index 15fe33e..f9d82ff 100644
> --- a/compat/mingw.c
> +++ b/compat/mingw.c
> @@ -903,16 +903,25 @@ char **make_augmented_environ(const char *const *vars)
>  	return env;
>  }
>  
> -/* this is the first function to call into WS_32; initialize it */
> -#undef gethostbyname
> -struct hostent *mingw_gethostbyname(const char *host)
> +static void ensure_socket_initialization(void)
>  {
>  	WSADATA wsa;
> +	static int initialized = 0;
> +
> +	if (initialized)
> +		return;
>  
>  	if (WSAStartup(MAKEWORD(2,2), &wsa))
>  		die("unable to initialize winsock subsystem, error %d",
>  			WSAGetLastError());
>  	atexit((void(*)(void)) WSACleanup);
> +	initialized = 1;
> +}
> +
> +#undef gethostbyname
> +struct hostent *mingw_gethostbyname(const char *host)
> +{
> +	ensure_socket_initialization();
>  	return gethostbyname(host);
>  }
>  

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 2/2] Enable support for IPv6 on MinGW
  2009-11-23 22:55 ` [PATCH 2/2] Enable support for IPv6 on MinGW Martin Storsjö
@ 2009-11-24  7:41   ` Johannes Sixt
  0 siblings, 0 replies; 7+ messages in thread
From: Johannes Sixt @ 2009-11-24  7:41 UTC (permalink / raw)
  To: Martin Storsjö; +Cc: git, gitster

Martin Storsjö schrieb:
> The IPv6 support functions are loaded dynamically, to maintain backwards
> compatibility with versions of Windows prior to XP, and fallback wrappers
> are provided, implemented in terms of gethostbyname and gethostbyaddr.
> 
> Signed-off-by: Martin Storsjo <martin@martin.st>

Acked-by: Johannes Sixt <j6t@kdbg.org>

-- Hannes

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH 0/2] Add support for IPv6 on MinGW
  2009-11-24  0:58 ` [PATCH 0/2] Add " Junio C Hamano
@ 2009-11-24 11:41   ` Martin Storsjö
  0 siblings, 0 replies; 7+ messages in thread
From: Martin Storsjö @ 2009-11-24 11:41 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On Mon, 23 Nov 2009, Junio C Hamano wrote:

> I am aware of the exchange between you and J6t on msysgit@googlegroups
> where he suggested you to send them here.  Giving better visibility to
> these patches for public review is good.
> 
> But you didn't have to Cc: me; in Windows API issues I have no clue so I
> won't be a good reviewer.  I do not even compile git on Windows myself,
> let alone testing nor using.

Ah, sorry for notifying you prematurely there.

> As hinted by J6t, he will be saying Ack or something else, so I'll act on
> these patches when it happens.

And thanks for handling this!

// Martin

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2009-11-24 11:41 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-11-23 22:54 [PATCH 0/2] Add support for IPv6 on MinGW Martin Storsjö
2009-11-23 22:55 ` [PATCH 1/2] Refactor winsock initialization into a separate function Martin Storsjö
2009-11-24  7:36   ` Johannes Sixt
2009-11-23 22:55 ` [PATCH 2/2] Enable support for IPv6 on MinGW Martin Storsjö
2009-11-24  7:41   ` Johannes Sixt
2009-11-24  0:58 ` [PATCH 0/2] Add " Junio C Hamano
2009-11-24 11:41   ` Martin Storsjö

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).