Fix some more socket bugs

- The functions that return a sockaddr now do so the same way the Linux
  Kernel does across platforms, e.g. getpeername(), accept4()

- Socket system calls on Windows will now only check for interrupts when
  a blocking operation needs to be performed.

- Write tests for recvfrom() system call
This commit is contained in:
Justine Tunney 2023-07-23 16:31:10 -07:00
parent ac92f25296
commit 0ba3199915
No known key found for this signature in database
GPG key ID: BE714B4575D6E328
49 changed files with 347 additions and 352 deletions

View file

@ -17,9 +17,12 @@
PERFORMANCE OF THIS SOFTWARE.
*/
#include "libc/calls/internal.h"
#include "libc/calls/struct/fd.internal.h"
#include "libc/dce.h"
#include "libc/intrin/asan.internal.h"
#include "libc/intrin/strace.internal.h"
#include "libc/nt/errors.h"
#include "libc/nt/winsock.h"
#include "libc/sock/internal.h"
#include "libc/sock/sock.h"
#include "libc/sock/struct/sockaddr.h"
@ -27,25 +30,63 @@
#include "libc/sock/syscall_fd.internal.h"
#include "libc/sysv/errfuns.h"
static int __getsockpeername(int fd, struct sockaddr *out_addr,
uint32_t *inout_addrsize, const char *name,
int impl_sysv(int, void *, uint32_t *),
int impl_win32(uint64_t, void *, uint32_t *)) {
int rc;
struct sockaddr_storage ss = {0};
uint32_t size = sizeof(ss);
if (IsWindows()) {
if (__isfdkind(fd, kFdSocket)) {
if ((rc = impl_win32(g_fds.p[fd].handle, &ss, &size))) {
if (impl_win32 == __sys_getsockname_nt &&
WSAGetLastError() == WSAEINVAL) {
// The socket has not been bound to an address with bind, or
// ADDR_ANY is specified in bind but connection has not yet
// occurred. -MSDN
ss.ss_family = ((struct SockFd *)g_fds.p[fd].extra)->family;
rc = 0;
} else {
rc = __winsockerr();
}
}
} else {
rc = ebadf();
}
} else {
rc = impl_sysv(fd, &ss, &size);
}
if (!rc) {
if (IsBsd()) {
__convert_bsd_to_sockaddr(&ss);
}
__write_sockaddr(&ss, out_addr, inout_addrsize);
}
STRACE("%s(%d, [%s]) -> %d% lm", name, fd,
DescribeSockaddr(out_addr, inout_addrsize ? *inout_addrsize : 0), rc);
return rc;
}
/**
* Returns details about network interface kernel granted socket.
* @return 0 on success or -1 w/ errno
* @see getpeername()
*/
int getsockname(int fd, struct sockaddr *out_addr, uint32_t *out_addrsize) {
int rc;
if (!out_addrsize || !out_addrsize ||
(IsAsan() && (!__asan_is_valid(out_addrsize, 4) ||
!__asan_is_valid(out_addr, *out_addrsize)))) {
rc = efault();
} else if (!IsWindows()) {
rc = sys_getsockname(fd, out_addr, out_addrsize);
} else if (__isfdkind(fd, kFdSocket)) {
rc = sys_getsockname_nt(&g_fds.p[fd], out_addr, out_addrsize);
} else {
rc = ebadf();
}
STRACE("getsockname(%d, [%s]) -> %d% lm", fd,
DescribeSockaddr(out_addr, out_addrsize ? *out_addrsize : 0), rc);
return rc;
int getsockname(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize) {
return __getsockpeername(fd, out_addr, inout_addrsize, "getsockname",
__sys_getsockname, __sys_getsockname_nt);
}
/**
* Returns details about remote end of connected socket.
* @return 0 on success or -1 w/ errno
* @see getsockname()
*/
int getpeername(int fd, struct sockaddr *out_addr, uint32_t *inout_addrsize) {
return __getsockpeername(fd, out_addr, inout_addrsize, "getpeername",
__sys_getpeername, __sys_getpeername_nt);
}