mirror of
https://github.com/dart-lang/sdk
synced 2024-11-05 18:22:09 +00:00
3c298dbca5
TEST=build Change-Id: I18fc7cfe725dc978d4b23de6191e455ac7cd75e5 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/293800 Reviewed-by: Siva Annamalai <asiva@google.com> Commit-Queue: Ryan Macnak <rmacnak@google.com>
325 lines
10 KiB
C++
325 lines
10 KiB
C++
// Copyright (c) 2013, 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_SOCKET_H_
|
|
#define RUNTIME_BIN_SOCKET_H_
|
|
|
|
#include "bin/builtin.h"
|
|
#include "bin/dartutils.h"
|
|
#include "bin/file.h"
|
|
#include "bin/reference_counting.h"
|
|
#include "bin/socket_base.h"
|
|
#include "bin/thread.h"
|
|
#include "bin/utils.h"
|
|
#include "platform/hashmap.h"
|
|
|
|
namespace dart {
|
|
namespace bin {
|
|
|
|
// TODO(bkonyi): Socket should also inherit from SocketBase once it is
|
|
// refactored to use instance methods when possible.
|
|
|
|
// We write Sockets into the native field of the _NativeSocket object
|
|
// on the Dart side. They are allocated in SetSocketIdNativeField(), and are
|
|
// deallocated either from the finalizer attached to _NativeSockets there, or
|
|
// from the eventhandler, whichever drops the last reference.
|
|
class Socket : public ReferenceCounted<Socket> {
|
|
public:
|
|
enum SocketRequest {
|
|
kLookupRequest = 0,
|
|
kListInterfacesRequest = 1,
|
|
kReverseLookupRequest = 2,
|
|
};
|
|
|
|
enum SocketFinalizer {
|
|
kFinalizerNormal,
|
|
kFinalizerListening,
|
|
kFinalizerStdio,
|
|
kFinalizerSignal,
|
|
};
|
|
|
|
// Keep in sync with constants in _NativeSocket in socket_patch.dart.
|
|
enum SocketType {
|
|
kTcpSocket = 18,
|
|
kUdpSocket = 19,
|
|
kInternalSocket = 20,
|
|
kInternalSignalSocket = 21,
|
|
};
|
|
|
|
explicit Socket(intptr_t fd);
|
|
|
|
intptr_t fd() const { return fd_; }
|
|
|
|
// Close fd and may need to decrement the count of handle by calling
|
|
// release().
|
|
void CloseFd();
|
|
// Set fd_ to closed. On fuchsia and win, shared socket should not
|
|
// release handle but only SetClosedFd().
|
|
void SetClosedFd();
|
|
|
|
Dart_Port isolate_port() const { return isolate_port_; }
|
|
|
|
Dart_Port port() const { return port_; }
|
|
void set_port(Dart_Port port) { port_ = port; }
|
|
|
|
uint8_t* udp_receive_buffer() const { return udp_receive_buffer_; }
|
|
void set_udp_receive_buffer(uint8_t* buffer) { udp_receive_buffer_ = buffer; }
|
|
|
|
static bool Initialize();
|
|
|
|
// Creates a socket which is bound and connected. The port to connect to is
|
|
// specified as the port component of the passed RawAddr structure.
|
|
static intptr_t CreateConnect(const RawAddr& addr);
|
|
static intptr_t CreateUnixDomainConnect(const RawAddr& addr);
|
|
// Creates a socket which is bound and connected. The port to connect to is
|
|
// specified as the port component of the passed RawAddr structure.
|
|
static intptr_t CreateBindConnect(const RawAddr& addr,
|
|
const RawAddr& source_addr);
|
|
static intptr_t CreateUnixDomainBindConnect(const RawAddr& addr,
|
|
const RawAddr& source_addr);
|
|
// Creates a datagram socket which is bound. The port to bind
|
|
// to is specified as the port component of the RawAddr structure.
|
|
static intptr_t CreateBindDatagram(const RawAddr& addr,
|
|
bool reuseAddress,
|
|
bool reusePort,
|
|
int ttl = 1);
|
|
|
|
static CObject* LookupRequest(const CObjectArray& request);
|
|
static CObject* ListInterfacesRequest(const CObjectArray& request);
|
|
static CObject* ReverseLookupRequest(const CObjectArray& request);
|
|
|
|
static Dart_Port GetServicePort();
|
|
|
|
static void SetSocketIdNativeField(Dart_Handle handle,
|
|
intptr_t id,
|
|
SocketFinalizer finalizer);
|
|
static void ReuseSocketIdNativeField(Dart_Handle handle,
|
|
Socket* socket,
|
|
SocketFinalizer finalizer);
|
|
static Socket* GetSocketIdNativeField(Dart_Handle socket);
|
|
|
|
static bool short_socket_read() { return short_socket_read_; }
|
|
static void set_short_socket_read(bool short_socket_read) {
|
|
short_socket_read_ = short_socket_read;
|
|
}
|
|
static bool short_socket_write() { return short_socket_write_; }
|
|
static void set_short_socket_write(bool short_socket_write) {
|
|
short_socket_write_ = short_socket_write;
|
|
}
|
|
|
|
static bool IsSignalSocketFlag(intptr_t flag) {
|
|
return ((flag & (0x1 << kInternalSignalSocket)) != 0);
|
|
}
|
|
|
|
private:
|
|
~Socket() {
|
|
ASSERT(fd_ == kClosedFd);
|
|
free(udp_receive_buffer_);
|
|
udp_receive_buffer_ = nullptr;
|
|
}
|
|
|
|
static constexpr int kClosedFd = -1;
|
|
|
|
static bool short_socket_read_;
|
|
static bool short_socket_write_;
|
|
|
|
intptr_t fd_;
|
|
Dart_Port isolate_port_;
|
|
Dart_Port port_;
|
|
uint8_t* udp_receive_buffer_;
|
|
|
|
friend class ReferenceCounted<Socket>;
|
|
DISALLOW_COPY_AND_ASSIGN(Socket);
|
|
};
|
|
|
|
class ServerSocket {
|
|
public:
|
|
static constexpr intptr_t kTemporaryFailure = -2;
|
|
|
|
static intptr_t Accept(intptr_t fd);
|
|
|
|
// Creates a socket which is bound and listens. The port to listen on is
|
|
// specified in the port component of the passed RawAddr structure.
|
|
//
|
|
// Returns a positive integer if the call is successful. In case of failure
|
|
// it returns:
|
|
//
|
|
// -1: system error (errno set)
|
|
// -5: invalid bindAddress
|
|
static intptr_t CreateBindListen(const RawAddr& addr,
|
|
intptr_t backlog,
|
|
bool v6_only = false);
|
|
static intptr_t CreateUnixDomainBindListen(const RawAddr& addr,
|
|
intptr_t backlog);
|
|
|
|
// Start accepting on a newly created listening socket. If it was unable to
|
|
// start accepting incoming sockets, the fd is invalidated.
|
|
static bool StartAccept(intptr_t fd);
|
|
|
|
private:
|
|
DISALLOW_ALLOCATION();
|
|
DISALLOW_IMPLICIT_CONSTRUCTORS(ServerSocket);
|
|
};
|
|
|
|
class ListeningSocketRegistry {
|
|
public:
|
|
ListeningSocketRegistry()
|
|
: sockets_by_port_(SameIntptrValue, kInitialSocketsCount),
|
|
sockets_by_fd_(SameIntptrValue, kInitialSocketsCount),
|
|
unix_domain_sockets_(nullptr),
|
|
mutex_() {}
|
|
|
|
~ListeningSocketRegistry() {
|
|
CloseAllSafe();
|
|
}
|
|
|
|
static void Initialize();
|
|
|
|
static ListeningSocketRegistry* Instance();
|
|
|
|
static void Cleanup();
|
|
|
|
// Bind `socket_object` to `addr`.
|
|
// Return Dart_True() if succeed.
|
|
// This function should be called from a dart runtime call in order to create
|
|
// a new (potentially shared) socket.
|
|
Dart_Handle CreateBindListen(Dart_Handle socket_object,
|
|
RawAddr addr,
|
|
intptr_t backlog,
|
|
bool v6_only,
|
|
bool shared);
|
|
// Bind unix domain socket`socket_object` to `path`.
|
|
// Return Dart_True() if succeed.
|
|
// This function should be called from a dart runtime call in order to create
|
|
// a new socket.
|
|
Dart_Handle CreateUnixDomainBindListen(Dart_Handle socket_object,
|
|
Namespace* namespc,
|
|
const char* path,
|
|
intptr_t backlog,
|
|
bool shared);
|
|
|
|
// This should be called from the event handler for every kCloseEvent it gets
|
|
// on listening sockets.
|
|
//
|
|
// Returns `true` if the last reference has been dropped and the underlying
|
|
// socket can be closed.
|
|
//
|
|
// The caller is responsible for obtaining the mutex first, before calling
|
|
// this function.
|
|
bool CloseSafe(Socket* socketfd);
|
|
|
|
Mutex* mutex() { return &mutex_; }
|
|
|
|
private:
|
|
struct OSSocket {
|
|
RawAddr address;
|
|
int port;
|
|
bool v6_only;
|
|
bool shared;
|
|
int ref_count;
|
|
intptr_t fd;
|
|
|
|
// Only applicable to Unix domain socket, where address.addr.sa_family
|
|
// == AF_UNIX.
|
|
Namespace* namespc;
|
|
|
|
// Singly linked lists of OSSocket instances which listen on the same port
|
|
// but on different addresses.
|
|
OSSocket* next;
|
|
|
|
OSSocket(RawAddr address,
|
|
int port,
|
|
bool v6_only,
|
|
bool shared,
|
|
Socket* socketfd,
|
|
Namespace* namespc)
|
|
: address(address),
|
|
port(port),
|
|
v6_only(v6_only),
|
|
shared(shared),
|
|
ref_count(0),
|
|
namespc(namespc),
|
|
next(nullptr) {
|
|
fd = socketfd->fd();
|
|
}
|
|
};
|
|
|
|
static constexpr intptr_t kInitialSocketsCount = 8;
|
|
|
|
OSSocket* FindOSSocketWithAddress(OSSocket* current, const RawAddr& addr) {
|
|
while (current != nullptr) {
|
|
if (SocketAddress::AreAddressesEqual(current->address, addr)) {
|
|
return current;
|
|
}
|
|
current = current->next;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
OSSocket* FindOSSocketWithPath(OSSocket* current,
|
|
Namespace* namespc,
|
|
const char* path) {
|
|
while (current != nullptr) {
|
|
ASSERT(current->address.addr.sa_family == AF_UNIX);
|
|
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
|
bool condition;
|
|
if (path[0] == '\0') {
|
|
condition = current->address.un.sun_path[0] == '\0' &&
|
|
strcmp(&(current->address.un.sun_path[1]), path + 1) == 0;
|
|
} else {
|
|
condition =
|
|
File::AreIdentical(current->namespc, current->address.un.sun_path,
|
|
namespc, path) == File::kIdentical;
|
|
}
|
|
if (condition) {
|
|
return current;
|
|
}
|
|
#else
|
|
if (File::AreIdentical(current->namespc, current->address.un.sun_path,
|
|
namespc, path) == File::kIdentical) {
|
|
return current;
|
|
}
|
|
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
|
current = current->next;
|
|
}
|
|
return nullptr;
|
|
}
|
|
|
|
static bool SameIntptrValue(void* key1, void* key2) {
|
|
return reinterpret_cast<intptr_t>(key1) == reinterpret_cast<intptr_t>(key2);
|
|
}
|
|
|
|
static uint32_t GetHashmapHashFromIntptr(intptr_t i) {
|
|
return static_cast<uint32_t>((i + 1) & 0xFFFFFFFF);
|
|
}
|
|
|
|
static void* GetHashmapKeyFromIntptr(intptr_t i) {
|
|
return reinterpret_cast<void*>(i + 1);
|
|
}
|
|
|
|
OSSocket* LookupByPort(intptr_t port);
|
|
void InsertByPort(intptr_t port, OSSocket* socket);
|
|
void RemoveByPort(intptr_t port);
|
|
|
|
OSSocket* LookupByFd(Socket* fd);
|
|
void InsertByFd(Socket* fd, OSSocket* socket);
|
|
void RemoveByFd(Socket* fd);
|
|
|
|
bool CloseOneSafe(OSSocket* os_socket, Socket* socket);
|
|
void CloseAllSafe();
|
|
|
|
SimpleHashMap sockets_by_port_;
|
|
SimpleHashMap sockets_by_fd_;
|
|
|
|
OSSocket* unix_domain_sockets_;
|
|
|
|
Mutex mutex_;
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(ListeningSocketRegistry);
|
|
};
|
|
|
|
} // namespace bin
|
|
} // namespace dart
|
|
|
|
#endif // RUNTIME_BIN_SOCKET_H_
|