mirror of https://github.com/WebAssembly/wasi-libc
Browse Source
These functions aren't specific to the underlying system call interface, so they don't need to be in the "bottom half". This also fixes src/functional/inet_pton.c and src/regression/inet_pton-empty-last-field.c in musl's libc-test.pull/63/head
Dan Gohman
6 years ago
5 changed files with 4 additions and 311 deletions
@ -1,46 +0,0 @@ |
|||
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
|
|||
//
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
|||
|
|||
#include <arpa/inet.h> |
|||
|
|||
#include <stdbool.h> |
|||
#include <stdint.h> |
|||
|
|||
int inet_aton(const char *cp, struct in_addr *inp) { |
|||
uint32_t max = UINT32_MAX; |
|||
uint32_t leading = 0; |
|||
int shift = 24; |
|||
for (;;) { |
|||
// Parse next part of the IPv4 address.
|
|||
typedef uint32_t int_t; |
|||
uint32_t min = 0; |
|||
int base = 0; |
|||
bool allow_negative = false; |
|||
#define PEEK(n) cp[n] |
|||
#define SKIP(n) \ |
|||
do { \ |
|||
cp += (n); \ |
|||
} while (0) |
|||
#include <common/parser_strtoint.h> |
|||
#undef PEEK |
|||
#undef SKIP |
|||
if (!have_number || have_overflow) |
|||
return 0; |
|||
|
|||
if (*cp == '\0') { |
|||
// End of string. Return the IPv4 address, combining the
|
|||
// previously parsed leading bytes with the trailing number.
|
|||
inp->s_addr = htonl(leading | number); |
|||
return 1; |
|||
} else if (shift > 0 && number <= UINT8_MAX && *cp++ == '.') { |
|||
// More components follow.
|
|||
leading |= number << shift; |
|||
shift -= 8; |
|||
max >>= 8; |
|||
} else { |
|||
// Parse error.
|
|||
return 0; |
|||
} |
|||
} |
|||
} |
@ -1,112 +0,0 @@ |
|||
// Copyright (c) 2015 Nuxi, https://nuxi.nl/
|
|||
//
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
|||
|
|||
#include <sys/socket.h> |
|||
|
|||
#include <arpa/inet.h> |
|||
#include <netinet/in.h> |
|||
|
|||
#include <errno.h> |
|||
#include <inttypes.h> |
|||
#include <stdbool.h> |
|||
#include <stdio.h> |
|||
#include <string.h> |
|||
|
|||
static const char *inet_ntop_inet(const uint8_t *restrict src, |
|||
char *restrict dst, size_t size) { |
|||
// Format the address.
|
|||
char buf[INET_ADDRSTRLEN]; |
|||
size_t len = |
|||
snprintf(buf, sizeof(buf), "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8, |
|||
src[0], src[1], src[2], src[3]); |
|||
|
|||
// Copy it back.
|
|||
if (len >= size) { |
|||
errno = ENOSPC; |
|||
return NULL; |
|||
} |
|||
strlcpy(dst, buf, size); |
|||
return dst; |
|||
} |
|||
|
|||
static const char *inet_ntop_inet6(const struct in6_addr *restrict src, |
|||
char *restrict dst, size_t size) { |
|||
// Extract groups from address.
|
|||
uint16_t groups[8]; |
|||
for (size_t i = 0; i < __arraycount(groups); ++i) |
|||
groups[i] = (uint16_t)src->s6_addr[i * 2] << 8 | src->s6_addr[i * 2 + 1]; |
|||
|
|||
// Find longest series of groups having value zero.
|
|||
struct { |
|||
size_t start; |
|||
size_t len; |
|||
} zeroes_cur = {}, zeroes_best = {}; |
|||
for (size_t i = 0; i < __arraycount(groups); ++i) { |
|||
if (groups[i] == 0) { |
|||
if (zeroes_best.len < ++zeroes_cur.len) |
|||
zeroes_best = zeroes_cur; |
|||
} else { |
|||
zeroes_cur.start = i + 1; |
|||
zeroes_cur.len = 0; |
|||
} |
|||
} |
|||
|
|||
// Format the address.
|
|||
char buf[INET6_ADDRSTRLEN]; |
|||
char *bufend = buf; |
|||
size_t i = 0; |
|||
int strip_colon = 1; |
|||
bool ipv4 = IN6_IS_ADDR_V4COMPAT(src) || IN6_IS_ADDR_V4MAPPED(src); |
|||
do { |
|||
size_t bufsize = buf + sizeof(buf) - bufend; |
|||
if (i == 6 && ipv4) { |
|||
// End address with IPv4 representation of the last four bytes.
|
|||
bufend += |
|||
snprintf(bufend, bufsize, |
|||
&":%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8[strip_colon], |
|||
src->s6_addr[12], src->s6_addr[13], src->s6_addr[14], |
|||
src->s6_addr[15]); |
|||
break; |
|||
} else if (i == zeroes_best.start && zeroes_best.len > 1) { |
|||
*bufend++ = ':'; |
|||
*bufend++ = ':'; |
|||
i += zeroes_best.len; |
|||
strip_colon = 1; |
|||
} else { |
|||
bufend += snprintf(bufend, bufsize, &":%" PRIx16[strip_colon], groups[i]); |
|||
++i; |
|||
strip_colon = 0; |
|||
} |
|||
} while (i < __arraycount(groups)); |
|||
*bufend++ = '\0'; |
|||
|
|||
// Copy it back.
|
|||
size_t len = bufend - buf; |
|||
if (len > size) { |
|||
errno = ENOSPC; |
|||
return NULL; |
|||
} |
|||
memcpy(dst, buf, len); |
|||
return dst; |
|||
} |
|||
|
|||
const char *inet_ntop(int af, const void *restrict src, char *restrict dst, |
|||
#ifdef __wasilibc_unmodified_upstream // bug fix
|
|||
size_t size) { |
|||
#else |
|||
socklen_t size) { |
|||
#endif |
|||
switch (af) { |
|||
case AF_INET: |
|||
return inet_ntop_inet(src, dst, size); |
|||
case AF_INET6: { |
|||
struct in6_addr v6addr; |
|||
memcpy(&v6addr, src, sizeof(v6addr)); |
|||
return inet_ntop_inet6(&v6addr, dst, size); |
|||
} |
|||
default: |
|||
errno = EAFNOSUPPORT; |
|||
return NULL; |
|||
} |
|||
} |
@ -1,153 +0,0 @@ |
|||
// Copyright (c) 2015 Nuxi, https://nuxi.nl/
|
|||
//
|
|||
// SPDX-License-Identifier: BSD-2-Clause
|
|||
|
|||
#include <sys/socket.h> |
|||
|
|||
#include <arpa/inet.h> |
|||
|
|||
#include <errno.h> |
|||
#include <limits.h> |
|||
#include <stdint.h> |
|||
#include <string.h> |
|||
|
|||
static int inet_pton4(const char *restrict src, uint8_t *restrict dst) { |
|||
uint8_t addr[4]; |
|||
for (size_t group = 0; group < __arraycount(addr); ++group) { |
|||
// Parse number between 0 and 255.
|
|||
if (*src == '0') { |
|||
// Zero.
|
|||
addr[group] = 0; |
|||
++src; |
|||
} else if (*src >= '1' && *src <= '9') { |
|||
// Number between 1 and 255.
|
|||
unsigned int number = *src++ - '0'; |
|||
if (*src >= '0' && *src <= '9') |
|||
number = number * 10 + *src++ - '0'; |
|||
if (*src >= '0' && *src <= '9') |
|||
number = number * 10 + *src++ - '0'; |
|||
if (number > 255) |
|||
return 0; |
|||
addr[group] = number; |
|||
} else { |
|||
// Number should consist of at least one digit.
|
|||
return 0; |
|||
} |
|||
|
|||
// Require a trailing null byte and dot separator between groups.
|
|||
if (*src++ != (group == __arraycount(addr) - 1 ? '\0' : '.')) |
|||
return 0; |
|||
} |
|||
|
|||
// Copy result back.
|
|||
memcpy(dst, addr, sizeof(addr)); |
|||
return 1; |
|||
} |
|||
|
|||
static int inet_pton6(const char *restrict src, uint8_t *restrict dst) { |
|||
#define NGROUPS 8 |
|||
uint8_t addr[NGROUPS * 2] = {}; |
|||
int leading_groups; |
|||
int groups; |
|||
|
|||
// Handle leading "::".
|
|||
if (src[0] == ':' && src[1] == ':') { |
|||
if (src[2] == '\0') { |
|||
// The IPv6 null address.
|
|||
memset(dst, '\0', NGROUPS * 2); |
|||
return 1; |
|||
} else { |
|||
// An address starting with "::", e.g. "::1".
|
|||
leading_groups = 0; |
|||
groups = 2; |
|||
src += 2; |
|||
} |
|||
} else { |
|||
// Address should start with a group of numbers.
|
|||
leading_groups = NGROUPS; |
|||
groups = 0; |
|||
} |
|||
|
|||
// Parse and groups of hexadecimal digits between 0 and ffff.
|
|||
for (;;) { |
|||
const char *group_start = src; |
|||
uint_fast16_t number = 0; |
|||
for (int i = 0; i < 4; ++i) { |
|||
if (*src >= '0' && *src <= '9') { |
|||
number = number * 16 + *src++ - '0'; |
|||
} else if (*src >= 'A' && *src <= 'F') { |
|||
number = number * 16 + *src++ - 'A' + 10; |
|||
} else if (*src >= 'a' && *src <= 'f') { |
|||
number = number * 16 + *src++ - 'a' + 10; |
|||
} else if (i == 0) { |
|||
return 0; |
|||
} |
|||
} |
|||
addr[groups * 2] = number >> 8; |
|||
addr[groups * 2 + 1] = number; |
|||
|
|||
if (src[0] == ':' && src[1] == ':') { |
|||
// "::" Can only be used once.
|
|||
++groups; |
|||
if (leading_groups < groups) |
|||
return 0; |
|||
leading_groups = groups; |
|||
src += 2; |
|||
if (*src == '\0') { |
|||
// "::" placed at the end of an address.
|
|||
if (groups > NGROUPS - 2) |
|||
return 0; |
|||
break; |
|||
} else { |
|||
// "::" placed somewhere in the middle of an address.
|
|||
groups += 2; |
|||
} |
|||
} else if (*src == ':') { |
|||
// Group separator.
|
|||
++groups; |
|||
++src; |
|||
} else if (*src == '\0') { |
|||
// End of address.
|
|||
++groups; |
|||
break; |
|||
} else { |
|||
// Potential trailing IPv4 address using dotted quad notation.
|
|||
if (groups > NGROUPS - 2) |
|||
return 0; |
|||
if (inet_pton4(group_start, &addr[groups * 2]) != 1) |
|||
return 0; |
|||
groups += 2; |
|||
break; |
|||
} |
|||
|
|||
// Next iteration would attempt to parse a ninth group.
|
|||
if (groups >= NGROUPS) |
|||
return 0; |
|||
} |
|||
|
|||
// Number of groups is insufficient, e.g. "1:2:3:4:5:6:7".
|
|||
if (groups < leading_groups) |
|||
return 0; |
|||
|
|||
// Zero the destination address. Copy the leading groups to the start
|
|||
// of the buffer and the trailing groups to the end.
|
|||
memset(dst, '\0', NGROUPS * 2); |
|||
memcpy(dst, addr, leading_groups * 2); |
|||
size_t trailing_groups = groups - leading_groups; |
|||
memcpy(dst + (NGROUPS - trailing_groups) * 2, addr + leading_groups * 2, |
|||
trailing_groups * 2); |
|||
#undef NGROUPS |
|||
return 1; |
|||
} |
|||
|
|||
int inet_pton(int af, const char *restrict src, void *restrict dst) { |
|||
switch (af) { |
|||
case AF_INET: |
|||
return inet_pton4(src, dst); |
|||
case AF_INET6: |
|||
return inet_pton6(src, dst); |
|||
default: |
|||
errno = EAFNOSUPPORT; |
|||
return -1; |
|||
} |
|||
} |
Loading…
Reference in new issue