mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 13:52:28 +00:00
Add unix domain socket support to redbean
This commit is contained in:
parent
4b23985b7f
commit
fc097ac275
25 changed files with 594 additions and 172 deletions
|
@ -71,8 +71,8 @@
|
||||||
* Like redbean, greenbean has superior performance too, with an
|
* Like redbean, greenbean has superior performance too, with an
|
||||||
* advantage on benchmarks biased towards high connection counts
|
* advantage on benchmarks biased towards high connection counts
|
||||||
*
|
*
|
||||||
* $ wrk -c 300 -t 32 --latency http://10.10.10.124:8080/
|
* $ wrk -c 300 -t 32 --latency http://127.0.0.1:8080/
|
||||||
* Running 10s test @ http://10.10.10.124:8080/
|
* Running 10s test @ http://127.0.0.1:8080/
|
||||||
* 32 threads and 300 connections
|
* 32 threads and 300 connections
|
||||||
* Thread Stats Avg Stdev Max +/- Stdev
|
* Thread Stats Avg Stdev Max +/- Stdev
|
||||||
* Latency 661.06us 5.11ms 96.22ms 98.85%
|
* Latency 661.06us 5.11ms 96.22ms 98.85%
|
||||||
|
|
|
@ -93,12 +93,21 @@ static int ioctl_siocgifconf_sysv(int fd, struct ifconf *ifc) {
|
||||||
return rc;
|
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
|
/* Used for all the ioctl that returns sockaddr structure that
|
||||||
* requires adjustment between Linux and XNU
|
* requires adjustment between Linux and XNU
|
||||||
*/
|
*/
|
||||||
static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
|
static int ioctl_siocgifaddr_sysv(int fd, uint64_t op, struct ifreq *ifr) {
|
||||||
if (sys_ioctl(fd, op, ifr) == -1) return -1;
|
if (sys_ioctl(fd, op, ifr) == -1) return -1;
|
||||||
if (IsBsd()) sockaddr2linux(&ifr->ifr_addr);
|
if (IsBsd()) Sockaddr2linux(&ifr->ifr_addr);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,8 +21,15 @@
|
||||||
|
|
||||||
int sys_accept(int server, void *addr, uint32_t *addrsize) {
|
int sys_accept(int server, void *addr, uint32_t *addrsize) {
|
||||||
int client;
|
int client;
|
||||||
if ((client = __sys_accept(server, addr, addrsize, 0)) != -1 && IsBsd()) {
|
uint32_t size;
|
||||||
sockaddr2linux(addr);
|
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;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,27 +21,26 @@
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
#include "libc/sock/sock.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) {
|
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;
|
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;
|
olderr = errno;
|
||||||
client = __sys_accept4(server, addr, addrsize, flags);
|
client = __sys_accept4(server, out_addr, out_addrsize, flags);
|
||||||
if (client == -1 && errno == ENOSYS) {
|
if (client == -1 && errno == ENOSYS) {
|
||||||
errno = olderr;
|
errno = olderr;
|
||||||
TriedAndTrue:
|
|
||||||
client = __fixupnewsockfd(__sys_accept(server, addr, addrsize, 0), flags);
|
|
||||||
} else if (SupportsLinux() && !once) {
|
|
||||||
once = true;
|
|
||||||
if (client == __NR_accept4_linux) {
|
|
||||||
demodernize = true;
|
demodernize = true;
|
||||||
goto TriedAndTrue;
|
TriedAndTrue:
|
||||||
}
|
client = __fixupnewsockfd(__sys_accept(server, out_addr, out_addrsize, 0),
|
||||||
|
flags);
|
||||||
}
|
}
|
||||||
if (client != -1 && IsBsd()) {
|
if (client != -1 && IsBsd()) {
|
||||||
sockaddr2linux(addr);
|
sockaddr2linux(&bsd, size, addr, addrsize);
|
||||||
}
|
}
|
||||||
return client;
|
return client;
|
||||||
}
|
}
|
||||||
|
|
31
libc/sock/bind-sysv.c
Normal file
31
libc/sock/bind-sysv.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,7 +16,6 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/calls/internal.h"
|
#include "libc/calls/internal.h"
|
||||||
#include "libc/calls/strace.internal.h"
|
#include "libc/calls/strace.internal.h"
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
|
@ -25,7 +24,6 @@
|
||||||
#include "libc/sock/sock.h"
|
#include "libc/sock/sock.h"
|
||||||
#include "libc/sock/sockdebug.h"
|
#include "libc/sock/sockdebug.h"
|
||||||
#include "libc/sock/syscall_fd.internal.h"
|
#include "libc/sock/syscall_fd.internal.h"
|
||||||
#include "libc/str/str.h"
|
|
||||||
#include "libc/sysv/errfuns.h"
|
#include "libc/sysv/errfuns.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,21 +38,11 @@
|
||||||
*/
|
*/
|
||||||
int bind(int fd, const void *addr, uint32_t addrsize) {
|
int bind(int fd, const void *addr, uint32_t addrsize) {
|
||||||
int rc;
|
int rc;
|
||||||
char addrbuf[72];
|
|
||||||
if (!addr || (IsAsan() && !__asan_is_valid(addr, addrsize))) {
|
if (!addr || (IsAsan() && !__asan_is_valid(addr, addrsize))) {
|
||||||
rc = efault();
|
rc = efault();
|
||||||
} else if (addrsize >= sizeof(struct sockaddr_in)) {
|
} else if (addrsize >= sizeof(struct sockaddr_in)) {
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
if (!IsBsd()) {
|
|
||||||
rc = sys_bind(fd, addr, addrsize);
|
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);
|
|
||||||
}
|
|
||||||
} else if (__isfdkind(fd, kFdSocket)) {
|
} else if (__isfdkind(fd, kFdSocket)) {
|
||||||
rc = sys_bind_nt(&g_fds.p[fd], addr, addrsize);
|
rc = sys_bind_nt(&g_fds.p[fd], addr, addrsize);
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -16,20 +16,16 @@
|
||||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||||
#include "libc/assert.h"
|
|
||||||
#include "libc/dce.h"
|
#include "libc/dce.h"
|
||||||
#include "libc/sock/internal.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) {
|
int sys_connect(int fd, const void *addr, uint32_t addrsize) {
|
||||||
|
union sockaddr_storage_bsd bsd;
|
||||||
if (!IsBsd()) {
|
if (!IsBsd()) {
|
||||||
return __sys_connect(fd, addr, addrsize);
|
return __sys_connect(fd, addr, addrsize);
|
||||||
|
} else if (!sockaddr2bsd(addr, addrsize, &bsd, &addrsize)) {
|
||||||
|
return __sys_connect(fd, &bsd.sa, addrsize);
|
||||||
} else {
|
} else {
|
||||||
char addr2[sizeof(struct sockaddr_un_bsd)]; /* sockaddr_un_bsd is the largest */
|
return -1;
|
||||||
assert(addrsize <= sizeof(addr2));
|
|
||||||
memcpy(&addr2, addr, addrsize);
|
|
||||||
sockaddr2bsd(&addr2[0]);
|
|
||||||
return __sys_connect(fd, &addr2, addrsize);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,16 @@
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
|
|
||||||
int sys_getpeername(int fd, void *out_addr, uint32_t *out_addrsize) {
|
int sys_getpeername(int fd, void *out_addr, uint32_t *out_addrsize) {
|
||||||
int rc = __sys_getpeername(fd, out_addr, out_addrsize);
|
int rc;
|
||||||
if (rc != -1 && IsBsd()) {
|
uint32_t size;
|
||||||
sockaddr2linux(out_addr);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,9 +20,16 @@
|
||||||
#include "libc/sock/internal.h"
|
#include "libc/sock/internal.h"
|
||||||
|
|
||||||
int sys_getsockname(int fd, void *out_addr, uint32_t *out_addrsize) {
|
int sys_getsockname(int fd, void *out_addr, uint32_t *out_addrsize) {
|
||||||
int rc = __sys_getsockname(fd, out_addr, out_addrsize);
|
int rc;
|
||||||
if (rc != -1 && IsBsd()) {
|
uint32_t size;
|
||||||
sockaddr2linux(out_addr);
|
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;
|
return rc;
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,18 @@ struct sockaddr_un_bsd {
|
||||||
char sun_path[108];
|
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
|
#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_accept(int32_t, void *, uint32_t *, int) dontdiscard hidden;
|
||||||
int32_t __sys_accept4(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_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_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_socketpair(int32_t, int32_t, int32_t, int32_t[2]) hidden;
|
||||||
|
|
||||||
int32_t sys_accept4(int32_t, void *, uint32_t *, int) dontdiscard 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;
|
int64_t GetNtBaseSocket(int64_t) hidden;
|
||||||
int sys_close_epoll(int) hidden;
|
int sys_close_epoll(int) hidden;
|
||||||
|
|
||||||
/**
|
int sockaddr2bsd(const void *, uint32_t, union sockaddr_storage_bsd *,
|
||||||
* Converts sockaddr (Linux/Windows) → sockaddr_bsd (XNU/BSD).
|
uint32_t *);
|
||||||
*/
|
void sockaddr2linux(const union sockaddr_storage_bsd *, uint32_t,
|
||||||
forceinline void sockaddr2bsd(void *saddr) {
|
union sockaddr_storage_linux *, uint32_t *);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
COSMOPOLITAN_C_END_
|
COSMOPOLITAN_C_END_
|
||||||
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
#endif /* !(__ASSEMBLER__ + __LINKER__ + 0) */
|
||||||
|
|
|
@ -45,19 +45,26 @@
|
||||||
*/
|
*/
|
||||||
ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
|
ssize_t recvfrom(int fd, void *buf, size_t size, uint32_t flags,
|
||||||
void *opt_out_srcaddr, uint32_t *opt_inout_srcaddrsize) {
|
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() &&
|
if (IsAsan() &&
|
||||||
(!__asan_is_valid(buf, size) ||
|
(!__asan_is_valid(buf, size) ||
|
||||||
(opt_out_srcaddr &&
|
(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();
|
rc = efault();
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
got = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
|
if (!IsBsd() || !opt_out_srcaddr) {
|
||||||
|
rc = sys_recvfrom(fd, buf, size, flags, opt_out_srcaddr,
|
||||||
opt_inout_srcaddrsize);
|
opt_inout_srcaddrsize);
|
||||||
if (opt_out_srcaddr && IsBsd() && got != -1) {
|
} else {
|
||||||
sockaddr2linux(opt_out_srcaddr);
|
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)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (__isfdkind(fd, kFdSocket)) {
|
if (__isfdkind(fd, kFdSocket)) {
|
||||||
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,
|
rc = sys_recvfrom_nt(&g_fds.p[fd], (struct iovec[]){{buf, size}}, 1,
|
||||||
|
|
|
@ -41,15 +41,24 @@
|
||||||
*/
|
*/
|
||||||
ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
|
ssize_t recvmsg(int fd, struct msghdr *msg, int flags) {
|
||||||
ssize_t rc, got;
|
ssize_t rc, got;
|
||||||
|
struct msghdr msg2;
|
||||||
|
union sockaddr_storage_bsd bsd;
|
||||||
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
|
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
|
||||||
rc = efault();
|
rc = efault();
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
got = sys_recvmsg(fd, msg, flags);
|
if (IsBsd() && msg->msg_name) {
|
||||||
// An address was provided, convert from BSD form
|
memcpy(&msg2, msg, sizeof(msg2));
|
||||||
if (msg->msg_name && IsBsd() && got != -1) {
|
if (!(rc = sockaddr2bsd(msg->msg_name, msg->msg_namelen, &bsd,
|
||||||
sockaddr2linux(msg->msg_name);
|
&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)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (!msg->msg_control) {
|
if (!msg->msg_control) {
|
||||||
if (__isfdkind(fd, kFdSocket)) {
|
if (__isfdkind(fd, kFdSocket)) {
|
||||||
|
|
|
@ -44,27 +44,22 @@
|
||||||
*/
|
*/
|
||||||
ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
|
ssize_t sendmsg(int fd, const struct msghdr *msg, int flags) {
|
||||||
int64_t rc;
|
int64_t rc;
|
||||||
char addr2[128];
|
|
||||||
struct msghdr msg2;
|
struct msghdr msg2;
|
||||||
|
union sockaddr_storage_bsd bsd;
|
||||||
|
|
||||||
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
|
if (IsAsan() && !__asan_is_valid_msghdr(msg)) {
|
||||||
rc = efault();
|
rc = efault();
|
||||||
} else if (!IsWindows()) {
|
} else if (!IsWindows()) {
|
||||||
if (IsBsd() && msg->msg_name) {
|
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));
|
memcpy(&msg2, msg, sizeof(msg2));
|
||||||
msg2.msg_name = &addr2[0];
|
if (!(rc = sockaddr2bsd(msg->msg_name, msg->msg_namelen, &bsd,
|
||||||
|
&msg2.msg_namelen))) {
|
||||||
|
msg2.msg_name = &bsd.sa;
|
||||||
rc = sys_sendmsg(fd, &msg2, flags);
|
rc = sys_sendmsg(fd, &msg2, flags);
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
rc = einval();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* else do the syscall */
|
|
||||||
rc = sys_sendmsg(fd, msg, flags);
|
rc = sys_sendmsg(fd, msg, flags);
|
||||||
|
}
|
||||||
} else if (__isfdopen(fd)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (msg->msg_control) {
|
if (msg->msg_control) {
|
||||||
rc = einval(); /* control msg not supported */
|
rc = einval(); /* control msg not supported */
|
||||||
|
|
|
@ -52,7 +52,8 @@
|
||||||
ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
|
ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
|
||||||
const void *opt_addr, uint32_t addrsize) {
|
const void *opt_addr, uint32_t addrsize) {
|
||||||
ssize_t rc;
|
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) ||
|
if (IsAsan() && (!__asan_is_valid(buf, size) ||
|
||||||
(opt_addr && !__asan_is_valid(opt_addr, addrsize)))) {
|
(opt_addr && !__asan_is_valid(opt_addr, addrsize)))) {
|
||||||
rc = efault();
|
rc = efault();
|
||||||
|
@ -61,12 +62,8 @@ ssize_t sendto(int fd, const void *buf, size_t size, uint32_t flags,
|
||||||
if (!IsWindows()) {
|
if (!IsWindows()) {
|
||||||
if (!IsBsd() || !opt_addr) {
|
if (!IsBsd() || !opt_addr) {
|
||||||
rc = sys_sendto(fd, buf, size, flags, opt_addr, addrsize);
|
rc = sys_sendto(fd, buf, size, flags, opt_addr, addrsize);
|
||||||
} else if (addrsize > sizeof(addr2)) {
|
} else if (!(rc = sockaddr2bsd(opt_addr, addrsize, &bsd, &bsdaddrsize))) {
|
||||||
rc = einval();
|
rc = sys_sendto(fd, buf, size, flags, &bsd, bsdaddrsize);
|
||||||
} else {
|
|
||||||
memcpy(&addr2, opt_addr, addrsize);
|
|
||||||
sockaddr2bsd(&addr2[0]);
|
|
||||||
rc = sys_sendto(fd, buf, size, flags, &addr2[0], addrsize);
|
|
||||||
}
|
}
|
||||||
} else if (__isfdopen(fd)) {
|
} else if (__isfdopen(fd)) {
|
||||||
if (__isfdkind(fd, kFdSocket)) {
|
if (__isfdkind(fd, kFdSocket)) {
|
||||||
|
|
66
libc/sock/sockaddr2bsd.c
Normal file
66
libc/sock/sockaddr2bsd.c
Normal 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();
|
||||||
|
}
|
||||||
|
}
|
60
libc/sock/sockaddr2linux.c
Normal file
60
libc/sock/sockaddr2linux.c
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2
libc/sysv/calls/__sys_bind.s
Normal file
2
libc/sysv/calls/__sys_bind.s
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.include "o/libc/sysv/macros.internal.inc"
|
||||||
|
.scall __sys_bind,0x0680680682068031,globl,hidden
|
|
@ -1,2 +0,0 @@
|
||||||
.include "o/libc/sysv/macros.internal.inc"
|
|
||||||
.scall sys_bind,0x0680680682068031,globl,hidden
|
|
|
@ -84,7 +84,7 @@ scall sys_recvfrom 0x01d01d01d201d02d globl hidden
|
||||||
scall sys_sendmsg 0x01c01c01c201c02e globl hidden
|
scall sys_sendmsg 0x01c01c01c201c02e globl hidden
|
||||||
scall sys_recvmsg 0x01b01b01b201b02f globl hidden
|
scall sys_recvmsg 0x01b01b01b201b02f globl hidden
|
||||||
scall sys_shutdown 0x0860860862086030 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_listen 0x06a06a06a206a032 globl hidden
|
||||||
scall __sys_getsockname 0x0200200202020033 globl hidden
|
scall __sys_getsockname 0x0200200202020033 globl hidden
|
||||||
scall __sys_getpeername 0x01f01f08d201f034 globl hidden
|
scall __sys_getpeername 0x01f01f08d201f034 globl hidden
|
||||||
|
|
116
test/libc/sock/unix_test.c
Normal file
116
test/libc/sock/unix_test.c
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
/*-*- 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/calls/internal.h"
|
||||||
|
#include "libc/calls/struct/timeval.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
|
#include "libc/intrin/kprintf.h"
|
||||||
|
#include "libc/nt/version.h"
|
||||||
|
#include "libc/runtime/runtime.h"
|
||||||
|
#include "libc/sock/sock.h"
|
||||||
|
#include "libc/sysv/consts/af.h"
|
||||||
|
#include "libc/sysv/consts/so.h"
|
||||||
|
#include "libc/sysv/consts/sock.h"
|
||||||
|
#include "libc/sysv/consts/sol.h"
|
||||||
|
#include "libc/testlib/testlib.h"
|
||||||
|
#include "libc/time/time.h"
|
||||||
|
|
||||||
|
char testlib_enable_tmp_setup_teardown;
|
||||||
|
|
||||||
|
void DatagramServer(void) {
|
||||||
|
char buf[256] = {0};
|
||||||
|
uint32_t len = sizeof(struct sockaddr_un);
|
||||||
|
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||||
|
alarm(3);
|
||||||
|
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_DGRAM, 0));
|
||||||
|
ASSERT_SYS(0, 0, bind(3, (void *)&addr, len));
|
||||||
|
bzero(&addr, sizeof(addr));
|
||||||
|
ASSERT_SYS(0, 0, getsockname(3, (void *)&addr, &len));
|
||||||
|
ASSERT_EQ(11, len);
|
||||||
|
ASSERT_STREQ("foo.sock", addr.sun_path);
|
||||||
|
ASSERT_SYS(0, 5, read(3, buf, 256));
|
||||||
|
EXPECT_STREQ("hello", buf);
|
||||||
|
ASSERT_SYS(0, 0, close(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unix, datagram) {
|
||||||
|
if (IsWindows()) return; // no unix datagram on windows :'(
|
||||||
|
int ws;
|
||||||
|
uint32_t len = sizeof(struct sockaddr_un);
|
||||||
|
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||||
|
if (!fork()) {
|
||||||
|
DatagramServer();
|
||||||
|
_Exit(0);
|
||||||
|
}
|
||||||
|
alarm(3);
|
||||||
|
while (!fileexists(addr.sun_path)) usleep(10000);
|
||||||
|
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_DGRAM, 0));
|
||||||
|
ASSERT_SYS(0, 5, sendto(3, "hello", 5, 0, (void *)&addr, len));
|
||||||
|
ASSERT_SYS(0, 0, close(3));
|
||||||
|
ASSERT_NE(-1, wait(&ws));
|
||||||
|
EXPECT_TRUE(WIFEXITED(ws));
|
||||||
|
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||||
|
alarm(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void StreamServer(void) {
|
||||||
|
char buf[256] = {0};
|
||||||
|
uint32_t len = sizeof(struct sockaddr_un);
|
||||||
|
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||||
|
alarm(3);
|
||||||
|
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_STREAM, 0));
|
||||||
|
ASSERT_SYS(0, 0, bind(3, (void *)&addr, len));
|
||||||
|
bzero(&addr, sizeof(addr));
|
||||||
|
ASSERT_SYS(0, 0, getsockname(3, (void *)&addr, &len));
|
||||||
|
ASSERT_EQ(2 + 8 + 1, len);
|
||||||
|
ASSERT_EQ(AF_UNIX, addr.sun_family);
|
||||||
|
ASSERT_STREQ("foo.sock", addr.sun_path);
|
||||||
|
ASSERT_SYS(0, 0, listen(3, 10));
|
||||||
|
bzero(&addr, sizeof(addr));
|
||||||
|
len = sizeof(addr);
|
||||||
|
ASSERT_SYS(0, 4, accept(3, &addr, &len));
|
||||||
|
ASSERT_EQ(AF_UNIX, addr.sun_family);
|
||||||
|
EXPECT_STREQ("", addr.sun_path);
|
||||||
|
ASSERT_SYS(0, 5, read(4, buf, 256));
|
||||||
|
EXPECT_STREQ("hello", buf);
|
||||||
|
ASSERT_SYS(0, 0, close(3));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST(unix, stream) {
|
||||||
|
if (IsWindows() && !IsAtLeastWindows10()) return;
|
||||||
|
int ws;
|
||||||
|
uint32_t len = sizeof(struct sockaddr_un);
|
||||||
|
struct sockaddr_un addr = {AF_UNIX, "foo.sock"};
|
||||||
|
// TODO(jart): move this line down when kFdProcess is gone
|
||||||
|
ASSERT_SYS(0, 3, socket(AF_UNIX, SOCK_STREAM, 0));
|
||||||
|
if (!fork()) {
|
||||||
|
close(3);
|
||||||
|
StreamServer();
|
||||||
|
_Exit(0);
|
||||||
|
}
|
||||||
|
alarm(3);
|
||||||
|
while (!fileexists(addr.sun_path)) usleep(10000);
|
||||||
|
ASSERT_SYS(0, 0, connect(3, (void *)&addr, len));
|
||||||
|
ASSERT_SYS(0, 5, write(3, "hello", 5));
|
||||||
|
ASSERT_SYS(0, 0, close(3));
|
||||||
|
ASSERT_NE(-1, wait(&ws));
|
||||||
|
EXPECT_TRUE(WIFEXITED(ws));
|
||||||
|
EXPECT_EQ(0, WEXITSTATUS(ws));
|
||||||
|
alarm(0);
|
||||||
|
}
|
160
third_party/lua/lunix.c
vendored
160
third_party/lua/lunix.c
vendored
|
@ -101,6 +101,12 @@ struct UnixErrno {
|
||||||
const char *call;
|
const char *call;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
union SockAddr {
|
||||||
|
struct sockaddr s;
|
||||||
|
struct sockaddr_in i;
|
||||||
|
struct sockaddr_un u;
|
||||||
|
};
|
||||||
|
|
||||||
static lua_State *GL;
|
static lua_State *GL;
|
||||||
|
|
||||||
static void *LuaRealloc(lua_State *L, void *p, size_t n) {
|
static void *LuaRealloc(lua_State *L, void *p, size_t n) {
|
||||||
|
@ -219,6 +225,42 @@ static int SysretInteger(lua_State *L, const char *call, int olderr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int MakeSockaddr(lua_State *L, int i, union SockAddr *sa,
|
||||||
|
uint32_t *salen) {
|
||||||
|
bzero(sa, sizeof(*sa));
|
||||||
|
if (lua_isstring(L, i)) {
|
||||||
|
sa->u.sun_family = AF_UNIX;
|
||||||
|
if (!memccpy(sa->u.sun_path, luaL_checkstring(L, i), 0,
|
||||||
|
sizeof(sa->u.sun_path))) {
|
||||||
|
luaL_error(L, "unix path too long");
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
*salen = sizeof(struct sockaddr_un);
|
||||||
|
return i + 1;
|
||||||
|
} else {
|
||||||
|
sa->i.sin_family = AF_INET;
|
||||||
|
sa->i.sin_addr.s_addr = htonl(luaL_optinteger(L, i, 0));
|
||||||
|
sa->i.sin_port = htons(luaL_optinteger(L, i + 1, 0));
|
||||||
|
*salen = sizeof(struct sockaddr_in);
|
||||||
|
return i + 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PushSockaddr(lua_State *L, const struct sockaddr_storage *ss) {
|
||||||
|
if (ss->ss_family == AF_INET) {
|
||||||
|
lua_pushinteger(L,
|
||||||
|
ntohl(((const struct sockaddr_in *)ss)->sin_addr.s_addr));
|
||||||
|
lua_pushinteger(L, ntohs(((const struct sockaddr_in *)ss)->sin_port));
|
||||||
|
return 2;
|
||||||
|
} else if (ss->ss_family == AF_UNIX) {
|
||||||
|
lua_pushstring(L, ((const struct sockaddr_un *)ss)->sun_path);
|
||||||
|
return 1;
|
||||||
|
} else {
|
||||||
|
luaL_error(L, "bad family");
|
||||||
|
unreachable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void CheckOptvalsize(lua_State *L, uint32_t want, uint32_t got) {
|
static void CheckOptvalsize(lua_State *L, uint32_t want, uint32_t got) {
|
||||||
if (!IsTiny()) {
|
if (!IsTiny()) {
|
||||||
if (want == got) return;
|
if (want == got) return;
|
||||||
|
@ -1095,6 +1137,7 @@ static int LuaUnixSetsockopt(lua_State *L) {
|
||||||
// ├─→ true
|
// ├─→ true
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
tv.tv_sec = luaL_checkinteger(L, 4);
|
tv.tv_sec = luaL_checkinteger(L, 4);
|
||||||
|
tv.tv_usec = luaL_optinteger(L, 5, 0) / 1000;
|
||||||
optval = &tv;
|
optval = &tv;
|
||||||
optsize = sizeof(tv);
|
optsize = sizeof(tv);
|
||||||
} else if (level == SOL_SOCKET && optname == SO_LINGER) {
|
} else if (level == SOL_SOCKET && optname == SO_LINGER) {
|
||||||
|
@ -1164,10 +1207,11 @@ static int LuaUnixGetsockopt(lua_State *L) {
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixSocket(lua_State *L) {
|
static int LuaUnixSocket(lua_State *L) {
|
||||||
int olderr = errno;
|
int olderr = errno;
|
||||||
|
int family = luaL_optinteger(L, 1, AF_INET);
|
||||||
return SysretInteger(
|
return SysretInteger(
|
||||||
L, "socket", olderr,
|
L, "socket", olderr,
|
||||||
socket(luaL_optinteger(L, 1, AF_INET), luaL_optinteger(L, 2, SOCK_STREAM),
|
socket(family, luaL_optinteger(L, 2, SOCK_STREAM),
|
||||||
luaL_optinteger(L, 3, IPPROTO_TCP)));
|
luaL_optinteger(L, 3, family == AF_INET ? IPPROTO_TCP : 0)));
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.socketpair([family:int[, type:int[, protocol:int]]])
|
// unix.socketpair([family:int[, type:int[, protocol:int]]])
|
||||||
|
@ -1187,33 +1231,29 @@ static int LuaUnixSocketpair(lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.bind(fd:int[, ip:uint32, port:uint16])
|
// unix.bind(fd:int[, ip:uint32, port:uint16])
|
||||||
|
// unix.bind(fd:int[, unixpath:str])
|
||||||
// ├─→ true
|
// ├─→ true
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixBind(lua_State *L) {
|
static int LuaUnixBind(lua_State *L) {
|
||||||
|
uint32_t salen;
|
||||||
|
union SockAddr sa;
|
||||||
int olderr = errno;
|
int olderr = errno;
|
||||||
|
MakeSockaddr(L, 2, &sa, &salen);
|
||||||
return SysretBool(L, "bind", olderr,
|
return SysretBool(L, "bind", olderr,
|
||||||
bind(luaL_checkinteger(L, 1),
|
bind(luaL_checkinteger(L, 1), &sa.s, salen));
|
||||||
&(struct sockaddr_in){
|
|
||||||
.sin_family = AF_INET,
|
|
||||||
.sin_addr.s_addr = htonl(luaL_optinteger(L, 2, 0)),
|
|
||||||
.sin_port = htons(luaL_optinteger(L, 3, 0)),
|
|
||||||
},
|
|
||||||
sizeof(struct sockaddr_in)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.connect(fd:int, ip:uint32, port:uint16)
|
// unix.connect(fd:int, ip:uint32, port:uint16)
|
||||||
|
// unix.connect(fd:int, unixpath:str)
|
||||||
// ├─→ true
|
// ├─→ true
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixConnect(lua_State *L) {
|
static int LuaUnixConnect(lua_State *L) {
|
||||||
|
uint32_t salen;
|
||||||
|
union SockAddr sa;
|
||||||
int olderr = errno;
|
int olderr = errno;
|
||||||
return SysretBool(
|
MakeSockaddr(L, 2, &sa, &salen);
|
||||||
L, "connect", olderr,
|
return SysretBool(L, "connect", olderr,
|
||||||
connect(luaL_checkinteger(L, 1),
|
connect(luaL_checkinteger(L, 1), &sa.s, salen));
|
||||||
&(struct sockaddr_in){
|
|
||||||
.sin_addr.s_addr = htonl(luaL_checkinteger(L, 2)),
|
|
||||||
.sin_port = htons(luaL_checkinteger(L, 3)),
|
|
||||||
},
|
|
||||||
sizeof(struct sockaddr_in)));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.listen(fd:int[, backlog:int])
|
// unix.listen(fd:int[, backlog:int])
|
||||||
|
@ -1225,42 +1265,34 @@ static int LuaUnixListen(lua_State *L) {
|
||||||
listen(luaL_checkinteger(L, 1), luaL_optinteger(L, 2, 10)));
|
listen(luaL_checkinteger(L, 1), luaL_optinteger(L, 2, 10)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int LuaUnixGetname(lua_State *L, const char *name,
|
||||||
|
int func(int, void *, uint32_t *)) {
|
||||||
|
int olderr;
|
||||||
|
uint32_t addrsize;
|
||||||
|
struct sockaddr_storage ss = {0};
|
||||||
|
olderr = errno;
|
||||||
|
addrsize = sizeof(ss) - 1;
|
||||||
|
if (!func(luaL_checkinteger(L, 1), &ss, &addrsize)) {
|
||||||
|
return PushSockaddr(L, &ss);
|
||||||
|
} else {
|
||||||
|
return SysretErrno(L, name, olderr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// unix.getsockname(fd:int)
|
// unix.getsockname(fd:int)
|
||||||
// ├─→ ip:uint32, port:uint16
|
// ├─→ ip:uint32, port:uint16
|
||||||
|
// ├─→ unixpath:str
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixGetsockname(lua_State *L) {
|
static int LuaUnixGetsockname(lua_State *L) {
|
||||||
int fd, olderr;
|
return LuaUnixGetname(L, "getsockname", getsockname);
|
||||||
uint32_t addrsize;
|
|
||||||
struct sockaddr_in sa;
|
|
||||||
olderr = errno;
|
|
||||||
addrsize = sizeof(sa);
|
|
||||||
fd = luaL_checkinteger(L, 1);
|
|
||||||
if (!getsockname(fd, &sa, &addrsize)) {
|
|
||||||
lua_pushinteger(L, ntohl(sa.sin_addr.s_addr));
|
|
||||||
lua_pushinteger(L, ntohs(sa.sin_port));
|
|
||||||
return 2;
|
|
||||||
} else {
|
|
||||||
return SysretErrno(L, "getsockname", olderr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.getpeername(fd:int)
|
// unix.getpeername(fd:int)
|
||||||
// ├─→ ip:uint32, port:uint16
|
// ├─→ ip:uint32, port:uint16
|
||||||
|
// ├─→ unixpath:str
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixGetpeername(lua_State *L) {
|
static int LuaUnixGetpeername(lua_State *L) {
|
||||||
int fd, olderr;
|
return LuaUnixGetname(L, "getpeername", getpeername);
|
||||||
uint32_t addrsize;
|
|
||||||
struct sockaddr_in sa;
|
|
||||||
olderr = errno;
|
|
||||||
addrsize = sizeof(sa);
|
|
||||||
fd = luaL_checkinteger(L, 1);
|
|
||||||
if (!getpeername(fd, &sa, &addrsize)) {
|
|
||||||
lua_pushinteger(L, ntohl(sa.sin_addr.s_addr));
|
|
||||||
lua_pushinteger(L, ntohs(sa.sin_port));
|
|
||||||
return 2;
|
|
||||||
} else {
|
|
||||||
return SysretErrno(L, "getpeername", olderr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.siocgifconf()
|
// unix.siocgifconf()
|
||||||
|
@ -1338,21 +1370,20 @@ static int LuaUnixGethostname(lua_State *L) {
|
||||||
|
|
||||||
// unix.accept(serverfd:int[, flags:int])
|
// unix.accept(serverfd:int[, flags:int])
|
||||||
// ├─→ clientfd:int, ip:uint32, port:uint16
|
// ├─→ clientfd:int, ip:uint32, port:uint16
|
||||||
|
// ├─→ clientfd:int, unixpath:str
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixAccept(lua_State *L) {
|
static int LuaUnixAccept(lua_State *L) {
|
||||||
uint32_t addrsize;
|
uint32_t addrsize;
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_storage ss;
|
||||||
int clientfd, serverfd, olderr, flags;
|
int clientfd, serverfd, olderr, flags;
|
||||||
olderr = errno;
|
olderr = errno;
|
||||||
addrsize = sizeof(sa);
|
addrsize = sizeof(ss);
|
||||||
serverfd = luaL_checkinteger(L, 1);
|
serverfd = luaL_checkinteger(L, 1);
|
||||||
flags = luaL_optinteger(L, 2, 0);
|
flags = luaL_optinteger(L, 2, 0);
|
||||||
clientfd = accept4(serverfd, &sa, &addrsize, flags);
|
clientfd = accept4(serverfd, &ss, &addrsize, flags);
|
||||||
if (clientfd != -1) {
|
if (clientfd != -1) {
|
||||||
lua_pushinteger(L, clientfd);
|
lua_pushinteger(L, clientfd);
|
||||||
lua_pushinteger(L, ntohl(sa.sin_addr.s_addr));
|
return 1 + PushSockaddr(L, &ss);
|
||||||
lua_pushinteger(L, ntohs(sa.sin_port));
|
|
||||||
return 3;
|
|
||||||
} else {
|
} else {
|
||||||
return SysretErrno(L, "accept", olderr);
|
return SysretErrno(L, "accept", olderr);
|
||||||
}
|
}
|
||||||
|
@ -1403,6 +1434,7 @@ static int LuaUnixPoll(lua_State *L) {
|
||||||
|
|
||||||
// unix.recvfrom(fd:int[, bufsiz:int[, flags:int]])
|
// unix.recvfrom(fd:int[, bufsiz:int[, flags:int]])
|
||||||
// ├─→ data:str, ip:uint32, port:uint16
|
// ├─→ data:str, ip:uint32, port:uint16
|
||||||
|
// ├─→ data:str, unixpath:str
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixRecvfrom(lua_State *L) {
|
static int LuaUnixRecvfrom(lua_State *L) {
|
||||||
char *buf;
|
char *buf;
|
||||||
|
@ -1410,22 +1442,20 @@ static int LuaUnixRecvfrom(lua_State *L) {
|
||||||
ssize_t rc;
|
ssize_t rc;
|
||||||
uint32_t addrsize;
|
uint32_t addrsize;
|
||||||
lua_Integer bufsiz;
|
lua_Integer bufsiz;
|
||||||
struct sockaddr_in sa;
|
struct sockaddr_storage ss;
|
||||||
int fd, flags, olderr = errno;
|
int fd, flags, pushed, olderr = errno;
|
||||||
addrsize = sizeof(sa);
|
addrsize = sizeof(ss);
|
||||||
fd = luaL_checkinteger(L, 1);
|
fd = luaL_checkinteger(L, 1);
|
||||||
bufsiz = luaL_optinteger(L, 2, 1500);
|
bufsiz = luaL_optinteger(L, 2, 1500);
|
||||||
bufsiz = MIN(bufsiz, 0x7ffff000);
|
bufsiz = MIN(bufsiz, 0x7ffff000);
|
||||||
flags = luaL_optinteger(L, 3, 0);
|
flags = luaL_optinteger(L, 3, 0);
|
||||||
buf = LuaAllocOrDie(L, bufsiz);
|
buf = LuaAllocOrDie(L, bufsiz);
|
||||||
rc = recvfrom(fd, buf, bufsiz, flags, &sa, &addrsize);
|
if ((rc = recvfrom(fd, buf, bufsiz, flags, &ss, &addrsize)) != -1) {
|
||||||
if (rc != -1) {
|
|
||||||
got = rc;
|
got = rc;
|
||||||
lua_pushlstring(L, buf, got);
|
lua_pushlstring(L, buf, got);
|
||||||
lua_pushinteger(L, ntohl(sa.sin_addr.s_addr));
|
pushed = 1 + PushSockaddr(L, &ss);
|
||||||
lua_pushinteger(L, ntohs(sa.sin_port));
|
|
||||||
free(buf);
|
free(buf);
|
||||||
return 3;
|
return pushed;
|
||||||
} else {
|
} else {
|
||||||
free(buf);
|
free(buf);
|
||||||
return SysretErrno(L, "recvfrom", olderr);
|
return SysretErrno(L, "recvfrom", olderr);
|
||||||
|
@ -1473,21 +1503,21 @@ static int LuaUnixSend(lua_State *L) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.sendto(fd:int, data:str, ip:uint32, port:uint16[, flags:int])
|
// unix.sendto(fd:int, data:str, ip:uint32, port:uint16[, flags:int])
|
||||||
|
// unix.sendto(fd:int, data:str, unixpath:str[, flags:int])
|
||||||
// ├─→ sent:int
|
// ├─→ sent:int
|
||||||
// └─→ nil, unix.Errno
|
// └─→ nil, unix.Errno
|
||||||
static int LuaUnixSendto(lua_State *L) {
|
static int LuaUnixSendto(lua_State *L) {
|
||||||
char *data;
|
char *data;
|
||||||
size_t sent, size;
|
size_t size;
|
||||||
struct sockaddr_in sa;
|
uint32_t salen;
|
||||||
int fd, flags, olderr = errno;
|
union SockAddr sa;
|
||||||
|
int i, fd, flags, olderr = errno;
|
||||||
fd = luaL_checkinteger(L, 1);
|
fd = luaL_checkinteger(L, 1);
|
||||||
data = luaL_checklstring(L, 2, &size);
|
data = luaL_checklstring(L, 2, &size);
|
||||||
bzero(&sa, sizeof(sa));
|
i = MakeSockaddr(L, 3, &sa, &salen);
|
||||||
sa.sin_addr.s_addr = htonl(luaL_checkinteger(L, 3));
|
flags = luaL_optinteger(L, i, 0);
|
||||||
sa.sin_port = htons(luaL_checkinteger(L, 4));
|
|
||||||
flags = luaL_optinteger(L, 5, 0);
|
|
||||||
return SysretInteger(L, "sendto", olderr,
|
return SysretInteger(L, "sendto", olderr,
|
||||||
sendto(fd, data, size, flags, &sa, sizeof(sa)));
|
sendto(fd, data, size, flags, &sa.s, salen));
|
||||||
}
|
}
|
||||||
|
|
||||||
// unix.shutdown(fd:int, how:int)
|
// unix.shutdown(fd:int, how:int)
|
||||||
|
|
89
tool/net/demo/unix-unix.lua
Normal file
89
tool/net/demo/unix-unix.lua
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
-- UNIX Domain Sockets Example
|
||||||
|
|
||||||
|
-- So we can detect that child died.
|
||||||
|
died = false
|
||||||
|
function OnSigchld(sig)
|
||||||
|
died = true
|
||||||
|
unix.wait() -- Prevent it from becoming a zombie
|
||||||
|
end
|
||||||
|
assert(unix.sigaction(unix.SIGCHLD, OnSigchld))
|
||||||
|
|
||||||
|
-- So keyboard interurpts only go to subprocess.
|
||||||
|
oldint = assert(unix.sigaction(unix.SIGINT, unix.SIG_IGN))
|
||||||
|
oldquit = assert(unix.sigaction(unix.SIGQUIT, unix.SIG_IGN))
|
||||||
|
|
||||||
|
-- UNIX domain sockets need a file
|
||||||
|
tmpdir = os.getenv('TMPDIR') or '/tmp'
|
||||||
|
unixpath = '%s/redbean-unix.sock.%d' % {tmpdir, unix.getpid()}
|
||||||
|
|
||||||
|
-- Create child process which is the server.
|
||||||
|
child = assert(unix.fork())
|
||||||
|
if child == 0 then
|
||||||
|
server = assert(unix.socket(unix.AF_UNIX, unix.SOCK_STREAM))
|
||||||
|
assert(unix.setsockopt(server, unix.SOL_SOCKET, unix.SO_RCVTIMEO, 2))
|
||||||
|
assert(unix.bind(server, unixpath))
|
||||||
|
assert(unix.listen(server))
|
||||||
|
client = assert(unix.accept(server))
|
||||||
|
data = assert(unix.read(client))
|
||||||
|
assert(data == 'ping!')
|
||||||
|
assert(assert(unix.write(client, 'pong!')) == 5)
|
||||||
|
assert(unix.close(client))
|
||||||
|
unix.exit(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wait for the child to create the the socket file.
|
||||||
|
function FileExists(path)
|
||||||
|
st, err = unix.stat(path)
|
||||||
|
return not err
|
||||||
|
end
|
||||||
|
expobackoff = 1
|
||||||
|
while not died do
|
||||||
|
if FileExists(unixpath) then
|
||||||
|
break
|
||||||
|
else
|
||||||
|
expobackoff = expobackoff << 1
|
||||||
|
unix.nanosleep(expobackoff // 1000000000,
|
||||||
|
expobackoff % 1000000000)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Now connect to the socket.
|
||||||
|
if not died then
|
||||||
|
client = assert(unix.socket(unix.AF_UNIX, unix.SOCK_STREAM))
|
||||||
|
assert(unix.connect(client, unixpath))
|
||||||
|
assert(assert(unix.write(client, 'ping!')) == 5)
|
||||||
|
data = assert(unix.read(client))
|
||||||
|
assert(data == 'pong!')
|
||||||
|
itworked = true
|
||||||
|
else
|
||||||
|
itworked = false
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Wait for client to terminate. We don't check error here because if
|
||||||
|
-- the child already died and the signal handler reaped it, then this
|
||||||
|
-- returns a ECHILD error which is fine.
|
||||||
|
unix.wait()
|
||||||
|
assert(itworked)
|
||||||
|
|
||||||
|
-- Now clean up the socket file.
|
||||||
|
unix.unlink(unixpath)
|
||||||
|
|
||||||
|
SetStatus(200)
|
||||||
|
SetHeader('Connection', 'close') -- be lazy and let _Exit() clean up signal handlers
|
||||||
|
SetHeader('Content-Type', 'text/html; charset=utf-8')
|
||||||
|
Write('<!doctype html>\r\n')
|
||||||
|
Write('<title>redbean unix domain sockets example</title>\r\n')
|
||||||
|
Write('<h1>\r\n')
|
||||||
|
Write('<img style="vertical-align:middle" src="data:image/png;base64,\r\n')
|
||||||
|
Write(EncodeBase64(LoadAsset('/redbean.png')))
|
||||||
|
Write('">\r\n')
|
||||||
|
Write('redbean unix domain sockets example\r\n')
|
||||||
|
Write('</h1>\r\n')
|
||||||
|
Write([[
|
||||||
|
<p>
|
||||||
|
<strong>It worked!</strong> We successfully sent a ping
|
||||||
|
pong via UNIX local sockets. Please check out the source
|
||||||
|
code to this example inside your redbean at unix-unix.lua.
|
||||||
|
</p>
|
||||||
|
]])
|
||||||
|
Write('</h1>\r\n')
|
|
@ -2546,8 +2546,10 @@ UNIX MODULE
|
||||||
|
|
||||||
`family` defaults to `AF_INET` and can be:
|
`family` defaults to `AF_INET` and can be:
|
||||||
|
|
||||||
- `AF_UNIX`
|
- `AF_INET`: Creates Internet Protocol Version 4 (IPv4) socket.
|
||||||
- `AF_INET`
|
|
||||||
|
- `AF_UNIX`: Creates local UNIX domain socket. On the New Technology
|
||||||
|
this requires Windows 10 and only works with `SOCK_STREAM`.
|
||||||
|
|
||||||
`type` defaults to `SOCK_STREAM` and can be:
|
`type` defaults to `SOCK_STREAM` and can be:
|
||||||
|
|
||||||
|
@ -2562,7 +2564,8 @@ UNIX MODULE
|
||||||
- `SOCK_CLOEXEC`
|
- `SOCK_CLOEXEC`
|
||||||
- `SOCK_NONBLOCK`
|
- `SOCK_NONBLOCK`
|
||||||
|
|
||||||
`protocol` defaults to `IPPROTO_TCP` and can be:
|
`protocol` defaults to `IPPROTO_TCP` for AF_INET` and `0` for
|
||||||
|
`AF_UNIX`. It can also be:
|
||||||
|
|
||||||
- `IPPROTO_IP`
|
- `IPPROTO_IP`
|
||||||
- `IPPROTO_ICMP`
|
- `IPPROTO_ICMP`
|
||||||
|
@ -2592,6 +2595,7 @@ UNIX MODULE
|
||||||
`protocol` defaults to `0`.
|
`protocol` defaults to `0`.
|
||||||
|
|
||||||
unix.bind(fd:int[, ip:uint32, port:uint16])
|
unix.bind(fd:int[, ip:uint32, port:uint16])
|
||||||
|
unix.bind(fd:int[, unixpath:str])
|
||||||
├─→ true
|
├─→ true
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
@ -2743,6 +2747,7 @@ UNIX MODULE
|
||||||
|
|
||||||
unix.accept(serverfd:int[, flags:int])
|
unix.accept(serverfd:int[, flags:int])
|
||||||
├─→ clientfd:int, ip:uint32, port:uint16
|
├─→ clientfd:int, ip:uint32, port:uint16
|
||||||
|
├─→ clientfd:int, unixpath:str
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
Accepts new client socket descriptor for a listening tcp socket.
|
Accepts new client socket descriptor for a listening tcp socket.
|
||||||
|
@ -2753,6 +2758,7 @@ UNIX MODULE
|
||||||
- `SOCK_NONBLOCK`
|
- `SOCK_NONBLOCK`
|
||||||
|
|
||||||
unix.connect(fd:int, ip:uint32, port:uint16)
|
unix.connect(fd:int, ip:uint32, port:uint16)
|
||||||
|
unix.connect(fd:int, unixpath:str)
|
||||||
├─→ true
|
├─→ true
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
@ -2764,16 +2770,21 @@ UNIX MODULE
|
||||||
|
|
||||||
unix.getsockname(fd:int)
|
unix.getsockname(fd:int)
|
||||||
├─→ ip:uint32, port:uint16
|
├─→ ip:uint32, port:uint16
|
||||||
|
├─→ unixpath:str
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
Retrieves the local address of a socket.
|
Retrieves the local address of a socket.
|
||||||
|
|
||||||
unix.getpeername(fd:int)
|
unix.getpeername(fd:int)
|
||||||
├─→ ip:uint32, port:uint16
|
├─→ ip:uint32, port:uint16
|
||||||
|
├─→ unixpath:str
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
Retrieves the remote address of a socket.
|
Retrieves the remote address of a socket.
|
||||||
|
|
||||||
|
This operation will either fail on `AF_UNIX` sockets or return an
|
||||||
|
empty string.
|
||||||
|
|
||||||
unix.recv(fd:int[, bufsiz:int[, flags:int]])
|
unix.recv(fd:int[, bufsiz:int[, flags:int]])
|
||||||
├─→ data:str
|
├─→ data:str
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
@ -2787,6 +2798,7 @@ UNIX MODULE
|
||||||
|
|
||||||
unix.recvfrom(fd:int[, bufsiz:int[, flags:int]])
|
unix.recvfrom(fd:int[, bufsiz:int[, flags:int]])
|
||||||
├─→ data:str, ip:uint32, port:uint16
|
├─→ data:str, ip:uint32, port:uint16
|
||||||
|
├─→ data:str, unixpath:str
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
`flags` may have any combination (using bitwise OR) of:
|
`flags` may have any combination (using bitwise OR) of:
|
||||||
|
@ -2810,6 +2822,7 @@ UNIX MODULE
|
||||||
- `MSG_NOSIGNAL`
|
- `MSG_NOSIGNAL`
|
||||||
|
|
||||||
unix.sendto(fd:int, data:str, ip:uint32, port:uint16[, flags:int])
|
unix.sendto(fd:int, data:str, ip:uint32, port:uint16[, flags:int])
|
||||||
|
unix.sendto(fd:int, data:str, unixpath:str[, flags:int])
|
||||||
├─→ sent:int
|
├─→ sent:int
|
||||||
└─→ nil, unix.Errno
|
└─→ nil, unix.Errno
|
||||||
|
|
||||||
|
|
|
@ -167,6 +167,7 @@ o/tinylinux/tool/net/redbean.com: \
|
||||||
o/$(MODE)/tool/net/demo/.init.lua.zip.o \
|
o/$(MODE)/tool/net/demo/.init.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/.reload.lua.zip.o \
|
o/$(MODE)/tool/net/demo/.reload.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
||||||
|
o/$(MODE)/tool/net/demo/unix-unix.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
|
||||||
|
@ -215,6 +216,7 @@ o/$(MODE)/tool/net/redbean-demo.com.dbg: \
|
||||||
o/$(MODE)/tool/net/largon2.o \
|
o/$(MODE)/tool/net/largon2.o \
|
||||||
o/$(MODE)/tool/net/net.pkg \
|
o/$(MODE)/tool/net/net.pkg \
|
||||||
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
o/$(MODE)/tool/net/demo/sql.lua.zip.o \
|
||||||
|
o/$(MODE)/tool/net/demo/unix-unix.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-rawsocket.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-subprocess.lua.zip.o \
|
||||||
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
|
o/$(MODE)/tool/net/demo/unix-webserver.lua.zip.o \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue