Mercurial
comparison third_party/libuv/src/inet.c @ 160:948de3f54cea
[ThirdParty] Added libuv
| author | June Park <parkjune1995@gmail.com> |
|---|---|
| date | Wed, 14 Jan 2026 19:39:52 -0800 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 159:05cf9467a1c3 | 160:948de3f54cea |
|---|---|
| 1 /* | |
| 2 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC") | |
| 3 * Copyright (c) 1996-1999 by Internet Software Consortium. | |
| 4 * | |
| 5 * Permission to use, copy, modify, and distribute this software for any | |
| 6 * purpose with or without fee is hereby granted, provided that the above | |
| 7 * copyright notice and this permission notice appear in all copies. | |
| 8 * | |
| 9 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES | |
| 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
| 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR | |
| 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
| 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
| 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT | |
| 15 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
| 16 */ | |
| 17 | |
| 18 #include <stdio.h> | |
| 19 #include <string.h> | |
| 20 #include <stdint.h> | |
| 21 | |
| 22 #include "uv.h" | |
| 23 #include "uv-common.h" | |
| 24 | |
| 25 #define UV__INET_ADDRSTRLEN 16 | |
| 26 #define UV__INET6_ADDRSTRLEN 46 | |
| 27 | |
| 28 | |
| 29 static int inet_ntop4(const unsigned char *src, char *dst, size_t size); | |
| 30 static int inet_ntop6(const unsigned char *src, char *dst, size_t size); | |
| 31 static int inet_pton4(const char *src, unsigned char *dst); | |
| 32 static int inet_pton6(const char *src, unsigned char *dst); | |
| 33 | |
| 34 | |
| 35 int uv_inet_ntop(int af, const void* src, char* dst, size_t size) { | |
| 36 switch (af) { | |
| 37 case AF_INET: | |
| 38 return (inet_ntop4(src, dst, size)); | |
| 39 case AF_INET6: | |
| 40 return (inet_ntop6(src, dst, size)); | |
| 41 default: | |
| 42 return UV_EAFNOSUPPORT; | |
| 43 } | |
| 44 /* NOTREACHED */ | |
| 45 } | |
| 46 | |
| 47 | |
| 48 static int inet_ntop4(const unsigned char *src, char *dst, size_t size) { | |
| 49 static const char fmt[] = "%u.%u.%u.%u"; | |
| 50 char tmp[UV__INET_ADDRSTRLEN]; | |
| 51 int l; | |
| 52 | |
| 53 l = snprintf(tmp, sizeof(tmp), fmt, src[0], src[1], src[2], src[3]); | |
| 54 if (l <= 0 || (size_t) l >= size) { | |
| 55 return UV_ENOSPC; | |
| 56 } | |
| 57 uv__strscpy(dst, tmp, size); | |
| 58 return 0; | |
| 59 } | |
| 60 | |
| 61 | |
| 62 static int inet_ntop6(const unsigned char *src, char *dst, size_t size) { | |
| 63 /* | |
| 64 * Note that int32_t and int16_t need only be "at least" large enough | |
| 65 * to contain a value of the specified size. On some systems, like | |
| 66 * Crays, there is no such thing as an integer variable with 16 bits. | |
| 67 * Keep this in mind if you think this function should have been coded | |
| 68 * to use pointer overlays. All the world's not a VAX. | |
| 69 */ | |
| 70 char tmp[UV__INET6_ADDRSTRLEN], *tp; | |
| 71 struct { int base, len; } best, cur; | |
| 72 unsigned int words[sizeof(struct in6_addr) / sizeof(uint16_t)]; | |
| 73 int i; | |
| 74 | |
| 75 /* | |
| 76 * Preprocess: | |
| 77 * Copy the input (bytewise) array into a wordwise array. | |
| 78 * Find the longest run of 0x00's in src[] for :: shorthanding. | |
| 79 */ | |
| 80 memset(words, '\0', sizeof words); | |
| 81 for (i = 0; i < (int) sizeof(struct in6_addr); i++) | |
| 82 words[i / 2] |= (src[i] << ((1 - (i % 2)) << 3)); | |
| 83 best.base = -1; | |
| 84 best.len = 0; | |
| 85 cur.base = -1; | |
| 86 cur.len = 0; | |
| 87 for (i = 0; i < (int) ARRAY_SIZE(words); i++) { | |
| 88 if (words[i] == 0) { | |
| 89 if (cur.base == -1) | |
| 90 cur.base = i, cur.len = 1; | |
| 91 else | |
| 92 cur.len++; | |
| 93 } else { | |
| 94 if (cur.base != -1) { | |
| 95 if (best.base == -1 || cur.len > best.len) | |
| 96 best = cur; | |
| 97 cur.base = -1; | |
| 98 } | |
| 99 } | |
| 100 } | |
| 101 if (cur.base != -1) { | |
| 102 if (best.base == -1 || cur.len > best.len) | |
| 103 best = cur; | |
| 104 } | |
| 105 if (best.base != -1 && best.len < 2) | |
| 106 best.base = -1; | |
| 107 | |
| 108 /* | |
| 109 * Format the result. | |
| 110 */ | |
| 111 tp = tmp; | |
| 112 for (i = 0; i < (int) ARRAY_SIZE(words); i++) { | |
| 113 /* Are we inside the best run of 0x00's? */ | |
| 114 if (best.base != -1 && i >= best.base && | |
| 115 i < (best.base + best.len)) { | |
| 116 if (i == best.base) | |
| 117 *tp++ = ':'; | |
| 118 continue; | |
| 119 } | |
| 120 /* Are we following an initial run of 0x00s or any real hex? */ | |
| 121 if (i != 0) | |
| 122 *tp++ = ':'; | |
| 123 /* Is this address an encapsulated IPv4? */ | |
| 124 if (i == 6 && best.base == 0 && (best.len == 6 || | |
| 125 (best.len == 7 && words[7] != 0x0001) || | |
| 126 (best.len == 5 && words[5] == 0xffff))) { | |
| 127 int err = inet_ntop4(src+12, tp, sizeof tmp - (tp - tmp)); | |
| 128 if (err) | |
| 129 return err; | |
| 130 tp += strlen(tp); | |
| 131 break; | |
| 132 } | |
| 133 tp += snprintf(tp, sizeof tmp - (tp - tmp), "%x", words[i]); | |
| 134 } | |
| 135 /* Was it a trailing run of 0x00's? */ | |
| 136 if (best.base != -1 && (best.base + best.len) == ARRAY_SIZE(words)) | |
| 137 *tp++ = ':'; | |
| 138 *tp++ = '\0'; | |
| 139 if ((size_t) (tp - tmp) > size) | |
| 140 return UV_ENOSPC; | |
| 141 uv__strscpy(dst, tmp, size); | |
| 142 return 0; | |
| 143 } | |
| 144 | |
| 145 | |
| 146 int uv_inet_pton(int af, const char* src, void* dst) { | |
| 147 if (src == NULL || dst == NULL) | |
| 148 return UV_EINVAL; | |
| 149 | |
| 150 switch (af) { | |
| 151 case AF_INET: | |
| 152 return (inet_pton4(src, dst)); | |
| 153 case AF_INET6: { | |
| 154 int len; | |
| 155 char tmp[UV__INET6_ADDRSTRLEN], *s, *p; | |
| 156 s = (char*) src; | |
| 157 p = strchr(src, '%'); | |
| 158 if (p != NULL) { | |
| 159 s = tmp; | |
| 160 len = p - src; | |
| 161 if (len > UV__INET6_ADDRSTRLEN-1) | |
| 162 return UV_EINVAL; | |
| 163 memcpy(s, src, len); | |
| 164 s[len] = '\0'; | |
| 165 } | |
| 166 return inet_pton6(s, dst); | |
| 167 } | |
| 168 default: | |
| 169 return UV_EAFNOSUPPORT; | |
| 170 } | |
| 171 /* NOTREACHED */ | |
| 172 } | |
| 173 | |
| 174 | |
| 175 static int inet_pton4(const char *src, unsigned char *dst) { | |
| 176 static const char digits[] = "0123456789"; | |
| 177 int saw_digit, octets, ch; | |
| 178 unsigned char tmp[sizeof(struct in_addr)], *tp; | |
| 179 | |
| 180 saw_digit = 0; | |
| 181 octets = 0; | |
| 182 *(tp = tmp) = 0; | |
| 183 while ((ch = *src++) != '\0') { | |
| 184 const char *pch; | |
| 185 | |
| 186 if ((pch = strchr(digits, ch)) != NULL) { | |
| 187 unsigned int nw = *tp * 10 + (pch - digits); | |
| 188 | |
| 189 if (saw_digit && *tp == 0) | |
| 190 return UV_EINVAL; | |
| 191 if (nw > 255) | |
| 192 return UV_EINVAL; | |
| 193 *tp = nw; | |
| 194 if (!saw_digit) { | |
| 195 if (++octets > 4) | |
| 196 return UV_EINVAL; | |
| 197 saw_digit = 1; | |
| 198 } | |
| 199 } else if (ch == '.' && saw_digit) { | |
| 200 if (octets == 4) | |
| 201 return UV_EINVAL; | |
| 202 *++tp = 0; | |
| 203 saw_digit = 0; | |
| 204 } else | |
| 205 return UV_EINVAL; | |
| 206 } | |
| 207 if (octets < 4) | |
| 208 return UV_EINVAL; | |
| 209 memcpy(dst, tmp, sizeof(struct in_addr)); | |
| 210 return 0; | |
| 211 } | |
| 212 | |
| 213 | |
| 214 static int inet_pton6(const char *src, unsigned char *dst) { | |
| 215 static const char xdigits_l[] = "0123456789abcdef", | |
| 216 xdigits_u[] = "0123456789ABCDEF"; | |
| 217 unsigned char tmp[sizeof(struct in6_addr)], *tp, *endp, *colonp; | |
| 218 const char *xdigits, *curtok; | |
| 219 int ch, seen_xdigits; | |
| 220 unsigned int val; | |
| 221 | |
| 222 memset((tp = tmp), '\0', sizeof tmp); | |
| 223 endp = tp + sizeof tmp; | |
| 224 colonp = NULL; | |
| 225 /* Leading :: requires some special handling. */ | |
| 226 if (*src == ':') | |
| 227 if (*++src != ':') | |
| 228 return UV_EINVAL; | |
| 229 curtok = src; | |
| 230 seen_xdigits = 0; | |
| 231 val = 0; | |
| 232 while ((ch = *src++) != '\0') { | |
| 233 const char *pch; | |
| 234 | |
| 235 if ((pch = strchr((xdigits = xdigits_l), ch)) == NULL) | |
| 236 pch = strchr((xdigits = xdigits_u), ch); | |
| 237 if (pch != NULL) { | |
| 238 val <<= 4; | |
| 239 val |= (pch - xdigits); | |
| 240 if (++seen_xdigits > 4) | |
| 241 return UV_EINVAL; | |
| 242 continue; | |
| 243 } | |
| 244 if (ch == ':') { | |
| 245 curtok = src; | |
| 246 if (!seen_xdigits) { | |
| 247 if (colonp) | |
| 248 return UV_EINVAL; | |
| 249 colonp = tp; | |
| 250 continue; | |
| 251 } else if (*src == '\0') { | |
| 252 return UV_EINVAL; | |
| 253 } | |
| 254 if (tp + sizeof(uint16_t) > endp) | |
| 255 return UV_EINVAL; | |
| 256 *tp++ = (unsigned char) (val >> 8) & 0xff; | |
| 257 *tp++ = (unsigned char) val & 0xff; | |
| 258 seen_xdigits = 0; | |
| 259 val = 0; | |
| 260 continue; | |
| 261 } | |
| 262 if (ch == '.' && ((tp + sizeof(struct in_addr)) <= endp)) { | |
| 263 int err = inet_pton4(curtok, tp); | |
| 264 if (err == 0) { | |
| 265 tp += sizeof(struct in_addr); | |
| 266 seen_xdigits = 0; | |
| 267 break; /*%< '\\0' was seen by inet_pton4(). */ | |
| 268 } | |
| 269 } | |
| 270 return UV_EINVAL; | |
| 271 } | |
| 272 if (seen_xdigits) { | |
| 273 if (tp + sizeof(uint16_t) > endp) | |
| 274 return UV_EINVAL; | |
| 275 *tp++ = (unsigned char) (val >> 8) & 0xff; | |
| 276 *tp++ = (unsigned char) val & 0xff; | |
| 277 } | |
| 278 if (colonp != NULL) { | |
| 279 /* | |
| 280 * Since some memmove()'s erroneously fail to handle | |
| 281 * overlapping regions, we'll do the shift by hand. | |
| 282 */ | |
| 283 const int n = tp - colonp; | |
| 284 int i; | |
| 285 | |
| 286 if (tp == endp) | |
| 287 return UV_EINVAL; | |
| 288 for (i = 1; i <= n; i++) { | |
| 289 endp[- i] = colonp[n - i]; | |
| 290 colonp[n - i] = 0; | |
| 291 } | |
| 292 tp = endp; | |
| 293 } | |
| 294 if (tp != endp) | |
| 295 return UV_EINVAL; | |
| 296 memcpy(dst, tmp, sizeof tmp); | |
| 297 return 0; | |
| 298 } |