Fix p_inet_pton on windows p_inet_pton on Windows should set errno properly for callers. Rewrite p_inet_pton to handle error cases correctly and add test cases to exercise this function.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 5f924a0..24cba23 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -12,6 +12,13 @@
#include "utf-conv.h"
#include "dir.h"
+/* define some standard errnos that the runtime may be missing. for example,
+ * mingw lacks EAFNOSUPPORT. */
+
+#ifndef EAFNOSUPPORT
+# define EAFNOSUPPORT (INT_MAX-1)
+#endif
+
GIT_INLINE(int) p_link(const char *old, const char *new)
{
GIT_UNUSED(old);
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index 087adcc..2f49052 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -518,44 +518,40 @@ p_gmtime_r (const time_t *timer, struct tm *result)
return result;
}
-int p_inet_pton(int af, const char* src, void* dst)
+int p_inet_pton(int af, const char *src, void *dst)
{
- union {
- struct sockaddr_in6 sin6;
- struct sockaddr_in sin;
- } sa;
- int srcsize;
+ struct sockaddr_storage sin;
+ void *addr;
+ int sin_len = sizeof(struct sockaddr_storage), addr_len;
+ int error = 0;
- switch(af)
- {
- case AF_INET:
- sa.sin.sin_family = AF_INET;
- srcsize = (int)sizeof(sa.sin);
- break;
- case AF_INET6:
- sa.sin6.sin6_family = AF_INET6;
- srcsize = (int)sizeof(sa.sin6);
- break;
- default:
- errno = WSAEPFNOSUPPORT;
- return -1;
+ if (af == AF_INET) {
+ addr = &((struct sockaddr_in *)&sin)->sin_addr;
+ addr_len = sizeof(struct in_addr);
+ } else if (af == AF_INET6) {
+ addr = &((struct sockaddr_in6 *)&sin)->sin6_addr;
+ addr_len = sizeof(struct in6_addr);
+ } else {
+ errno = EAFNOSUPPORT;
+ return -1;
}
- if (WSAStringToAddress((LPSTR)src, af, NULL, (struct sockaddr *) &sa, &srcsize) != 0)
- {
- errno = WSAGetLastError();
- return -1;
+ if ((error = WSAStringToAddressA((LPSTR)src, af, NULL, (LPSOCKADDR)&sin, &sin_len)) == 0) {
+ memcpy(dst, addr, addr_len);
+ return 1;
}
- switch(af)
- {
- case AF_INET:
- memcpy(dst, &sa.sin.sin_addr, sizeof(sa.sin.sin_addr));
- break;
- case AF_INET6:
- memcpy(dst, &sa.sin6.sin6_addr, sizeof(sa.sin6.sin6_addr));
- break;
+ switch(WSAGetLastError()) {
+ case WSAEINVAL:
+ return 0;
+ case WSAEFAULT:
+ errno = ENOSPC;
+ return -1;
+ case WSA_NOT_ENOUGH_MEMORY:
+ errno = ENOMEM;
+ return -1;
}
- return 1;
+ errno = EINVAL;
+ return -1;
}
diff --git a/tests-clar/core/posix.c b/tests-clar/core/posix.c
new file mode 100644
index 0000000..0d9443f
--- /dev/null
+++ b/tests-clar/core/posix.c
@@ -0,0 +1,84 @@
+#ifndef _WIN32
+# include <arpa/inet.h>
+#else
+# include <ws2tcpip.h>
+# ifdef _MSC_VER
+# pragma comment(lib, "ws2_32")
+# endif
+#endif
+
+#include "clar_libgit2.h"
+#include "posix.h"
+
+void test_core_posix__initialize(void)
+{
+#ifdef GIT_WIN32
+ /* on win32, the WSA context needs to be initialized
+ * before any socket calls can be performed */
+ WSADATA wsd;
+
+ cl_git_pass(WSAStartup(MAKEWORD(2,2), &wsd));
+ cl_assert(LOBYTE(wsd.wVersion) == 2 && HIBYTE(wsd.wVersion) == 2);
+#endif
+}
+
+void test_core_posix__inet_pton(void)
+{
+ struct in_addr addr;
+ struct in6_addr addr6;
+ size_t i;
+
+ struct in_addr_data {
+ const char *p;
+ const uint8_t n[4];
+ };
+
+ struct in6_addr_data {
+ const char *p;
+ const uint8_t n[16];
+ };
+
+ static struct in_addr_data in_addr_data[] = {
+ { "0.0.0.0", { 0, 0, 0, 0 } },
+ { "10.42.101.8", { 10, 42, 101, 8 } },
+ { "127.0.0.1", { 127, 0, 0, 1 } },
+ { "140.177.10.12", { 140, 177, 10, 12 } },
+ { "204.232.175.90", { 204, 232, 175, 90 } },
+ { "255.255.255.255", { 255, 255, 255, 255 } },
+ };
+
+ static struct in6_addr_data in6_addr_data[] = {
+ { "::", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } },
+ { "::1", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
+ { "0:0:0:0:0:0:0:1", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 } },
+ { "2001:db8:8714:3a90::12", { 0x20, 0x01, 0x0d, 0xb8, 0x87, 0x14, 0x3a, 0x90, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12 } },
+ { "fe80::f8ba:c2d6:86be:3645", { 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xba, 0xc2, 0xd6, 0x86, 0xbe, 0x36, 0x45 } },
+ { "::ffff:204.152.189.116", { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcc, 0x98, 0xbd, 0x74 } },
+ };
+
+ /* Test some ipv4 addresses */
+ for (i = 0; i < 6; i++) {
+ cl_assert(p_inet_pton(AF_INET, in_addr_data[i].p, &addr) == 1);
+ cl_assert(memcmp(&addr, in_addr_data[i].n, sizeof(struct in_addr)) == 0);
+ }
+
+ /* Test some ipv6 addresses */
+ for (i = 0; i < 6; i++) {
+ cl_assert(p_inet_pton(AF_INET6, in6_addr_data[i].p, &addr6) == 1);
+ cl_assert(memcmp(&addr6, in6_addr_data[i].n, sizeof(struct in6_addr)) == 0);
+ }
+
+ /* Test some invalid strings */
+ cl_assert(p_inet_pton(AF_INET, "", &addr) == 0);
+ cl_assert(p_inet_pton(AF_INET, "foo", &addr) == 0);
+ cl_assert(p_inet_pton(AF_INET, " 127.0.0.1", &addr) == 0);
+ cl_assert(p_inet_pton(AF_INET, "bar", &addr) == 0);
+ cl_assert(p_inet_pton(AF_INET, "10.foo.bar.1", &addr) == 0);
+
+ /* Test unsupported address families */
+ cl_git_fail(p_inet_pton(12, "52.472", NULL)); /* AF_DECnet */
+ cl_assert_equal_i(EAFNOSUPPORT, errno);
+
+ cl_git_fail(p_inet_pton(5, "315.124", NULL)); /* AF_CHAOS */
+ cl_assert_equal_i(EAFNOSUPPORT, errno);
+}