Skip to content

Commit fe3b2b7

Browse files
mstorsjogitster
authored andcommitted
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 <[email protected]> Acked-by: Johannes Sixt <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent b7cc9f8 commit fe3b2b7

File tree

3 files changed

+181
-2
lines changed

3 files changed

+181
-2
lines changed

Makefile

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -982,7 +982,6 @@ ifneq (,$(findstring MINGW,$(uname_S)))
982982
NEEDS_CRYPTO_WITH_SSL = YesPlease
983983
NO_LIBGEN_H = YesPlease
984984
NO_SYMLINK_HEAD = YesPlease
985-
NO_IPV6 = YesPlease
986985
NO_SETENV = YesPlease
987986
NO_UNSETENV = YesPlease
988987
NO_STRCASESTR = YesPlease

compat/mingw.c

Lines changed: 168 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -903,18 +903,165 @@ char **make_augmented_environ(const char *const *vars)
903903
return env;
904904
}
905905

906+
/*
907+
* Note, this isn't a complete replacement for getaddrinfo. It assumes
908+
* that service contains a numerical port, or that it it is null. It
909+
* does a simple search using gethostbyname, and returns one IPv4 host
910+
* if one was found.
911+
*/
912+
static int WSAAPI getaddrinfo_stub(const char *node, const char *service,
913+
const struct addrinfo *hints,
914+
struct addrinfo **res)
915+
{
916+
struct hostent *h = gethostbyname(node);
917+
struct addrinfo *ai;
918+
struct sockaddr_in *sin;
919+
920+
if (!h)
921+
return WSAGetLastError();
922+
923+
ai = xmalloc(sizeof(struct addrinfo));
924+
*res = ai;
925+
ai->ai_flags = 0;
926+
ai->ai_family = AF_INET;
927+
ai->ai_socktype = hints->ai_socktype;
928+
switch (hints->ai_socktype) {
929+
case SOCK_STREAM:
930+
ai->ai_protocol = IPPROTO_TCP;
931+
break;
932+
case SOCK_DGRAM:
933+
ai->ai_protocol = IPPROTO_UDP;
934+
break;
935+
default:
936+
ai->ai_protocol = 0;
937+
break;
938+
}
939+
ai->ai_addrlen = sizeof(struct sockaddr_in);
940+
ai->ai_canonname = strdup(h->h_name);
941+
942+
sin = xmalloc(ai->ai_addrlen);
943+
memset(sin, 0, ai->ai_addrlen);
944+
sin->sin_family = AF_INET;
945+
if (service)
946+
sin->sin_port = htons(atoi(service));
947+
sin->sin_addr = *(struct in_addr *)h->h_addr;
948+
ai->ai_addr = (struct sockaddr *)sin;
949+
ai->ai_next = 0;
950+
return 0;
951+
}
952+
953+
static void WSAAPI freeaddrinfo_stub(struct addrinfo *res)
954+
{
955+
free(res->ai_canonname);
956+
free(res->ai_addr);
957+
free(res);
958+
}
959+
960+
static int WSAAPI getnameinfo_stub(const struct sockaddr *sa, socklen_t salen,
961+
char *host, DWORD hostlen,
962+
char *serv, DWORD servlen, int flags)
963+
{
964+
const struct sockaddr_in *sin = (const struct sockaddr_in *)sa;
965+
if (sa->sa_family != AF_INET)
966+
return EAI_FAMILY;
967+
if (!host && !serv)
968+
return EAI_NONAME;
969+
970+
if (host && hostlen > 0) {
971+
struct hostent *ent = NULL;
972+
if (!(flags & NI_NUMERICHOST))
973+
ent = gethostbyaddr((const char *)&sin->sin_addr,
974+
sizeof(sin->sin_addr), AF_INET);
975+
976+
if (ent)
977+
snprintf(host, hostlen, "%s", ent->h_name);
978+
else if (flags & NI_NAMEREQD)
979+
return EAI_NONAME;
980+
else
981+
snprintf(host, hostlen, "%s", inet_ntoa(sin->sin_addr));
982+
}
983+
984+
if (serv && servlen > 0) {
985+
struct servent *ent = NULL;
986+
if (!(flags & NI_NUMERICSERV))
987+
ent = getservbyport(sin->sin_port,
988+
flags & NI_DGRAM ? "udp" : "tcp");
989+
990+
if (ent)
991+
snprintf(serv, servlen, "%s", ent->s_name);
992+
else
993+
snprintf(serv, servlen, "%d", ntohs(sin->sin_port));
994+
}
995+
996+
return 0;
997+
}
998+
999+
static HMODULE ipv6_dll = NULL;
1000+
static void (WSAAPI *ipv6_freeaddrinfo)(struct addrinfo *res);
1001+
static int (WSAAPI *ipv6_getaddrinfo)(const char *node, const char *service,
1002+
const struct addrinfo *hints,
1003+
struct addrinfo **res);
1004+
static int (WSAAPI *ipv6_getnameinfo)(const struct sockaddr *sa, socklen_t salen,
1005+
char *host, DWORD hostlen,
1006+
char *serv, DWORD servlen, int flags);
1007+
/*
1008+
* gai_strerror is an inline function in the ws2tcpip.h header, so we
1009+
* don't need to try to load that one dynamically.
1010+
*/
1011+
1012+
static void socket_cleanup(void)
1013+
{
1014+
WSACleanup();
1015+
if (ipv6_dll)
1016+
FreeLibrary(ipv6_dll);
1017+
ipv6_dll = NULL;
1018+
ipv6_freeaddrinfo = freeaddrinfo_stub;
1019+
ipv6_getaddrinfo = getaddrinfo_stub;
1020+
ipv6_getnameinfo = getnameinfo_stub;
1021+
}
1022+
9061023
static void ensure_socket_initialization(void)
9071024
{
9081025
WSADATA wsa;
9091026
static int initialized = 0;
1027+
const char *libraries[] = { "ws2_32.dll", "wship6.dll", NULL };
1028+
const char **name;
9101029

9111030
if (initialized)
9121031
return;
9131032

9141033
if (WSAStartup(MAKEWORD(2,2), &wsa))
9151034
die("unable to initialize winsock subsystem, error %d",
9161035
WSAGetLastError());
917-
atexit((void(*)(void)) WSACleanup);
1036+
1037+
for (name = libraries; *name; name++) {
1038+
ipv6_dll = LoadLibrary(*name);
1039+
if (!ipv6_dll)
1040+
continue;
1041+
1042+
ipv6_freeaddrinfo = (void (WSAAPI *)(struct addrinfo *))
1043+
GetProcAddress(ipv6_dll, "freeaddrinfo");
1044+
ipv6_getaddrinfo = (int (WSAAPI *)(const char *, const char *,
1045+
const struct addrinfo *,
1046+
struct addrinfo **))
1047+
GetProcAddress(ipv6_dll, "getaddrinfo");
1048+
ipv6_getnameinfo = (int (WSAAPI *)(const struct sockaddr *,
1049+
socklen_t, char *, DWORD,
1050+
char *, DWORD, int))
1051+
GetProcAddress(ipv6_dll, "getnameinfo");
1052+
if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
1053+
FreeLibrary(ipv6_dll);
1054+
ipv6_dll = NULL;
1055+
} else
1056+
break;
1057+
}
1058+
if (!ipv6_freeaddrinfo || !ipv6_getaddrinfo || !ipv6_getnameinfo) {
1059+
ipv6_freeaddrinfo = freeaddrinfo_stub;
1060+
ipv6_getaddrinfo = getaddrinfo_stub;
1061+
ipv6_getnameinfo = getnameinfo_stub;
1062+
}
1063+
1064+
atexit(socket_cleanup);
9181065
initialized = 1;
9191066
}
9201067

@@ -925,6 +1072,26 @@ struct hostent *mingw_gethostbyname(const char *host)
9251072
return gethostbyname(host);
9261073
}
9271074

1075+
void mingw_freeaddrinfo(struct addrinfo *res)
1076+
{
1077+
ipv6_freeaddrinfo(res);
1078+
}
1079+
1080+
int mingw_getaddrinfo(const char *node, const char *service,
1081+
const struct addrinfo *hints, struct addrinfo **res)
1082+
{
1083+
ensure_socket_initialization();
1084+
return ipv6_getaddrinfo(node, service, hints, res);
1085+
}
1086+
1087+
int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
1088+
char *host, DWORD hostlen, char *serv, DWORD servlen,
1089+
int flags)
1090+
{
1091+
ensure_socket_initialization();
1092+
return ipv6_getnameinfo(sa, salen, host, hostlen, serv, servlen, flags);
1093+
}
1094+
9281095
int mingw_socket(int domain, int type, int protocol)
9291096
{
9301097
int sockfd;

compat/mingw.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
#include <winsock2.h>
2+
#include <ws2tcpip.h>
23

34
/*
45
* things that are not available in header files
@@ -178,6 +179,18 @@ char *mingw_getenv(const char *name);
178179
struct hostent *mingw_gethostbyname(const char *host);
179180
#define gethostbyname mingw_gethostbyname
180181

182+
void mingw_freeaddrinfo(struct addrinfo *res);
183+
#define freeaddrinfo mingw_freeaddrinfo
184+
185+
int mingw_getaddrinfo(const char *node, const char *service,
186+
const struct addrinfo *hints, struct addrinfo **res);
187+
#define getaddrinfo mingw_getaddrinfo
188+
189+
int mingw_getnameinfo(const struct sockaddr *sa, socklen_t salen,
190+
char *host, DWORD hostlen, char *serv, DWORD servlen,
191+
int flags);
192+
#define getnameinfo mingw_getnameinfo
193+
181194
int mingw_socket(int domain, int type, int protocol);
182195
#define socket mingw_socket
183196

0 commit comments

Comments
 (0)