user: implement mlibc as the libc, finally.
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
This commit is contained in:
@@ -0,0 +1,307 @@
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <bits/ensure.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <mlibc/bitutil.hpp>
|
||||
#include <mlibc/debug.hpp>
|
||||
|
||||
const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
|
||||
const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
|
||||
|
||||
uint32_t htonl(uint32_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint32_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
uint16_t htons(uint16_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint16_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
uint32_t ntohl(uint32_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint32_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
uint16_t ntohs(uint16_t x) {
|
||||
#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
|
||||
return mlibc::bit_util<uint16_t>::byteswap(x);
|
||||
#else
|
||||
return x;
|
||||
#endif
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// IPv4 address manipulation.
|
||||
// ----------------------------------------------------------------------------
|
||||
in_addr_t inet_addr(const char *p) {
|
||||
struct in_addr a;
|
||||
if(!inet_aton(p, &a))
|
||||
return -1;
|
||||
return a.s_addr;
|
||||
}
|
||||
|
||||
in_addr_t inet_network(const char *) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
char *inet_ntoa(struct in_addr addr) {
|
||||
// string: xxx.yyy.zzz.aaa
|
||||
// 4 * 3 + 3 + 1 = 12 + 4 = 16
|
||||
thread_local static char buffer[16];
|
||||
uint32_t proper = htonl(addr.s_addr);
|
||||
snprintf(buffer, sizeof(buffer), "%d.%d.%d.%d",
|
||||
(proper >> 24) & 0xff, ((proper >> 16) & 0xff),
|
||||
(proper >> 8) & 0xff, proper & 0xff);
|
||||
return buffer;
|
||||
}
|
||||
int inet_aton(const char *string, struct in_addr *dest) {
|
||||
int array[4];
|
||||
int i = 0;
|
||||
char *end;
|
||||
|
||||
for (; i < 4; i++) {
|
||||
array[i] = strtoul(string, &end, 0);
|
||||
if (*end && *end != '.')
|
||||
return 0;
|
||||
if (!*end)
|
||||
break;
|
||||
string = end + 1;
|
||||
}
|
||||
|
||||
switch (i) {
|
||||
case 0:
|
||||
dest->s_addr = htonl(array[0]);
|
||||
break;
|
||||
case 1:
|
||||
if (array[0] > 255 || array[1] > 0xffffff)
|
||||
return 0;
|
||||
dest->s_addr = htonl((array[0] << 24) | array[1]);
|
||||
break;
|
||||
case 2:
|
||||
if (array[0] > 255 || array[1] > 255 ||
|
||||
array[2] > 0xffff)
|
||||
return 0;
|
||||
dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) |
|
||||
array[2]);
|
||||
break;
|
||||
case 3:
|
||||
if (array[0] > 255 || array[1] > 255 ||
|
||||
array[2] > 255 || array[3] > 255)
|
||||
return 0;
|
||||
dest->s_addr = htonl((array[0] << 24) | (array[1] << 16) |
|
||||
(array[2] << 8) | array[3]);
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Generic IP address manipulation.
|
||||
// ----------------------------------------------------------------------------
|
||||
const char *inet_ntop(int af, const void *__restrict src, char *__restrict dst,
|
||||
socklen_t size) {
|
||||
switch (af) {
|
||||
case AF_INET: {
|
||||
auto source = reinterpret_cast<const struct in_addr*>(src);
|
||||
uint32_t addr = ntohl(source->s_addr);
|
||||
if (snprintf(dst, size, "%d.%d.%d.%d",
|
||||
(addr >> 24) & 0xff,
|
||||
(addr >> 16) & 0xff,
|
||||
(addr >> 8) & 0xff,
|
||||
addr & 0xff) < (int)size)
|
||||
return dst;
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
auto source = reinterpret_cast<const struct in6_addr*>(src);
|
||||
size_t cur_zeroes_off = 0;
|
||||
size_t cur_zeroes_len = 0;
|
||||
size_t max_zeroes_off = 0;
|
||||
size_t max_zeroes_len = 0;
|
||||
|
||||
/* we look for the largest block of zeroed quartet(s) */
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
auto ptr = source->s6_addr + (i * 2);
|
||||
if(!ptr[0] && !ptr[1]) {
|
||||
cur_zeroes_len++;
|
||||
if(max_zeroes_len < cur_zeroes_len) {
|
||||
max_zeroes_len = cur_zeroes_len;
|
||||
max_zeroes_off = cur_zeroes_off;
|
||||
}
|
||||
} else {
|
||||
/* advance the offset to the next quartet to check */
|
||||
cur_zeroes_len = 0;
|
||||
cur_zeroes_off = i + 1;
|
||||
}
|
||||
}
|
||||
|
||||
size_t off = 0;
|
||||
for(size_t i = 0; i < 8; i++) {
|
||||
auto ptr = source->s6_addr + (i * 2);
|
||||
|
||||
/* if we are at the beginning of the largest block of zeroed quartets, place "::" */
|
||||
if(i == max_zeroes_off && max_zeroes_len >= 2) {
|
||||
if(off < size) {
|
||||
dst[off++] = ':';
|
||||
}
|
||||
if(off < size) {
|
||||
dst[off++] = ':';
|
||||
}
|
||||
i += max_zeroes_len - 1;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* place a colon if we're not at the beginning of the string and it is not already there */
|
||||
if(off && dst[off - 1] != ':') {
|
||||
if(off < size) {
|
||||
dst[off++] = ':';
|
||||
}
|
||||
}
|
||||
|
||||
off += snprintf(dst + off, size - off, "%x", ptr[0] << 8 | ptr[1]);
|
||||
}
|
||||
|
||||
dst[off] = 0;
|
||||
|
||||
return dst;
|
||||
}
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
errno = ENOSPC;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int inet_pton(int af, const char *__restrict src, void *__restrict dst) {
|
||||
switch (af) {
|
||||
case AF_INET: {
|
||||
uint8_t array[4] = {};
|
||||
for (int i = 0; i < 4; i++) {
|
||||
char *end;
|
||||
long int value = strtol(src, &end, 10);
|
||||
if (value > 255)
|
||||
return 0;
|
||||
if (*end != '\0' && *end != '.')
|
||||
return 0;
|
||||
src = end + 1;
|
||||
array[i] = value;
|
||||
}
|
||||
auto addr = reinterpret_cast<struct in_addr*>(dst);
|
||||
uint32_t ip = (array[0] << 24) | (array[1] << 16) | (array[2] << 8) | array[3];
|
||||
addr->s_addr = htonl(ip);
|
||||
break;
|
||||
}
|
||||
case AF_INET6: {
|
||||
size_t i = 0;
|
||||
uint16_t array[8] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
frg::optional<size_t> doubleColonOffset = frg::null_opt;
|
||||
|
||||
auto reservedRange = [&]() -> bool {
|
||||
if(i && ((doubleColonOffset && doubleColonOffset.value()) || !doubleColonOffset)) {
|
||||
return (ntohs(array[0]) >> 8) == 0;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
for(; i < 8; i++) {
|
||||
char *end = nullptr;
|
||||
auto value = strtol(src, &end, 16);
|
||||
|
||||
if (value > UINT16_MAX)
|
||||
return 0;
|
||||
if(end[0] != '\0' && end[0] != ':' && end[0] != '.')
|
||||
return 0;
|
||||
|
||||
if(end[0] == '.' && reservedRange() && i < 7) {
|
||||
char *ipv4end = nullptr;
|
||||
auto value0 = strtol(src, &ipv4end, 10);
|
||||
if(ipv4end[0] != '.' || value0 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
src = ipv4end + 1;
|
||||
auto value1 = strtol(src, &ipv4end, 10);
|
||||
if(ipv4end[0] != '.' || value1 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
array[i++] = htons((value0 << 8) | value1);
|
||||
src = ipv4end + 1;
|
||||
|
||||
auto value2 = strtol(src, &ipv4end, 10);
|
||||
if(ipv4end[0] != '.' || value2 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
src = ipv4end + 1;
|
||||
auto value3 = strtol(src, &ipv4end, 10);
|
||||
if(value3 > UINT8_MAX || src == ipv4end)
|
||||
return 0;
|
||||
array[i] = htons((value2 << 8) | value3);
|
||||
break;
|
||||
} else if(end[0] == ':' && end[1] == ':') {
|
||||
if(doubleColonOffset)
|
||||
return 0;
|
||||
doubleColonOffset = i + 1;
|
||||
src = end + 2;
|
||||
} else if(end[0] == ':' || end[0] == '\0') {
|
||||
src = end + 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
array[i] = htons(value);
|
||||
|
||||
if(end[0] == '\0')
|
||||
break;
|
||||
}
|
||||
|
||||
auto addr = reinterpret_cast<struct in6_addr *>(dst);
|
||||
|
||||
if(doubleColonOffset) {
|
||||
size_t suffix = i - doubleColonOffset.value() + 1;
|
||||
memset(addr->s6_addr, 0, 16);
|
||||
|
||||
for(size_t j = 0; j < doubleColonOffset.value(); j++) {
|
||||
addr->s6_addr16[j] = array[j];
|
||||
}
|
||||
|
||||
for(size_t j = 0; j < suffix; j++) {
|
||||
addr->s6_addr16[8 - suffix + j] = array[doubleColonOffset.value() + j];
|
||||
}
|
||||
} else {
|
||||
for(size_t j = 0; j < 8; j++) {
|
||||
addr->s6_addr16[j] = array[j];
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
errno = EAFNOSUPPORT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
struct in_addr inet_makeaddr(in_addr_t, in_addr_t) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
|
||||
in_addr_t inet_netof(struct in_addr) {
|
||||
__ensure(!"Not implemented");
|
||||
__builtin_unreachable();
|
||||
}
|
||||
Reference in New Issue
Block a user