mirror of
https://github.com/git/git.git
synced 2024-10-31 06:17:56 +01:00
Enable support for IPv6 on MinGW
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> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
b7cc9f8259
commit
fe3b2b7b82
3 changed files with 181 additions and 2 deletions
1
Makefile
1
Makefile
|
@ -982,7 +982,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
|
||||||
NEEDS_CRYPTO_WITH_SSL = YesPlease
|
NEEDS_CRYPTO_WITH_SSL = YesPlease
|
||||||
NO_LIBGEN_H = YesPlease
|
NO_LIBGEN_H = YesPlease
|
||||||
NO_SYMLINK_HEAD = YesPlease
|
NO_SYMLINK_HEAD = YesPlease
|
||||||
NO_IPV6 = YesPlease
|
|
||||||
NO_SETENV = YesPlease
|
NO_SETENV = YesPlease
|
||||||
NO_UNSETENV = YesPlease
|
NO_UNSETENV = YesPlease
|
||||||
NO_STRCASESTR = YesPlease
|
NO_STRCASESTR = YesPlease
|
||||||
|
|
169
compat/mingw.c
169
compat/mingw.c
|
@ -903,10 +903,129 @@ char **make_augmented_environ(const char *const *vars)
|
||||||
return env;
|
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)
|
static void ensure_socket_initialization(void)
|
||||||
{
|
{
|
||||||
WSADATA wsa;
|
WSADATA wsa;
|
||||||
static int initialized = 0;
|
static int initialized = 0;
|
||||||
|
const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL };
|
||||||
|
const char **name;
|
||||||
|
|
||||||
if (initialized)
|
if (initialized)
|
||||||
return;
|
return;
|
||||||
|
@ -914,7 +1033,35 @@ static void ensure_socket_initialization(void)
|
||||||
if (WSAStartup(MAKEWORD(2,2), &wsa))
|
if (WSAStartup(MAKEWORD(2,2), &wsa))
|
||||||
die("unable to initialize winsock subsystem, error %d",
|
die("unable to initialize winsock subsystem, error %d",
|
||||||
WSAGetLastError());
|
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;
|
initialized = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -925,6 +1072,26 @@ struct hostent *mingw_gethostbyname(const char *host)
|
||||||
return gethostbyname(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 mingw_socket(int domain, int type, int protocol)
|
||||||
{
|
{
|
||||||
int sockfd;
|
int sockfd;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
#include <winsock2.h>
|
#include <winsock2.h>
|
||||||
|
#include <ws2tcpip.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* things that are not available in header files
|
* 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);
|
struct hostent *mingw_gethostbyname(const char *host);
|
||||||
#define gethostbyname mingw_gethostbyname
|
#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);
|
int mingw_socket(int domain, int type, int protocol);
|
||||||
#define socket mingw_socket
|
#define socket mingw_socket
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue