Add unix domain socket support to redbean

This commit is contained in:
Justine Tunney 2022-06-22 03:04:25 -07:00
parent 4b23985b7f
commit fc097ac275
25 changed files with 594 additions and 172 deletions

View file

@ -93,12 +93,21 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
return rc;
}
forceinline void Sockaddr2linux(void *saddr) {
char *p;
if (saddr) {
p = saddr;
p[0] = p[1];
p[1] = 0;
}
}
/* Used for all the ioctl that returns sockaddr structure that
* requires adjustment between Linux and XNU
*/
static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
if (sys_ioctl(fd, op, ifr) == -1) return -1;
if (IsBsd()) sockaddr2linux(&ifr->ifr_addr);
if (IsBsd()) Sockaddr2linux(&ifr->ifr_addr);
return 0;
}

View file

@ -21,8 +21,15 @@
int sys_accept(int server, void *addr, uint32_t *addrsize) {
int client;
if ((client = __sys_accept(server, addr, addrsize, 0)) != -1 && IsBsd()) {
sockaddr2linux(addr);
uint32_t size;
union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
client = __sys_accept(server, addr, addrsize, 0);
} else {
size = sizeof(bsd);
if ((client = __sys_accept(server, &bsd, &size, 0)) != -1) {
sockaddr2linux(&bsd, size, addr, addrsize);
}
}
return client;
}

View file

@ -21,27 +21,26 @@
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#define __NR_accept4_linux 0x0120 /* rhel5:enosysevil */
int sys_accept4(int server, void *addr, uint32_t *addrsize, int flags) {
static bool once, demodernize;
if (!flags) return sys_accept(server, addr, addrsize);
int olderr, client;
if (!flags || demodernize) goto TriedAndTrue;
union sockaddr_storage_bsd bsd;
uint32_t size = sizeof(bsd);
void *out_addr = !IsBsd() ? addr : &bsd;
uint32_t *out_addrsize = !IsBsd() ? addrsize : &size;
static bool demodernize;
if (demodernize) goto TriedAndTrue;
olderr = errno;
client = __sys_accept4(server, addr, addrsize, flags);
client = __sys_accept4(server, out_addr, out_addrsize, flags);
if (client == -1 && errno == ENOSYS) {
errno = olderr;
demodernize = true;
TriedAndTrue:
client = __fixupnewsockfd(__sys_accept(server, addr, addrsize, 0), flags);
} else if (SupportsLinux() && !once) {
once = true;
if (client == __NR_accept4_linux) {
demodernize = true;
goto TriedAndTrue;
}
client = __fixupnewsockfd(__sys_accept(server, out_addr, out_addrsize, 0),
flags);
}
if (client != -1 && IsBsd()) {
sockaddr2linux(addr);
sockaddr2linux(&bsd, size, addr, addrsize);
}
return client;
}

31
libc/sock/bind-sysv.c Normal file
View file

@ -0,0 +1,31 @@
/*-*- 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 2020 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/dce.h"
#include "libc/sock/internal.h"
int sys_bind(int fd, const void *addr, uint32_t addrsize) {
union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
return __sys_bind(fd, addr, addrsize);
} else if (!sockaddr2bsd(addr, addrsize, &bsd, &addrsize)) {
return __sys_bind(fd, &bsd.sa, addrsize);
} else {
return -1;
}
}

View file

@ -16,7 +16,6 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/calls/internal.h"
#include "libc/calls/strace.internal.h"
#include "libc/dce.h"
@ -25,7 +24,6 @@
#include "libc/sock/sock.h"
#include "libc/sock/sockdebug.h"
#include "libc/sock/syscall_fd.internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
/**
@ -40,21 +38,11 @@
*/
int bind(int fd, const void *addr, uint32_t addrsize) {
int rc;
char addrbuf[72];
if (!addr || (IsAsan() && !__asan_is_valid(addr, addrsize))) {
rc = efault();
} else if (addrsize >= sizeof(struct sockaddr_in)) {
if (!IsWindows()) {
if (!IsBsd()) {
rc = sys_bind(fd, addr, addrsize);
} else {
char addr2[sizeof(
struct sockaddr_un_bsd)]; /* sockaddr_un_bsd is the largest */
assert(addrsize <= sizeof(addr2));
memcpy(&addr2, addr, addrsize);
sockaddr2bsd(&addr2[0]);
rc = sys_bind(fd, &addr2, addrsize);
}
rc = sys_bind(fd, addr, addrsize);
} else if (__isfdkind(fd, kFdSocket)) {
rc = sys_bind_nt(&g_fds.p[fd], addr, addrsize);
} else {

View file

@ -16,20 +16,16 @@
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/assert.h"
#include "libc/dce.h"
#include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/errfuns.h"
int sys_connect(int fd, const void *addr, uint32_t addrsize) {
union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
return __sys_connect(fd, addr, addrsize);
} else if (!sockaddr2bsd(addr, addrsize, &bsd, &addrsize)) {
return __sys_connect(fd, &bsd.sa, addrsize);
} else {
char addr2[sizeof(struct sockaddr_un_bsd)]; /* sockaddr_un_bsd is the largest */
assert(addrsize <= sizeof(addr2));
memcpy(&addr2, addr, addrsize);
sockaddr2bsd(&addr2[0]);
return __sys_connect(fd, &addr2, addrsize);
return -1;
}
}

View file

@ -20,9 +20,16 @@
#include "libc/sock/internal.h"
int sys_getpeername(int fd, void *out_addr, uint32_t *out_addrsize) {
int rc = __sys_getpeername(fd, out_addr, out_addrsize);
if (rc != -1 && IsBsd()) {
sockaddr2linux(out_addr);
int rc;
uint32_t size;
union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
rc = __sys_getpeername(fd, out_addr, out_addrsize);
} else {
size = sizeof(bsd);
if ((rc = __sys_getpeername(fd, &bsd, &size)) != -1) {
sockaddr2linux(&bsd, size, out_addr, out_addrsize);
}
}
return rc;
}

View file

@ -20,9 +20,16 @@
#include "libc/sock/internal.h"
int sys_getsockname(int fd, void *out_addr, uint32_t *out_addrsize) {
int rc = __sys_getsockname(fd, out_addr, out_addrsize);
if (rc != -1 && IsBsd()) {
sockaddr2linux(out_addr);
int rc;
uint32_t size;
union sockaddr_storage_bsd bsd;
if (!IsBsd()) {
rc = __sys_getsockname(fd, out_addr, out_addrsize);
} else {
size = sizeof(bsd);
if ((rc = __sys_getsockname(fd, &bsd, &size)) != -1) {
sockaddr2linux(&bsd, size, out_addr, out_addrsize);
}
}
return rc;
}

View file

@ -52,6 +52,18 @@ struct sockaddr_un_bsd {
char sun_path[108];
};
union sockaddr_storage_bsd {
struct sockaddr_bsd sa;
struct sockaddr_in_bsd sin;
struct sockaddr_un_bsd sun;
};
union sockaddr_storage_linux {
struct sockaddr sa;
struct sockaddr_in sin;
struct sockaddr_un sun;
};
/* ------------------------------------------------------------------------------------*/
#define SOCKFD_OVERLAP_BUFSIZ 128
@ -79,10 +91,11 @@ void _firewall(const void *, uint32_t) hidden;
int32_t __sys_accept(int32_t, void *, uint32_t *, int) dontdiscard hidden;
int32_t __sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden;
int32_t __sys_bind(int32_t, const void *, uint32_t) hidden;
int32_t __sys_connect(int32_t, const void *, uint32_t) hidden;
int32_t __sys_socket(int32_t, int32_t, int32_t) hidden;
int32_t __sys_getsockname(int32_t, void *, uint32_t *) hidden;
int32_t __sys_getpeername(int32_t, void *, uint32_t *) hidden;
int32_t __sys_getsockname(int32_t, void *, uint32_t *) hidden;
int32_t __sys_socket(int32_t, int32_t, int32_t) hidden;
int32_t __sys_socketpair(int32_t, int32_t, int32_t, int32_t[2]) hidden;
int32_t sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard hidden;
@ -137,29 +150,10 @@ struct SockFd *_dupsockfd(struct SockFd *) hidden;
int64_t GetNtBaseSocket(int64_t) hidden;
int sys_close_epoll(int) hidden;
/**
* Converts sockaddr (Linux/Windows) sockaddr_bsd (XNU/BSD).
*/
forceinline void sockaddr2bsd(void *saddr) {
char *p;
if (saddr) {
p = saddr;
p[1] = p[0];
p[0] = sizeof(struct sockaddr_in_bsd);
}
}
/**
* Converts sockaddr_in_bsd (XNU/BSD) sockaddr (Linux/Windows).
*/
forceinline void sockaddr2linux(void *saddr) {
char *p;
if (saddr) {
p = saddr;
p[0] = p[1];
p[1] = 0;
}
}
int sockaddr2bsd(const void *, uint32_t, union sockaddr_storage_bsd *,
uint32_t *);
void sockaddr2linux(const union sockaddr_storage_bsd *, uint32_t,
union sockaddr_storage_linux *, uint32_t *);
COSMOPOLITAN_C_END_
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */

View file

@ -45,19 +45,26 @@
*/
ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) {
ssize_t rc, got;
ssize_t rc;
uint32_t sz;
union sockaddr_storage_bsd bsd;
if (IsAsan() &&
(!__asan_is_valid(buf, size) ||
(opt_out_srcaddr &&
!__asan_is_valid(opt_out_srcaddr, *opt_inout_srcaddrsize)))) {
(!__asan_is_valid(opt_inout_srcaddrsize,
sizeof(*opt_inout_srcaddrsize)) ||
!__asan_is_valid(opt_out_srcaddr, *opt_inout_srcaddrsize))))) {
rc = efault();
} else if (!IsWindows()) {
got = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
opt_inout_srcaddrsize);
if (opt_out_srcaddr && IsBsd() && got != -1) {
sockaddr2linux(opt_out_srcaddr);
if (!IsBsd() || !opt_out_srcaddr) {
rc = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
opt_inout_srcaddrsize);
} else {
sz = sizeof(bsd);
if ((rc = sys_recvfrom(fd, buf, size, flags, &bsd, &sz)) != -1) {
sockaddr2linux(&bsd, sz, opt_out_srcaddr, opt_inout_srcaddrsize);
}
}
rc = got;
} else if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdSocket)) {
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,

View file

@ -41,15 +41,24 @@
*/
ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
ssize_t rc, got;
struct msghdr msg2;
union sockaddr_storage_bsd bsd;
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
rc = efault();
} else if (!IsWindows()) {
got = sys_recvmsg(fd, msg, flags);
// An address was provided, convert from BSD form
if (msg->msg_name && IsBsd() && got != -1) {
sockaddr2linux(msg->msg_name);
if (IsBsd() && msg->msg_name) {
memcpy(&msg2, msg, sizeof(msg2));
if (!(rc = sockaddr2bsd(msg->msg_name, msg->msg_namelen, &bsd,
&msg2.msg_namelen))) {
msg2.msg_name = &bsd.sa;
if ((rc = sys_recvmsg(fd, &msg2, flags)) != -1) {
sockaddr2linux(msg2.msg_name, msg2.msg_namelen, msg->msg_name,
&msg->msg_namelen);
}
}
} else {
rc = sys_recvmsg(fd, msg, flags);
}
rc = got;
} else if (__isfdopen(fd)) {
if (!msg->msg_control) {
if (__isfdkind(fd, kFdSocket)) {

View file

@ -44,27 +44,22 @@
*/
ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
int64_t rc;
char addr2[128];
struct msghdr msg2;
union sockaddr_storage_bsd bsd;
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
rc = efault();
} else if (!IsWindows()) {
if (IsBsd() && msg->msg_name) {
/* An optional address is provided, convert it to the BSD form */
if (msg->msg_namelen <= sizeof(addr2)) {
memcpy(&addr2[0], msg->msg_name, msg->msg_namelen);
sockaddr2bsd(&addr2[0]);
/* Copy all of msg (except for msg_name) into the new ephemeral local */
memcpy(&msg2, msg, sizeof(msg2));
msg2.msg_name = &addr2[0];
memcpy(&msg2, msg, sizeof(msg2));
if (!(rc = sockaddr2bsd(msg->msg_name, msg->msg_namelen, &bsd,
&msg2.msg_namelen))) {
msg2.msg_name = &bsd.sa;
rc = sys_sendmsg(fd, &msg2, flags);
} else {
rc = einval();
}
} else {
rc = sys_sendmsg(fd, msg, flags);
}
/* else do the syscall */
rc = sys_sendmsg(fd, msg, flags);
} else if (__isfdopen(fd)) {
if (msg->msg_control) {
rc = einval(); /* control msg not supported */

View file

@ -52,7 +52,8 @@
ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
const void *opt_addr, uint32_t addrsize) {
ssize_t rc;
char addr2[sizeof(struct sockaddr_un_bsd)];
uint32_t bsdaddrsize;
union sockaddr_storage_bsd bsd;
if (IsAsan() && (!__asan_is_valid(buf, size) ||
(opt_addr && !__asan_is_valid(opt_addr, addrsize)))) {
rc = efault();
@ -61,12 +62,8 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
if (!IsWindows()) {
if (!IsBsd() || !opt_addr) {
rc = sys_sendto(fd, buf, size, flags, opt_addr, addrsize);
} else if (addrsize > sizeof(addr2)) {
rc = einval();
} else {
memcpy(&addr2, opt_addr, addrsize);
sockaddr2bsd(&addr2[0]);
rc = sys_sendto(fd, buf, size, flags, &addr2[0], addrsize);
} else if (!(rc = sockaddr2bsd(opt_addr, addrsize, &bsd, &bsdaddrsize))) {
rc = sys_sendto(fd, buf, size, flags, &bsd, bsdaddrsize);
}
} else if (__isfdopen(fd)) {
if (__isfdkind(fd, kFdSocket)) {

66
libc/sock/sockaddr2bsd.c Normal file
View file

@ -0,0 +1,66 @@
/*-*- 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/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h"
/**
* Converts sockaddr (Linux/Windows) sockaddr_bsd (XNU/BSD).
*/
int sockaddr2bsd(const void *addr, uint32_t addrsize,
union sockaddr_storage_bsd *out_addr, uint32_t *out_addrsize) {
uint32_t len, famsize;
if (addrsize >= sizeof(((struct sockaddr *)addr)->sa_family)) {
if (((struct sockaddr *)addr)->sa_family == AF_INET) {
if (addrsize >= sizeof(struct sockaddr_in)) {
out_addr->sin.sin_len = 0;
out_addr->sin.sin_family = AF_INET;
out_addr->sin.sin_port = ((struct sockaddr_in *)addr)->sin_port;
out_addr->sin.sin_addr = ((struct sockaddr_in *)addr)->sin_addr;
bzero(&out_addr->sin.sin_zero, sizeof(out_addr->sin.sin_zero));
*out_addrsize = sizeof(struct sockaddr_in_bsd);
return 0;
} else {
return einval();
}
} else if (((struct sockaddr *)addr)->sa_family == AF_UNIX) {
famsize = sizeof(((struct sockaddr_un *)addr)->sun_family);
if (addrsize >= famsize &&
(len = strnlen(((struct sockaddr_un *)addr)->sun_path,
addrsize - famsize)) <
sizeof(out_addr->sun.sun_path)) {
out_addr->sun.sun_len = 0;
out_addr->sun.sun_family = AF_UNIX;
memcpy(out_addr->sun.sun_path, ((struct sockaddr_un *)addr)->sun_path,
len);
out_addr->sun.sun_path[len] = 0;
*out_addrsize = sizeof(out_addr->sun.sun_len) +
sizeof(out_addr->sun.sun_family) + len;
return 0;
} else {
return einval();
}
} else {
return epfnosupport();
}
} else {
return einval();
}
}

View file

@ -0,0 +1,60 @@
/*-*- 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/intrin/kprintf.h"
#include "libc/macros.internal.h"
#include "libc/sock/internal.h"
#include "libc/str/str.h"
#include "libc/sysv/consts/af.h"
#include "libc/sysv/errfuns.h"
/**
* Converts sockaddr_bsd (XNU/BSD) sockaddr (Linux/Windows).
*/
void sockaddr2linux(const union sockaddr_storage_bsd *addr, uint32_t addrsize,
union sockaddr_storage_linux *out_addr,
uint32_t *inout_addrsize) {
uint32_t len, size;
if (out_addr && inout_addrsize) {
size = *inout_addrsize;
bzero(out_addr, size);
if (addrsize >= sizeof(addr->sa.sa_family)) {
if (addr->sa.sa_family == AF_INET) {
if (addrsize >= sizeof(struct sockaddr_in_bsd) &&
size >= sizeof(struct sockaddr_in)) {
out_addr->sin.sin_family = AF_INET;
out_addr->sin.sin_port = addr->sin.sin_port;
out_addr->sin.sin_addr = addr->sin.sin_addr;
*inout_addrsize = sizeof(struct sockaddr_in);
}
} else if (addr->sa.sa_family == AF_UNIX) {
if (addrsize >=
sizeof(addr->sun.sun_len) + sizeof(addr->sun.sun_family) &&
size >= sizeof(out_addr->sun.sun_family)) {
len = strnlen(((struct sockaddr_un *)addr)->sun_path,
MIN(addrsize - (sizeof(addr->sun.sun_len) +
sizeof(addr->sun.sun_family)),
size - sizeof(out_addr->sun.sun_family)));
out_addr->sun.sun_family = AF_UNIX;
if (len) memcpy(out_addr->sun.sun_path, addr->sun.sun_path, len);
*inout_addrsize = sizeof(out_addr->sun.sun_family) + len + 1;
}
}
}
}
}

View file

@ -0,0 +1,2 @@
.include "o/libc/sysv/macros.internal.inc"
.scall __sys_bind,0x0680680682068031,globl,hidden

View file

@ -1,2 +0,0 @@
.include "o/libc/sysv/macros.internal.inc"
.scall sys_bind,0x0680680682068031,globl,hidden

View file

@ -84,7 +84,7 @@ scall sys_recvfrom 0x01d01d01d201d02d globl hidden
scall sys_sendmsg 0x01c01c01c201c02e globl hidden
scall sys_recvmsg 0x01b01b01b201b02f globl hidden
scall sys_shutdown 0x0860860862086030 globl hidden
scall sys_bind 0x0680680682068031 globl hidden
scall __sys_bind 0x0680680682068031 globl hidden
scall sys_listen 0x06a06a06a206a032 globl hidden
scall __sys_getsockname 0x0200200202020033 globl hidden
scall __sys_getpeername 0x01f01f08d201f034 globl hidden