Skip to content

Commit 01ec7e0

Browse files
committed
Add inet_aton, inet_ntop, inet_pton.
And disable declarations for many functions that aren't implemented.
1 parent eba0a62 commit 01ec7e0

13 files changed

Lines changed: 450 additions & 0 deletions

File tree

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// Copyright (c) 2015 Nuxi, https://nuxi.nl/
2+
//
3+
// SPDX-License-Identifier: BSD-2-Clause
4+
5+
// Parser of integer literals as performed by strtol(), scanf(), etc.
6+
7+
// Result of parsing.
8+
bool have_number = false;
9+
bool have_overflow = false;
10+
int_t number = 0;
11+
12+
{
13+
// Negative or positive number?
14+
bool negative = false;
15+
if (allow_negative && PEEK(0) == '-') {
16+
negative = true;
17+
SKIP(1);
18+
} else if (PEEK(0) == '+') {
19+
SKIP(1);
20+
}
21+
22+
// Determine the base.
23+
if ((base == 0 || base == 16) && PEEK(0) == '0' &&
24+
(PEEK(1) == 'x' || PEEK(1) == 'X') &&
25+
((PEEK(2) >= '0' && PEEK(2) <= '9') ||
26+
(PEEK(2) >= 'A' && PEEK(2) <= 'F') ||
27+
(PEEK(2) >= 'a' && PEEK(2) <= 'f'))) {
28+
SKIP(2);
29+
base = 16;
30+
} else if (base == 0) {
31+
base = PEEK(0) == '0' ? 8 : 10;
32+
}
33+
34+
// Only perform conversion if the base is valid.
35+
if (base >= 2 && base <= 36) {
36+
uint_fast8_t radix = base;
37+
38+
// Determine the highest value up to which we can parse so that the
39+
// next digit does not cause an overflow.
40+
uintmax_t ceil;
41+
uint_fast8_t last_digit;
42+
if (negative) {
43+
ceil = -(min / radix);
44+
last_digit = -(min % radix);
45+
} else {
46+
ceil = max / radix;
47+
last_digit = max % radix;
48+
}
49+
50+
uintmax_t value = 0;
51+
for (;;) {
52+
// Parse next digit.
53+
uint_fast8_t digit;
54+
if (PEEK(0) >= '0' && PEEK(0) <= '9')
55+
digit = PEEK(0) - '0';
56+
else if (PEEK(0) >= 'A' && PEEK(0) <= 'Z')
57+
digit = PEEK(0) - 'A' + 10;
58+
else if (PEEK(0) >= 'a' && PEEK(0) <= 'z')
59+
digit = PEEK(0) - 'a' + 10;
60+
else
61+
break;
62+
if (digit >= radix)
63+
break;
64+
SKIP(1);
65+
66+
// Add it to result.
67+
have_number = true;
68+
if (value > ceil || (value == ceil && digit > last_digit)) {
69+
// Addition of the new digit would cause an overflow.
70+
have_overflow = true;
71+
} else {
72+
value = value * radix + digit;
73+
}
74+
}
75+
76+
if (have_overflow) {
77+
// Set value to min or max depending whether the input is negative
78+
// and whether the output type is signed.
79+
number = (int_t)-1 >= 0 || !negative ? max : min;
80+
} else {
81+
// Return parsed value.
82+
number = negative ? -value : value;
83+
}
84+
}
85+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// Copyright (c) 2016 Nuxi, https://nuxi.nl/
2+
//
3+
// SPDX-License-Identifier: BSD-2-Clause
4+
5+
#include <arpa/inet.h>
6+
7+
#include <stdbool.h>
8+
#include <stdint.h>
9+
10+
int inet_aton(const char *cp, struct in_addr *inp) {
11+
uint32_t max = UINT32_MAX;
12+
uint32_t leading = 0;
13+
int shift = 24;
14+
for (;;) {
15+
// Parse next part of the IPv4 address.
16+
typedef uint32_t int_t;
17+
uint32_t min = 0;
18+
int base = 0;
19+
bool allow_negative = false;
20+
#define PEEK(n) cp[n]
21+
#define SKIP(n) \
22+
do { \
23+
cp += (n); \
24+
} while (0)
25+
#include <common/parser_strtoint.h>
26+
#undef PEEK
27+
#undef SKIP
28+
if (!have_number || have_overflow)
29+
return 0;
30+
31+
if (*cp == '\0') {
32+
// End of string. Return the IPv4 address, combining the
33+
// previously parsed leading bytes with the trailing number.
34+
inp->s_addr = htonl(leading | number);
35+
return 1;
36+
} else if (shift > 0 && number <= UINT8_MAX && *cp++ == '.') {
37+
// More components follow.
38+
leading |= number << shift;
39+
shift -= 8;
40+
max >>= 8;
41+
} else {
42+
// Parse error.
43+
return 0;
44+
}
45+
}
46+
}
Lines changed: 112 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,112 @@
1+
// Copyright (c) 2015 Nuxi, https://nuxi.nl/
2+
//
3+
// SPDX-License-Identifier: BSD-2-Clause
4+
5+
#include <sys/socket.h>
6+
7+
#include <arpa/inet.h>
8+
#include <netinet/in.h>
9+
10+
#include <errno.h>
11+
#include <inttypes.h>
12+
#include <stdbool.h>
13+
#include <stdio.h>
14+
#include <string.h>
15+
16+
static const char *inet_ntop_inet(const uint8_t *restrict src,
17+
char *restrict dst, size_t size) {
18+
// Format the address.
19+
char buf[INET_ADDRSTRLEN];
20+
size_t len =
21+
snprintf(buf, sizeof(buf), "%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8,
22+
src[0], src[1], src[2], src[3]);
23+
24+
// Copy it back.
25+
if (len >= size) {
26+
errno = ENOSPC;
27+
return NULL;
28+
}
29+
strlcpy(dst, buf, size);
30+
return dst;
31+
}
32+
33+
static const char *inet_ntop_inet6(const struct in6_addr *restrict src,
34+
char *restrict dst, size_t size) {
35+
// Extract groups from address.
36+
uint16_t groups[8];
37+
for (size_t i = 0; i < __arraycount(groups); ++i)
38+
groups[i] = (uint16_t)src->s6_addr[i * 2] << 8 | src->s6_addr[i * 2 + 1];
39+
40+
// Find longest series of groups having value zero.
41+
struct {
42+
size_t start;
43+
size_t len;
44+
} zeroes_cur = {}, zeroes_best = {};
45+
for (size_t i = 0; i < __arraycount(groups); ++i) {
46+
if (groups[i] == 0) {
47+
if (zeroes_best.len < ++zeroes_cur.len)
48+
zeroes_best = zeroes_cur;
49+
} else {
50+
zeroes_cur.start = i + 1;
51+
zeroes_cur.len = 0;
52+
}
53+
}
54+
55+
// Format the address.
56+
char buf[INET6_ADDRSTRLEN];
57+
char *bufend = buf;
58+
size_t i = 0;
59+
int strip_colon = 1;
60+
bool ipv4 = IN6_IS_ADDR_V4COMPAT(src) || IN6_IS_ADDR_V4MAPPED(src);
61+
do {
62+
size_t bufsize = buf + sizeof(buf) - bufend;
63+
if (i == 6 && ipv4) {
64+
// End address with IPv4 representation of the last four bytes.
65+
bufend +=
66+
snprintf(bufend, bufsize,
67+
&":%" PRIu8 ".%" PRIu8 ".%" PRIu8 ".%" PRIu8[strip_colon],
68+
src->s6_addr[12], src->s6_addr[13], src->s6_addr[14],
69+
src->s6_addr[15]);
70+
break;
71+
} else if (i == zeroes_best.start && zeroes_best.len > 1) {
72+
*bufend++ = ':';
73+
*bufend++ = ':';
74+
i += zeroes_best.len;
75+
strip_colon = 1;
76+
} else {
77+
bufend += snprintf(bufend, bufsize, &":%" PRIx16[strip_colon], groups[i]);
78+
++i;
79+
strip_colon = 0;
80+
}
81+
} while (i < __arraycount(groups));
82+
*bufend++ = '\0';
83+
84+
// Copy it back.
85+
size_t len = bufend - buf;
86+
if (len > size) {
87+
errno = ENOSPC;
88+
return NULL;
89+
}
90+
memcpy(dst, buf, len);
91+
return dst;
92+
}
93+
94+
const char *inet_ntop(int af, const void *restrict src, char *restrict dst,
95+
#ifdef __wasilibc_unmodified_upstream // bug fix
96+
size_t size) {
97+
#else
98+
socklen_t size) {
99+
#endif
100+
switch (af) {
101+
case AF_INET:
102+
return inet_ntop_inet(src, dst, size);
103+
case AF_INET6: {
104+
struct in6_addr v6addr;
105+
memcpy(&v6addr, src, sizeof(v6addr));
106+
return inet_ntop_inet6(&v6addr, dst, size);
107+
}
108+
default:
109+
errno = EAFNOSUPPORT;
110+
return NULL;
111+
}
112+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
// Copyright (c) 2015 Nuxi, https://nuxi.nl/
2+
//
3+
// SPDX-License-Identifier: BSD-2-Clause
4+
5+
#include <sys/socket.h>
6+
7+
#include <arpa/inet.h>
8+
9+
#include <errno.h>
10+
#include <limits.h>
11+
#include <stdint.h>
12+
#include <string.h>
13+
14+
static int inet_pton4(const char *restrict src, uint8_t *restrict dst) {
15+
uint8_t addr[4];
16+
for (size_t group = 0; group < __arraycount(addr); ++group) {
17+
// Parse number between 0 and 255.
18+
if (*src == '0') {
19+
// Zero.
20+
addr[group] = 0;
21+
++src;
22+
} else if (*src >= '1' && *src <= '9') {
23+
// Number between 1 and 255.
24+
unsigned int number = *src++ - '0';
25+
if (*src >= '0' && *src <= '9')
26+
number = number * 10 + *src++ - '0';
27+
if (*src >= '0' && *src <= '9')
28+
number = number * 10 + *src++ - '0';
29+
if (number > 255)
30+
return 0;
31+
addr[group] = number;
32+
} else {
33+
// Number should consist of at least one digit.
34+
return 0;
35+
}
36+
37+
// Require a trailing null byte and dot separator between groups.
38+
if (*src++ != (group == __arraycount(addr) - 1 ? '\0' : '.'))
39+
return 0;
40+
}
41+
42+
// Copy result back.
43+
memcpy(dst, addr, sizeof(addr));
44+
return 1;
45+
}
46+
47+
static int inet_pton6(const char *restrict src, uint8_t *restrict dst) {
48+
#define NGROUPS 8
49+
uint8_t addr[NGROUPS * 2] = {};
50+
int leading_groups;
51+
int groups;
52+
53+
// Handle leading "::".
54+
if (src[0] == ':' && src[1] == ':') {
55+
if (src[2] == '\0') {
56+
// The IPv6 null address.
57+
memset(dst, '\0', NGROUPS * 2);
58+
return 1;
59+
} else {
60+
// An address starting with "::", e.g. "::1".
61+
leading_groups = 0;
62+
groups = 2;
63+
src += 2;
64+
}
65+
} else {
66+
// Address should start with a group of numbers.
67+
leading_groups = NGROUPS;
68+
groups = 0;
69+
}
70+
71+
// Parse and groups of hexadecimal digits between 0 and ffff.
72+
for (;;) {
73+
const char *group_start = src;
74+
uint_fast16_t number = 0;
75+
for (int i = 0; i < 4; ++i) {
76+
if (*src >= '0' && *src <= '9') {
77+
number = number * 16 + *src++ - '0';
78+
} else if (*src >= 'A' && *src <= 'F') {
79+
number = number * 16 + *src++ - 'A' + 10;
80+
} else if (*src >= 'a' && *src <= 'f') {
81+
number = number * 16 + *src++ - 'a' + 10;
82+
} else if (i == 0) {
83+
return 0;
84+
}
85+
}
86+
addr[groups * 2] = number >> 8;
87+
addr[groups * 2 + 1] = number;
88+
89+
if (src[0] == ':' && src[1] == ':') {
90+
// "::" Can only be used once.
91+
++groups;
92+
if (leading_groups < groups)
93+
return 0;
94+
leading_groups = groups;
95+
src += 2;
96+
if (*src == '\0') {
97+
// "::" placed at the end of an address.
98+
if (groups > NGROUPS - 2)
99+
return 0;
100+
break;
101+
} else {
102+
// "::" placed somewhere in the middle of an address.
103+
groups += 2;
104+
}
105+
} else if (*src == ':') {
106+
// Group separator.
107+
++groups;
108+
++src;
109+
} else if (*src == '\0') {
110+
// End of address.
111+
++groups;
112+
break;
113+
} else {
114+
// Potential trailing IPv4 address using dotted quad notation.
115+
if (groups > NGROUPS - 2)
116+
return 0;
117+
if (inet_pton4(group_start, &addr[groups * 2]) != 1)
118+
return 0;
119+
groups += 2;
120+
break;
121+
}
122+
123+
// Next iteration would attempt to parse a ninth group.
124+
if (groups >= NGROUPS)
125+
return 0;
126+
}
127+
128+
// Number of groups is insufficient, e.g. "1:2:3:4:5:6:7".
129+
if (groups < leading_groups)
130+
return 0;
131+
132+
// Zero the destination address. Copy the leading groups to the start
133+
// of the buffer and the trailing groups to the end.
134+
memset(dst, '\0', NGROUPS * 2);
135+
memcpy(dst, addr, leading_groups * 2);
136+
size_t trailing_groups = groups - leading_groups;
137+
memcpy(dst + (NGROUPS - trailing_groups) * 2, addr + leading_groups * 2,
138+
trailing_groups * 2);
139+
#undef NGROUPS
140+
return 1;
141+
}
142+
143+
int inet_pton(int af, const char *restrict src, void *restrict dst) {
144+
switch (af) {
145+
case AF_INET:
146+
return inet_pton4(src, dst);
147+
case AF_INET6:
148+
return inet_pton6(src, dst);
149+
default:
150+
errno = EAFNOSUPPORT;
151+
return -1;
152+
}
153+
}

0 commit comments

Comments
 (0)