Polyfill IPv6 on non-Linux

This commit is contained in:
Justine Tunney 2022-09-08 06:06:22 -07:00
parent b73e35c6fa
commit 0547eabcd6
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
10 changed files with 185 additions and 78 deletions

View file

@ -18,7 +18,6 @@
#define in_addr_t uint32_t #define in_addr_t uint32_t
#define in_addr_t uint32_t #define in_addr_t uint32_t
#define in_port_t uint16_t #define in_port_t uint16_t
#define in_port_t uint16_t
#define ino_t uint64_t #define ino_t uint64_t
#define key_t int32_t #define key_t int32_t
#define loff_t int64_t #define loff_t int64_t

View file

@ -38,6 +38,12 @@ OpenBSD Sorting (BSD-3)\\n\
Copyright 1993 The Regents of the University of California\""); Copyright 1993 The Regents of the University of California\"");
asm(".include \"libc/disclaimer.inc\""); asm(".include \"libc/disclaimer.inc\"");
#define SWAPTYPE_BYTEV 1
#define SWAPTYPE_INTV 2
#define SWAPTYPE_LONGV 3
#define SWAPTYPE_INT 4
#define SWAPTYPE_LONG 5
#define CMPPAR int (*cmp)(const void *, const void *, void *),void *arg #define CMPPAR int (*cmp)(const void *, const void *, void *),void *arg
#define CMPARG cmp, arg #define CMPARG cmp, arg
#define CMP(a, b) cmp(a, b, arg) #define CMP(a, b) cmp(a, b, arg)
@ -46,30 +52,6 @@ asm(".include \"libc/disclaimer.inc\"");
static inline char *med3(char *, char *, char *, CMPPAR); static inline char *med3(char *, char *, char *, CMPPAR);
static inline void swapfunc(char *, char *, size_t, int); static inline void swapfunc(char *, char *, size_t, int);
/*
* Qsort routine from Bentley & McIlroy's "Engineering a Sort Function".
*
* This version differs from Bentley & McIlroy in the following ways:
* 1. The partition value is swapped into a[0] instead of being
* stored out of line.
*
* 2. The swap function can swap 32-bit aligned elements on 64-bit
* platforms instead of swapping them as byte-aligned.
*
* 3. It uses David Musser's introsort algorithm to fall back to
* heapsort(3) when the recursion depth reaches 2*lg(n + 1).
* This avoids quicksort's quadratic behavior for pathological
* input without appreciably changing the average run time.
*
* 4. Tail recursion is eliminated when sorting the larger of two
* subpartitions to save stack space.
*/
#define SWAPTYPE_BYTEV 1
#define SWAPTYPE_INTV 2
#define SWAPTYPE_LONGV 3
#define SWAPTYPE_INT 4
#define SWAPTYPE_LONG 5
#define TYPE_ALIGNED(TYPE, a, es) \ #define TYPE_ALIGNED(TYPE, a, es) \
(((char *)a - (char *)0) % sizeof(TYPE) == 0 && es % sizeof(TYPE) == 0) (((char *)a - (char *)0) % sizeof(TYPE) == 0 && es % sizeof(TYPE) == 0)

View file

@ -18,6 +18,7 @@
*/ */
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/struct/sockaddr.internal.h" #include "libc/sock/struct/sockaddr.internal.h"
#include "libc/sock/struct/sockaddr6-bsd.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -41,6 +42,21 @@ int sockaddr2bsd(const void *addr, uint32_t addrsize,
} else { } else {
return einval(); return einval();
} }
} else if (((struct sockaddr *)addr)->sa_family == AF_INET6) {
if (addrsize >= sizeof(struct sockaddr_in6)) {
out_addr->sin6.sin6_len = 0;
out_addr->sin6.sin6_family = AF_INET6;
out_addr->sin6.sin6_port = ((struct sockaddr_in6 *)addr)->sin6_port;
out_addr->sin6.sin6_flowinfo =
((struct sockaddr_in6 *)addr)->sin6_flowinfo;
out_addr->sin6.sin6_addr = ((struct sockaddr_in6 *)addr)->sin6_addr;
out_addr->sin6.sin6_scope_id =
((struct sockaddr_in6 *)addr)->sin6_scope_id;
*out_addrsize = sizeof(struct sockaddr_in6_bsd);
return 0;
} else {
return einval();
}
} else if (((struct sockaddr *)addr)->sa_family == AF_UNIX) { } else if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
famsize = sizeof(((struct sockaddr_un *)addr)->sun_family); famsize = sizeof(((struct sockaddr_un *)addr)->sun_family);
if (addrsize >= famsize && if (addrsize >= famsize &&

View file

@ -19,6 +19,7 @@
#include "libc/macros.internal.h" #include "libc/macros.internal.h"
#include "libc/sock/internal.h" #include "libc/sock/internal.h"
#include "libc/sock/struct/sockaddr.internal.h" #include "libc/sock/struct/sockaddr.internal.h"
#include "libc/sock/struct/sockaddr6-bsd.internal.h"
#include "libc/str/str.h" #include "libc/str/str.h"
#include "libc/sysv/consts/af.h" #include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h" #include "libc/sysv/errfuns.h"
@ -42,6 +43,16 @@ void sockaddr2linux(const union sockaddr_storage_bsd *addr, uint32_t addrsize,
out_addr->sin.sin_addr = addr->sin.sin_addr; out_addr->sin.sin_addr = addr->sin.sin_addr;
*inout_addrsize = sizeof(struct sockaddr_in); *inout_addrsize = sizeof(struct sockaddr_in);
} }
} else if (addr->sa.sa_family == AF_INET6) {
if (addrsize >= sizeof(struct sockaddr_in6_bsd) &&
size >= sizeof(struct sockaddr_in6)) {
out_addr->sin6.sin6_family = AF_INET6;
out_addr->sin6.sin6_port = addr->sin6.sin6_port;
out_addr->sin6.sin6_addr = addr->sin6.sin6_addr;
out_addr->sin6.sin6_flowinfo = addr->sin6.sin6_flowinfo;
out_addr->sin6.sin6_scope_id = addr->sin6.sin6_scope_id;
*inout_addrsize = sizeof(struct sockaddr_in6);
}
} else if (addr->sa.sa_family == AF_UNIX) { } else if (addr->sa.sa_family == AF_UNIX) {
if (addrsize >= if (addrsize >=
sizeof(addr->sun.sun_len) + sizeof(addr->sun.sun_family) && sizeof(addr->sun.sun_len) + sizeof(addr->sun.sun_family) &&

View file

@ -2,6 +2,7 @@
#define COSMOPOLITAN_LIBC_SOCK_STRUCT_SOCKADDR_INTERNAL_H_ #define COSMOPOLITAN_LIBC_SOCK_STRUCT_SOCKADDR_INTERNAL_H_
#include "libc/mem/alloca.h" #include "libc/mem/alloca.h"
#include "libc/sock/struct/sockaddr.h" #include "libc/sock/struct/sockaddr.h"
#include "libc/sock/struct/sockaddr6-bsd.internal.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0) #if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_ COSMOPOLITAN_C_START_
@ -29,12 +30,14 @@ struct sockaddr_un_bsd {
union sockaddr_storage_bsd { union sockaddr_storage_bsd {
struct sockaddr_bsd sa; struct sockaddr_bsd sa;
struct sockaddr_in_bsd sin; struct sockaddr_in_bsd sin;
struct sockaddr_in6_bsd sin6;
struct sockaddr_un_bsd sun; struct sockaddr_un_bsd sun;
}; };
union sockaddr_storage_linux { union sockaddr_storage_linux {
struct sockaddr sa; struct sockaddr sa;
struct sockaddr_in sin; struct sockaddr_in sin;
struct sockaddr_in6 sin6;
struct sockaddr_un sun; struct sockaddr_un sun;
}; };

View file

@ -0,0 +1,18 @@
#ifndef COSMOPOLITAN_LIBC_SOCK_STRUCT_SOCKADDR6_BSD_INTERNAL_H_
#define COSMOPOLITAN_LIBC_SOCK_STRUCT_SOCKADDR6_BSD_INTERNAL_H_
#include "libc/sock/struct/sockaddr6.h"
#if !(__ASSEMBLER__ + __LINKER__ + 0)
COSMOPOLITAN_C_START_
struct sockaddr_in6_bsd {
uint8_t sin6_len;
uint8_t sin6_family;
uint16_t sin6_port;
uint32_t sin6_flowinfo;
struct in6_addr sin6_addr;
uint32_t sin6_scope_id;
};
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
#endif /* COSMOPOLITAN_LIBC_SOCK_STRUCT_SOCKADDR6_BSD_INTERNAL_H_ */

View file

@ -17,47 +17,22 @@
PERFORMANCE OF THIS SOFTWARE. PERFORMANCE OF THIS SOFTWARE.
*/ */
#include "libc/calls/strace.internal.h" #include "libc/calls/strace.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/macros.internal.h"
#include "libc/nexgen32e/bsr.h"
#include "libc/nexgen32e/x86feature.h"
#include "libc/runtime/runtime.h" #include "libc/runtime/runtime.h"
forceinline void longsorter(long *x, size_t n, size_t t) { static void longsorter(long *A, size_t n) {
long a, b, c; long t, p;
size_t i, p, q; size_t i, j;
for (p = t; p > 0; p >>= 1) { if (n < 2) return;
for (i = 0; i < n - p; ++i) { for (p = A[n / 2], i = 0, j = n - 1;; i++, j--) {
if (!(i & p)) { while (A[i] < p) i++;
a = x[i + 0]; while (A[j] > p) j--;
b = x[i + p]; if (i >= j) break;
if (a > b) c = a, a = b, b = c; t = A[i];
x[i + 0] = a; A[i] = A[j];
x[i + p] = b; A[j] = t;
}
}
for (q = t; q > p; q >>= 1) {
for (i = 0; i < n - q; ++i) {
if (!(i & p)) {
a = x[i + p];
b = x[i + q];
if (a > b) c = a, a = b, b = c;
x[i + p] = a;
x[i + q] = b;
}
}
}
} }
} longsorter(A, i);
longsorter(A + i, n - i);
static microarchitecture("avx2") optimizespeed noasan
void longsort_avx2(long *x, size_t n, size_t t) {
longsorter(x, n, t);
}
static optimizesize noasan void longsort_pure(long *x, size_t n, size_t t) {
longsorter(x, n, t);
} }
/** /**
@ -67,21 +42,9 @@ static optimizesize noasan void longsort_pure(long *x, size_t n, size_t t) {
* -Lord Capulet * -Lord Capulet
* *
*/ */
void longsort(long *x, size_t n) { void longsort(long *A, size_t n) {
size_t t, m; longsorter(A, n);
if (IsAsan()) {
if (__builtin_mul_overflow(n, sizeof(long), &m)) m = -1;
__asan_verify(x, m);
}
if (n > 1) {
t = 1ul << bsrl(n - 1);
if (!IsTiny() && X86_HAVE(AVX2)) {
longsort_avx2(x, n, t);
} else {
longsort_pure(x, n, t);
}
}
if (n > 1000) { if (n > 1000) {
STRACE("longsort(%p, %'zu)", x, n); STRACE("longsort(%p, %'zu)", A, n);
} }
} }

View file

@ -22,6 +22,7 @@
#include "libc/mem/mem.h" #include "libc/mem/mem.h"
#include "libc/nexgen32e/bsr.h" #include "libc/nexgen32e/bsr.h"
#include "libc/runtime/gc.internal.h" #include "libc/runtime/gc.internal.h"
#include "libc/runtime/runtime.h"
#include "libc/stdio/rand.h" #include "libc/stdio/rand.h"
#include "libc/stdio/stdio.h" #include "libc/stdio/stdio.h"
#include "libc/str/str.h" #include "libc/str/str.h"
@ -62,10 +63,15 @@ TEST(qsort, equivalence_random) {
qsort(b, n, sizeof(long), CompareLong); qsort(b, n, sizeof(long), CompareLong);
heapsort(c, n, sizeof(long), CompareLong); heapsort(c, n, sizeof(long), CompareLong);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long))); ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
memcpy(c, a, n * sizeof(long));
mergesort(c, n, sizeof(long), CompareLong); mergesort(c, n, sizeof(long), CompareLong);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long))); ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
memcpy(c, a, n * sizeof(long));
smoothsort(c, n, sizeof(long), CompareLong); smoothsort(c, n, sizeof(long), CompareLong);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long))); ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
memcpy(c, a, n * sizeof(long));
longsort(c, n);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
} }
TEST(qsort, equivalence_reverse) { TEST(qsort, equivalence_reverse) {
@ -80,10 +86,15 @@ TEST(qsort, equivalence_reverse) {
qsort(b, n, sizeof(long), CompareLong); qsort(b, n, sizeof(long), CompareLong);
heapsort(c, n, sizeof(long), CompareLong); heapsort(c, n, sizeof(long), CompareLong);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long))); ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
memcpy(c, a, n * sizeof(long));
mergesort(c, n, sizeof(long), CompareLong); mergesort(c, n, sizeof(long), CompareLong);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long))); ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
memcpy(c, a, n * sizeof(long));
smoothsort(c, n, sizeof(long), CompareLong); smoothsort(c, n, sizeof(long), CompareLong);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long))); ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
memcpy(c, a, n * sizeof(long));
longsort(c, n);
ASSERT_EQ(0, memcmp(b, c, n * sizeof(long)));
} }
BENCH(qsort, bench) { BENCH(qsort, bench) {
@ -102,6 +113,8 @@ BENCH(qsort, bench) {
mergesort(p2, n, sizeof(long), CompareLong)); mergesort(p2, n, sizeof(long), CompareLong));
EZBENCH2("smoothsort nearly", memcpy(p2, p1, n * sizeof(long)), EZBENCH2("smoothsort nearly", memcpy(p2, p1, n * sizeof(long)),
smoothsort(p2, n, sizeof(long), CompareLong)); smoothsort(p2, n, sizeof(long), CompareLong));
EZBENCH2("longsort nearly", memcpy(p2, p1, n * sizeof(long)),
longsort(p2, n));
printf("\n"); printf("\n");
for (i = 0; i < n; ++i) p1[i] = n - i; for (i = 0; i < n; ++i) p1[i] = n - i;
@ -113,6 +126,8 @@ BENCH(qsort, bench) {
mergesort(p2, n, sizeof(long), CompareLong)); mergesort(p2, n, sizeof(long), CompareLong));
EZBENCH2("smoothsort reverse", memcpy(p2, p1, n * sizeof(long)), EZBENCH2("smoothsort reverse", memcpy(p2, p1, n * sizeof(long)),
smoothsort(p2, n, sizeof(long), CompareLong)); smoothsort(p2, n, sizeof(long), CompareLong));
EZBENCH2("longsort reverse", memcpy(p2, p1, n * sizeof(long)),
longsort(p2, n));
printf("\n"); printf("\n");
rngset(p1, n * sizeof(long), 0, 0); rngset(p1, n * sizeof(long), 0, 0);
@ -124,6 +139,8 @@ BENCH(qsort, bench) {
mergesort(p2, n, sizeof(long), CompareLong)); mergesort(p2, n, sizeof(long), CompareLong));
EZBENCH2("smoothsort random", memcpy(p2, p1, n * sizeof(long)), EZBENCH2("smoothsort random", memcpy(p2, p1, n * sizeof(long)),
smoothsort(p2, n, sizeof(long), CompareLong)); smoothsort(p2, n, sizeof(long), CompareLong));
EZBENCH2("longsort random", memcpy(p2, p1, n * sizeof(long)),
longsort(p2, n));
printf("\n"); printf("\n");
for (i = 0; i < n / 2; ++i) { for (i = 0; i < n / 2; ++i) {
@ -138,4 +155,5 @@ BENCH(qsort, bench) {
mergesort(p2, n, sizeof(long), CompareLong)); mergesort(p2, n, sizeof(long), CompareLong));
EZBENCH2("smoothsort 2n", memcpy(p2, p1, n * sizeof(long)), EZBENCH2("smoothsort 2n", memcpy(p2, p1, n * sizeof(long)),
smoothsort(p2, n, sizeof(long), CompareLong)); smoothsort(p2, n, sizeof(long), CompareLong));
EZBENCH2("longsort 2n", memcpy(p2, p1, n * sizeof(long)), longsort(p2, n));
} }

View file

@ -0,0 +1,93 @@
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi
Copyright 2022 Justine Alexandra Roberts Tunney
Permission to use, copy, modify, and/or distribute this software for
any purpose with or without fee is hereby granted, provided that the
above copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL
WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE
AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/calls.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
#include "libc/sock/struct/sockaddr6.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/consts/ipproto.h"
#include "libc/sysv/consts/limits.h"
#include "libc/sysv/consts/sock.h"
#include "libc/testlib/testlib.h"
TEST(ipv4, test) {
int ws, pid;
char buf[16] = {0};
int64_t inoffset;
uint32_t addrsize = sizeof(struct sockaddr_in);
struct sockaddr_in addr = {
.sin_family = AF_INET,
.sin_addr.s_addr = htonl(0x7f000001),
};
ASSERT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
ASSERT_SYS(0, 0, bind(3, &addr, sizeof(addr)));
ASSERT_SYS(0, 0, getsockname(3, &addr, &addrsize));
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
ASSERT_NE(-1, (pid = fork()));
if (!pid) {
ASSERT_SYS(0, 4, accept(3, &addr, &addrsize));
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
ASSERT_SYS(0, 0, close(4));
ASSERT_SYS(0, 0, close(3));
_Exit(0);
}
EXPECT_SYS(0, 0, close(3));
EXPECT_SYS(0, 3, socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
EXPECT_SYS(0, 0, connect(3, &addr, sizeof(addr)));
EXPECT_SYS(0, 5, read(3, buf, 16));
EXPECT_STREQ("hello", buf);
EXPECT_SYS(0, 0, close(3));
EXPECT_NE(-1, wait(&ws));
ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws));
}
TEST(ipv6, test) {
int ws, pid;
char buf[16] = {0};
int64_t inoffset;
uint32_t addrsize = sizeof(struct sockaddr_in6);
struct sockaddr_in6 addr = {
.sin6_family = AF_INET6,
.sin6_addr.s6_addr[15] = 1,
};
ASSERT_SYS(0, 3, socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP));
ASSERT_SYS(0, 0, bind(3, &addr, sizeof(addr)));
ASSERT_SYS(0, 0, getsockname(3, &addr, &addrsize));
ASSERT_EQ(AF_INET6, addr.sin6_family);
ASSERT_NE(0, addr.sin6_port);
ASSERT_SYS(0, 0, listen(3, SOMAXCONN));
ASSERT_NE(-1, (pid = fork()));
if (!pid) {
ASSERT_SYS(0, 4, accept(3, &addr, &addrsize));
ASSERT_SYS(0, 5, send(4, "hello", 5, 0));
ASSERT_SYS(0, 0, close(4));
ASSERT_SYS(0, 0, close(3));
_Exit(0);
}
EXPECT_SYS(0, 0, close(3));
EXPECT_SYS(0, 3, socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP));
EXPECT_SYS(0, 0, connect(3, &addr, sizeof(addr)));
EXPECT_SYS(0, 5, read(3, buf, 16));
EXPECT_STREQ("hello", buf);
EXPECT_SYS(0, 0, close(3));
EXPECT_NE(-1, wait(&ws));
ASSERT_TRUE(WIFEXITED(ws));
ASSERT_EQ(0, WEXITSTATUS(ws));
}

View file

@ -69,6 +69,10 @@ o/$(MODE)/test/libc/sock/sendrecvmsg_test.com.runs \
o/$(MODE)/test/libc/sock/nointernet_test.com.runs: \ o/$(MODE)/test/libc/sock/nointernet_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet recvfd sendfd private .PLEDGE = stdio rpath wpath cpath fattr proc inet recvfd sendfd
o/$(MODE)/test/libc/sock/socket_test.com.runs: .INTERNET = 1 # todo: ipv6 filtering
o/$(MODE)/test/libc/sock/socket_test.com.runs: \
private .PLEDGE = stdio rpath wpath cpath fattr proc inet
$(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk $(TEST_LIBC_SOCK_OBJS): test/libc/sock/test.mk
.PHONY: o/$(MODE)/test/libc/sock .PHONY: o/$(MODE)/test/libc/sock