20#define LWIP_DONT_PROVIDE_BYTEORDER_FUNCTIONS 1
22#include "pedigree/kernel/Subsystem.h"
23#include "pedigree/kernel/process/Process.h"
24#include "pedigree/kernel/process/Scheduler.h"
25#include "pedigree/kernel/process/TerminationDeferral.h"
26#include "pedigree/kernel/process/Thread.h"
27#include "pedigree/kernel/processor/Processor.h"
28#include "pedigree/kernel/processor/types.h"
29#include "pedigree/kernel/syscallError.h"
30#include "pedigree/kernel/utilities/HashTable.h"
31#include "pedigree/kernel/utilities/Pointers.h"
32#include "pedigree/kernel/utilities/Tree.h"
33#include "pedigree/kernel/utilities/UniqueResource.h"
40#include "eventfd-syscalls.h"
41#include "file-syscalls.h"
43#include "modules/subsys/posix/FileDescriptor.h"
44#include "modules/subsys/posix/PosixSubsystem.h"
45#include "modules/subsys/posix/ResolvedPath.h"
46#include "modules/subsys/posix/UnixFilesystem.h"
52#include "modules/system/vfs/File.h"
53#include "modules/system/vfs/MountView.h"
54#include "modules/system/vfs/VFS.h"
55#include "mqueue-netlink.h"
56#include "net-syscalls.h"
57#include "recvmmsg-syscalls.h"
58#include "sandbox-state.h"
59#include "signalfd-syscalls.h"
60#include "timerfd-syscalls.h"
65#include <netinet/tcp.h>
69#include <netinet/in.h>
73Mutex LwipSocketSyscalls::m_SyscallObjectsLock;
77Mutex UnixSocketSyscalls::m_SyscallObjectsLock;
80struct NetbufReleaser {
81 static void release(
struct netbuf* buffer) {
82 netbuf_delete(buffer);
90 bool prepare(
const struct msghdr&
message,
int type,
int domain,
bool sending,
91 bool kernelBuffer =
false) {
93 for (
size_t i = 0; i < static_cast<size_t>(
message.msg_iovlen); ++i) {
94 if (
message.msg_iov[i].iov_len >
static_cast<size_t>(SSIZE_MAX) - requested) {
95 SYSCALL_ERROR(InvalidArgument);
98 requested +=
message.msg_iov[i].iov_len;
100 size_t capacity = requested;
102 if (type == SOCK_STREAM && capacity > 65536) {
104 }
else if (domain == AF_UNIX && type == SOCK_SEQPACKET && capacity > MAX_UNIX_STREAM_QUEUE) {
106 syscallError(EMSGSIZE);
109 capacity = MAX_UNIX_STREAM_QUEUE;
110 }
else if (domain == AF_INET && type == SOCK_DGRAM && capacity > 65535) {
112 syscallError(EMSGSIZE);
116 }
else if (domain == 16 && !sending && capacity > 65536) {
122 SYSCALL_ERROR(OutOfMemory);
126 m_Vector = {m_Bytes.get(), capacity};
131 for (
size_t i = 0; i < static_cast<size_t>(
message.msg_iovlen) && copied < capacity; ++i) {
132 const size_t amount =
message.msg_iov[i].iov_len < capacity - copied
136 MemoryCopy(m_Bytes.get() + copied,
message.msg_iov[i].iov_base, amount);
139 SYSCALL_ERROR(BadAddress);
147 void attach(
struct msghdr&
message) {
152 bool copyReceived(
const struct msghdr& target,
size_t received) {
154 const size_t length = received < m_Vector.iov_len ? received : m_Vector.iov_len;
156 for (
size_t i = 0; i < static_cast<size_t>(target.msg_iovlen) && copied < length; ++i) {
157 const size_t amount =
158 target.msg_iov[i].iov_len < length - copied ? target.msg_iov[i].iov_len : length - copied;
160 SYSCALL_ERROR(BadAddress);
170 struct iovec m_Vector = {};
173bool copySocketAddress(
const struct sockaddr_storage* address, socklen_t length,
174 struct sockaddr_storage& result) {
175 if (length <
sizeof(sa_family_t) || length >
sizeof(result)) {
176 SYSCALL_ERROR(InvalidArgument);
180 SYSCALL_ERROR(BadAddress);
183 if ((result.ss_family == AF_INET && length <
sizeof(
struct sockaddr_in)) ||
184 (result.ss_family == AF_INET6 && length <
sizeof(
struct sockaddr_in6))) {
185 SYSCALL_ERROR(InvalidArgument);
191bool validateSocketMessageFlags(
int flags,
bool sending,
int domain = 0,
int type = 0) {
192 int supported = sending ? 0 : MSG_DONTWAIT;
193 if (sending && domain == AF_UNIX && type == SOCK_SEQPACKET) {
194 supported |= MSG_DONTWAIT;
197 if (sending || domain == 16) {
200 supported |= MSG_NOSIGNAL;
206 if (!sending && domain == 16) {
208 supported |= MSG_WAITALL;
213 supported |= MSG_TRUNC;
216#ifdef MSG_CMSG_CLOEXEC
218 supported |= MSG_CMSG_CLOEXEC;
222 if (flags & ~supported) {
223 SYSCALL_ERROR(OperationNotSupported);
229constexpr size_t MaximumControlBytes = CMSG_SPACE(SocketRights::MaximumDescriptors *
sizeof(
int));
233 const size_t controlLength =
static_cast<size_t>(
message.msg_controllen);
234 if (!controlLength) {
238 SYSCALL_ERROR(BadAddress);
241 if (controlLength > MaximumControlBytes) {
242 SYSCALL_ERROR(InvalidArgument);
248 SYSCALL_ERROR(BadAddress);
252 constexpr size_t HeaderLength = CMSG_LEN(0);
253 if (controlLength < HeaderLength) {
254 SYSCALL_ERROR(InvalidArgument);
258 struct cmsghdr header = {};
259 MemoryCopy(&header, control.get(),
sizeof(header));
260 const size_t recordLength =
static_cast<size_t>(header.cmsg_len);
261 if (recordLength < HeaderLength || recordLength > controlLength) {
262 SYSCALL_ERROR(InvalidArgument);
265 if (header.cmsg_level != SOL_SOCKET || header.cmsg_type != SCM_RIGHTS) {
266 SYSCALL_ERROR(OperationNotSupported);
270 const size_t alignedRecordLength = CMSG_ALIGN(recordLength);
271 if ((controlLength != recordLength && controlLength != alignedRecordLength) ||
272 alignedRecordLength < recordLength) {
273 SYSCALL_ERROR(InvalidArgument);
277 const size_t descriptorBytes = recordLength - HeaderLength;
278 if (!descriptorBytes || (descriptorBytes %
sizeof(
int))) {
279 SYSCALL_ERROR(InvalidArgument);
282 const size_t descriptorCount = descriptorBytes /
sizeof(int);
283 if (descriptorCount > SocketRights::MaximumDescriptors) {
284 SYSCALL_ERROR(InvalidArgument);
289 SYSCALL_ERROR(TooManyReferences);
296 SYSCALL_ERROR(BadFileDescriptor);
300 const uint8_t* descriptorData = control.get() + HeaderLength;
301 for (
size_t i = 0; i < descriptorCount; ++i) {
303 MemoryCopy(&fd, descriptorData + (i *
sizeof(fd)),
sizeof(fd));
305 if (fd < 0 || !subsystem->acquireFileDescriptor(
static_cast<size_t>(fd), descriptor)) {
307 SYSCALL_ERROR(BadFileDescriptor);
313 SYSCALL_ERROR(OperationNotSupported);
320 (descriptor->getTimerFdImpl() && !transferred->timerFdPublished()) ||
321 (descriptor->getSignalFdImpl() && !transferred->signalFdPublished())) {
324 SYSCALL_ERROR(BadFileDescriptor);
327 transferred->
fd = ~static_cast<size_t>(0);
329 rights->append(transferred);
336static File* findTrackedUnixSocket(
const String& pathname) {
345static void releaseTrackedUnixSocket(
File* file) {
353static Thread* beginInterruptibleSocketCall() {
354#if defined(PEDIGREE_EXTERNAL_SOURCE)
359 thread->clearInterruption();
364bool finishInterruptibleSocketCall(
Thread* thread, ssize_t result) {
365#if defined(PEDIGREE_EXTERNAL_SOURCE)
370 const bool interrupted = thread->getInterruptionReason() == Thread::InterruptedBySignal;
371 thread->clearInterruption();
373 if (interrupted && result < 0) {
374 SYSCALL_ERROR(Interrupted);
384 N_NOTICE(
" -> isSaneSocket: descriptor is null");
385 SYSCALL_ERROR(BadFileDescriptor);
390 N_NOTICE(
" -> isSaneSocket: no network implementation found");
391 syscallError(ENOTSOCK);
398static const int socketTypeMask = 0xF;
399static const int socketCreationFlags = SOCK_NONBLOCK | SOCK_CLOEXEC;
400static const int linuxTcpNoDelay = 1;
402static bool splitSocketType(
int argument,
int& type,
int& flags) {
403 type = argument & socketTypeMask;
404 flags = argument & socketCreationFlags;
405 if (argument != (type | flags)) {
406 SYSCALL_ERROR(InvalidArgument);
413static void setSocketDescriptorFlags(
FileDescriptor* descriptor,
int flags) {
414 descriptor->
setFlags((flags & SOCK_CLOEXEC) ? FD_CLOEXEC : 0);
415 descriptor->
setStatusFlags((flags & SOCK_NONBLOCK) ? O_NONBLOCK : 0);
418static bool unixSocketPath(
const struct sockaddr_storage* address, socklen_t addressLength,
419 String& path,
bool allowUnnamed) {
420 const size_t pathOffset = offsetof(
struct sockaddr_un, sun_path);
421 if (!address || addressLength < pathOffset || addressLength >
sizeof(
struct sockaddr_un)) {
422 SYSCALL_ERROR(InvalidArgument);
426 const struct sockaddr_un* un =
reinterpret_cast<const struct sockaddr_un*
>(address);
427 const size_t pathLength = addressLength - pathOffset;
434 SYSCALL_ERROR(InvalidArgument);
438 if (!un->sun_path[0]) {
439 static constexpr char digits[] =
"0123456789abcdef";
440 char encoded[1 + 2 *
sizeof(un->sun_path) + 1];
441 size_t encodedLength = 1;
443 for (
size_t i = 1; i < pathLength; ++i) {
444 const uint8_t value =
static_cast<uint8_t
>(un->sun_path[i]);
445 encoded[encodedLength++] = digits[value >> 4];
446 encoded[encodedLength++] = digits[value & 0xf];
448 encoded[encodedLength] = 0;
449 path.assign(encoded, encodedLength);
453 char boundedPath[
sizeof(un->sun_path) + 1];
454 ByteSet(boundedPath, 0,
sizeof(boundedPath));
455 MemoryCopy(boundedPath, un->sun_path, pathLength);
456 normalisePath(path, boundedPath);
457 if (path.length() >=
sizeof(un->sun_path)) {
458 SYSCALL_ERROR(NameTooLong);
464static bool isAbstractUnixSocket(
const String& address) {
465 return address.length() && address[0] ==
'\1';
468static uint8_t decodeHexDigit(
char value) {
469 return value >=
'a' ?
static_cast<uint8_t
>(value -
'a' + 10) : static_cast<uint8_t>(value -
'0');
472static void writeUnixSocketAddress(
const String& value,
struct sockaddr_storage* address,
473 socklen_t* addressLength) {
474 const size_t pathOffset = offsetof(
struct sockaddr_un, sun_path);
475 const bool abstract = isAbstractUnixSocket(value);
476 const size_t nameLength = abstract ? (value.length() - 1) / 2 : value.length();
477 const size_t required = pathOffset + (abstract ? 1 + nameLength
478 : nameLength ? nameLength + 1
480 const size_t capacity = addressLength ? *addressLength : 0;
482 if (address && capacity) {
483 ByteSet(address, 0, capacity <
sizeof(sockaddr_un) ? capacity : sizeof(sockaddr_un));
484 auto* un =
reinterpret_cast<struct sockaddr_un*
>(address);
485 if (capacity >=
sizeof(sa_family_t)) {
486 un->sun_family = AF_UNIX;
488 if (capacity > pathOffset) {
489 const size_t available = capacity - pathOffset;
491 const size_t amount = nameLength < available - 1 ? nameLength : available - 1;
492 for (
size_t i = 0; i < amount; ++i) {
493 un->sun_path[i + 1] =
static_cast<char>((decodeHexDigit(value[1 + 2 * i]) << 4) |
494 decodeHexDigit(value[2 + 2 * i]));
496 }
else if (nameLength) {
497 const size_t amount = nameLength < available - 1 ? nameLength : available - 1;
498 MemoryCopy(un->sun_path, value.cstr(), amount);
503 *addressLength = required;
507static uint8_t lwipSocketOption(
int option) {
510 return SOF_REUSEADDR;
512 return SOF_KEEPALIVE;
514 return SOF_BROADCAST;
520static int lwipErrorNumber(
err_t error) {
521 const int result = err_to_errno(error);
522 return result < 0 ? Error::IoError : result;
525static err_t sockaddrToIpaddr(
const struct sockaddr_storage* saddr, uint16_t& port,
526 ip_addr_t* result,
bool isbind =
true) {
527 ByteSet(result, 0,
sizeof(*result));
529 if (saddr->ss_family == AF_INET) {
530 const struct sockaddr_in* sin =
reinterpret_cast<const struct sockaddr_in*
>(saddr);
531 result->u_addr.ip4.addr = sin->sin_addr.s_addr;
536 if (!sin->sin_addr.s_addr) {
542 port = BIG_TO_HOST16(sin->sin_port);
546 ERROR(
"sockaddrToIpaddr: only AF_INET is supported at the moment.");
552int posix_socket(
int domain,
int type,
int protocol) {
553 N_NOTICE(
"socket(" << domain <<
", " << type <<
", " << protocol <<
")");
557 if (!splitSocketType(type, socketType, flags)) {
563 if (domain == AF_UNIX) {
564 if (socketType != SOCK_STREAM && socketType != SOCK_DGRAM && socketType != SOCK_SEQPACKET) {
565 SYSCALL_ERROR(OperationNotSupported);
569 }
else if (network) {
570 syscalls = posix_network_socket(domain, socketType, protocol, network);
574 }
else if (domain == 16) {
581 if (!syscalls->create()) {
588 setSocketDescriptorFlags(f, flags);
590 const size_t fd = installDescriptor(f, installed);
591 syscalls->associate(f);
593 N_NOTICE(
" -> " <<
Dec << fd <<
Hex);
594 return static_cast<int>(fd);
597int posix_socketpair(
int domain,
int type,
int protocol,
int sv[2]) {
598 N_NOTICE(
"socketpair");
601 PosixSubsystem::SafeWrite)) {
602 N_NOTICE(
"socketpair -> invalid address");
603 SYSCALL_ERROR(BadAddress);
607 if (domain != AF_UNIX) {
608 N_NOTICE(
" -> bad domain");
609 syscallError(EAFNOSUPPORT);
615 if (!splitSocketType(type, socketType, flags)) {
618 if (socketType != SOCK_STREAM && socketType != SOCK_SEQPACKET) {
619 SYSCALL_ERROR(OperationNotSupported);
624 if (!syscallsA->
create()) {
626 N_NOTICE(
" -> failed to create first socket");
631 if (!syscallsB->
create()) {
634 N_NOTICE(
" -> failed to create second socket");
638 if (!syscallsA->
pairWith(syscallsB)) {
641 N_NOTICE(
" -> failed to pair");
651 setSocketDescriptorFlags(fA, flags);
652 setSocketDescriptorFlags(fB, flags);
656 const size_t fdA = installDescriptor(fA, installedA);
657 const size_t fdB = installDescriptor(fB, installedB);
659 syscallsA->associate(fA);
660 syscallsB->associate(fB);
662 const int result[2] = {
static_cast<int>(fdA),
static_cast<int>(fdB)};
664 removeDescriptor(result[0], installedA);
665 removeDescriptor(result[1], installedB);
666 SYSCALL_ERROR(BadAddress);
670 N_NOTICE(
" -> " << result[0] <<
", " << result[1]);
674int posix_connect(
int sock,
const struct sockaddr_storage* address, socklen_t addrlen) {
677 struct sockaddr_storage snapshot = {};
678 if (!copySocketAddress(address, addrlen, snapshot)) {
682 N_NOTICE(
"connect(" << sock <<
", " <<
reinterpret_cast<uintptr_t
>(address) <<
", " << addrlen
686 acquireDescriptor(sock, f);
687 if (!isSaneSocket(f)) {
691 if (snapshot.ss_family != f->
networkImpl->getDomain()) {
692 syscallError(EAFNOSUPPORT);
693 N_NOTICE(
" -> incorrect address family passed to connect()");
697 Thread* thread = beginInterruptibleSocketCall();
698 const int result = f->
networkImpl->connect(&snapshot, addrlen);
699 return finishInterruptibleSocketCall(thread,
static_cast<ssize_t
>(result)) ? result : -1;
702ssize_t posix_send(
int sock,
const void* buff,
size_t bufflen,
int flags) {
706 PosixSubsystem::SafeRead)) {
707 N_NOTICE(
"send -> invalid address");
708 SYSCALL_ERROR(BadAddress);
712 N_NOTICE(
"send(" << sock <<
", " << buff <<
", " << bufflen <<
", " << flags <<
")");
715 acquireDescriptor(sock, f);
716 return posix_send_descriptor(f, buff, bufflen, flags);
719ssize_t posix_send_descriptor(
const DescriptorLease& f,
const void* buff,
size_t bufflen,
int flags,
721 if (!isSaneSocket(f)) {
725 struct iovec vector = {
const_cast<void*
>(buff), bufflen};
735 if (!isSaneSocket(f) ||
741 SocketPayload payload;
746 struct msghdr snapshot = *
message;
747 payload.attach(snapshot);
748 Thread* thread = beginInterruptibleSocketCall();
749 const ssize_t result = f->
networkImpl->sendto_msg(&snapshot, rights);
750 return finishInterruptibleSocketCall(thread, result) ? result : -1;
753ssize_t posix_sendto(
int sock,
const void* buff,
size_t bufflen,
int flags,
754 struct sockaddr_storage* address, socklen_t addrlen) {
758 PosixSubsystem::SafeRead)) {
759 N_NOTICE(
"sendto -> invalid address for transmission buffer");
760 SYSCALL_ERROR(BadAddress);
763 struct sockaddr_storage destination = {};
764 const struct sockaddr_storage* destinationAddress =
nullptr;
766 if (addrlen <
sizeof(sa_family_t) || addrlen >
sizeof(destination)) {
767 N_NOTICE(
"sendto -> invalid destination address length");
768 SYSCALL_ERROR(InvalidArgument);
772 N_NOTICE(
"sendto -> invalid destination address");
773 SYSCALL_ERROR(BadAddress);
776 destinationAddress = &destination;
779 N_NOTICE(
"sendto(" << sock <<
", " << buff <<
", " << bufflen <<
", " << flags <<
", " << address
780 <<
", " << addrlen <<
")");
783 acquireDescriptor(sock, f);
784 if (!isSaneSocket(f)) {
788 struct iovec vector = {
const_cast<void*
>(buff), bufflen};
790 message.msg_name =
const_cast<struct sockaddr_storage*
>(destinationAddress);
795 return posix_sendmsg_descriptor(f, &
message);
798ssize_t posix_recv(
int sock,
void* buff,
size_t bufflen,
int flags) {
802 PosixSubsystem::SafeWrite)) {
803 N_NOTICE(
"recv -> invalid address");
804 SYSCALL_ERROR(BadAddress);
808 N_NOTICE(
"recv(" << sock <<
", " << buff <<
", " << bufflen <<
", " << flags <<
")");
811 acquireDescriptor(sock, f);
812 ssize_t n = posix_recv_descriptor(f, buff, bufflen, flags);
814 N_NOTICE(
" -> " << n);
818ssize_t posix_recv_descriptor(
const DescriptorLease& f,
void* buff,
size_t bufflen,
int flags) {
819 if (!isSaneSocket(f)) {
822 if (!validateSocketMessageFlags(flags,
false, f->
networkImpl->getDomain())) {
826 struct iovec vector = {buff, bufflen};
831 return posix_recvmsg_descriptor(f, &
message);
836 if (!isSaneSocket(f)) {
840 const int pendingError = f->
networkImpl->takeReceiveError();
842 syscallError(pendingError);
845 SocketPayload payload;
849 struct msghdr snapshot = *
message;
850 payload.attach(snapshot);
851 Thread* thread = beginInterruptibleSocketCall();
852 const ssize_t result = f->
networkImpl->recvfrom_msg(&snapshot, rights);
853 if (!finishInterruptibleSocketCall(thread, result) ||
854 (result >= 0 && !payload.copyReceived(*
message,
static_cast<size_t>(result)))) {
860 message->msg_namelen = snapshot.msg_namelen;
861 message->msg_controllen = snapshot.msg_controllen;
862 message->msg_flags = snapshot.msg_flags;
866ssize_t posix_recvfrom(
int sock,
void* buff,
size_t bufflen,
int flags,
867 struct sockaddr_storage* address, socklen_t* addrlen) {
868 N_NOTICE(
"recvfrom");
871 acquireDescriptor(sock, f);
872 if (!isSaneSocket(f) || !validateSocketMessageFlags(flags,
false, f->
networkImpl->getDomain())) {
877 PosixSubsystem::SafeWrite)) {
878 N_NOTICE(
"recvfrom -> invalid receive buffer");
879 SYSCALL_ERROR(BadAddress);
883 struct sockaddr_storage source = {};
884 struct sockaddr_storage* sourceAddress =
nullptr;
885 socklen_t sourceCapacity = 0;
888 N_NOTICE(
"recvfrom -> invalid source address length");
889 SYSCALL_ERROR(BadAddress);
892 if (sourceCapacity >
static_cast<socklen_t
>(INT_MAX)) {
893 SYSCALL_ERROR(InvalidArgument);
897 const size_t checkedCapacity =
898 sourceCapacity <
sizeof(source) ? sourceCapacity : sizeof(source);
899 if (checkedCapacity &&
901 PosixSubsystem::SafeWrite)) {
902 N_NOTICE(
"recvfrom -> invalid source address buffer");
903 SYSCALL_ERROR(BadAddress);
906 sourceAddress = &source;
909 N_NOTICE(
"recvfrom(" << sock <<
", " << buff <<
", " << bufflen <<
", " << flags <<
", "
910 << address <<
", " << addrlen);
912 struct iovec vector = {buff, bufflen};
917 message.msg_name = sourceAddress;
918 message.msg_namelen = sourceAddress ?
sizeof(source) : 0;
919 ssize_t n = posix_recvmsg_descriptor(f, &
message);
920 const socklen_t sourceLength =
message.msg_namelen;
922 if (n >= 0 && sourceAddress) {
923 size_t copyLength = sourceLength;
924 if (copyLength > sourceCapacity) {
925 copyLength = sourceCapacity;
927 if (copyLength >
sizeof(source)) {
928 copyLength =
sizeof(source);
932 SYSCALL_ERROR(BadAddress);
937 N_NOTICE(
" -> " << n);
941int posix_bind(
int sock,
const struct sockaddr_storage* address, socklen_t addrlen) {
944 struct sockaddr_storage snapshot = {};
945 if (!copySocketAddress(address, addrlen, snapshot)) {
949 N_NOTICE(
"bind(" << sock <<
", " << address <<
", " << addrlen <<
")");
952 acquireDescriptor(sock, f);
953 if (!isSaneSocket(f)) {
957 if (f->
networkImpl->getDomain() != snapshot.ss_family) {
958 syscallError(EAFNOSUPPORT);
965int posix_listen(
int sock,
int backlog) {
966 N_NOTICE(
"listen(" << sock <<
", " << backlog <<
")");
969 acquireDescriptor(sock, f);
970 if (!isSaneSocket(f)) {
976 SYSCALL_ERROR(InvalidArgument);
983int posix_accept(
int sock,
struct sockaddr_storage* address, socklen_t* addrlen) {
984 return posix_accept4(sock, address, addrlen, 0);
987int posix_accept4(
int sock,
struct sockaddr_storage* address, socklen_t* addrlen,
int flags) {
990 if (flags & ~socketCreationFlags) {
991 SYSCALL_ERROR(InvalidArgument);
995 struct sockaddr_storage acceptedAddress;
996 ByteSet(&acceptedAddress, 0,
sizeof(acceptedAddress));
997 socklen_t acceptedLength =
sizeof(acceptedAddress);
998 socklen_t addressCapacity = 0;
999 const bool returnAddress = address !=
nullptr;
1000 if (returnAddress) {
1003 PosixSubsystem::SafeWrite)) {
1004 N_NOTICE(
"accept4 -> invalid address length");
1005 SYSCALL_ERROR(BadAddress);
1008 if (addressCapacity >
static_cast<socklen_t
>(INT_MAX)) {
1009 SYSCALL_ERROR(InvalidArgument);
1013 const size_t writableLength = addressCapacity <
sizeof(acceptedAddress)
1014 ?
static_cast<size_t>(addressCapacity)
1015 : sizeof(acceptedAddress);
1016 if (writableLength &&
1018 PosixSubsystem::SafeWrite)) {
1019 N_NOTICE(
"accept4 -> invalid address");
1020 SYSCALL_ERROR(BadAddress);
1025 N_NOTICE(
"accept4(" << sock <<
", " << address <<
", " << addrlen <<
", " << flags <<
")");
1028 acquireDescriptor(sock, f);
1029 if (!isSaneSocket(f)) {
1035 SYSCALL_ERROR(OperationNotSupported);
1039 Thread* thread = beginInterruptibleSocketCall();
1041 int r = f->
networkImpl->accept(&acceptedAddress, &acceptedLength, flags, &accepted);
1042 if (!finishInterruptibleSocketCall(thread,
static_cast<ssize_t
>(r))) {
1045 if (r >= 0 && returnAddress) {
1046 const size_t copyLength = addressCapacity < acceptedLength
1047 ?
static_cast<size_t>(addressCapacity)
1048 : static_cast<size_t>(acceptedLength);
1049 if (acceptedLength >
sizeof(acceptedAddress) ||
1052 removeDescriptor(r, accepted);
1053 SYSCALL_ERROR(BadAddress);
1057 N_NOTICE(
" -> " <<
Dec << r);
1061int posix_shutdown(
int socket,
int how) {
1062 N_NOTICE(
"shutdown(" << socket <<
", " << how <<
")");
1065 acquireDescriptor(socket, f);
1066 if (!isSaneSocket(f)) {
1074int socketName(
int socket,
struct sockaddr_storage* address, socklen_t* addressLength,
bool peer) {
1075 socklen_t capacity = 0;
1077 SYSCALL_ERROR(BadAddress);
1080 if (capacity > INT_MAX) {
1081 SYSCALL_ERROR(InvalidArgument);
1086 acquireDescriptor(socket, f);
1087 if (!isSaneSocket(f)) {
1091 struct sockaddr_storage result = {};
1092 socklen_t length =
sizeof(result);
1093 const int status = peer ? f->
networkImpl->getpeername(&result, &length)
1098 if (length >
sizeof(result)) {
1099 SYSCALL_ERROR(IoError);
1103 const size_t copied = capacity < length ? capacity : length;
1106 SYSCALL_ERROR(BadAddress);
1113int posix_getpeername(
int socket,
struct sockaddr_storage* address, socklen_t* address_len) {
1114 return socketName(socket, address, address_len,
true);
1117int posix_getsockname(
int socket,
struct sockaddr_storage* address, socklen_t* address_len) {
1118 return socketName(socket, address, address_len,
false);
1121int posix_setsockopt(
int sock,
int level,
int optname,
const void* optvalue, socklen_t optlen) {
1122 if (optlen <
sizeof(
int)) {
1123 SYSCALL_ERROR(InvalidArgument);
1128 SYSCALL_ERROR(BadAddress);
1132 acquireDescriptor(sock, f);
1133 if (!isSaneSocket(f)) {
1136 return f->
networkImpl->setsockopt(level, optname, &value,
sizeof(value));
1139int posix_getsockopt(
int sock,
int level,
int optname,
void* optvalue, socklen_t* optlen) {
1140 socklen_t capacity = 0;
1142 SYSCALL_ERROR(BadAddress);
1145 if (capacity > INT_MAX) {
1146 SYSCALL_ERROR(InvalidArgument);
1151 struct ucred credentials;
1153 socklen_t length =
sizeof(value);
1155 acquireDescriptor(sock, f);
1156 if (!isSaneSocket(f)) {
1159 const int pendingError =
1160 level == SOL_SOCKET && optname == SO_ERROR ? f->
networkImpl->takeReceiveError() : 0;
1162 value.scalar = pendingError;
1163 length =
sizeof(value.scalar);
1164 }
else if (f->
networkImpl->getsockopt(level, optname, &value, &length) < 0) {
1167 if (length >
sizeof(value)) {
1168 SYSCALL_ERROR(IoError);
1171 const socklen_t copied = capacity < length ? capacity : length;
1174 SYSCALL_ERROR(BadAddress);
1180ssize_t posix_sendmsg(
int sockfd,
const struct msghdr* msg,
int flags) {
1181 N_NOTICE(
"sendmsg(" << sockfd <<
", " << msg <<
", " << flags <<
")");
1185 SYSCALL_ERROR(BadAddress);
1190 if (!parseSocketRights(
message, rights)) {
1194 constexpr size_t MaximumIoVectors = 1024;
1195 const size_t vectorCount =
static_cast<size_t>(
message.msg_iovlen);
1196 if (vectorCount > MaximumIoVectors) {
1197 SYSCALL_ERROR(InvalidArgument);
1205 struct iovec* vectors = vectorOwner.get();
1208 SYSCALL_ERROR(BadAddress);
1211 constexpr size_t MaximumIoBytes =
static_cast<size_t>(SSIZE_MAX);
1212 size_t totalLength = 0;
1213 for (
size_t i = 0; i < vectorCount; ++i) {
1214 if (vectors[i].iov_len > MaximumIoBytes - totalLength) {
1215 SYSCALL_ERROR(InvalidArgument);
1219 vectors[i].iov_len, 1, PosixSubsystem::SafeRead)) {
1220 SYSCALL_ERROR(BadAddress);
1223 totalLength += vectors[i].iov_len;
1226 struct sockaddr_storage address = {};
1228 if (
message.msg_namelen >
sizeof(address)) {
1229 SYSCALL_ERROR(InvalidArgument);
1233 SYSCALL_ERROR(BadAddress);
1239 message.msg_control =
nullptr;
1244 acquireDescriptor(sockfd, f);
1245 if (!isSaneSocket(f)) {
1252 SYSCALL_ERROR(OperationNotSupported);
1255 if (rights && f->
networkImpl->getType() == SOCK_STREAM && !totalLength) {
1256 SYSCALL_ERROR(InvalidArgument);
1260 const ssize_t n = posix_sendmsg_descriptor(f, &
message, rights);
1261 N_NOTICE(
" -> " << n);
1265ssize_t posix_recvmsg(
int sockfd,
struct msghdr* msg,
int flags) {
1266 N_NOTICE(
"recvmsg(" << sockfd <<
", " << msg <<
", " << flags <<
")");
1269 acquireDescriptor(sockfd, f);
1270 if (!isSaneSocket(f) || !validateSocketMessageFlags(flags,
false, f->
networkImpl->getDomain())) {
1274 return posix_recvmsg_user_descriptor(f, msg, flags);
1277ssize_t posix_recvmsg_user_descriptor(
const DescriptorLease& f,
struct msghdr* msg,
int flags,
1278 unsigned int* receivedLength) {
1279 if (!isSaneSocket(f) || !validateSocketMessageFlags(flags,
false, f->
networkImpl->getDomain()))
1284 PosixSubsystem::SafeWrite)) {
1285 SYSCALL_ERROR(BadAddress);
1288 if (receivedLength &&
1290 sizeof(*receivedLength), PosixSubsystem::SafeWrite)) {
1291 SYSCALL_ERROR(BadAddress);
1294 const struct msghdr originalMessage =
message;
1296 constexpr size_t MaximumIoVectors = 1024;
1297 const size_t vectorCount =
static_cast<size_t>(
message.msg_iovlen);
1298 if (vectorCount > MaximumIoVectors) {
1299 SYSCALL_ERROR(InvalidArgument);
1307 struct iovec* vectors = vectorOwner.get();
1310 SYSCALL_ERROR(BadAddress);
1313 constexpr size_t MaximumIoBytes =
static_cast<size_t>(SSIZE_MAX);
1314 size_t totalLength = 0;
1315 for (
size_t i = 0; i < vectorCount; ++i) {
1316 if (vectors[i].iov_len > MaximumIoBytes - totalLength) {
1317 SYSCALL_ERROR(InvalidArgument);
1321 vectors[i].iov_len, 1, PosixSubsystem::SafeWrite)) {
1322 SYSCALL_ERROR(BadAddress);
1325 totalLength += vectors[i].iov_len;
1328 void* userName =
message.msg_name;
1329 const size_t userNameCapacity =
message.msg_namelen;
1330 void* userControl =
message.msg_control;
1331 const size_t userControlCapacity =
static_cast<size_t>(
message.msg_controllen);
1332 struct sockaddr_storage address = {};
1334 const size_t checkedCapacity =
1335 userNameCapacity <
sizeof(address) ? userNameCapacity : sizeof(address);
1337 PosixSubsystem::SafeWrite)) {
1338 SYSCALL_ERROR(BadAddress);
1342 message.msg_namelen = checkedCapacity;
1344 if (userControlCapacity) {
1346 SYSCALL_ERROR(BadAddress);
1349 const size_t checkedCapacity =
1350 userControlCapacity < MaximumControlBytes ? userControlCapacity : MaximumControlBytes;
1352 PosixSubsystem::SafeWrite)) {
1353 SYSCALL_ERROR(BadAddress);
1358 message.msg_control =
nullptr;
1363 const ssize_t n = posix_recvmsg_descriptor(f, &
message, &rights);
1366 struct msghdr result = originalMessage;
1367 const size_t rightsCount = rights ? rights->count() : 0;
1368 size_t disclosedCount = 0;
1369 if (rightsCount && userControl && userControlCapacity >= CMSG_LEN(
sizeof(
int))) {
1370 disclosedCount = (userControlCapacity - CMSG_LEN(0)) /
sizeof(
int);
1371 if (disclosedCount > rightsCount) {
1372 disclosedCount = rightsCount;
1378 if (disclosedCount) {
1384 size_t publishedCount = 0;
1385 auto rollback = [&]() {
1386 for (
size_t i = 0; i < publishedCount; ++i) {
1388 installedLeases.get()[i]);
1389 installedLeases.get()[i].reset();
1393 for (; publishedCount < disclosedCount; ++publishedCount) {
1395 if ((rights->descriptor(publishedCount)->networkImpl && !received->
networkPublished()) ||
1396 (rights->descriptor(publishedCount)->getEventFdImpl() && !received->
eventFdPublished()) ||
1397 (rights->descriptor(publishedCount)->getTimerFdImpl() && !received->timerFdPublished()) ||
1398 (rights->descriptor(publishedCount)->getSignalFdImpl() &&
1399 !received->signalFdPublished())) {
1402 SYSCALL_ERROR(BadFileDescriptor);
1405 int descriptorFlags = 0;
1406#ifdef MSG_CMSG_CLOEXEC
1407 descriptorFlags = (flags & MSG_CMSG_CLOEXEC) ? FD_CLOEXEC : 0;
1409 received->
setFlags(descriptorFlags);
1412 installedFds.get()[publishedCount] =
static_cast<int>(fd);
1415 size_t controlBytes = 0;
1417 if (disclosedCount) {
1418 const size_t fullSpace = CMSG_SPACE(disclosedCount *
sizeof(
int));
1419 controlBytes = userControlCapacity < fullSpace ? userControlCapacity : fullSpace;
1421 ByteSet(control.get(), 0, controlBytes);
1423 struct cmsghdr header = {};
1424 header.cmsg_len = CMSG_LEN(disclosedCount *
sizeof(
int));
1425 header.cmsg_level = SOL_SOCKET;
1426 header.cmsg_type = SCM_RIGHTS;
1427 MemoryCopy(control.get(), &header,
sizeof(header));
1428 MemoryCopy(control.get() + CMSG_LEN(0), installedFds.get(), disclosedCount *
sizeof(
int));
1432 size_t nameBytes =
message.msg_namelen;
1433 if (nameBytes > userNameCapacity) {
1434 nameBytes = userNameCapacity;
1436 if (nameBytes >
sizeof(address)) {
1437 nameBytes =
sizeof(address);
1441 SYSCALL_ERROR(BadAddress);
1448 SYSCALL_ERROR(BadAddress);
1452 result.msg_namelen =
message.msg_namelen;
1453 result.msg_controllen = controlBytes;
1454 result.msg_flags =
message.msg_flags;
1456 if (disclosedCount < rightsCount) {
1457 result.msg_flags |= MSG_CTRUNC;
1460 const unsigned int length =
static_cast<unsigned int>(n);
1464 SYSCALL_ERROR(BadAddress);
1468 N_NOTICE(
" -> " << n);
1472NetworkSyscalls::NetworkSyscalls(
int domain,
int type,
int protocol)
1475 m_Protocol(protocol),
1476 m_NetworkNamespace(
Processor::information().getCurrentThread()
1477 ? posix_sandbox_network(*
Processor::information().getCurrentThread())
1480 m_ReadinessNotifications(),
1482 m_DescriptorOwners(0),
1483 m_DescriptorAdmissionOpen(true),
1484 m_LastDescriptorClosed(false),
1485 m_DescriptorLifetime() {}
1487int NetworkSyscalls::takeReceiveError() {
1491 error = m_ReceiveError;
1499void NetworkSyscalls::deferReceiveError(
int error) {
1502 if (!m_ReceiveError && error)
1503 ++m_ReceiveErrorGeneration;
1504 m_ReceiveError = error;
1509ReadyMask NetworkSyscalls::pendingReceiveReadiness()
const {
1511 return m_ReceiveError ? ReadyError : ReadyNone;
1518 generations.error += m_ReceiveErrorGeneration;
1526NetworkSyscalls::~NetworkSyscalls() {
1530bool NetworkSyscalls::create() {
1534ssize_t NetworkSyscalls::sendto(
const void* buffer,
size_t bufferlen,
int flags,
1535 const struct sockaddr_storage* address, socklen_t addrlen) {
1537 iov.iov_base =
const_cast<void*
>(buffer);
1538 iov.iov_len = bufferlen;
1541 msg.msg_name =
const_cast<struct sockaddr_storage*
>(address);
1542 msg.msg_namelen = addrlen;
1545 msg.msg_control =
nullptr;
1546 msg.msg_controllen = 0;
1547 msg.msg_flags = flags;
1550 return sendto_msg(&msg, rights);
1553ssize_t NetworkSyscalls::recvfrom(
void* buffer,
size_t bufferlen,
int flags,
1554 struct sockaddr_storage* address, socklen_t* addrlen) {
1556 iov.iov_base = buffer;
1557 iov.iov_len = bufferlen;
1560 msg.msg_name = address;
1561 msg.msg_namelen = addrlen ? *addrlen : 0;
1564 msg.msg_control =
nullptr;
1565 msg.msg_controllen = 0;
1566 msg.msg_flags = flags;
1568 ssize_t result = recvfrom_msg(&msg,
nullptr);
1572 *addrlen = msg.msg_namelen;
1579int NetworkSyscalls::shutdown(
int how) {
1583bool NetworkSyscalls::canPoll()
const {
1587bool NetworkSyscalls::poll(
bool& read,
bool& write,
bool& error,
Semaphore*
waiter) {
1599 return ReadyInvalid | pendingReceiveReadiness();
1604 if (!m_DescriptorAdmissionOpen) {
1608 ++m_DescriptorOwners;
1612void NetworkSyscalls::removeDescriptorOwner() {
1613 bool closeEndpoint =
false;
1616 assert(m_DescriptorOwners);
1617 --m_DescriptorOwners;
1618 if (!m_DescriptorOwners) {
1619 m_DescriptorAdmissionOpen =
false;
1624 closeEndpoint = usesLocalEndpointLifetime() || m_Domain == 16;
1628 if (closeEndpoint) {
1634 if (!usesLocalEndpointLifetime() || !lifetime) {
1639 if (!m_DescriptorLifetime) {
1640 m_DescriptorLifetime = lifetime;
1646 return m_DescriptorLifetime;
1653 lifetime = pedigree_std::move(m_DescriptorLifetime);
1667bool NetworkSyscalls::monitor(
Thread* pThread,
Event* pEvent) {
1671bool NetworkSyscalls::unmonitor(
Event* pEvent) {
1679bool NetworkSyscalls::isBlocking()
const {
1683void NetworkSyscalls::setBlocking(
bool blocking) {
1684 m_Blocking = blocking;
1689 if (m_LastDescriptorClosed) {
1693 m_DescriptorAdmissionOpen =
false;
1694 m_LastDescriptorClosed =
true;
1698bool NetworkSyscalls::hasLastDescriptorClosed()
const {
1700 return m_LastDescriptorClosed;
1703LwipSocketSyscalls::LwipSocketSyscalls(
int domain,
int type,
int protocol)
1704 :
NetworkSyscalls(domain, type, protocol), m_Socket(nullptr), m_ReceiveLock(), m_Metadata() {}
1706LwipSocketSyscalls::~LwipSocketSyscalls() {
1715 struct netconn* socket = m_Socket;
1720 m_SyscallObjects.
remove(socket);
1722 UNLOCK_TCPIP_CORE();
1730 struct pbuf* partialPacket =
nullptr;
1731 struct netbuf* partialBuffer =
nullptr;
1736 const ReadyMask previous = readinessLevelLocked();
1737 m_Metadata.closed =
true;
1738 m_Metadata.peerClosed =
true;
1739 m_Metadata.writeClosed =
true;
1740 partialPacket = m_Metadata.pb;
1741 partialBuffer = m_Metadata.buf;
1742 m_Metadata.pb =
nullptr;
1743 m_Metadata.buf =
nullptr;
1744 m_Metadata.offset = 0;
1745 m_Metadata.partialRead =
false;
1746 m_Metadata.receivingQueuedData =
false;
1747 recordReadinessRisesLocked(previous);
1752 if (partialBuffer) {
1753 netbuf_delete(partialBuffer);
1754 }
else if (partialPacket) {
1758 netconn_delete(socket);
1764void LwipSocketSyscalls::setBlocking(
bool blocking) {
1765 NetworkSyscalls::setBlocking(blocking);
1767 netconn_set_nonblocking(m_Socket, blocking ? 0 : 1);
1771void LwipSocketSyscalls::registerSocket() {
1775 if (!m_SyscallObjects.
lookup(m_Socket)) {
1779 if (m_Socket->socket < 0) {
1781 const ReadyMask previous = readinessLevelLocked();
1782 m_Metadata.recv += -1 - m_Socket->socket;
1783 m_Socket->socket = 0;
1784 recordReadinessRisesLocked(previous);
1786 m_SyscallObjects.
insert(m_Socket,
this);
1789 UNLOCK_TCPIP_CORE();
1793 netconn_type connType = NETCONN_INVALID;
1797 N_NOTICE(
"LwipSocketSyscalls: using default protocol for socket type");
1798 if (m_Type == SOCK_DGRAM) {
1799 m_Protocol = IPPROTO_UDP;
1800 }
else if (m_Type == SOCK_STREAM) {
1801 m_Protocol = IPPROTO_TCP;
1805 if (m_Domain == AF_INET) {
1806 switch (m_Protocol) {
1808 connType = NETCONN_TCP;
1811 connType = NETCONN_UDP;
1814 }
else if (m_Domain == AF_INET6) {
1815 switch (m_Protocol) {
1817 connType = NETCONN_TCP_IPV6;
1820 connType = NETCONN_UDP_IPV6;
1823 }
else if (m_Domain == AF_PACKET) {
1824 connType = NETCONN_RAW;
1826 WARNING(
"LwipSocketSyscalls: domain " << m_Domain <<
" is not known!");
1827 SYSCALL_ERROR(InvalidArgument);
1831 if (connType == NETCONN_INVALID) {
1832 N_NOTICE(
"LwipSocketSyscalls: invalid socket creation parameters");
1833 SYSCALL_ERROR(InvalidArgument);
1849 if (NETCONNTYPE_GROUP(m_Socket->type) != NETCONN_TCP) {
1851 const ReadyMask previous = readinessLevelLocked();
1852 m_Metadata.send = 1;
1853 recordReadinessRisesLocked(previous);
1863 ByteSet(&ipaddr, 0,
sizeof(ipaddr));
1865 err_t err = sockaddrToIpaddr(address, port, &ipaddr,
false);
1867 N_NOTICE(
"failed to convert sockaddr");
1868 lwipToSyscallError(err);
1873 bool blocking = isBlocking();
1874 netconn_set_nonblocking(m_Socket, blocking ? 0 : 1);
1876 N_NOTICE(
"using socket " << m_Socket <<
"!");
1877 N_NOTICE(
" -> connecting to remote " << ipaddr_ntoa(&ipaddr) <<
" on port " <<
Dec << port);
1879 err = netconn_connect(m_Socket, &ipaddr, port);
1881 N_NOTICE(
" -> lwip error");
1882 lwipToSyscallError(err);
1888 if (NETCONNTYPE_GROUP(m_Socket->type) != NETCONN_TCP) {
1890 const ReadyMask previous = readinessLevelLocked();
1891 m_Metadata.send = 1;
1892 recordReadinessRisesLocked(previous);
1895 N_NOTICE(
" -> ok!");
1899ssize_t LwipSocketSyscalls::sendto_msg(
const struct msghdr* msghdr,
1902 SYSCALL_ERROR(OperationNotSupported);
1907 const bool tcp = NETCONNTYPE_GROUP(m_Socket->type) == NETCONN_TCP;
1908 ip_addr_t destination = {};
1909 uint16_t destinationPort = 0;
1910 bool hasDestination =
false;
1912 if (msghdr->msg_name) {
1916 SYSCALL_ERROR(Unimplemented);
1919 if (m_Domain != AF_INET) {
1920 SYSCALL_ERROR(OperationNotSupported);
1923 if (msghdr->msg_namelen <
sizeof(
struct sockaddr_in)) {
1924 SYSCALL_ERROR(InvalidArgument);
1928 const struct sockaddr_storage* address =
1929 reinterpret_cast<const struct sockaddr_storage*
>(msghdr->msg_name);
1930 err = sockaddrToIpaddr(address, destinationPort, &destination,
false);
1932 lwipToSyscallError(err);
1935 hasDestination =
true;
1939 bool hasPayload =
false;
1940 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
1941 if (msghdr->msg_iov[i].iov_len) {
1952 bool sendAvailable =
false;
1955 sendAvailable = m_Metadata.send != 0;
1957 if (!isBlocking() && !sendAvailable) {
1958 N_NOTICE(
" -> send queue full, would block");
1959 SYSCALL_ERROR(NoMoreProcesses);
1963 size_t bytesWritten = 0;
1967 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
1968 void* buffer = msghdr->msg_iov[i].iov_base;
1969 size_t bufferlen = msghdr->msg_iov[i].iov_len;
1974 size_t thisBytesWritten = 0;
1975 err = netconn_write_partly(m_Socket, buffer, bufferlen, NETCONN_COPY | NETCONN_MORE,
1978 lwipToSyscallError(err);
1983 bytesWritten += thisBytesWritten;
1984 if (thisBytesWritten < bufferlen) {
1989 NetbufOwner buffer = NetbufOwner::adopt(netbuf_new());
1991 SYSCALL_ERROR(OutOfMemory);
1995 size_t datagramLength = 0;
1996 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
1997 const size_t fragmentLength = msghdr->msg_iov[i].iov_len;
1998 if (fragmentLength >
static_cast<size_t>(0xFFFF) - datagramLength) {
1999 SYSCALL_ERROR(TooBig);
2002 datagramLength += fragmentLength;
2006 reinterpret_cast<char*
>(netbuf_alloc(buffer.get(),
static_cast<u16_t
>(datagramLength)));
2008 SYSCALL_ERROR(OutOfMemory);
2013 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
2014 const size_t fragmentLength = msghdr->msg_iov[i].iov_len;
2015 if (fragmentLength) {
2016 MemoryCopy(payload + offset, msghdr->msg_iov[i].iov_base, fragmentLength);
2017 offset += fragmentLength;
2021 err = hasDestination ? netconn_sendto(m_Socket, buffer.get(), &destination, destinationPort)
2022 : netconn_send(m_Socket, buffer.get());
2024 lwipToSyscallError(err);
2028 bytesWritten += datagramLength;
2032 if (!bytesWritten) {
2042 return bytesWritten;
2045ssize_t LwipSocketSyscalls::recvfrom_msg(
struct msghdr* msghdr,
2056 const bool tcp = NETCONNTYPE_GROUP(netconn_type(m_Socket)) == NETCONN_TCP;
2057 const int inputFlags = msghdr->msg_flags;
2058 const bool blocking = isBlocking() && !(inputFlags & MSG_DONTWAIT);
2059 if ((inputFlags & MSG_TRUNC) && (tcp || m_Type != SOCK_DGRAM)) {
2060 SYSCALL_ERROR(OperationNotSupported);
2063 if (msghdr->msg_name && tcp) {
2065 SYSCALL_ERROR(Unimplemented);
2068 if (msghdr->msg_name && m_Domain != AF_INET) {
2069 SYSCALL_ERROR(OperationNotSupported);
2072 msghdr->msg_flags = 0;
2073 if (!msghdr->msg_name) {
2074 msghdr->msg_namelen = 0;
2077 size_t vectorIndex = 0;
2078 size_t vectorOffset = 0;
2079 while (vectorIndex <
static_cast<size_t>(msghdr->msg_iovlen) &&
2080 !msghdr->msg_iov[vectorIndex].iov_len) {
2083 if (tcp && vectorIndex ==
static_cast<size_t>(msghdr->msg_iovlen)) {
2089 bool noData =
false;
2092 if (m_Metadata.closed) {
2095 noData = !(m_Metadata.recv || m_Metadata.partialRead);
2104 N_NOTICE(
" -> no more data available, would block");
2105 SYSCALL_ERROR(NoMoreProcesses);
2110 size_t totalLen = 0;
2111 size_t packetLength = 0;
2113 if (!m_Metadata.pb) {
2114 struct pbuf* pb =
nullptr;
2115 struct netbuf* buf =
nullptr;
2122 if (totalLen && !m_Metadata.recv) {
2128 m_Metadata.receivingQueuedData = m_Metadata.recv != 0;
2135 err = netconn_recv_tcp_pbuf(m_Socket, &pb);
2137 err = netconn_recv(m_Socket, &buf);
2142 ReadyMask changed = ReadyRead | ReadyReadHangup;
2145 const ReadyMask previous = readinessLevelLocked();
2146 m_Metadata.receivingQueuedData =
false;
2147 m_Metadata.closed =
true;
2148 m_Metadata.peerClosed =
true;
2149 if (m_Metadata.writeClosed) {
2150 changed |= ReadyHangup;
2152 recordReadinessRisesLocked(previous);
2160 m_Metadata.receivingQueuedData =
false;
2163 N_NOTICE(
" -> lwIP error");
2165 lwipToSyscallError(err);
2171 if (pb ==
nullptr && buf !=
nullptr) {
2177 m_Metadata.receivingQueuedData =
false;
2181 SYSCALL_ERROR(IoError);
2189 m_Metadata.offset = 0;
2191 m_Metadata.buf = buf;
2192 m_Metadata.partialRead =
true;
2193 m_Metadata.receivingQueuedData =
false;
2197 packetLength = m_Metadata.pb->
tot_len;
2198 if (!tcp && msghdr->msg_name) {
2199 const ip_addr_t* sourceAddress = netbuf_fromaddr(m_Metadata.buf);
2200 const uint16_t sourcePort = netbuf_fromport(m_Metadata.buf);
2201 struct sockaddr_in source = {};
2202 source.sin_family = AF_INET;
2203 source.sin_port = HOST_TO_BIG16(sourcePort);
2204 source.sin_addr.s_addr = ip_addr_get_ip4_u32(sourceAddress);
2206 const size_t addressCapacity = msghdr->msg_namelen;
2207 const size_t addressLength =
2208 addressCapacity <
sizeof(source) ? addressCapacity : sizeof(source);
2209 if (addressLength) {
2210 MemoryCopy(msghdr->msg_name, &source, addressLength);
2212 msghdr->msg_namelen =
sizeof(source);
2215 size_t readOffset = m_Metadata.offset;
2216 while (vectorIndex <
static_cast<size_t>(msghdr->msg_iovlen) && readOffset < packetLength) {
2217 const struct iovec& vector = msghdr->msg_iov[vectorIndex];
2218 size_t bufferlen = vector.iov_len - vectorOffset;
2219 const size_t available = packetLength - readOffset;
2220 if (bufferlen > available) {
2221 bufferlen = available;
2224 pbuf_copy_partial(m_Metadata.pb,
reinterpret_cast<uint8_t*
>(vector.iov_base) + vectorOffset,
2225 bufferlen, readOffset);
2226 totalLen += bufferlen;
2227 readOffset += bufferlen;
2228 vectorOffset += bufferlen;
2230 if (vectorOffset == vector.iov_len) {
2236 while (vectorIndex <
static_cast<size_t>(msghdr->msg_iovlen) &&
2237 !msghdr->msg_iov[vectorIndex].iov_len) {
2243 if (tcp && readOffset < packetLength) {
2245 m_Metadata.offset = readOffset;
2247 struct pbuf* completedPacket =
nullptr;
2248 struct netbuf* completedBuffer =
nullptr;
2251 completedPacket = m_Metadata.pb;
2252 completedBuffer = m_Metadata.buf;
2253 m_Metadata.pb =
nullptr;
2254 m_Metadata.buf =
nullptr;
2255 m_Metadata.offset = 0;
2256 m_Metadata.partialRead =
false;
2259 if (!tcp && readOffset < packetLength) {
2260 msghdr->msg_flags |= MSG_TRUNC;
2263 if (completedBuffer) {
2264 netbuf_delete(completedBuffer);
2265 }
else if (completedPacket) {
2273 }
while (vectorIndex <
static_cast<size_t>(msghdr->msg_iovlen));
2283 N_NOTICE(
" -> " << totalLen);
2284 if (!tcp && (inputFlags & MSG_TRUNC) && totalLen < packetLength) {
2285 return packetLength;
2290int LwipSocketSyscalls::listen(
int backlog) {
2291 err_t err = netconn_listen_with_backlog(m_Socket, backlog);
2293 N_NOTICE(
" -> lwIP error");
2294 lwipToSyscallError(err);
2300 m_Metadata.listening =
true;
2306int LwipSocketSyscalls::bind(
const struct sockaddr_storage* address, socklen_t addrlen) {
2309 err_t conversion = sockaddrToIpaddr(address, port, &ipaddr);
2310 if (conversion !=
ERR_OK) {
2311 lwipToSyscallError(conversion);
2315 err_t err = netconn_bind(m_Socket, &ipaddr, port);
2317 N_NOTICE(
" -> lwIP error");
2318 lwipToSyscallError(err);
2327 struct netconn* new_conn;
2328 err_t err = netconn_accept(m_Socket, &new_conn);
2330 N_NOTICE(
" -> lwIP error");
2331 lwipToSyscallError(err);
2338 err = netconn_peer(new_conn, &peer, &port);
2340 netconn_delete(new_conn);
2341 lwipToSyscallError(err);
2346 struct sockaddr_in* sin =
reinterpret_cast<struct sockaddr_in*
>(address);
2347 sin->sin_family = AF_INET;
2348 sin->sin_port = HOST_TO_BIG16(port);
2349 sin->sin_addr.s_addr = peer.u_addr.ip4.addr;
2350 *addrlen =
sizeof(sockaddr_in);
2353 obj->m_Socket = new_conn;
2356 const ReadyMask previous = obj->readinessLevelLocked();
2357 obj->m_Metadata.send = 1;
2358 obj->recordReadinessRisesLocked(previous);
2364 setSocketDescriptorFlags(desc, flags);
2368 const size_t fd = installDescriptor(desc, installed);
2371 *accepted = pedigree_std::move(installed);
2373 obj->associate(desc);
2375 return static_cast<int>(fd);
2378int LwipSocketSyscalls::shutdown(
int how) {
2381 if (how == SHUT_RDWR) {
2383 }
else if (how == SHUT_RD) {
2385 }
else if (how == SHUT_WR) {
2388 SYSCALL_ERROR(InvalidArgument);
2392 err_t err = netconn_shutdown(m_Socket, rx, tx);
2394 lwipToSyscallError(err);
2398 ReadyMask changed = ReadyNone;
2401 const ReadyMask previous = readinessLevelLocked();
2403 m_Metadata.closed =
true;
2404 changed |= ReadyRead | ReadyReadHangup;
2407 m_Metadata.writeClosed =
true;
2408 changed |= ReadyWrite;
2410 if ((m_Metadata.closed || m_Metadata.peerClosed) && m_Metadata.writeClosed) {
2411 changed |= ReadyHangup;
2413 recordReadinessRisesLocked(previous);
2423 err_t err = netconn_peer(m_Socket, &peer, &port);
2425 N_NOTICE(
" -> getpeername failed");
2426 lwipToSyscallError(err);
2431 struct sockaddr_in* sin =
reinterpret_cast<struct sockaddr_in*
>(address);
2432 sin->sin_family = AF_INET;
2433 sin->sin_port = HOST_TO_BIG16(port);
2434 sin->sin_addr.s_addr = peer.u_addr.ip4.addr;
2435 *address_len =
sizeof(sockaddr_in);
2443 err_t err = netconn_addr(m_Socket, &self, &port);
2445 lwipToSyscallError(err);
2450 struct sockaddr_in* sin =
reinterpret_cast<struct sockaddr_in*
>(address);
2451 sin->sin_family = AF_INET;
2452 sin->sin_port = HOST_TO_BIG16(port);
2453 sin->sin_addr.s_addr = self.u_addr.ip4.addr;
2454 *address_len =
sizeof(sockaddr_in);
2459int LwipSocketSyscalls::setsockopt(
int level,
int optname,
const void* optvalue, socklen_t optlen) {
2460 if (optlen <
sizeof(
int)) {
2461 SYSCALL_ERROR(InvalidArgument);
2465 const int value = *
reinterpret_cast<const int*
>(optvalue);
2466 if (level == SOL_SOCKET) {
2467 const uint8_t option = lwipSocketOption(optname);
2470 struct ip_pcb* pcb = m_Socket ? m_Socket->pcb.ip :
nullptr;
2472 UNLOCK_TCPIP_CORE();
2473 SYSCALL_ERROR(InvalidArgument);
2482 UNLOCK_TCPIP_CORE();
2487 if (m_Protocol == IPPROTO_TCP && level == IPPROTO_TCP) {
2488#pragma GCC diagnostic push
2489#pragma GCC diagnostic ignored "-Wold-style-cast"
2490 if (optname == linuxTcpNoDelay) {
2492 struct tcp_pcb* pcb = m_Socket ? m_Socket->pcb.tcp :
nullptr;
2494 UNLOCK_TCPIP_CORE();
2495 SYSCALL_ERROR(InvalidArgument);
2499 N_NOTICE(
" -> TCP_NODELAY");
2500 N_NOTICE(
" --> val=" << value);
2504 tcp_nagle_disable(pcb);
2506 tcp_nagle_enable(pcb);
2509 UNLOCK_TCPIP_CORE();
2512#pragma GCC diagnostic pop
2515 SYSCALL_ERROR(ProtocolNotAvailable);
2519int LwipSocketSyscalls::getsockopt(
int level,
int optname,
void* optvalue, socklen_t* optlen) {
2520 if (*optlen <
sizeof(
int)) {
2521 SYSCALL_ERROR(InvalidArgument);
2526 bool clearedError =
false;
2527 if (level == SOL_SOCKET) {
2528 if (optname == SO_TYPE) {
2530 }
else if (optname == SO_ERROR) {
2533 const ReadyMask previous = readinessLevelLocked();
2534 value = lwipErrorNumber(m_Metadata.error);
2535 clearedError = m_Metadata.error !=
ERR_OK;
2536 m_Metadata.error =
ERR_OK;
2537 recordReadinessRisesLocked(previous);
2540 const uint8_t option = lwipSocketOption(optname);
2542 SYSCALL_ERROR(ProtocolNotAvailable);
2546 struct ip_pcb* pcb = m_Socket ? m_Socket->pcb.ip :
nullptr;
2548 UNLOCK_TCPIP_CORE();
2549 SYSCALL_ERROR(InvalidArgument);
2553 UNLOCK_TCPIP_CORE();
2555 }
else if (m_Protocol == IPPROTO_TCP && level == IPPROTO_TCP && optname == linuxTcpNoDelay) {
2557 struct tcp_pcb* pcb = m_Socket ? m_Socket->pcb.tcp :
nullptr;
2559 UNLOCK_TCPIP_CORE();
2560 SYSCALL_ERROR(InvalidArgument);
2563 value = tcp_nagle_disabled(pcb) ? 1 : 0;
2564 UNLOCK_TCPIP_CORE();
2566 SYSCALL_ERROR(ProtocolNotAvailable);
2570 *
reinterpret_cast<int*
>(optvalue) = value;
2571 *optlen =
sizeof(int);
2578bool LwipSocketSyscalls::canPoll()
const {
2582ReadyMask LwipSocketSyscalls::readinessLevelLocked()
const {
2583 ReadyMask ready = ReadyNone;
2584 if (m_Metadata.recv || m_Metadata.partialRead || m_Metadata.receivingQueuedData ||
2585 m_Metadata.closed || m_Metadata.peerClosed) {
2588 if (m_Metadata.send && m_Metadata.error ==
ERR_OK) {
2589 ready |= ReadyWrite;
2591 if (m_Metadata.closed || m_Metadata.peerClosed) {
2592 ready |= ReadyReadHangup;
2594 if ((m_Metadata.closed || m_Metadata.peerClosed) && m_Metadata.writeClosed) {
2595 ready |= ReadyHangup;
2597 if (m_Metadata.error !=
ERR_OK) {
2598 ready |= ReadyError;
2604void LwipSocketSyscalls::recordReadinessRisesLocked(ReadyMask previous) {
2605 const ReadyMask current = readinessLevelLocked();
2606 if (!(previous & ReadyRead) && (current & ReadyRead)) {
2607 ++m_Metadata.generations.read;
2609 if (!(previous & ReadyWrite) && (current & ReadyWrite)) {
2610 ++m_Metadata.generations.write;
2612 if (!(previous & ReadyError) && (current & ReadyError)) {
2613 ++m_Metadata.generations.error;
2615 if (!(previous & ReadyHangup) && (current & ReadyHangup)) {
2616 ++m_Metadata.generations.hangup;
2618 if (!(previous & ReadyReadHangup) && (current & ReadyReadHangup)) {
2619 ++m_Metadata.generations.readHangup;
2628 return ReadyInvalid | ReadyHangup;
2631 if (hasLastDescriptorClosed()) {
2632 return ReadyInvalid | ReadyHangup;
2636 ReadyMask ready = readinessLevelLocked();
2638 ready &= ~ReadyRead;
2641 ready &= ~ReadyWrite;
2643 return ready | pendingReceiveReadiness();
2653 return withReceiveErrorGeneration(m_Metadata.generations);
2659 if (!(read || write || error)) {
2667 write = m_Metadata.send != 0;
2672 read = m_Metadata.recv || m_Metadata.partialRead || m_Metadata.closed || m_Metadata.peerClosed;
2677 error = m_Metadata.error !=
ERR_OK || pendingReceiveReadiness();
2692 for (
auto it = m_Metadata.semaphores.
begin(); it != m_Metadata.semaphores.
end();) {
2694 it = m_Metadata.semaphores.
erase(it);
2707 obj = m_SyscallObjects.
lookup(conn);
2712 if (conn && conn->socket < 0 && evt == NETCONN_EVT_RCVPLUS) {
2723 ReadyMask changed = ReadyNone;
2726 const ReadyMask previous = obj->readinessLevelLocked();
2729 case NETCONN_EVT_RCVPLUS:
2731 ++(obj->m_Metadata.recv);
2732 changed |= ReadyRead;
2733 if (NETCONNTYPE_GROUP(conn->type) == NETCONN_TCP && !len && !obj->m_Metadata.listening) {
2734 obj->m_Metadata.peerClosed =
true;
2735 changed |= ReadyReadHangup;
2736 if (obj->m_Metadata.writeClosed) {
2737 changed |= ReadyHangup;
2741 case NETCONN_EVT_RCVMINUS:
2743 if (obj->m_Metadata.recv) {
2744 --(obj->m_Metadata.recv);
2747 case NETCONN_EVT_SENDPLUS:
2749 obj->m_Metadata.send = 1;
2750 changed |= ReadyWrite;
2752 case NETCONN_EVT_SENDMINUS:
2754 obj->m_Metadata.send = 0;
2755 changed |= ReadyWrite;
2757 case NETCONN_EVT_ERROR:
2759 obj->m_Metadata.error = netconn_err(conn);
2760 if (obj->m_Metadata.error ==
ERR_OK) {
2761 obj->m_Metadata.error =
ERR_IF;
2763 changed |= ReadyError;
2766 N_NOTICE(
"Unknown netconn callback error.");
2769 obj->recordReadinessRisesLocked(previous);
2773 for (
auto& it : obj->m_Metadata.semaphores) {
2783void LwipSocketSyscalls::lwipToSyscallError(
err_t err) {
2785 N_NOTICE(
" -> lwip strerror gives '" << lwip_strerr(err) <<
"'");
2786 syscallError(lwipErrorNumber(err));
2790LwipSocketSyscalls::LwipMetadata::LwipMetadata()
2799 receivingQueuedData(false),
2807enum class UnixSocketReferenceOwnership { Heap, Vfs };
2812 : m_Socket(socket), m_Ownership(ownership) {}
2819 if (m_Ownership == UnixSocketReferenceOwnership::Vfs) {
2820 releaseTrackedUnixSocket(m_Socket);
2832 UnixSocketReferenceOwnership m_Ownership;
2836static Mutex g_AbstractUnixSocketsLock;
2841 : m_Reference(reference), m_Retired(
false) {}
2848 UnixSocketSyscalls::unregisterSocket(socket, peers);
2849 for (
auto peer : peers) {
2850 UnixSocketSyscalls::notifySocket(
2851 peer, ReadyRead | ReadyWrite | ReadyError | ReadyReadHangup | ReadyHangup);
2859 return m_Reference ? m_Reference->get() :
nullptr;
2867 if (m_Retired.compareAndSwap(
false,
true)) {
2880#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
2881using UnixEndpointReceiveLeaseHook = void (*)();
2882static UnixEndpointReceiveLeaseHook g_UnixEndpointReceiveLeaseHook =
nullptr;
2883static UnixEndpointMutationLockHook g_UnixEndpointMutationLockHook =
nullptr;
2884static UnixEndpointReadinessLeaseHook g_UnixEndpointReadinessLeaseHook =
nullptr;
2886void invokeUnixEndpointMutationLockHook() {
2887 UnixEndpointMutationLockHook hook =
2888 __atomic_exchange_n(&g_UnixEndpointMutationLockHook,
2889 static_cast<UnixEndpointMutationLockHook
>(
nullptr), __ATOMIC_ACQ_REL);
2895void invokeUnixEndpointReadinessLeaseHook() {
2896 UnixEndpointReadinessLeaseHook hook =
2897 __atomic_exchange_n(&g_UnixEndpointReadinessLeaseHook,
2898 static_cast<UnixEndpointReadinessLeaseHook
>(
nullptr), __ATOMIC_ACQ_REL);
2905#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
2906void setUnixEndpointMutationLockHookForTest(UnixEndpointMutationLockHook hook) {
2907 __atomic_store_n(&g_UnixEndpointMutationLockHook, hook, __ATOMIC_RELEASE);
2910void setUnixEndpointReadinessLeaseHookForTest(UnixEndpointReadinessLeaseHook hook) {
2911 __atomic_store_n(&g_UnixEndpointReadinessLeaseHook, hook, __ATOMIC_RELEASE);
2915UnixSocketSyscalls::EndpointMutationGuard::EndpointMutationGuard(
UnixSocketSyscalls& socket)
2916 : m_Socket(socket), m_Guard(socket.m_EndpointMutationLock) {
2917#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
2918 invokeUnixEndpointMutationLockHook();
2922UnixSocketSyscalls::EndpointMutationGuard::~EndpointMutationGuard() {
2923 m_Socket.m_EndpointMutationReleaseInProgress =
true;
2926 m_Socket.m_EndpointMutationReleaseInProgress =
false;
2927 m_Socket.tryCompleteEndpointClose();
2930UnixSocketSyscalls::EndpointMutationPairGuard::EndpointMutationPairGuard(
UnixSocketSyscalls& first,
2936#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
2937 invokeUnixEndpointMutationLockHook();
2941UnixSocketSyscalls::EndpointMutationPairGuard::~EndpointMutationPairGuard() {
2942 m_First.m_EndpointMutationReleaseInProgress =
true;
2943 m_Second.m_EndpointMutationReleaseInProgress =
true;
2950 m_First.m_EndpointMutationReleaseInProgress =
false;
2951 m_Second.m_EndpointMutationReleaseInProgress =
false;
2952 m_First.tryCompleteEndpointClose();
2953 m_Second.tryCompleteEndpointClose();
2956UnixSocketSyscalls::EndpointReadinessGuard::EndpointReadinessGuard()
2957 : m_Socket(nullptr), m_Lifetime(), m_Lease(), m_Acquired(false) {}
2959UnixSocketSyscalls::EndpointReadinessGuard::EndpointReadinessGuard(
UnixSocketSyscalls& socket)
2960 : EndpointReadinessGuard() {
2961 const bool acquired = acquire(socket);
2965bool UnixSocketSyscalls::EndpointReadinessGuard::acquire(
UnixSocketSyscalls& socket) {
2966 assert(!m_Acquired);
2968 m_Lifetime = socket.acquireDescriptorLifetime();
2970#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
2972 invokeUnixEndpointReadinessLeaseHook();
2982UnixSocketSyscalls::EndpointReadinessGuard::~EndpointReadinessGuard() {
2989 m_Socket->tryCompleteEndpointClose();
2992UnixSocketSyscalls::UnixSocketSyscalls(
int domain,
int type,
int protocol)
2996 m_EndpointMutationReleaseInProgress(false),
2997 m_EndpointClosePending(false),
2998 m_EndpointRetired(false),
2999 m_EndpointCloseFinalized(false),
3002 m_ClosingLocalEndpoint(),
3003 m_ClosingRemoteEndpoint(),
3006 m_OwnsAbstractName(false) {}
3008UnixSocketSyscalls::~UnixSocketSyscalls() {
3012void UnixSocketSyscalls::registerSocket(
UnixSocket* socket) {
3020 m_SyscallObjects.
insert(socket,
this);
3021 }
else if (current !=
this) {
3022 FATAL(
"A Unix socket has multiple NetworkSyscalls owners.");
3026 m_PendingListeners.
remove(socket);
3030 if (!socket || !peer) {
3035 m_Peers.
insert(socket, peer);
3036 m_Peers.
insert(peer, socket);
3038 m_PendingListeners.
insert(peer, listener);
3043 if (!socket || !peer) {
3048 if (m_Peers.
lookup(socket) == peer) {
3051 if (m_Peers.
lookup(peer) == socket) {
3054 m_PendingListeners.
remove(peer);
3065 m_SyscallObjects.
remove(socket);
3071 if (m_Peers.
lookup(peer) == socket) {
3074 m_PendingListeners.
remove(peer);
3076 m_PendingListeners.
remove(socket);
3082 it != m_PendingListeners.
end(); ++it) {
3083 if (it.value() == socket) {
3084 pendingEndpoints.
pushBack(it.key());
3088 for (
auto pending : pendingEndpoints) {
3093 if (m_Peers.
lookup(pendingPeer) == pending) {
3094 m_Peers.
remove(pendingPeer);
3097 m_PendingListeners.
remove(pending);
3102void UnixSocketSyscalls::notifySocket(
UnixSocket* socket, ReadyMask mask) {
3103 if (!socket || !mask) {
3108 EndpointReadinessGuard notification;
3111 target = m_SyscallObjects.
lookup(socket);
3112 if (!target || !notification.acquire(*target)) {
3121void UnixSocketSyscalls::notifyPeer(
UnixSocket* socket, ReadyMask mask) {
3126 peer = m_Peers.
lookup(socket);
3130 notifySocket(peer, mask);
3133bool UnixSocketSyscalls::publishAbstractSocket(
3135 const String key = abstractKey(address);
3137 if (g_AbstractUnixSockets.contains(key)) {
3138 SYSCALL_ERROR(AddressInUse);
3141 if (!g_AbstractUnixSockets.insert(key, reference)) {
3142 SYSCALL_ERROR(OutOfMemory);
3149 if (isAbstractUnixSocket(address)) {
3150 const String key = abstractKey(address);
3152 auto result = g_AbstractUnixSockets.lookup(key);
3153 if (!result.hasValue()) {
3154 SYSCALL_ERROR(DoesNotExist);
3157 return result.value();
3160 File* file = findTrackedUnixSocket(address);
3162 SYSCALL_ERROR(DoesNotExist);
3166 releaseTrackedUnixSocket(file);
3167 SYSCALL_ERROR(DoesNotExist);
3174void UnixSocketSyscalls::removeAbstractSocket(
const String& address,
UnixSocket* socket) {
3175 const String key = abstractKey(address);
3177 auto current = g_AbstractUnixSockets.lookup(key);
3178 if (current.hasValue() && current.value()->get() == socket) {
3179 g_AbstractUnixSockets.remove(key);
3183String UnixSocketSyscalls::abstractKey(
const String& address)
const {
3188 m_NetworkNamespace ?
static_cast<unsigned long long>(m_NetworkNamespace->identity()) : 0ULL,
3196 return m_LocalEndpoint;
3199void UnixSocketSyscalls::replaceLocalEndpoint(
UnixSocket* socket,
bool tracked,
3200 const String* localPath) {
3202 socket, tracked ? UnixSocketReferenceOwnership::Vfs : UnixSocketReferenceOwnership::Heap));
3203 replaceLocalEndpoint(reference, localPath,
false);
3207 const String* localPath,
bool ownsAbstractName) {
3208 UnixSocket* socket = reference ? reference->
get() :
nullptr;
3212 registerSocket(socket);
3215 previous = pedigree_std::move(m_LocalEndpoint);
3216 m_LocalEndpoint = pedigree_std::move(replacement);
3218 m_LocalPath = *localPath;
3220 m_OwnsAbstractName = ownsAbstractName;
3234 m_EndpointClosePending =
true;
3236 }
else if (!m_EndpointClosePending) {
3245 tryCompleteEndpointClose();
3248void UnixSocketSyscalls::tryCompleteEndpointClose() {
3249 if (!m_EndpointClosePending || m_EndpointCloseFinalized || m_EndpointMutationReleaseInProgress) {
3258 if (!m_EndpointRetired) {
3266 if (!m_EndpointRetired) {
3267 m_EndpointMutationReleaseInProgress =
true;
3272 if (m_OwnsAbstractName && isAbstractUnixSocket(m_LocalPath) && m_LocalEndpoint) {
3273 abstractName = m_LocalPath;
3274 abstractSocket = m_LocalEndpoint->get();
3276 m_ClosingLocalEndpoint = pedigree_std::move(m_LocalEndpoint);
3277 m_ClosingRemoteEndpoint = pedigree_std::move(m_RemoteEndpoint);
3278 m_LocalPath.clear();
3279 m_RemotePath.clear();
3280 m_OwnsAbstractName =
false;
3283 if (abstractSocket) {
3284 removeAbstractSocket(abstractName, abstractSocket);
3287 if (m_ClosingLocalEndpoint) {
3290 m_ClosingLocalEndpoint->retire();
3293 m_EndpointRetired =
true;
3296 m_EndpointMutationReleaseInProgress =
false;
3300 !m_EndpointCloseFinalized.compareAndSwap(
false,
true)) {
3304 N_NOTICE(
"UnixSocketSyscalls::~UnixSocketSyscalls");
3305 m_ClosingLocalEndpoint.
reset();
3306 m_ClosingRemoteEndpoint.
reset();
3308 m_EndpointClosePending =
false;
3315 if (hasLastDescriptorClosed()) {
3316 SYSCALL_ERROR(BadFileDescriptor);
3322 registerSocket(local->
get());
3327 replaceLocalEndpoint(
3328 new UnixSocket(
String(), g_pUnixSocketBacking,
nullptr,
nullptr, getSocketType()),
false);
3333int UnixSocketSyscalls::connect(
const struct sockaddr_storage* address, socklen_t addrlen) {
3335 if (!unixSocketPath(address, addrlen, pathname,
false)) {
3339 EndpointMutationGuard mutationGuard(*
this);
3340 if (hasLastDescriptorClosed()) {
3341 SYSCALL_ERROR(BadFileDescriptor);
3346 SYSCALL_ERROR(BadFileDescriptor);
3351 N_NOTICE(
" -> unix connect: '" << pathname <<
"'");
3354 if (!targetReference) {
3355 N_NOTICE(
" -> unix socket '" << pathname <<
"' doesn't exist");
3360 if (getType() != SOCK_DGRAM) {
3361 N_NOTICE(
" -> connection-oriented");
3362 if (target->getType() != getSocketType()) {
3363 SYSCALL_ERROR(ProtocolWrongType);
3366 if (target->getState() != UnixSocket::Listening) {
3367 SYSCALL_ERROR(ConnectionRefused);
3375 localPath = m_LocalPath;
3378 new UnixSocket(localPath, g_pUnixSocketBacking,
nullptr,
nullptr, getSocketType());
3383 if (!localSocket->bind(remote,
false)) {
3385 SYSCALL_ERROR(IsConnected);
3388 registerPeer(localSocket, remote, target);
3389 if (!target->addSocket(remote)) {
3390 unregisterPeer(localSocket, remote);
3391 remote->failConnection();
3393 SYSCALL_ERROR(ConnectionRefused);
3396 notifySocket(target, ReadyRead);
3398 N_NOTICE(
" -> stream connected and queued");
3400 if (target->getType() != UnixSocket::Datagram) {
3401 SYSCALL_ERROR(ProtocolWrongType);
3404 if (target->getState() == UnixSocket::Closed) {
3405 SYSCALL_ERROR(ConnectionRefused);
3408 N_NOTICE(
" -> dgram");
3414 previousRemote = pedigree_std::move(m_RemoteEndpoint);
3415 m_RemoteEndpoint = pedigree_std::move(targetReference);
3416 m_RemotePath = pathname;
3419 if (getType() == SOCK_DGRAM) {
3423 N_NOTICE(
" -> remote is now " << pathname);
3425 if (getType() != SOCK_DGRAM && !isBlocking()) {
3426 SYSCALL_ERROR(InProgress);
3433ssize_t UnixSocketSyscalls::sendto_msg(
const struct msghdr* msghdr,
3435 N_NOTICE(
"UnixSocketSyscalls::sendto_msg");
3442 local = m_LocalEndpoint;
3443 remoteReference = m_RemoteEndpoint;
3444 localPath = m_LocalPath;
3447 SYSCALL_ERROR(BadFileDescriptor);
3452 const bool blocking = isBlocking() && !(msghdr->msg_flags & MSG_DONTWAIT);
3453 if (getType() != SOCK_DGRAM) {
3454 if (localSocket->wasConnected()) {
3455 remoteReference = local->reference();
3457 remoteReference.
reset();
3461 UnixSocket* remote = remoteReference ? remoteReference->
get() :
nullptr;
3462 if (getType() != SOCK_DGRAM && !remote) {
3463 const bool closed = localSocket->getState() == UnixSocket::Closed;
3464 N_NOTICE(
" -> " << (closed ?
"closed" :
"not connected"));
3465 syscallError(closed ? Error::BrokenPipe : Error::NotConnected);
3468 if (getType() != SOCK_DGRAM && localSocket->writeShutdown()) {
3469 SYSCALL_ERROR(BrokenPipe);
3473 if (getType() == SOCK_DGRAM && (msghdr->msg_name || !remote)) {
3474 if (!msghdr->msg_name) {
3475 syscallError(EDESTADDRREQ);
3476 N_NOTICE(
" -> sendto on unconnected socket with no address");
3481 if (!unixSocketPath(
reinterpret_cast<const struct sockaddr_storage*
>(msghdr->msg_name),
3482 msghdr->msg_namelen, pathname,
false)) {
3486 N_NOTICE(
" -> unix connect: '" << pathname <<
"'");
3488 remoteReference = acquireSocket(pathname);
3489 if (!remoteReference) {
3490 N_NOTICE(
" -> unix socket '" << pathname <<
"' doesn't exist");
3493 remote = remoteReference->
get();
3496 if (getType() == SOCK_DGRAM && (!remote || remote->getType() != UnixSocket::Datagram ||
3497 remote->getState() == UnixSocket::Closed)) {
3498 syscallError(remote && remote->getType() != UnixSocket::Datagram ? Error::ProtocolWrongType
3499 : Error::ConnectionRefused);
3503 if (getType() == SOCK_STREAM) {
3504 bool hasPayload =
false;
3505 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
3506 if (msghdr->msg_iov[i].iov_len) {
3516 N_NOTICE(
" -> transmitting!");
3518 uint64_t numWritten = 0;
3519 bool completedWrite =
false;
3520 bool interrupted =
false;
3521 int packetError = 0;
3522 if (getType() != SOCK_STREAM) {
3523 size_t datagramLength = 0;
3524 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
3525 if (msghdr->msg_iov[i].iov_len >
static_cast<size_t>(SSIZE_MAX) - datagramLength) {
3526 SYSCALL_ERROR(InvalidArgument);
3529 datagramLength += msghdr->msg_iov[i].iov_len;
3533 const void* buffer =
nullptr;
3534 if (datagramLength) {
3537 SYSCALL_ERROR(OutOfMemory);
3541 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
3542 MemoryCopy(datagram.get() + offset, msghdr->msg_iov[i].iov_base,
3543 msghdr->msg_iov[i].iov_len);
3544 offset += msghdr->msg_iov[i].iov_len;
3546 buffer = datagram.get();
3549 if (getType() == SOCK_SEQPACKET) {
3550 completedWrite = localSocket->
sendPacket(datagramLength,
reinterpret_cast<uintptr_t
>(buffer),
3551 blocking, rights, &packetError);
3554 remote->
sendDatagram(datagramLength,
reinterpret_cast<uintptr_t
>(buffer), blocking,
3555 reinterpret_cast<uintptr_t
>(localPath.cstr()), rights, &packetError);
3557 numWritten = completedWrite ? datagramLength : 0;
3559 numWritten = localSocket->
sendStream(msghdr->msg_iov,
static_cast<size_t>(msghdr->msg_iovlen),
3560 isBlocking(), rights, &interrupted);
3561 completedWrite = numWritten;
3563 if (completedWrite) {
3564 if (getType() != SOCK_DGRAM) {
3565 notifyPeer(localSocket, ReadyRead);
3567 notifySocket(remote, ReadyRead);
3570 if (!completedWrite) {
3572 syscallError(packetError);
3576 SYSCALL_ERROR(Interrupted);
3577 N_NOTICE(
" -> -1 (EINTR)");
3581 if (getType() != SOCK_DGRAM &&
3582 (localSocket->getState() == UnixSocket::Closed || localSocket->writeShutdown())) {
3583 SYSCALL_ERROR(BrokenPipe);
3584 N_NOTICE(
" -> -1 (EPIPE)");
3589 SYSCALL_ERROR(NoMoreProcesses);
3590 N_NOTICE(
" -> -1 (EAGAIN)");
3594 N_NOTICE(
" -> " << numWritten);
3598ssize_t UnixSocketSyscalls::recvfrom_msg(
struct msghdr* msghdr,
3604 const int inputFlags = msghdr->msg_flags;
3605 const bool blocking = isBlocking() && !(inputFlags & MSG_DONTWAIT);
3607 if ((inputFlags & MSG_TRUNC) && getType() == SOCK_STREAM) {
3608 SYSCALL_ERROR(OperationNotSupported);
3615 SYSCALL_ERROR(BadFileDescriptor);
3619 if (getType() == SOCK_SEQPACKET && !localSocket->wasConnected()) {
3620 SYSCALL_ERROR(NotConnected);
3625 uint64_t numRead = 0;
3626 uint64_t datagramLength = 0;
3627 bool consumedDatagram =
false;
3628 bool interrupted =
false;
3629 if (getType() != SOCK_STREAM) {
3630 size_t datagramCapacity = 0;
3631 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen); ++i) {
3632 if (msghdr->msg_iov[i].iov_len >
static_cast<size_t>(SSIZE_MAX) - datagramCapacity) {
3633 SYSCALL_ERROR(InvalidArgument);
3636 datagramCapacity += msghdr->msg_iov[i].iov_len;
3640 void* buffer =
nullptr;
3641 if (datagramCapacity) {
3644 SYSCALL_ERROR(OutOfMemory);
3647 buffer = datagram.get();
3651 if (getType() == SOCK_SEQPACKET) {
3652 consumedDatagram = localSocket->receivePacket(
3653 datagramCapacity,
reinterpret_cast<uintptr_t
>(buffer), blocking, receivedRights, numRead,
3654 datagramLength, &interrupted);
3657 localSocket->
receiveDatagram(datagramCapacity,
reinterpret_cast<uintptr_t
>(buffer),
3658 blocking, remote, receivedRights, numRead, datagramLength);
3661 *rights = receivedRights;
3663 if (consumedDatagram && numRead) {
3665 for (
size_t i = 0; i < static_cast<size_t>(msghdr->msg_iovlen) && offset < numRead; ++i) {
3666 const size_t remaining =
static_cast<size_t>(numRead) - offset;
3667 const size_t amount =
3668 msghdr->msg_iov[i].iov_len < remaining ? msghdr->msg_iov[i].iov_len : remaining;
3669 MemoryCopy(msghdr->msg_iov[i].iov_base, datagram.get() + offset, amount);
3674 numRead = localSocket->
receiveStream(msghdr->msg_iov,
static_cast<size_t>(msghdr->msg_iovlen),
3675 blocking, rights, &interrupted);
3678#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
3679 UnixEndpointReceiveLeaseHook leaseHook =
3680 __atomic_load_n(&g_UnixEndpointReceiveLeaseHook, __ATOMIC_ACQUIRE);
3690 if ((numRead || consumedDatagram) && getType() != SOCK_DGRAM) {
3693 notifyPeer(localSocket, ReadyWrite);
3696 if ((numRead || consumedDatagram) && msghdr->msg_name) {
3697 writeUnixSocketAddress(remote,
reinterpret_cast<struct sockaddr_storage*
>(msghdr->msg_name),
3698 &msghdr->msg_namelen);
3701 msghdr->msg_flags = 0;
3703 if (consumedDatagram && numRead < datagramLength) {
3704 msghdr->msg_flags |= MSG_TRUNC;
3707 if (!numRead && !consumedDatagram) {
3709 SYSCALL_ERROR(Interrupted);
3710 N_NOTICE(
" -> -1 (EINTR)");
3714 if (getType() != SOCK_DGRAM && (localSocket->getState() == UnixSocket::Closed ||
3715 (getType() == SOCK_SEQPACKET && localSocket->readShutdown()))) {
3716 N_NOTICE(
" -> 0 (EOF)");
3721 SYSCALL_ERROR(NoMoreProcesses);
3722 N_NOTICE(
" -> -1 (EAGAIN)");
3728 if (consumedDatagram && (inputFlags & MSG_TRUNC)) {
3729 N_NOTICE(
" -> " << datagramLength);
3730 return datagramLength;
3733 N_NOTICE(
" -> " << numRead);
3742 SYSCALL_ERROR(BadFileDescriptor);
3747 if (localSocket->getType() == UnixSocket::Datagram) {
3748 SYSCALL_ERROR(OperationNotSupported);
3754 if (!localSocket->markListening()) {
3755 SYSCALL_ERROR(InvalidArgument);
3764 String adjusted_pathname;
3765 if (!unixSocketPath(address, addrlen, adjusted_pathname,
true)) {
3768 if (!adjusted_pathname.length()) {
3774 if (hasLastDescriptorClosed()) {
3775 SYSCALL_ERROR(BadFileDescriptor);
3780 if (!m_LocalEndpoint) {
3781 SYSCALL_ERROR(BadFileDescriptor);
3784 if (m_LocalPath.length()) {
3785 SYSCALL_ERROR(InvalidArgument);
3790 N_NOTICE(
" -> unix bind: '" << adjusted_pathname <<
"'");
3792 if (isAbstractUnixSocket(adjusted_pathname)) {
3794 new UnixSocket(
String(), g_pUnixSocketBacking,
nullptr,
nullptr, getSocketType());
3796 SYSCALL_ERROR(OutOfMemory);
3802 if (!publishAbstractSocket(adjusted_pathname, reference)) {
3806 replaceLocalEndpoint(reference, &adjusted_pathname,
true);
3811 if (adjusted_pathname.
endswith(
'/')) {
3813 SYSCALL_ERROR(IsADirectory);
3818 auto context = process->acquireFilesystemContext();
3820 if (!context || !view) {
3821 SYSCALL_ERROR(DoesNotExist);
3826 if (!view->resolveParent(context,
FilesystemPathRef(), adjusted_pathname, parent, basename))
3828 parentLease.retain(parent);
3829 if (!parent || parent->provider() != view || !parent->node()->
isDirectory()) {
3830 SYSCALL_ERROR(NotADirectory);
3833 if (!basename.length() || basename ==
"." || basename ==
"..") {
3834 SYSCALL_ERROR(AddressInUse);
3837 if (basename.length() > NAME_MAX) {
3838 SYSCALL_ERROR(NameTooLong);
3841 File* parentDirectory = parent->node();
3842 if (parentDirectory->getFilesystem()->
isReadOnly()) {
3843 SYSCALL_ERROR(ReadOnlyFilesystem);
3848 UnixSocket* socket =
new UnixSocket(basename, parentDirectory->getFilesystem(), parentDirectory,
3849 nullptr, getSocketType());
3851 SYSCALL_ERROR(OutOfMemory);
3858 const Directory::AddStatus addStatus =
3859 view->createEphemeral(parent, socket, LandlockAccess::MakeSock);
3860 if (addStatus != Directory::AddStatus::Added) {
3864 syscallError(error);
3865 }
else if (addStatus == Directory::AddStatus::IoError) {
3866 SYSCALL_ERROR(IoError);
3867 }
else if (addStatus == Directory::AddStatus::Detached) {
3868 SYSCALL_ERROR(DoesNotExist);
3870 SYSCALL_ERROR(AddressInUse);
3874 N_NOTICE(
" -> basename=" << basename);
3879 replaceLocalEndpoint(socket,
true, &adjusted_pathname);
3885int UnixSocketSyscalls::accept(
struct sockaddr_storage* address, socklen_t* addrlen,
int flags,
3887 N_NOTICE(
"unix accept");
3892 local = m_LocalEndpoint;
3893 localPath = m_LocalPath;
3896 SYSCALL_ERROR(BadFileDescriptor);
3902 SYSCALL_ERROR(OutOfMemory);
3908 N_NOTICE(
"accept() failed");
3909 SYSCALL_ERROR(NoMoreProcesses);
3914 N_NOTICE(
"accept() got a socket");
3916 writeUnixSocketAddress(remote->
getName(), address, addrlen);
3918 obj->m_NetworkNamespace = m_NetworkNamespace;
3919 obj->m_RemotePath = remote->
getName();
3920 obj->replaceLocalEndpoint(remote,
false, &localPath);
3925 setSocketDescriptorFlags(desc, flags);
3929 const size_t fd = installDescriptor(desc, installed);
3932 *accepted = pedigree_std::move(installed);
3934 obj->associate(desc);
3936 return static_cast<int>(fd);
3946int UnixSocketSyscalls::shutdown(
int how) {
3947 N_NOTICE(
"UnixSocketSyscalls::shutdown");
3948 if (how != SHUT_RD && how != SHUT_WR && how != SHUT_RDWR) {
3949 SYSCALL_ERROR(InvalidArgument);
3955 SYSCALL_ERROR(BadFileDescriptor);
3959 if (!socket->shutdown(how)) {
3963 notifySocket(socket, ReadyRead | ReadyWrite);
3964 notifyPeer(socket, ReadyRead | ReadyWrite);
3968int UnixSocketSyscalls::getpeername(
struct sockaddr_storage* address, socklen_t* address_len) {
3969 N_NOTICE(
"UNIX getpeername");
3974 local = m_LocalEndpoint;
3975 remotePath = m_RemotePath;
3978 SYSCALL_ERROR(BadFileDescriptor);
3981 if (!local->
get()->wasConnected()) {
3982 SYSCALL_ERROR(NotConnected);
3986 writeUnixSocketAddress(remotePath, address, address_len);
3988 N_NOTICE(
" -> " << remotePath);
3992int UnixSocketSyscalls::getsockname(
struct sockaddr_storage* address, socklen_t* address_len) {
3993 N_NOTICE(
"UNIX getsockname");
3997 if (!m_LocalEndpoint) {
3998 SYSCALL_ERROR(BadFileDescriptor);
4001 localPath = m_LocalPath;
4003 writeUnixSocketAddress(localPath, address, address_len);
4005 N_NOTICE(
" -> " << localPath);
4009int UnixSocketSyscalls::setsockopt(
int level,
int optname,
const void* optvalue, socklen_t optlen) {
4010 if (level == SOL_SOCKET && optname == SO_REUSEADDR) {
4011 if (optlen <
sizeof(
int)) {
4012 SYSCALL_ERROR(InvalidArgument);
4018 (void)*
reinterpret_cast<const int*
>(optvalue);
4022 SYSCALL_ERROR(ProtocolNotAvailable);
4026int UnixSocketSyscalls::getsockopt(
int level,
int optname,
void* optvalue, socklen_t* optlen) {
4027 if (level == SOL_SOCKET) {
4028 if (optname == SO_TYPE || optname == SO_ERROR) {
4029 if (*optlen <
sizeof(
int)) {
4030 SYSCALL_ERROR(InvalidArgument);
4034 int value = getType();
4035 if (optname == SO_ERROR) {
4038 SYSCALL_ERROR(BadFileDescriptor);
4042 const UnixSocket::SocketState state = localSocket->getState();
4043 if (localSocket->wasConnected()) {
4045 }
else if (state == UnixSocket::Connecting) {
4046 value = Error::InProgress;
4047 }
else if (state == UnixSocket::Closed) {
4048 value = Error::ConnectionRefused;
4050 value = Error::NotConnected;
4054 *
reinterpret_cast<int*
>(optvalue) = value;
4055 *optlen =
sizeof(value);
4057 }
else if (optname == SO_PEERCRED) {
4058 N_NOTICE(
" -> SO_PEERCRED");
4061 SYSCALL_ERROR(BadFileDescriptor);
4065 if (!localSocket->wasConnected()) {
4066 SYSCALL_ERROR(NotConnected);
4069 if (*optlen <
sizeof(
struct ucred)) {
4070 SYSCALL_ERROR(InvalidArgument);
4075 struct ucred* targetCreds =
reinterpret_cast<struct ucred*
>(optvalue);
4076 struct ucred sourceCreds = localSocket->getPeerCredentials();
4078 N_NOTICE(
" --> pid=" <<
Dec << sourceCreds.pid);
4079 N_NOTICE(
" --> uid=" <<
Dec << sourceCreds.uid);
4080 N_NOTICE(
" --> gid=" <<
Dec << sourceCreds.gid);
4082 *targetCreds = sourceCreds;
4083 *optlen =
sizeof(sourceCreds);
4089 SYSCALL_ERROR(ProtocolNotAvailable);
4093bool UnixSocketSyscalls::canPoll()
const {
4094 return static_cast<bool>(acquireLocalEndpoint());
4102 return ReadyInvalid | ReadyHangup;
4105 if (hasLastDescriptorClosed()) {
4106 return ReadyInvalid | ReadyHangup;
4111 return ReadyInvalid;
4115 const UnixSocket::SocketState state = local->getState();
4116 if (state == UnixSocket::Closed) {
4117 ReadyMask ready = ReadyHangup;
4119 ready |= ReadyRead | ReadyReadHangup;
4121 if (!local->wasConnected()) {
4122 ready |= ReadyError;
4124 return ready | pendingReceiveReadiness();
4127 ReadyMask ready = ReadyNone;
4128 if (reading && local->
select(
false, 0)) {
4130 if (local->readShutdown()) {
4131 ready |= ReadyReadHangup;
4136 if (getType() == SOCK_DGRAM) {
4139 ready |= ReadyWrite;
4140 }
else if (local->
select(
true, 0)) {
4141 ready |= ReadyWrite;
4145 return ready | pendingReceiveReadiness();
4150 if (!query || hasLastDescriptorClosed()) {
4155 return withReceiveErrorGeneration(endpoint ? endpoint->
get()->readinessGenerations()
4159bool UnixSocketSyscalls::poll(
bool& read,
bool& write,
bool& error,
Semaphore*
waiter) {
4162 const bool checkRead = read;
4163 const bool checkWrite = write;
4166 error = pendingReceiveReadiness();
4173 const UnixSocket::SocketState state = local->getState();
4174 if (state == UnixSocket::Closed) {
4185 read = local->
select(
false, 0);
4190 write = local->
select(
true, 0);
4195 local->addWaiter(
waiter, checkRead, checkWrite);
4208bool UnixSocketSyscalls::monitor(
Thread* pThread,
Event* pEvent) {
4214 local->
get()->addWaiter(pThread, pEvent);
4218bool UnixSocketSyscalls::unmonitor(
Event* pEvent) {
4224 local->
get()->removeWaiter(pEvent);
4229 if (!other || other ==
this) {
4238 firstMutation = secondMutation;
4239 secondMutation = temporary;
4243 if (hasLastDescriptorClosed() || other->hasLastDescriptorClosed()) {
4249 if (!local || !otherLocal) {
4255 if (!localSocket->bind(otherSocket)) {
4259 registerPeer(localSocket, otherSocket);
4262 otherSocket->acknowledgeBind();
4268 previousRemote = pedigree_std::move(m_RemoteEndpoint);
4269 m_RemoteEndpoint = otherLocal->reference();
4273 otherPreviousRemote = pedigree_std::move(other->m_RemoteEndpoint);
4274 other->m_RemoteEndpoint = local->reference();
4277 other->notifyReadiness(ReadyWrite);
4281UnixSocket::SocketType UnixSocketSyscalls::getSocketType()
const {
4282 if (getType() == SOCK_STREAM) {
4283 return UnixSocket::Streaming;
4285 if (getType() == SOCK_SEQPACKET) {
4286 return UnixSocket::SequencedPacket;
4289 return UnixSocket::Datagram;
4292#if HOSTED && PEDIGREE_HOSTED_SMOKE_TESTS
4294class UnixEndpointLifetimeProbe :
public UnixSocket {
4298 m_Destructions(destructions) {}
4300 ~UnixEndpointLifetimeProbe()
override {
4301 m_Destructions += 1;
4308struct UnixEndpointReplacementContext {
4312 continueReceive(0, false),
4327UnixEndpointReplacementContext* g_UnixEndpointReplacementContext =
nullptr;
4329void holdRetiredUnixEndpointLease() {
4330 UnixEndpointReplacementContext* context = g_UnixEndpointReplacementContext;
4335 context->leaseHeld += 1;
4336 context->continueReceive.acquire();
4339int blockedUnixEndpointReceive(
void* parameter) {
4340 UnixEndpointReplacementContext* context =
4341 reinterpret_cast<UnixEndpointReplacementContext*
>(parameter);
4343 struct iovec vector = {&byte,
sizeof(byte)};
4348 context->entered += 1;
4349 context->result = context->socket->recvfrom_msg(&
message,
nullptr);
4350 context->returned += 1;
4355bool runHostedUnixEndpointLifetimeRegression(
Process* process) {
4356 constexpr size_t Attempts = 10000;
4359 socket.replaceLocalEndpoint(
new UnixEndpointLifetimeProbe(destructions),
false);
4361 UnixEndpointReplacementContext context(&socket);
4363 new Thread(process, blockedUnixEndpointReceive, &context,
nullptr,
false,
true,
true);
4364 receiver->setName(
"hosted Unix endpoint generation receive");
4365 context.receiver = receiver;
4366 g_UnixEndpointReplacementContext = &context;
4367 __atomic_store_n(&g_UnixEndpointReceiveLeaseHook, &holdRetiredUnixEndpointLease,
4369 const bool started = receiver->
start();
4371 bool blocked =
false;
4372 for (
size_t attempt = 0; attempt < Attempts && started; ++attempt) {
4374 uintptr_t debugAddress = 0;
4375 if (context.entered == 1 && !context.returned && receiver->
getWaitDebugInfo(info) &&
4376 info.queue && info.queued && receiver->
getDebugState(debugAddress) == Thread::SemWait) {
4383 String replacementPath(
"hosted-replacement");
4384 socket.replaceLocalEndpoint(
new UnixEndpointLifetimeProbe(destructions),
false, &replacementPath);
4385 bool leaseHeld =
false;
4386 for (
size_t attempt = 0; attempt < Attempts && started; ++attempt) {
4388 if (context.leaseHeld == 1 && receiver->
getWaitDebugInfo(info) && info.queue && info.queued &&
4389 info.channelOwner == &context.continueReceive) {
4395 const bool retainedWhileInUse = leaseHeld && destructions == 0;
4396 context.continueReceive.release();
4397 const bool joined = started && receiver->
join();
4398 __atomic_store_n(&g_UnixEndpointReceiveLeaseHook,
nullptr, __ATOMIC_RELEASE);
4399 g_UnixEndpointReplacementContext =
nullptr;
4401 bool passed = started && blocked && retainedWhileInUse && joined && context.returned == 1 &&
4402 context.result == 0 && destructions == 1 &&
4403 (socket.
queryReady(
true,
true) & ReadyWrite);
4404 socket.lastDescriptorClosed();
4405 passed = passed && destructions == 2;
4409 "HOSTED-SYSCALL-TEST: FAIL unix-bind-replacement-lifetime: "
4410 "endpoint replacement freed a blocked receive generation or failed to wake it");
4414 NOTICE(
"HOSTED-SYSCALL-TEST: PASS unix-bind-replacement-lifetime");
SharedPointer< EpollInstance > epollImpl
Epoll implementation for this descriptor (if it is an epoll object).
void setNetworkImpl(const SharedPointer< NetworkSyscalls > &implementation)
void setFlags(int newFlags)
Set flags, distributing any associated changes as needed.
bool eventFdPublished() const
SharedPointer< EventFd > getEventFdImpl() const
int getStatusFlags() const
Get current status flags.
void setStatusFlags(int newFlags)
Set status flags, distributing any associated changes as needed.
SharedPointer< NetworkSyscalls > networkImpl
Network syscall implementation for this descriptor (if it's a socket).
size_t fd
Descriptor number.
bool networkPublished() const
virtual bool retainVfsReference()
virtual void releaseVfsReference()
virtual bool isSocket() const
virtual bool isDirectory()
virtual ReadyMask queryReady(bool reading, bool writing)
static void netconnCallback(struct netconn *conn, enum netconn_evt evt, uint16_t len)
ReadinessGenerations readinessGenerations() override
virtual int connect(const struct sockaddr_storage *address, socklen_t addrlen)
virtual void lastDescriptorClosed()
virtual int getpeername(struct sockaddr_storage *address, socklen_t *address_len)
virtual int accept(struct sockaddr_storage *address, socklen_t *addrlen, int flags, DescriptorLease *accepted=nullptr)
virtual ReadyMask queryReady(bool reading, bool writing)
virtual bool poll(bool &read, bool &write, bool &error, Semaphore *waiter)
virtual bool create()
Implementation-specific final socket creation logic.
virtual int getsockname(struct sockaddr_storage *address, socklen_t *address_len)
bool isOwnedByCurrentThread() const
bool beginDescriptorClose()
virtual ReadyMask queryReady(bool reading, bool writing)
MUST_USE_RESULT bool addDescriptorOwner()
virtual void lastDescriptorClosed()
OperationBarrier m_ReadinessNotifications
ReadinessGenerations readinessGenerations() override
void retainDescriptorLifetime(const SharedPointer< NetworkSyscalls > &lifetime)
MUST_USE_RESULT bool tryAcquire(Lease &lease)
bool closeFileDescriptor(size_t fd, const DescriptorLease &descriptor)
static bool copyFromUser(void *destination, const void *source, size_t count, size_t elementSize=1)
size_t installFileDescriptor(FileDescriptor *descriptor, DescriptorLease &lease, size_t minimum=0)
static bool checkUserBuffer(uintptr_t addr, size_t count, size_t elementSize, size_t flags, size_t *extent=nullptr)
static bool copyToUser(void *destination, const void *source, size_t count, size_t elementSize=1)
static bool checkAddress(uintptr_t addr, size_t extent, size_t flags)
static ProcessorInformation & information()
void notifyReadiness(ReadyMask mask)
void closeReadiness(ReadyMask mask=ReadyInvalid|ReadyHangup)
static Scheduler & instance()
bool tryAcquire(size_t n=1)
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
static bool create(size_t descriptorCount, SharedPointer< SocketRights > &rights)
bool endswith(const char c) const
bool getWaitDebugInfo(WaitDebugInfo &info)
DebugState getDebugState(uintptr_t &address)
An iterator applicable for many data structures.
void remove(const K &key)
E lookup(const K &key) const
void insert(const K &key, const E &value)
virtual int listen(int backlog)
virtual void lastDescriptorClosed()
ReadinessGenerations readinessGenerations() override
bool pairWith(UnixSocketSyscalls *other)
virtual int bind(const struct sockaddr_storage *address, socklen_t addrlen)
virtual bool create()
Implementation-specific final socket creation logic.
Mutex m_EndpointMutationLock
virtual ReadyMask queryReady(bool reading, bool writing)
Mutex m_EndpointStateLock
uint64_t sendStream(uint64_t size, uintptr_t buffer, bool bCanBlock, const SharedPointer< SocketRights > &rights, bool *interrupted=nullptr)
bool sendDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, uintptr_t source, const SharedPointer< SocketRights > &rights, int *error=nullptr)
uint64_t receiveStream(uint64_t size, uintptr_t buffer, bool bCanBlock, SharedPointer< SocketRights > *rights, bool *interrupted=nullptr)
virtual int select(bool bWriting=false, int timeout=0)
bool receiveDatagram(uint64_t size, uintptr_t buffer, bool bCanBlock, String &from, SharedPointer< SocketRights > &rights, uint64_t &bytesRead, uint64_t &datagramLength)
bool sendPacket(uint64_t size, uintptr_t buffer, bool bCanBlock, const SharedPointer< SocketRights > &rights, int *error=nullptr)
static bool checkAccess(File *pFile, bool bRead, bool bWrite, bool bExecute)
void trackFile(File *pFile)
Track a File object that exists. It is necessary to keep track of File objects, or at least those tha...
Iterator erase(Iterator &Iter)
void pushBack(const T &value)
u8_t pbuf_free(struct pbuf *p)
u16_t pbuf_copy_partial(const struct pbuf *buf, void *dataptr, u16_t len, u16_t offset)
#define ip_set_option(pcb, opt)
#define ip_get_option(pcb, opt)
#define ip_reset_option(pcb, opt)