Files
sdk/runtime/bin/eventhandler_fuchsia.h
T
Slava Egorov e50d3b98a3 [io] Support Unix domain sockets on Windows
Basic support for Unix domain sockets on Windows within
the limitations of the operating system itself: no 
support for abstract addresses, datagram or 
packet sockets and ancillary data.

This also fixes File::GetType on Windows to correctly
identify reparse points representing AF_UNIX sockets
as such, rather then identify them as links.

Finally, it is worth noting that there is an existing
discrepancy between POSIX OSes and Windows: on POSIX OSes
File(sockPath).existsSync() returns true, but on Windows the 
same code returns false because Unix domain sockets are not 
considered regular files by stat. 

This CL does a bunch of refactoring around RawAddr class which
surves as a wrapper around various structures in sockaddr_* family.
Distinguishing anonymous AF_UNIX address from abstract AF_UNIX
address requires passing around the length of the address
structure. Thus we incorporate this information into
RawAddr. This will also make possible to properly support
full-range of abstract AF_UNIX addresses in the future because
supporting these requires properly handling embedded NUL bytes.
(See https://github.com/dart-lang/sdk/issues/46158).

Fixes https://github.com/dart-lang/sdk/issues/41161

TEST=standalone/io/unix_socket

Cq-Include-Trybots: luci.dart.try:vm-fuchsia-release-x64-try
Change-Id: I016cb33ebdd62f0cac1ae97d822105366a6a6964
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/457720
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Slava Egorov <vegorov@google.com>
2025-10-29 05:25:24 -07:00

180 lines
5.0 KiB
C++

// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
#ifndef RUNTIME_BIN_EVENTHANDLER_FUCHSIA_H_
#define RUNTIME_BIN_EVENTHANDLER_FUCHSIA_H_
#if !defined(RUNTIME_BIN_EVENTHANDLER_H_)
#error Do not include eventhandler_fuchsia.h directly; use eventhandler.h.
#endif
#include <errno.h>
#include <lib/fdio/unsafe.h>
#include <sys/socket.h>
#include <unistd.h>
#include <zircon/status.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/object.h>
#include <zircon/syscalls/port.h>
#include "bin/reference_counting.h"
#include "bin/thread.h"
#include "platform/signal_blocker.h"
namespace dart {
namespace bin {
class DescriptorInfo;
struct RawAddr;
class IOHandle : public ReferenceCounted<IOHandle> {
public:
explicit IOHandle(intptr_t fd)
: ReferenceCounted(),
mutex_(),
write_events_enabled_(true),
read_events_enabled_(true),
close_events_enabled_(true),
fd_(fd),
handle_(ZX_HANDLE_INVALID),
wait_key_(0),
fdio_(fdio_unsafe_fd_to_io(fd)) {}
intptr_t fd() const { return fd_; }
// Called from SocketBase::{Read(), Write()} and ServerSocket::Accept() on
// the Dart thread.
intptr_t Read(void* buffer, intptr_t num_bytes);
intptr_t Write(const void* buffer, intptr_t num_bytes);
intptr_t Accept(RawAddr* addr);
intptr_t AvailableBytes();
// Called from the EventHandler thread.
void Close();
uint32_t MaskToEpollEvents(intptr_t mask);
// If port is ZX_HANDLE_INVALID, AsyncWait uses the port from the previous
// call with a valid port handle.
bool AsyncWait(zx_handle_t port, uint32_t events, uint64_t key);
void CancelWait(zx_handle_t port, uint64_t key);
uint32_t WaitEnd(zx_signals_t observed);
intptr_t ToggleEvents(intptr_t event_mask);
static intptr_t EpollEventsToMask(intptr_t events);
private:
~IOHandle() {
if (fdio_ != nullptr) {
fdio_unsafe_release(fdio_);
}
}
bool AsyncWaitLocked(zx_handle_t port, uint32_t events, uint64_t key);
// Mutex that protects the state here.
Mutex mutex_;
bool write_events_enabled_;
bool read_events_enabled_;
bool close_events_enabled_;
// Bytes remaining to be read from the socket. Read events should only be
// re-enabled when this drops to zero.
intptr_t available_bytes_;
// TODO(zra): Add flag to enable/disable peer closed signal?
intptr_t fd_;
zx_handle_t handle_;
zx_handle_t port_;
uint64_t wait_key_;
fdio_t* fdio_;
friend class ReferenceCounted<IOHandle>;
DISALLOW_COPY_AND_ASSIGN(IOHandle);
};
class DescriptorInfo : public DescriptorInfoBase {
public:
explicit DescriptorInfo(intptr_t fd) : DescriptorInfoBase(fd) {
IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
handle->Retain();
}
virtual ~DescriptorInfo() {
IOHandle* handle = reinterpret_cast<IOHandle*>(fd_);
handle->Release();
}
virtual void Close() {
IOHandle* handle = reinterpret_cast<IOHandle*>(fd_);
handle->Close();
}
IOHandle* io_handle() const { return reinterpret_cast<IOHandle*>(fd_); }
private:
DISALLOW_COPY_AND_ASSIGN(DescriptorInfo);
};
class DescriptorInfoSingle : public DescriptorInfoSingleMixin<DescriptorInfo> {
public:
explicit DescriptorInfoSingle(intptr_t fd) : DescriptorInfoSingleMixin(fd) {}
virtual ~DescriptorInfoSingle() {}
private:
DISALLOW_COPY_AND_ASSIGN(DescriptorInfoSingle);
};
class DescriptorInfoMultiple
: public DescriptorInfoMultipleMixin<DescriptorInfo> {
public:
explicit DescriptorInfoMultiple(intptr_t fd)
: DescriptorInfoMultipleMixin(fd) {}
virtual ~DescriptorInfoMultiple() {}
private:
DISALLOW_COPY_AND_ASSIGN(DescriptorInfoMultiple);
};
class EventHandlerImplementation {
public:
EventHandlerImplementation();
~EventHandlerImplementation();
void UpdatePort(intptr_t old_mask, DescriptorInfo* di);
// Gets the socket data structure for a given file
// descriptor. Creates a new one if one is not found.
DescriptorInfo* GetDescriptorInfo(intptr_t fd, bool is_listening);
void SendData(intptr_t id, Dart_Port dart_port, int64_t data);
void Start(EventHandler* handler);
void Shutdown();
private:
static constexpr uint64_t kInterruptPacketKey = 1;
static void Poll(uword args);
static void* GetHashmapKeyFromFd(intptr_t fd);
static uint32_t GetHashmapHashFromFd(intptr_t fd);
static void AddToPort(zx_handle_t port_handle, DescriptorInfo* di);
static void RemoveFromPort(zx_handle_t port_handle, DescriptorInfo* di);
int64_t GetTimeout() const;
void HandlePacket(zx_port_packet_t* pkt);
void HandleTimeout();
void WakeupHandler(intptr_t id, Dart_Port dart_port, int64_t data);
intptr_t GetPollEvents(intptr_t events);
void HandleInterrupt(InterruptMessage* msg);
SimpleHashMap socket_map_;
TimeoutQueue timeout_queue_;
bool shutdown_;
zx_handle_t port_handle_;
DISALLOW_COPY_AND_ASSIGN(EventHandlerImplementation);
};
} // namespace bin
} // namespace dart
#endif // RUNTIME_BIN_EVENTHANDLER_FUCHSIA_H_