[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>
This commit is contained in:
committed by
Commit Queue
parent
de2737affe
commit
e50d3b98a3
@@ -4,6 +4,18 @@
|
||||
|
||||
### Libraries
|
||||
|
||||
#### `dart:io`
|
||||
|
||||
- Added support for Unix domain sockets (`AF_UNIX`) on Windows. Support is
|
||||
restricted to subset of features supported by the OS. Windows currently does
|
||||
not support the following features for `AF_UNIX` sockets: datagram sockets,
|
||||
ancillary data or abstract socket addresses. Unix domain sockets are
|
||||
represented in the file-system using _reparse points_ which leads to some
|
||||
discrepancies in the behavior of `dart:io` APIs: for example
|
||||
`File(socketPath).existsSync()` will return `true` on POSIX operating systems,
|
||||
but `false` on Windows. Use `FileSystemEntity.typeSync()` instead to get
|
||||
portable behavior.
|
||||
|
||||
#### `dart:js_util`
|
||||
|
||||
- dart2wasm no longer supports `dart:js_util`. Any code that imports
|
||||
|
||||
@@ -127,9 +127,10 @@ intptr_t IOHandle::Write(const void* buffer, intptr_t num_bytes) {
|
||||
return written_bytes;
|
||||
}
|
||||
|
||||
intptr_t IOHandle::Accept(struct sockaddr* addr, socklen_t* addrlen) {
|
||||
intptr_t IOHandle::Accept(RawAddr* addr) {
|
||||
MutexLocker ml(&mutex_);
|
||||
const intptr_t socket = NO_RETRY_EXPECTED(accept(fd_, addr, addrlen));
|
||||
const intptr_t socket =
|
||||
NO_RETRY_EXPECTED(accept(fd_, &addr->addr, &addr->size));
|
||||
const int err = errno;
|
||||
LOG_INFO("IOHandle::Accept: fd = %ld. socket = %ld\n", fd_, socket);
|
||||
|
||||
|
||||
@@ -26,6 +26,7 @@ namespace dart {
|
||||
namespace bin {
|
||||
|
||||
class DescriptorInfo;
|
||||
struct RawAddr;
|
||||
|
||||
class IOHandle : public ReferenceCounted<IOHandle> {
|
||||
public:
|
||||
@@ -46,7 +47,7 @@ class IOHandle : public ReferenceCounted<IOHandle> {
|
||||
// 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(struct sockaddr* addr, socklen_t* addrlen);
|
||||
intptr_t Accept(RawAddr* addr);
|
||||
intptr_t AvailableBytes();
|
||||
|
||||
// Called from the EventHandler thread.
|
||||
|
||||
@@ -68,25 +68,17 @@ OverlappedBuffer::OverlappedBuffer(Handle* handle,
|
||||
: buflen_(buffer_size), operation_(operation), handle_(handle) {
|
||||
memset(GetBufferStart(), 0, GetBufferSize());
|
||||
if (operation == kRecvFrom) {
|
||||
// Reserve part of the buffer for the length of source sockaddr
|
||||
// and source sockaddr.
|
||||
const int kAdditionalSize =
|
||||
sizeof(struct sockaddr_storage) + sizeof(socklen_t);
|
||||
ASSERT(buflen_ > kAdditionalSize);
|
||||
buflen_ -= kAdditionalSize;
|
||||
from_len_addr_ =
|
||||
reinterpret_cast<socklen_t*>(GetBufferStart() + GetBufferSize());
|
||||
*from_len_addr_ = sizeof(struct sockaddr_storage);
|
||||
from_ = reinterpret_cast<struct sockaddr*>(from_len_addr_ + 1);
|
||||
// Reserve part of the buffer for the length of source address.
|
||||
ASSERT(buflen_ > sizeof(RawAddr));
|
||||
buflen_ -= sizeof(RawAddr);
|
||||
from_ = reinterpret_cast<RawAddr*>(GetBufferStart() + GetBufferSize());
|
||||
// WSARecv needs to know how many bytes it can write.
|
||||
from_->size = sizeof(sockaddr_storage);
|
||||
} else {
|
||||
from_len_addr_ = nullptr;
|
||||
from_ = nullptr;
|
||||
}
|
||||
index_ = 0;
|
||||
data_length_ = 0;
|
||||
if (operation_ == kAccept) {
|
||||
client_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
}
|
||||
|
||||
// Retain handle for the duration of the operation.
|
||||
handle->Retain();
|
||||
@@ -114,8 +106,13 @@ std::unique_ptr<OverlappedBuffer> OverlappedBuffer::AllocateBuffer(
|
||||
}
|
||||
|
||||
std::unique_ptr<OverlappedBuffer> OverlappedBuffer::AllocateAcceptBuffer(
|
||||
Handle* handle) {
|
||||
return AllocateBuffer(handle, 2 * kAcceptExAddressStorageSize, kAccept);
|
||||
Handle* handle,
|
||||
ADDRESS_FAMILY sa_family) {
|
||||
auto result =
|
||||
AllocateBuffer(handle, 2 * kAcceptExAddressStorageSize, kAccept);
|
||||
result->client_ =
|
||||
socket(sa_family, SOCK_STREAM, sa_family == AF_UNIX ? 0 : IPPROTO_TCP);
|
||||
return result;
|
||||
}
|
||||
|
||||
std::unique_ptr<OverlappedBuffer> OverlappedBuffer::AllocateReadBuffer(
|
||||
@@ -129,7 +126,7 @@ std::unique_ptr<OverlappedBuffer> OverlappedBuffer::AllocateRecvFromBuffer(
|
||||
int buffer_size) {
|
||||
// For calling recvfrom additional buffer space is needed for the source
|
||||
// address information.
|
||||
buffer_size += sizeof(socklen_t) + sizeof(struct sockaddr_storage);
|
||||
buffer_size += sizeof(RawAddr);
|
||||
return AllocateBuffer(handle, buffer_size, kRecvFrom);
|
||||
}
|
||||
|
||||
@@ -405,8 +402,7 @@ bool Handle::IssueWriteLocked(MonitorLocker* ml,
|
||||
|
||||
bool Handle::IssueSendToLocked(MonitorLocker* ml,
|
||||
std::unique_ptr<OverlappedBuffer> buffer,
|
||||
struct sockaddr* sa,
|
||||
socklen_t sa_len) {
|
||||
const RawAddr& addr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -493,7 +489,7 @@ void SocketHandle::HandleIssueError() {
|
||||
}
|
||||
|
||||
bool ListenSocket::IssueAcceptLocked(MonitorLocker* ml) {
|
||||
auto buffer = OverlappedBuffer::AllocateAcceptBuffer(this);
|
||||
auto buffer = OverlappedBuffer::AllocateAcceptBuffer(this, sa_family_);
|
||||
DWORD received;
|
||||
BOOL ok;
|
||||
ok = EventHandler::delegate()->accept_ex()(
|
||||
@@ -546,12 +542,14 @@ void ListenSocket::AcceptComplete(std::unique_ptr<OverlappedBuffer> buffer) {
|
||||
buffer->GetBufferStart(), 0, kAcceptExAddressStorageSize,
|
||||
kAcceptExAddressStorageSize, &local_addr, &local_addr_length,
|
||||
&remote_addr, &remote_addr_length);
|
||||
RawAddr* raw_remote_addr = new RawAddr;
|
||||
memmove(raw_remote_addr, remote_addr, remote_addr_length);
|
||||
|
||||
auto raw_remote_addr = std::make_unique<RawAddr>();
|
||||
memmove(&raw_remote_addr->addr, remote_addr, remote_addr_length);
|
||||
raw_remote_addr->size = remote_addr_length;
|
||||
|
||||
// Insert the accepted socket into the list.
|
||||
ClientSocket* client_socket =
|
||||
new ClientSocket(client, std::unique_ptr<RawAddr>(raw_remote_addr));
|
||||
new ClientSocket(client, std::move(raw_remote_addr));
|
||||
client_socket->mark_connected();
|
||||
if (accepted_head_ == nullptr) {
|
||||
accepted_head_ = client_socket;
|
||||
@@ -662,24 +660,14 @@ intptr_t Handle::Read(void* buffer, intptr_t num_bytes) {
|
||||
return num_bytes;
|
||||
}
|
||||
|
||||
intptr_t Handle::RecvFrom(void* buffer,
|
||||
intptr_t num_bytes,
|
||||
struct sockaddr* sa,
|
||||
socklen_t sa_len) {
|
||||
intptr_t Handle::RecvFrom(void* buffer, intptr_t num_bytes, RawAddr* from) {
|
||||
MonitorLocker ml(&monitor_);
|
||||
if (data_ready_ == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
num_bytes =
|
||||
data_ready_->Read(buffer, Utils::Minimum<intptr_t>(num_bytes, INT_MAX));
|
||||
if (data_ready_->from()->sa_family == AF_INET) {
|
||||
ASSERT(sa_len >= sizeof(struct sockaddr_in));
|
||||
memmove(sa, data_ready_->from(), sizeof(struct sockaddr_in));
|
||||
} else {
|
||||
ASSERT(data_ready_->from()->sa_family == AF_INET6);
|
||||
ASSERT(sa_len >= sizeof(struct sockaddr_in6));
|
||||
memmove(sa, data_ready_->from(), sizeof(struct sockaddr_in6));
|
||||
}
|
||||
*from = *data_ready_->from();
|
||||
// Always dispose of the buffer, as UDP messages must be read in their
|
||||
// entirety to match how recvfrom works in a socket.
|
||||
data_ready_ = nullptr;
|
||||
@@ -709,8 +697,7 @@ intptr_t Handle::Write(const void* data, intptr_t num_bytes) {
|
||||
|
||||
intptr_t Handle::SendTo(const void* data,
|
||||
intptr_t num_bytes,
|
||||
struct sockaddr* sa,
|
||||
socklen_t sa_len) {
|
||||
const RawAddr& addr) {
|
||||
MonitorLocker ml(&monitor_);
|
||||
if (HasPendingWrite() || IsClosed()) {
|
||||
return 0;
|
||||
@@ -726,7 +713,7 @@ intptr_t Handle::SendTo(const void* data,
|
||||
}
|
||||
auto buffer = OverlappedBuffer::AllocateSendToBuffer(this, num_bytes);
|
||||
buffer->Write(data, num_bytes);
|
||||
if (!IssueSendToLocked(&ml, std::move(buffer), sa, sa_len)) {
|
||||
if (!IssueSendToLocked(&ml, std::move(buffer), addr)) {
|
||||
return -1;
|
||||
}
|
||||
return num_bytes;
|
||||
@@ -975,14 +962,14 @@ bool ClientSocket::PopulateRemoteAddr(RawAddr& addr) {
|
||||
|
||||
bool DatagramSocket::IssueSendToLocked(MonitorLocker* ml,
|
||||
std::unique_ptr<OverlappedBuffer> buffer,
|
||||
struct sockaddr* sa,
|
||||
socklen_t sa_len) {
|
||||
const RawAddr& addr) {
|
||||
ASSERT(!HasPendingWrite());
|
||||
ASSERT(buffer->operation() == OverlappedBuffer::kSendTo);
|
||||
|
||||
pending_write_ = buffer.get();
|
||||
int rc = WSASendTo(socket(), pending_write_->GetWASBUF(), 1, nullptr, 0, sa,
|
||||
sa_len, pending_write_->GetCleanOverlapped(), nullptr);
|
||||
int rc = WSASendTo(socket(), pending_write_->GetWASBUF(), 1, nullptr, 0,
|
||||
&addr.addr, addr.size,
|
||||
pending_write_->GetCleanOverlapped(), nullptr);
|
||||
if ((rc == NO_ERROR) || (WSAGetLastError() == WSA_IO_PENDING)) {
|
||||
buffer.release(); // HandleIOCompletion will take ownership.
|
||||
return true;
|
||||
@@ -1001,7 +988,7 @@ bool DatagramSocket::IssueRecvFromLocked(MonitorLocker* ml) {
|
||||
pending_read_ = buffer.get();
|
||||
DWORD flags = 0;
|
||||
int rc = WSARecvFrom(socket(), buffer->GetWASBUF(), 1, nullptr, &flags,
|
||||
buffer->from(), buffer->from_len_addr(),
|
||||
&buffer->from()->addr, &buffer->from()->size,
|
||||
buffer->GetCleanOverlapped(), nullptr);
|
||||
if ((rc == NO_ERROR) || (WSAGetLastError() == WSA_IO_PENDING)) {
|
||||
buffer.release(); // HandleIOCompletion will take ownership.
|
||||
|
||||
@@ -47,7 +47,9 @@ class OverlappedBuffer {
|
||||
kConnect
|
||||
};
|
||||
|
||||
static std::unique_ptr<OverlappedBuffer> AllocateAcceptBuffer(Handle* handle);
|
||||
static std::unique_ptr<OverlappedBuffer> AllocateAcceptBuffer(
|
||||
Handle* handle,
|
||||
ADDRESS_FAMILY sa_family);
|
||||
static std::unique_ptr<OverlappedBuffer> AllocateReadBuffer(Handle* handle,
|
||||
int buffer_size);
|
||||
static std::unique_ptr<OverlappedBuffer> AllocateRecvFromBuffer(
|
||||
@@ -86,9 +88,7 @@ class OverlappedBuffer {
|
||||
SOCKET client() const { return client_; }
|
||||
char* GetBufferStart() { return reinterpret_cast<char*>(&buffer_data_); }
|
||||
int GetBufferSize() const { return buflen_; }
|
||||
struct sockaddr* from() const { return from_; }
|
||||
socklen_t* from_len_addr() const { return from_len_addr_; }
|
||||
socklen_t from_len() const { return from_ == nullptr ? 0 : *from_len_addr_; }
|
||||
RawAddr* from() const { return from_; }
|
||||
|
||||
// Returns the address of the OVERLAPPED structure with all fields
|
||||
// initialized to zero.
|
||||
@@ -144,8 +144,7 @@ class OverlappedBuffer {
|
||||
|
||||
// For the recvfrom operation additional storace is allocated for the
|
||||
// source sockaddr.
|
||||
socklen_t* from_len_addr_; // Pointer to source sockaddr size storage.
|
||||
struct sockaddr* from_; // Pointer to source sockaddr storage.
|
||||
RawAddr* from_;
|
||||
|
||||
// Buffer for recv/send/AcceptEx. This must be at the end of the
|
||||
// object as the object is allocated larger than it's definition
|
||||
@@ -174,15 +173,11 @@ class Handle : public ReferenceCounted<Handle>, public DescriptorInfoBase {
|
||||
intptr_t Available();
|
||||
bool DataReady();
|
||||
intptr_t Read(void* buffer, intptr_t num_bytes);
|
||||
intptr_t RecvFrom(void* buffer,
|
||||
intptr_t num_bytes,
|
||||
struct sockaddr* sa,
|
||||
socklen_t addr_len);
|
||||
intptr_t RecvFrom(void* buffer, intptr_t num_bytes, RawAddr* from);
|
||||
virtual intptr_t Write(const void* buffer, intptr_t num_bytes);
|
||||
virtual intptr_t SendTo(const void* buffer,
|
||||
intptr_t num_bytes,
|
||||
struct sockaddr* sa,
|
||||
socklen_t sa_len);
|
||||
const RawAddr& addr);
|
||||
|
||||
// Internal interface used by the event handler.
|
||||
virtual bool IssueReadLocked(MonitorLocker* ml);
|
||||
@@ -274,8 +269,7 @@ class Handle : public ReferenceCounted<Handle>, public DescriptorInfoBase {
|
||||
std::unique_ptr<OverlappedBuffer> buffer);
|
||||
virtual bool IssueSendToLocked(MonitorLocker* ml,
|
||||
std::unique_ptr<OverlappedBuffer> buffer,
|
||||
struct sockaddr* sa,
|
||||
socklen_t sa_len);
|
||||
const RawAddr& addr);
|
||||
|
||||
int flags_ = 0;
|
||||
|
||||
@@ -375,8 +369,9 @@ class SocketHandle : public Handle {
|
||||
// Information on listen sockets.
|
||||
class ListenSocket : public DescriptorInfoMultipleMixin<SocketHandle> {
|
||||
public:
|
||||
explicit ListenSocket(intptr_t s)
|
||||
explicit ListenSocket(intptr_t s, ADDRESS_FAMILY sa_family)
|
||||
: DescriptorInfoMultipleMixin(s, kListenSocket),
|
||||
sa_family_(sa_family),
|
||||
pending_accept_count_(0),
|
||||
accepted_head_(nullptr),
|
||||
accepted_tail_(nullptr),
|
||||
@@ -409,6 +404,8 @@ class ListenSocket : public DescriptorInfoMultipleMixin<SocketHandle> {
|
||||
|
||||
bool IssueAcceptLocked(MonitorLocker* ml);
|
||||
|
||||
ADDRESS_FAMILY sa_family_;
|
||||
|
||||
// The number of asynchronous `IssueAccept` operations which haven't completed
|
||||
// yet.
|
||||
int pending_accept_count_;
|
||||
@@ -429,7 +426,7 @@ class ListenSocket : public DescriptorInfoMultipleMixin<SocketHandle> {
|
||||
class ClientSocket : public DescriptorInfoSingleMixin<SocketHandle> {
|
||||
public:
|
||||
explicit ClientSocket(intptr_t s,
|
||||
std::unique_ptr<RawAddr> remote_addr = nullptr)
|
||||
std::unique_ptr<RawAddr>&& remote_addr = nullptr)
|
||||
: DescriptorInfoSingleMixin(s, kClientSocket),
|
||||
next_(nullptr),
|
||||
connected_(false),
|
||||
@@ -508,8 +505,7 @@ class DatagramSocket : public DescriptorInfoSingleMixin<SocketHandle> {
|
||||
private:
|
||||
virtual bool IssueSendToLocked(MonitorLocker* ml,
|
||||
std::unique_ptr<OverlappedBuffer> buffer,
|
||||
sockaddr* sa,
|
||||
socklen_t sa_len);
|
||||
const RawAddr& addr);
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(DatagramSocket);
|
||||
};
|
||||
|
||||
@@ -1128,11 +1128,41 @@ File::StdioHandleType File::GetStdioHandleType(int fd) {
|
||||
return kPipe;
|
||||
}
|
||||
|
||||
static BOOL GetReparsePointTag(const wchar_t* path, DWORD* tag) {
|
||||
WIN32_FIND_DATA data;
|
||||
HANDLE result = FindFirstFileW(path, &data);
|
||||
if (result == INVALID_HANDLE_VALUE) {
|
||||
return FALSE;
|
||||
}
|
||||
FindClose(result);
|
||||
|
||||
if ((data.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
|
||||
// The meaning of |dwReserved0| is documented in
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags
|
||||
*tag = data.dwReserved0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
File::Type File::GetType(const wchar_t* path, bool follow_links) {
|
||||
DWORD attributes = GetFileAttributesW(path);
|
||||
if (attributes == INVALID_FILE_ATTRIBUTES) {
|
||||
return File::kDoesNotExist;
|
||||
} else if ((attributes & FILE_ATTRIBUTE_REPARSE_POINT) != 0) {
|
||||
DWORD tag;
|
||||
if (!GetReparsePointTag(path, &tag)) {
|
||||
return File::kDoesNotExist;
|
||||
}
|
||||
|
||||
// We treat only Unix domain sockets specially - all other reparse points
|
||||
// we treat as links, even though there are many other types of them. See:
|
||||
// https://learn.microsoft.com/en-us/windows/win32/fileio/reparse-point-tags
|
||||
if (tag == IO_REPARSE_TAG_AF_UNIX) {
|
||||
return File::kIsSock;
|
||||
}
|
||||
|
||||
if (follow_links) {
|
||||
HANDLE target_handle = CreateFileW(
|
||||
path, 0, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
|
||||
|
||||
+58
-53
@@ -92,7 +92,7 @@ void ListeningSocketRegistry::RemoveByFd(Socket* fd) {
|
||||
}
|
||||
|
||||
Dart_Handle ListeningSocketRegistry::CreateBindListen(Dart_Handle socket_object,
|
||||
RawAddr addr,
|
||||
const RawAddr& addr,
|
||||
intptr_t backlog,
|
||||
bool v6_only,
|
||||
bool shared) {
|
||||
@@ -209,42 +209,39 @@ Dart_Handle ListeningSocketRegistry::CreateUnixDomainBindListen(
|
||||
return result;
|
||||
}
|
||||
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
// Abstract unix domain socket doesn't exist in file system.
|
||||
if (File::Exists(namespc, addr.un.sun_path) && path[0] != '@') {
|
||||
#else
|
||||
if (File::Exists(namespc, addr.un.sun_path)) {
|
||||
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
if (unix_domain_sockets_ != nullptr) {
|
||||
// If there is a socket listening on this file. Ensure
|
||||
// that it was created with `shared` mode and current `shared`
|
||||
// is also true.
|
||||
OSSocket* os_socket = unix_domain_sockets_;
|
||||
OSSocket* os_socket_same_addr =
|
||||
FindOSSocketWithPath(os_socket, namespc, addr.un.sun_path);
|
||||
if (os_socket_same_addr != nullptr) {
|
||||
if (!os_socket_same_addr->shared || !shared) {
|
||||
OSError os_error(-1,
|
||||
"The shared flag to bind() needs to be `true` if "
|
||||
"binding multiple times on the same path.",
|
||||
OSError::kUnknown);
|
||||
return DartUtils::NewDartOSError(&os_error);
|
||||
}
|
||||
|
||||
// This socket creation is the exact same as the one which originally
|
||||
// created the socket. Feed the same fd and store it into the native
|
||||
// field of dart socket_object. Sockets here will share same fd but
|
||||
// contain a different port() through EventHandler_SendData.
|
||||
Socket* socketfd = new Socket(os_socket_same_addr->fd);
|
||||
os_socket_same_addr->ref_count++;
|
||||
// We set as a side-effect the file descriptor on the dart
|
||||
// socket_object.
|
||||
Socket::ReuseSocketIdNativeField(socket_object, socketfd,
|
||||
Socket::kFinalizerListening);
|
||||
InsertByFd(socketfd, os_socket_same_addr);
|
||||
return Dart_True();
|
||||
if (unix_domain_sockets_ != nullptr) {
|
||||
// If there is a socket listening on this file. Ensure
|
||||
// that it was created with `shared` mode and current `shared`
|
||||
// is also true.
|
||||
OSSocket* os_socket_same_addr =
|
||||
FindMatchingUnixDomainSocket(unix_domain_sockets_, namespc, addr);
|
||||
if (os_socket_same_addr != nullptr) {
|
||||
if (!os_socket_same_addr->shared || !shared) {
|
||||
OSError os_error(-1,
|
||||
"The shared flag to bind() needs to be `true` if "
|
||||
"binding multiple times on the same path.",
|
||||
OSError::kUnknown);
|
||||
return DartUtils::NewDartOSError(&os_error);
|
||||
}
|
||||
|
||||
// This socket creation is the exact same as the one which originally
|
||||
// created the socket. Feed the same fd and store it into the native
|
||||
// field of dart socket_object. Sockets here will share same fd but
|
||||
// contain a different port() through EventHandler_SendData.
|
||||
Socket* socketfd = new Socket(os_socket_same_addr->fd);
|
||||
os_socket_same_addr->ref_count++;
|
||||
// We set as a side-effect the file descriptor on the dart
|
||||
// socket_object.
|
||||
Socket::ReuseSocketIdNativeField(socket_object, socketfd,
|
||||
Socket::kFinalizerListening);
|
||||
InsertByFd(socketfd, os_socket_same_addr);
|
||||
return Dart_True();
|
||||
}
|
||||
}
|
||||
|
||||
if (addr.is_pathname_unix_socket() &&
|
||||
File::GetType(namespc, addr.un.sun_path, /*follow_links=*/false) !=
|
||||
File::kDoesNotExist) {
|
||||
// Unix domain socket by default doesn't allow binding to an existing file.
|
||||
// An error (EADDRINUSE) will be returned back. However, hanging is noticed
|
||||
// on Android so we throw an exception for all platforms.
|
||||
@@ -255,11 +252,13 @@ Dart_Handle ListeningSocketRegistry::CreateUnixDomainBindListen(
|
||||
|
||||
// There is no socket listening on that path, so we create new one.
|
||||
intptr_t fd = ServerSocket::CreateUnixDomainBindListen(addr, backlog);
|
||||
|
||||
if (fd < 0) {
|
||||
return DartUtils::NewDartOSError();
|
||||
}
|
||||
|
||||
if (!ServerSocket::StartAccept(fd)) {
|
||||
OSError os_error(-1, "Failed to start accept", OSError::kUnknown);
|
||||
return DartUtils::NewDartOSError(&os_error);
|
||||
}
|
||||
Socket* socketfd = new Socket(fd);
|
||||
OSSocket* os_socket =
|
||||
new OSSocket(addr, -1, false, shared, socketfd, namespc);
|
||||
@@ -420,7 +419,7 @@ void FUNCTION_NAME(Socket_CreateBindConnect)(Dart_NativeArguments args) {
|
||||
|
||||
void FUNCTION_NAME(Socket_CreateUnixDomainBindConnect)(
|
||||
Dart_NativeArguments args) {
|
||||
#if defined(DART_HOST_OS_WINDOWS) || defined(DART_HOST_OS_FUCHSIA)
|
||||
#if defined(DART_HOST_OS_FUCHSIA)
|
||||
OSError os_error(
|
||||
-1, "Unix domain sockets are not available on this operating system.",
|
||||
OSError::kUnknown);
|
||||
@@ -465,7 +464,7 @@ void FUNCTION_NAME(Socket_CreateUnixDomainBindConnect)(
|
||||
}
|
||||
|
||||
void FUNCTION_NAME(Socket_CreateUnixDomainConnect)(Dart_NativeArguments args) {
|
||||
#if defined(DART_HOST_OS_WINDOWS) || defined(DART_HOST_OS_FUCHSIA)
|
||||
#if defined(DART_HOST_OS_FUCHSIA)
|
||||
OSError os_error(
|
||||
-1, "Unix domain sockets are not available on this operating system.",
|
||||
OSError::kUnknown);
|
||||
@@ -638,8 +637,9 @@ void FUNCTION_NAME(Socket_RecvFrom)(Dart_NativeArguments args) {
|
||||
type = IPv6;
|
||||
}
|
||||
// Format the address to a string using the numeric format.
|
||||
char numeric_address[INET6_ADDRSTRLEN];
|
||||
SocketBase::FormatNumericAddress(addr, numeric_address, INET6_ADDRSTRLEN);
|
||||
char numeric_address[SocketAddress::kMaxAddressStringLength];
|
||||
SocketBase::FormatNumericAddress(addr, numeric_address,
|
||||
ARRAY_SIZE(numeric_address));
|
||||
|
||||
// Create a Datagram object with the data and sender address and port.
|
||||
const int kNumArgs = 5;
|
||||
@@ -910,8 +910,7 @@ void FUNCTION_NAME(Socket_GetRemotePeer)(Dart_NativeArguments args) {
|
||||
entry = Dart_NewList(2);
|
||||
} else {
|
||||
entry = Dart_NewList(3);
|
||||
RawAddr raw = addr->addr();
|
||||
Dart_ListSetAt(entry, 2, SocketAddress::ToTypedData(raw));
|
||||
Dart_ListSetAt(entry, 2, SocketAddress::ToTypedData(addr->addr()));
|
||||
}
|
||||
Dart_ListSetAt(entry, 0, Dart_NewInteger(type));
|
||||
Dart_ListSetAt(entry, 1, Dart_NewStringFromCString(addr->as_string()));
|
||||
@@ -1022,7 +1021,7 @@ void FUNCTION_NAME(ServerSocket_CreateBindListen)(Dart_NativeArguments args) {
|
||||
|
||||
void FUNCTION_NAME(ServerSocket_CreateUnixDomainBindListen)(
|
||||
Dart_NativeArguments args) {
|
||||
#if defined(DART_HOST_OS_WINDOWS)
|
||||
#if defined(DART_HOST_OS_FUCHSIA)
|
||||
OSError os_error(
|
||||
-1, "Unix domain sockets are not available on this operating system.",
|
||||
OSError::kUnknown);
|
||||
@@ -1084,7 +1083,7 @@ CObject* Socket::LookupRequest(const CObjectArray& request) {
|
||||
new CObjectString(CObject::NewString(addr->as_string()));
|
||||
entry->SetAt(1, as_string);
|
||||
|
||||
RawAddr raw = addr->addr();
|
||||
const auto& raw = addr->addr();
|
||||
CObjectUint8Array* data = SocketAddress::ToCObject(raw);
|
||||
entry->SetAt(2, data);
|
||||
|
||||
@@ -1113,11 +1112,13 @@ CObject* Socket::ReverseLookupRequest(const CObjectArray& request) {
|
||||
memset(reinterpret_cast<void*>(&addr), 0, sizeof(RawAddr));
|
||||
if (len == sizeof(in_addr)) {
|
||||
addr.in.sin_family = AF_INET;
|
||||
addr.size = sizeof(sockaddr_in);
|
||||
memmove(reinterpret_cast<void*>(&addr.in.sin_addr), addr_object.Buffer(),
|
||||
len);
|
||||
} else {
|
||||
ASSERT(len == sizeof(in6_addr));
|
||||
addr.in6.sin6_family = AF_INET6;
|
||||
addr.size = sizeof(sockaddr_in6);
|
||||
memmove(reinterpret_cast<void*>(&addr.in6.sin6_addr),
|
||||
addr_object.Buffer(), len);
|
||||
}
|
||||
@@ -1160,7 +1161,7 @@ CObject* Socket::ListInterfacesRequest(const CObjectArray& request) {
|
||||
new CObjectString(CObject::NewString(addr->as_string()));
|
||||
entry->SetAt(1, as_string);
|
||||
|
||||
RawAddr raw = addr->addr();
|
||||
const auto& raw = addr->addr();
|
||||
CObjectUint8Array* data = SocketAddress::ToCObject(raw);
|
||||
entry->SetAt(2, data);
|
||||
|
||||
@@ -1671,21 +1672,25 @@ void FUNCTION_NAME(ResourceHandleImpl_toRawSocket)(Dart_NativeArguments args) {
|
||||
Dart_GetField(handle_object, DartUtils::NewString("_handle")));
|
||||
intptr_t fd = DartUtils::GetIntegerValue(handle_field);
|
||||
|
||||
SocketAddress* socket_address = reinterpret_cast<SocketAddress*>(
|
||||
Dart_ScopeAllocate(sizeof(SocketAddress)));
|
||||
ASSERT(socket_address != nullptr);
|
||||
SocketBase::GetSocketName(fd, socket_address);
|
||||
RawAddr raw;
|
||||
if (!SocketBase::GetSocketName(fd, &raw)) {
|
||||
OSError os_error(-1, "Failed to get socket address", OSError::kUnknown);
|
||||
Dart_SetReturnValue(args, DartUtils::NewDartOSError(&os_error));
|
||||
return;
|
||||
}
|
||||
|
||||
const SocketAddress socket_address(raw);
|
||||
|
||||
// return a list describing socket_address: (type, hostname, typed_data_addr,
|
||||
// fd)
|
||||
Dart_Handle list = ThrowIfError(Dart_NewList(4));
|
||||
ThrowIfError(Dart_ListSetAt(
|
||||
list, 0, ThrowIfError(Dart_NewInteger(socket_address->GetType()))));
|
||||
list, 0, ThrowIfError(Dart_NewInteger(socket_address.GetType()))));
|
||||
ThrowIfError(Dart_ListSetAt(
|
||||
list, 1,
|
||||
ThrowIfError(Dart_NewStringFromCString(socket_address->as_string()))));
|
||||
ThrowIfError(Dart_NewStringFromCString(socket_address.as_string()))));
|
||||
ThrowIfError(Dart_ListSetAt(
|
||||
list, 2, SocketAddress::ToTypedData(socket_address->addr())));
|
||||
list, 2, SocketAddress::ToTypedData(socket_address.addr())));
|
||||
ThrowIfError(Dart_ListSetAt(list, 3, ThrowIfError(Dart_NewInteger(fd))));
|
||||
|
||||
Dart_SetReturnValue(args, list);
|
||||
|
||||
+14
-20
@@ -183,7 +183,7 @@ class ListeningSocketRegistry {
|
||||
// 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,
|
||||
const RawAddr& addr,
|
||||
intptr_t backlog,
|
||||
bool v6_only,
|
||||
bool shared);
|
||||
@@ -226,7 +226,7 @@ class ListeningSocketRegistry {
|
||||
// but on different addresses.
|
||||
OSSocket* next;
|
||||
|
||||
OSSocket(RawAddr address,
|
||||
OSSocket(const RawAddr& address,
|
||||
int port,
|
||||
bool v6_only,
|
||||
bool shared,
|
||||
@@ -255,30 +255,24 @@ class ListeningSocketRegistry {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
OSSocket* FindOSSocketWithPath(OSSocket* current,
|
||||
Namespace* namespc,
|
||||
const char* path) {
|
||||
OSSocket* FindMatchingUnixDomainSocket(OSSocket* current,
|
||||
Namespace* namespc,
|
||||
const RawAddr& addr) {
|
||||
if (addr.is_abstract_unix_socket()) {
|
||||
return FindOSSocketWithAddress(current, addr);
|
||||
}
|
||||
|
||||
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 (current->address.is_abstract_unix_socket()) {
|
||||
continue;
|
||||
}
|
||||
if (condition) {
|
||||
return current;
|
||||
}
|
||||
#else
|
||||
|
||||
if (File::AreIdentical(current->namespc, current->address.un.sun_path,
|
||||
namespc, path) == File::kIdentical) {
|
||||
namespc, addr.un.sun_path) == File::kIdentical) {
|
||||
return current;
|
||||
}
|
||||
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
|
||||
current = current->next;
|
||||
}
|
||||
return nullptr;
|
||||
|
||||
+25
-50
@@ -22,7 +22,7 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
int SocketAddress::GetType() {
|
||||
int SocketAddress::GetType() const {
|
||||
switch (addr_.ss.ss_family) {
|
||||
case AF_INET6:
|
||||
return TYPE_IPV6;
|
||||
@@ -36,41 +36,6 @@ int SocketAddress::GetType() {
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t SocketAddress::GetAddrLength(const RawAddr& addr,
|
||||
bool unnamed_unix_socket) {
|
||||
ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6) ||
|
||||
(addr.ss.ss_family == AF_UNIX));
|
||||
switch (addr.ss.ss_family) {
|
||||
case AF_INET6:
|
||||
return sizeof(struct sockaddr_in6);
|
||||
case AF_INET:
|
||||
return sizeof(struct sockaddr_in);
|
||||
case AF_UNIX: {
|
||||
// For an abstract UNIX socket, trailing null bytes in the name are
|
||||
// meaningful. That is, the bytes '\0/tmp/dbus-xxxx' are a different name
|
||||
// than '\0/tmp/dbus-xxxx\0\0\0...'. The length of the address structure
|
||||
// passed to connect() etc. tells those calls how many bytes of the name
|
||||
// to look at. Therefore, when computing the length of the address in
|
||||
// this case, any trailing null bytes are trimmed.
|
||||
// TODO(dart:io): Support abstract UNIX socket addresses that have
|
||||
// trailing null bytes on purpose.
|
||||
// https://github.com/dart-lang/sdk/issues/46158
|
||||
intptr_t nulls = 0;
|
||||
if (!unnamed_unix_socket && addr.un.sun_path[0] == '\0') {
|
||||
intptr_t i = sizeof(addr.un.sun_path) - 1;
|
||||
while (addr.un.sun_path[i] == '\0') {
|
||||
nulls++;
|
||||
i--;
|
||||
}
|
||||
}
|
||||
return sizeof(struct sockaddr_un) - nulls;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
intptr_t SocketAddress::GetInAddrLength(const RawAddr& addr) {
|
||||
ASSERT((addr.ss.ss_family == AF_INET) || (addr.ss.ss_family == AF_INET6));
|
||||
return (addr.ss.ss_family == AF_INET6) ? sizeof(struct in6_addr)
|
||||
@@ -88,14 +53,13 @@ bool SocketAddress::AreAddressesEqual(const RawAddr& a, const RawAddr& b) {
|
||||
sizeof(a.in6.sin6_addr)) == 0 &&
|
||||
a.in6.sin6_scope_id == b.in6.sin6_scope_id;
|
||||
} else if (a.ss.ss_family == AF_UNIX) {
|
||||
// This is not used anywhere. The comparison of file path is done via
|
||||
// File::AreIdentical().
|
||||
int len = sizeof(a.un.sun_path);
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (a.un.sun_path[i] != b.un.sun_path[i]) return false;
|
||||
if (a.un.sun_path[i] == '\0') return true;
|
||||
if (a.size != b.size) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
return (a.size <= offsetof(decltype(a.un), sun_path)) ||
|
||||
(memcmp(a.un.sun_path, b.un.sun_path,
|
||||
a.size - offsetof(decltype(a.un), sun_path)) == 0);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
return false;
|
||||
@@ -119,10 +83,12 @@ void SocketAddress::GetSockAddr(Dart_Handle obj, RawAddr* addr) {
|
||||
memset(reinterpret_cast<void*>(addr), 0, sizeof(RawAddr));
|
||||
if (len == sizeof(in_addr)) {
|
||||
addr->in.sin_family = AF_INET;
|
||||
addr->size = sizeof(sockaddr_in);
|
||||
memmove(reinterpret_cast<void*>(&addr->in.sin_addr), data, len);
|
||||
} else {
|
||||
ASSERT(len == sizeof(in6_addr));
|
||||
addr->in6.sin6_family = AF_INET6;
|
||||
addr->size = sizeof(sockaddr_in6);
|
||||
memmove(reinterpret_cast<void*>(&addr->in6.sin6_addr), data, len);
|
||||
}
|
||||
Dart_TypedDataReleaseData(obj);
|
||||
@@ -134,7 +100,7 @@ Dart_Handle SocketAddress::GetUnixDomainSockAddr(const char* path,
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
NamespaceScope ns(namespc, path);
|
||||
path = ns.path();
|
||||
bool is_abstract = (path[0] == '@');
|
||||
const bool is_abstract = (path[0] == '@');
|
||||
if (is_abstract) {
|
||||
// The following 107 bytes after the leading null byte represents the name
|
||||
// of unix domain socket. Without reseting, even users provide the same path
|
||||
@@ -142,8 +108,11 @@ Dart_Handle SocketAddress::GetUnixDomainSockAddr(const char* path,
|
||||
// connection will be rejected.
|
||||
bzero(addr->un.sun_path, sizeof(addr->un.sun_path));
|
||||
}
|
||||
#else
|
||||
const bool is_abstract = false;
|
||||
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
if (sizeof(path) > sizeof(addr->un.sun_path)) {
|
||||
const auto path_len = strlen(path);
|
||||
if (path_len >= sizeof(addr->un.sun_path)) {
|
||||
OSError os_error(-1,
|
||||
"The length of path exceeds the limit. "
|
||||
"Check out man 7 unix page",
|
||||
@@ -151,7 +120,10 @@ Dart_Handle SocketAddress::GetUnixDomainSockAddr(const char* path,
|
||||
return DartUtils::NewDartOSError(&os_error);
|
||||
}
|
||||
addr->un.sun_family = AF_UNIX;
|
||||
Utils::SNPrint(addr->un.sun_path, sizeof(addr->un.sun_path), "%s", path);
|
||||
// Trailing '\0' is not meaningful for abstract namespace sockets.
|
||||
const auto path_total_bytes = path_len + (is_abstract ? 0 : 1);
|
||||
memmove(addr->un.sun_path, path, path_total_bytes);
|
||||
addr->size = offsetof(decltype(addr->un), sun_path) + path_total_bytes;
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_ANDROID)
|
||||
// In case of abstract namespace, transfer the leading '@' into a null byte.
|
||||
if (is_abstract) {
|
||||
@@ -248,13 +220,15 @@ void FUNCTION_NAME(InternetAddress_Parse)(Dart_NativeArguments args) {
|
||||
DartUtils::GetStringValue(Dart_GetNativeArgument(args, 0));
|
||||
ASSERT(address != nullptr);
|
||||
RawAddr raw;
|
||||
memset(&raw, 0, sizeof(raw));
|
||||
memset(&raw.addr, 0, sizeof(raw.addr));
|
||||
int type = strchr(address, ':') == nullptr ? SocketAddress::TYPE_IPV4
|
||||
: SocketAddress::TYPE_IPV6;
|
||||
if (type == SocketAddress::TYPE_IPV4) {
|
||||
raw.addr.sa_family = AF_INET;
|
||||
raw.size = sizeof(sockaddr_in);
|
||||
} else {
|
||||
raw.addr.sa_family = AF_INET6;
|
||||
raw.size = sizeof(sockaddr_in6);
|
||||
}
|
||||
bool ok = SocketBase::ParseAddress(type, address, &raw);
|
||||
if (!ok) {
|
||||
@@ -288,8 +262,7 @@ void FUNCTION_NAME(InternetAddress_ParseScopedLinkLocalAddress)(
|
||||
void FUNCTION_NAME(InternetAddress_RawAddrToString)(Dart_NativeArguments args) {
|
||||
RawAddr addr;
|
||||
SocketAddress::GetSockAddr(Dart_GetNativeArgument(args, 0), &addr);
|
||||
// INET6_ADDRSTRLEN is larger than INET_ADDRSTRLEN
|
||||
char str[INET6_ADDRSTRLEN];
|
||||
char str[SocketAddress::kMaxAddressStringLength];
|
||||
bool ok = SocketBase::RawAddrToString(&addr, str);
|
||||
if (!ok) {
|
||||
str[0] = '\0';
|
||||
@@ -307,13 +280,15 @@ void FUNCTION_NAME(SocketBase_IsBindError)(Dart_NativeArguments args) {
|
||||
bool SocketBase::IsValidAddress(const char* address) {
|
||||
ASSERT(address != nullptr);
|
||||
RawAddr raw;
|
||||
memset(&raw, 0, sizeof(raw));
|
||||
memset(&raw.addr, 0, sizeof(raw.addr));
|
||||
int type = strchr(address, ':') == nullptr ? SocketAddress::TYPE_IPV4
|
||||
: SocketAddress::TYPE_IPV6;
|
||||
if (type == SocketAddress::TYPE_IPV4) {
|
||||
raw.addr.sa_family = AF_INET;
|
||||
raw.size = sizeof(sockaddr_in);
|
||||
} else {
|
||||
raw.addr.sa_family = AF_INET6;
|
||||
raw.size = sizeof(sockaddr_in6);
|
||||
}
|
||||
return SocketBase::ParseAddress(type, address, &raw);
|
||||
}
|
||||
|
||||
+57
-27
@@ -30,12 +30,48 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
union RawAddr {
|
||||
struct sockaddr_in in;
|
||||
struct sockaddr_in6 in6;
|
||||
struct sockaddr_un un;
|
||||
struct sockaddr_storage ss;
|
||||
struct sockaddr addr;
|
||||
struct RawAddr {
|
||||
union {
|
||||
sockaddr_in in;
|
||||
sockaddr_in6 in6;
|
||||
sockaddr_un un;
|
||||
sockaddr_storage ss;
|
||||
sockaddr addr;
|
||||
};
|
||||
socklen_t size = sizeof(sockaddr_storage);
|
||||
|
||||
static RawAddr FromInet4or6(const sockaddr* sa) {
|
||||
RawAddr raw;
|
||||
switch (sa->sa_family) {
|
||||
case AF_INET:
|
||||
raw.size = sizeof(sockaddr_in);
|
||||
break;
|
||||
case AF_INET6:
|
||||
raw.size = sizeof(sockaddr_in6);
|
||||
break;
|
||||
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
memmove(&raw.addr, sa, raw.size);
|
||||
return raw;
|
||||
}
|
||||
|
||||
bool is_pathname_unix_socket() const {
|
||||
return ss.ss_family == AF_UNIX && !is_unnamed_unix_socket() &&
|
||||
un.sun_path[0] != '\0';
|
||||
}
|
||||
|
||||
bool is_abstract_unix_socket() const {
|
||||
return ss.ss_family == AF_UNIX && !is_unnamed_unix_socket() &&
|
||||
un.sun_path[0] == '\0';
|
||||
}
|
||||
|
||||
bool is_unnamed_unix_socket() const {
|
||||
// Socket is unnamed if its sockaddr contains exactly |ss.ss_family|
|
||||
// and no sun_path data at all.
|
||||
return ss.ss_family == AF_UNIX && size == sizeof(decltype(ss.ss_family));
|
||||
}
|
||||
};
|
||||
|
||||
class SocketAddress {
|
||||
@@ -56,19 +92,15 @@ class SocketAddress {
|
||||
ADDRESS_LAST = ADDRESS_ANY_IP_V6,
|
||||
};
|
||||
|
||||
// Unix domain socket may be unnamed. In this case addr_.un.sun_path contains
|
||||
// garbage and should not be inspected.
|
||||
explicit SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket = false);
|
||||
explicit SocketAddress(const RawAddr& addr);
|
||||
|
||||
~SocketAddress() {}
|
||||
|
||||
int GetType();
|
||||
int GetType() const;
|
||||
|
||||
const char* as_string() const { return as_string_; }
|
||||
const RawAddr& addr() const { return addr_; }
|
||||
|
||||
static intptr_t GetAddrLength(const RawAddr& addr,
|
||||
bool unnamed_unix_socket = false);
|
||||
static intptr_t GetInAddrLength(const RawAddr& addr);
|
||||
static bool AreAddressesEqual(const RawAddr& a, const RawAddr& b);
|
||||
static void GetSockAddr(Dart_Handle obj, RawAddr* addr);
|
||||
@@ -83,19 +115,17 @@ class SocketAddress {
|
||||
static void SetAddrScope(RawAddr* addr, intptr_t scope_id);
|
||||
static intptr_t GetAddrScope(const RawAddr& addr);
|
||||
|
||||
private:
|
||||
#if defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) || \
|
||||
defined(DART_HOST_OS_ANDROID)
|
||||
// Unix domain address is only on Linux, Mac OS and Android now.
|
||||
// unix(7) require sun_path to be 108 bytes on Linux and Android, 104 bytes on
|
||||
// Mac OS.
|
||||
static constexpr intptr_t kMaxUnixPathLength =
|
||||
sizeof(((struct sockaddr_un*)nullptr)->sun_path);
|
||||
char as_string_[kMaxUnixPathLength];
|
||||
#if !defined(DART_HOST_OS_FUCHSIA)
|
||||
static constexpr intptr_t kMaxAddressStringLength =
|
||||
sizeof(decltype(sockaddr_un::sun_path));
|
||||
#else
|
||||
char as_string_[INET6_ADDRSTRLEN];
|
||||
#endif // defined(DART_HOST_OS_LINUX) || defined(DART_HOST_OS_MACOS) ||
|
||||
// defined(DART_HOST_OS_ANDROID)
|
||||
static constexpr intptr_t kMaxAddressStringLength = INET6_ADDRSTRLEN;
|
||||
#endif // !defined(DART_HOST_OS_FUCHSIA)
|
||||
static_assert(kMaxAddressStringLength >= INET6_ADDRSTRLEN);
|
||||
static_assert(kMaxAddressStringLength >= INET_ADDRSTRLEN);
|
||||
|
||||
private:
|
||||
char as_string_[kMaxAddressStringLength];
|
||||
RawAddr addr_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(SocketAddress);
|
||||
@@ -103,10 +133,10 @@ class SocketAddress {
|
||||
|
||||
class InterfaceSocketAddress {
|
||||
public:
|
||||
InterfaceSocketAddress(struct sockaddr* sa,
|
||||
InterfaceSocketAddress(const RawAddr& addr,
|
||||
const char* interface_name,
|
||||
intptr_t interface_index)
|
||||
: socket_address_(new SocketAddress(sa)),
|
||||
: socket_address_(new SocketAddress(addr)),
|
||||
interface_name_(interface_name),
|
||||
interface_index_(interface_index) {}
|
||||
|
||||
@@ -228,7 +258,7 @@ class SocketBase : public AllStatic {
|
||||
// to bind the socket to a specific IP.
|
||||
static bool IsBindError(intptr_t error_number);
|
||||
static intptr_t GetPort(intptr_t fd);
|
||||
static bool GetSocketName(intptr_t fd, SocketAddress* p_sa);
|
||||
static bool GetSocketName(intptr_t fd, RawAddr* raw);
|
||||
static SocketAddress* GetRemotePeer(intptr_t fd, intptr_t* port);
|
||||
static void GetError(intptr_t fd, OSError* os_error);
|
||||
static int GetType(intptr_t fd);
|
||||
|
||||
@@ -52,18 +52,15 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) {
|
||||
SocketAddress::SocketAddress(const RawAddr& addr) : addr_(addr) {
|
||||
// Fuchsia does not support unix domain sockets.
|
||||
if (unnamed_unix_socket) {
|
||||
if (addr.is_unnamed_unix_socket()) {
|
||||
FATAL("Fuchsia does not support unix domain sockets.");
|
||||
}
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
if (!SocketBase::FormatNumericAddress(addr, as_string_,
|
||||
kMaxAddressStringLength)) {
|
||||
as_string_[0] = 0;
|
||||
}
|
||||
socklen_t salen = GetAddrLength(*reinterpret_cast<RawAddr*>(sa));
|
||||
memmove(reinterpret_cast<void*>(&addr_), sa, salen);
|
||||
}
|
||||
|
||||
bool SocketBase::Initialize() {
|
||||
@@ -74,9 +71,8 @@ bool SocketBase::Initialize() {
|
||||
bool SocketBase::FormatNumericAddress(const RawAddr& addr,
|
||||
char* address,
|
||||
int len) {
|
||||
socklen_t salen = SocketAddress::GetAddrLength(addr);
|
||||
LOG_INFO("SocketBase::FormatNumericAddress: calling getnameinfo\n");
|
||||
return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len,
|
||||
return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, addr.size, address, len,
|
||||
nullptr, 0, NI_NUMERICHOST) == 0));
|
||||
}
|
||||
|
||||
@@ -182,30 +178,18 @@ intptr_t SocketBase::SendMessage(intptr_t fd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SocketBase::GetSocketName(intptr_t fd, SocketAddress* p_sa) {
|
||||
bool SocketBase::GetSocketName(intptr_t fd, RawAddr* raw) {
|
||||
ASSERT(fd >= 0);
|
||||
ASSERT(p_sa != nullptr);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sockaddr_un contains sa_family_t sun_family and char[] sun_path.
|
||||
// If size is the size of sa_family_t, this is an unnamed socket and
|
||||
// sun_path contains garbage.
|
||||
new (p_sa) SocketAddress(&raw.addr,
|
||||
/*unnamed_unix_socket=*/size == sizeof(sa_family_t));
|
||||
return true;
|
||||
ASSERT(raw != nullptr);
|
||||
return NO_RETRY_EXPECTED(getsockname(fd, &raw->addr, &raw->size)) == 0;
|
||||
}
|
||||
|
||||
intptr_t SocketBase::GetPort(intptr_t fd) {
|
||||
IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
|
||||
ASSERT(handle->fd() >= 0);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
LOG_INFO("SocketBase::GetPort: calling getsockname(%ld)\n", handle->fd());
|
||||
if (NO_RETRY_EXPECTED(getsockname(handle->fd(), &raw.addr, &size))) {
|
||||
if (NO_RETRY_EXPECTED(getsockname(handle->fd(), &raw.addr, &raw.size))) {
|
||||
return 0;
|
||||
}
|
||||
return SocketAddress::GetAddrPort(raw);
|
||||
@@ -215,12 +199,11 @@ SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
|
||||
IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
|
||||
ASSERT(handle->fd() >= 0);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (NO_RETRY_EXPECTED(getpeername(handle->fd(), &raw.addr, &size))) {
|
||||
if (NO_RETRY_EXPECTED(getpeername(handle->fd(), &raw.addr, &raw.size))) {
|
||||
return nullptr;
|
||||
}
|
||||
*port = SocketAddress::GetAddrPort(raw);
|
||||
return new SocketAddress(&raw.addr);
|
||||
return new SocketAddress(raw);
|
||||
}
|
||||
|
||||
void SocketBase::GetError(intptr_t fd, OSError* os_error) {
|
||||
@@ -279,7 +262,7 @@ AddressList<SocketAddress>* SocketBase::LookupAddress(const char* host,
|
||||
AddressList<SocketAddress>* addresses = new AddressList<SocketAddress>(count);
|
||||
for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) {
|
||||
if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
|
||||
addresses->SetAt(i, new SocketAddress(c->ai_addr));
|
||||
addresses->SetAt(i, new SocketAddress(RawAddr::FromInet4or6(c->ai_addr)));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -357,9 +340,9 @@ AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces(
|
||||
for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
|
||||
char* ifa_name = DartUtils::ScopedCopyCString(ifa->ifa_name);
|
||||
addresses->SetAt(
|
||||
i, new InterfaceSocketAddress(ifa->ifa_addr, ifa_name,
|
||||
if_nametoindex(ifa->ifa_name)));
|
||||
addresses->SetAt(i, new InterfaceSocketAddress(
|
||||
RawAddr::FromInet4or6(ifa->ifa_addr), ifa_name,
|
||||
if_nametoindex(ifa->ifa_name)));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ AddressList<SocketAddress>* SocketBase::LookupAddress(const char* host,
|
||||
AddressList<SocketAddress>* addresses = new AddressList<SocketAddress>(count);
|
||||
for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) {
|
||||
if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
|
||||
addresses->SetAt(i, new SocketAddress(c->ai_addr));
|
||||
addresses->SetAt(i, new SocketAddress(RawAddr::FromInet4or6(c->ai_addr)));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -125,7 +125,7 @@ bool SocketBase::JoinMulticast(intptr_t fd,
|
||||
int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
|
||||
struct group_req mreq;
|
||||
mreq.gr_interface = interfaceIndex;
|
||||
memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr));
|
||||
memmove(&mreq.gr_group, &addr.ss, addr.size);
|
||||
return NO_RETRY_EXPECTED(
|
||||
setsockopt(fd, proto, MCAST_JOIN_GROUP, &mreq, sizeof(mreq))) == 0;
|
||||
}
|
||||
@@ -137,7 +137,7 @@ bool SocketBase::LeaveMulticast(intptr_t fd,
|
||||
int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
|
||||
struct group_req mreq;
|
||||
mreq.gr_interface = interfaceIndex;
|
||||
memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr));
|
||||
memmove(&mreq.gr_group, &addr.ss, addr.size);
|
||||
return NO_RETRY_EXPECTED(setsockopt(fd, proto, MCAST_LEAVE_GROUP, &mreq,
|
||||
sizeof(mreq))) == 0;
|
||||
}
|
||||
|
||||
@@ -78,7 +78,7 @@ AddressList<SocketAddress>* SocketBase::LookupAddress(const char* host,
|
||||
AddressList<SocketAddress>* addresses = new AddressList<SocketAddress>(count);
|
||||
for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) {
|
||||
if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
|
||||
addresses->SetAt(i, new SocketAddress(c->ai_addr));
|
||||
addresses->SetAt(i, new SocketAddress(RawAddr::FromInet4or6(c->ai_addr)));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,23 +25,18 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sa, bool unnamed_unix_socket) {
|
||||
if (unnamed_unix_socket) {
|
||||
SocketAddress::SocketAddress(const RawAddr& addr) : addr_(addr) {
|
||||
if (addr.is_unnamed_unix_socket()) {
|
||||
// This is an unnamed unix domain socket.
|
||||
as_string_[0] = 0;
|
||||
} else if (sa->sa_family == AF_UNIX) {
|
||||
struct sockaddr_un* un = ((struct sockaddr_un*)sa);
|
||||
memmove(as_string_, un->sun_path, sizeof(un->sun_path));
|
||||
} else if (addr.ss.ss_family == AF_UNIX) {
|
||||
memmove(as_string_, addr.un.sun_path, sizeof(addr.un.sun_path));
|
||||
} else {
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
if (!SocketBase::FormatNumericAddress(*reinterpret_cast<RawAddr*>(sa),
|
||||
as_string_, INET6_ADDRSTRLEN)) {
|
||||
if (!SocketBase::FormatNumericAddress(addr, as_string_,
|
||||
kMaxAddressStringLength)) {
|
||||
as_string_[0] = 0;
|
||||
}
|
||||
}
|
||||
socklen_t salen =
|
||||
GetAddrLength(*reinterpret_cast<RawAddr*>(sa), unnamed_unix_socket);
|
||||
memmove(reinterpret_cast<void*>(&addr_), sa, salen);
|
||||
}
|
||||
|
||||
bool SocketBase::Initialize() {
|
||||
@@ -52,8 +47,7 @@ bool SocketBase::Initialize() {
|
||||
bool SocketBase::FormatNumericAddress(const RawAddr& addr,
|
||||
char* address,
|
||||
int len) {
|
||||
socklen_t salen = SocketAddress::GetAddrLength(addr);
|
||||
return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, salen, address, len,
|
||||
return (NO_RETRY_EXPECTED(getnameinfo(&addr.addr, addr.size, address, len,
|
||||
nullptr, 0, NI_NUMERICHOST)) == 0);
|
||||
}
|
||||
|
||||
@@ -87,9 +81,8 @@ intptr_t SocketBase::RecvFrom(intptr_t fd,
|
||||
RawAddr* addr,
|
||||
SocketOpKind sync) {
|
||||
ASSERT(fd >= 0);
|
||||
socklen_t addr_len = sizeof(addr->ss);
|
||||
ssize_t read_bytes = TEMP_FAILURE_RETRY(
|
||||
recvfrom(fd, buffer, num_bytes, 0, &addr->addr, &addr_len));
|
||||
recvfrom(fd, buffer, num_bytes, 0, &addr->addr, &addr->size));
|
||||
if ((sync == kAsync) && (read_bytes == -1) && (errno == EWOULDBLOCK)) {
|
||||
// If the read would block we need to retry and therefore return 0
|
||||
// as the number of bytes written.
|
||||
@@ -206,9 +199,8 @@ intptr_t SocketBase::SendTo(intptr_t fd,
|
||||
const RawAddr& addr,
|
||||
SocketOpKind sync) {
|
||||
ASSERT(fd >= 0);
|
||||
ssize_t written_bytes =
|
||||
TEMP_FAILURE_RETRY(sendto(fd, buffer, num_bytes, 0, &addr.addr,
|
||||
SocketAddress::GetAddrLength(addr)));
|
||||
ssize_t written_bytes = TEMP_FAILURE_RETRY(
|
||||
sendto(fd, buffer, num_bytes, 0, &addr.addr, addr.size));
|
||||
ASSERT(EAGAIN == EWOULDBLOCK);
|
||||
if ((sync == kAsync) && (written_bytes == -1) && (errno == EWOULDBLOCK)) {
|
||||
// If the would block we need to retry and therefore return 0 as
|
||||
@@ -279,28 +271,16 @@ intptr_t SocketBase::SendMessage(intptr_t fd,
|
||||
return written_bytes;
|
||||
}
|
||||
|
||||
bool SocketBase::GetSocketName(intptr_t fd, SocketAddress* p_sa) {
|
||||
bool SocketBase::GetSocketName(intptr_t fd, RawAddr* raw) {
|
||||
ASSERT(fd >= 0);
|
||||
ASSERT(p_sa != nullptr);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sockaddr_un contains sa_family_t sun_family and char[] sun_path.
|
||||
// If size is the size of sa_family_t, this is an unnamed socket and
|
||||
// sun_path contains garbage.
|
||||
new (p_sa) SocketAddress(&raw.addr,
|
||||
/*unnamed_unix_socket=*/size == sizeof(sa_family_t));
|
||||
return true;
|
||||
ASSERT(raw != nullptr);
|
||||
return NO_RETRY_EXPECTED(getsockname(fd, &raw->addr, &raw->size)) == 0;
|
||||
}
|
||||
|
||||
intptr_t SocketBase::GetPort(intptr_t fd) {
|
||||
ASSERT(fd >= 0);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &size))) {
|
||||
if (NO_RETRY_EXPECTED(getsockname(fd, &raw.addr, &raw.size))) {
|
||||
return 0;
|
||||
}
|
||||
return SocketAddress::GetAddrPort(raw);
|
||||
@@ -309,19 +289,11 @@ intptr_t SocketBase::GetPort(intptr_t fd) {
|
||||
SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
|
||||
ASSERT(fd >= 0);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (NO_RETRY_EXPECTED(getpeername(fd, &raw.addr, &size))) {
|
||||
if (NO_RETRY_EXPECTED(getpeername(fd, &raw.addr, &raw.size))) {
|
||||
return nullptr;
|
||||
}
|
||||
// sockaddr_un contains sa_family_t sun_family and char[] sun_path.
|
||||
// If size is the size of sa_family_t, this is an unnamed socket and
|
||||
// sun_path contains garbage.
|
||||
if (size == sizeof(sa_family_t)) {
|
||||
*port = 0;
|
||||
return new SocketAddress(&raw.addr, /*unnamed_unix_socket=*/true);
|
||||
}
|
||||
*port = SocketAddress::GetAddrPort(raw);
|
||||
return new SocketAddress(&raw.addr);
|
||||
return new SocketAddress(raw);
|
||||
}
|
||||
|
||||
intptr_t SocketBase::GetStdioHandle(intptr_t num) {
|
||||
@@ -333,9 +305,8 @@ bool SocketBase::ReverseLookup(const RawAddr& addr,
|
||||
intptr_t host_len,
|
||||
OSError** os_error) {
|
||||
ASSERT(host_len >= NI_MAXHOST);
|
||||
int status = NO_RETRY_EXPECTED(
|
||||
getnameinfo(&addr.addr, SocketAddress::GetAddrLength(addr), host,
|
||||
host_len, nullptr, 0, NI_NAMEREQD));
|
||||
int status = NO_RETRY_EXPECTED(getnameinfo(
|
||||
&addr.addr, addr.size, host, host_len, nullptr, 0, NI_NAMEREQD));
|
||||
if (status != 0) {
|
||||
ASSERT(*os_error == nullptr);
|
||||
*os_error =
|
||||
@@ -396,9 +367,9 @@ AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces(
|
||||
for (struct ifaddrs* ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
|
||||
if (ShouldIncludeIfaAddrs(ifa, lookup_family)) {
|
||||
char* ifa_name = DartUtils::ScopedCopyCString(ifa->ifa_name);
|
||||
addresses->SetAt(
|
||||
i, new InterfaceSocketAddress(ifa->ifa_addr, ifa_name,
|
||||
if_nametoindex(ifa->ifa_name)));
|
||||
addresses->SetAt(i, new InterfaceSocketAddress(
|
||||
RawAddr::FromInet4or6(ifa->ifa_addr), ifa_name,
|
||||
if_nametoindex(ifa->ifa_name)));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,23 +20,19 @@
|
||||
namespace dart {
|
||||
namespace bin {
|
||||
|
||||
SocketAddress::SocketAddress(struct sockaddr* sockaddr,
|
||||
bool unnamed_unix_socket) {
|
||||
// Unix domain sockets not supported on Win. Remove this assert if enabled.
|
||||
ASSERT(!unnamed_unix_socket);
|
||||
ASSERT(INET6_ADDRSTRLEN >= INET_ADDRSTRLEN);
|
||||
RawAddr* raw = reinterpret_cast<RawAddr*>(sockaddr);
|
||||
|
||||
// Clear the port before calling WSAAddressToString as WSAAddressToString
|
||||
// includes the port in the formatted string.
|
||||
int err =
|
||||
SocketBase::FormatNumericAddress(*raw, as_string_, INET6_ADDRSTRLEN);
|
||||
|
||||
if (err != 0) {
|
||||
SocketAddress::SocketAddress(const RawAddr& addr) : addr_(addr) {
|
||||
if (addr.is_unnamed_unix_socket()) {
|
||||
as_string_[0] = 0;
|
||||
} else if (addr.ss.ss_family == AF_UNIX) {
|
||||
memmove(as_string_, addr.un.sun_path, sizeof(addr.un.sun_path));
|
||||
} else {
|
||||
int err = SocketBase::FormatNumericAddress(addr, as_string_,
|
||||
kMaxAddressStringLength);
|
||||
|
||||
if (err != 0) {
|
||||
as_string_[0] = 0;
|
||||
}
|
||||
}
|
||||
memmove(reinterpret_cast<void*>(&addr_), sockaddr,
|
||||
SocketAddress::GetAddrLength(*raw));
|
||||
}
|
||||
|
||||
static Mutex* init_mutex = new Mutex();
|
||||
@@ -62,18 +58,16 @@ bool SocketBase::Initialize() {
|
||||
bool SocketBase::FormatNumericAddress(const RawAddr& addr,
|
||||
char* address,
|
||||
int len) {
|
||||
socklen_t salen = SocketAddress::GetAddrLength(addr);
|
||||
DWORD l = len;
|
||||
RawAddr& raw = const_cast<RawAddr&>(addr);
|
||||
wchar_t* waddress = reinterpret_cast<wchar_t*>(
|
||||
Dart_ScopeAllocate((salen + 1) * sizeof(wchar_t)));
|
||||
wchar_t buf[SocketAddress::kMaxAddressStringLength];
|
||||
DWORD result_len = ARRAY_SIZE(buf);
|
||||
intptr_t result =
|
||||
WSAAddressToStringW(&raw.addr, salen, nullptr, waddress, &l);
|
||||
WSAAddressToStringW(&raw.addr, raw.size, nullptr, buf, &result_len);
|
||||
if (result != 0) {
|
||||
return true;
|
||||
}
|
||||
WideToUtf8Scope wide_name(waddress);
|
||||
strncpy(address, wide_name.utf8(), l);
|
||||
WideToUtf8Scope wide_name(buf);
|
||||
strncpy(address, wide_name.utf8(), len);
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -96,8 +90,7 @@ intptr_t SocketBase::RecvFrom(intptr_t fd,
|
||||
RawAddr* addr,
|
||||
SocketOpKind sync) {
|
||||
Handle* handle = reinterpret_cast<Handle*>(fd);
|
||||
socklen_t addr_len = sizeof(addr->ss);
|
||||
return handle->RecvFrom(buffer, num_bytes, &addr->addr, addr_len);
|
||||
return handle->RecvFrom(buffer, num_bytes, addr);
|
||||
}
|
||||
|
||||
bool SocketControlMessage::is_file_descriptors_control_message() {
|
||||
@@ -141,8 +134,7 @@ intptr_t SocketBase::SendTo(intptr_t fd,
|
||||
SocketOpKind sync) {
|
||||
Handle* handle = reinterpret_cast<Handle*>(fd);
|
||||
RawAddr& raw = const_cast<RawAddr&>(addr);
|
||||
return handle->SendTo(buffer, num_bytes, &raw.addr,
|
||||
SocketAddress::GetAddrLength(addr));
|
||||
return handle->SendTo(buffer, num_bytes, raw);
|
||||
}
|
||||
|
||||
intptr_t SocketBase::SendMessage(intptr_t fd,
|
||||
@@ -156,29 +148,18 @@ intptr_t SocketBase::SendMessage(intptr_t fd,
|
||||
return -1;
|
||||
}
|
||||
|
||||
bool SocketBase::GetSocketName(intptr_t fd, SocketAddress* p_sa) {
|
||||
bool SocketBase::GetSocketName(intptr_t fd, RawAddr* raw) {
|
||||
ASSERT(fd >= 0);
|
||||
ASSERT(p_sa != nullptr);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (getsockname(fd, &raw.addr, &size) == SOCKET_ERROR) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// sockaddr_un contains sa_family_t sun_family and char[] sun_path.
|
||||
// If size is the size of sa_family_t, this is an unnamed socket and
|
||||
// sun_path contains garbage.
|
||||
new (p_sa) SocketAddress(&raw.addr,
|
||||
/*unnamed_unix_socket=*/size == sizeof(u_short));
|
||||
return true;
|
||||
ASSERT(raw != nullptr);
|
||||
return getsockname(fd, &raw->addr, &raw->size) != SOCKET_ERROR;
|
||||
}
|
||||
|
||||
intptr_t SocketBase::GetPort(intptr_t fd) {
|
||||
ASSERT(reinterpret_cast<Handle*>(fd)->is_socket());
|
||||
SocketHandle* socket_handle = reinterpret_cast<SocketHandle*>(fd);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (getsockname(socket_handle->socket(), &raw.addr, &size) == SOCKET_ERROR) {
|
||||
if (getsockname(socket_handle->socket(), &raw.addr, &raw.size) ==
|
||||
SOCKET_ERROR) {
|
||||
return 0;
|
||||
}
|
||||
return SocketAddress::GetAddrPort(raw);
|
||||
@@ -192,16 +173,17 @@ SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
|
||||
reinterpret_cast<ClientSocket*>(fd)->PopulateRemoteAddr(raw)) {
|
||||
// `raw` was populated by `ClientSocket::PopulateRemoteAddr`.
|
||||
} else {
|
||||
socklen_t size = sizeof(raw);
|
||||
if (getpeername(socket_handle->socket(), &raw.addr, &size)) {
|
||||
if (getpeername(socket_handle->socket(), &raw.addr, &raw.size)) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
*port = SocketAddress::GetAddrPort(raw);
|
||||
// Clear the port before calling WSAAddressToString as WSAAddressToString
|
||||
// includes the port in the formatted string.
|
||||
SocketAddress::SetAddrPort(&raw, 0);
|
||||
return new SocketAddress(&raw.addr);
|
||||
if (raw.ss.ss_family != AF_UNIX) {
|
||||
SocketAddress::SetAddrPort(&raw, 0);
|
||||
}
|
||||
return new SocketAddress(raw);
|
||||
}
|
||||
|
||||
bool SocketBase::IsBindError(intptr_t error_number) {
|
||||
@@ -278,7 +260,11 @@ AddressList<SocketAddress>* SocketBase::LookupAddress(const char* host,
|
||||
intptr_t i = 0;
|
||||
for (struct addrinfo* c = info; c != nullptr; c = c->ai_next) {
|
||||
if ((c->ai_family == AF_INET) || (c->ai_family == AF_INET6)) {
|
||||
addresses->SetAt(i, new SocketAddress(c->ai_addr));
|
||||
RawAddr raw;
|
||||
memmove(&raw.addr, c->ai_addr, c->ai_addrlen);
|
||||
raw.size = c->ai_addrlen;
|
||||
|
||||
addresses->SetAt(i, new SocketAddress(raw));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
@@ -291,8 +277,8 @@ bool SocketBase::ReverseLookup(const RawAddr& addr,
|
||||
intptr_t host_len,
|
||||
OSError** os_error) {
|
||||
ASSERT(host_len >= NI_MAXHOST);
|
||||
int status = getnameinfo(&addr.addr, SocketAddress::GetAddrLength(addr), host,
|
||||
host_len, nullptr, 0, NI_NAMEREQD);
|
||||
int status = getnameinfo(&addr.addr, addr.size, host, host_len, nullptr, 0,
|
||||
NI_NAMEREQD);
|
||||
if (status != 0) {
|
||||
ASSERT(*os_error == nullptr);
|
||||
DWORD error_code = WSAGetLastError();
|
||||
@@ -316,25 +302,23 @@ bool SocketBase::ParseAddress(int type, const char* address, RawAddr* addr) {
|
||||
}
|
||||
|
||||
bool SocketBase::RawAddrToString(RawAddr* addr, char* str) {
|
||||
// According to InetNtopW(), buffer should be large enough for at least 46
|
||||
// characters for IPv6 and 16 for IPv4.
|
||||
COMPILE_ASSERT(INET6_ADDRSTRLEN >= 46);
|
||||
wchar_t tmp_buffer[INET6_ADDRSTRLEN];
|
||||
wchar_t tmp_buffer[SocketAddress::kMaxAddressStringLength];
|
||||
if (addr->addr.sa_family == AF_INET) {
|
||||
if (InetNtop(AF_INET, &addr->in.sin_addr, tmp_buffer, INET_ADDRSTRLEN) ==
|
||||
nullptr) {
|
||||
if (InetNtop(AF_INET, &addr->in.sin_addr, tmp_buffer,
|
||||
ARRAY_SIZE(tmp_buffer)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
ASSERT(addr->addr.sa_family == AF_INET6);
|
||||
if (InetNtop(AF_INET6, &addr->in6.sin6_addr, tmp_buffer,
|
||||
INET6_ADDRSTRLEN) == nullptr) {
|
||||
ARRAY_SIZE(tmp_buffer)) == nullptr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
WideToUtf8Scope wide_to_utf8_scope(tmp_buffer);
|
||||
if (wide_to_utf8_scope.length() <= INET6_ADDRSTRLEN) {
|
||||
strncpy(str, wide_to_utf8_scope.utf8(), INET6_ADDRSTRLEN);
|
||||
if (wide_to_utf8_scope.length() < SocketAddress::kMaxAddressStringLength) {
|
||||
strncpy(str, wide_to_utf8_scope.utf8(),
|
||||
SocketAddress::kMaxAddressStringLength);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -385,7 +369,7 @@ AddressList<InterfaceSocketAddress>* SocketBase::ListInterfaces(
|
||||
!(a->Flags & IP_ADAPTER_IPV6_ENABLED));
|
||||
addresses->SetAt(i,
|
||||
new InterfaceSocketAddress(
|
||||
u->Address.lpSockaddr,
|
||||
RawAddr::FromInet4or6(u->Address.lpSockaddr),
|
||||
StringUtilsWin::WideToUtf8(a->FriendlyName),
|
||||
a->Ipv6IfIndex != 0 ? a->Ipv6IfIndex : a->IfIndex));
|
||||
i++;
|
||||
@@ -521,7 +505,7 @@ bool SocketBase::JoinMulticast(intptr_t fd,
|
||||
int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
|
||||
struct group_req mreq;
|
||||
mreq.gr_interface = interfaceIndex;
|
||||
memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr));
|
||||
memmove(&mreq.gr_group, &addr.ss, addr.size);
|
||||
return setsockopt(handle->socket(), proto, MCAST_JOIN_GROUP,
|
||||
reinterpret_cast<char*>(&mreq), sizeof(mreq)) == 0;
|
||||
}
|
||||
@@ -534,7 +518,7 @@ bool SocketBase::LeaveMulticast(intptr_t fd,
|
||||
int proto = addr.addr.sa_family == AF_INET ? IPPROTO_IP : IPPROTO_IPV6;
|
||||
struct group_req mreq;
|
||||
mreq.gr_interface = interfaceIndex;
|
||||
memmove(&mreq.gr_group, &addr.ss, SocketAddress::GetAddrLength(addr));
|
||||
memmove(&mreq.gr_group, &addr.ss, addr.size);
|
||||
return setsockopt(handle->socket(), proto, MCAST_LEAVE_GROUP,
|
||||
reinterpret_cast<char*>(&mreq), sizeof(mreq)) == 0;
|
||||
}
|
||||
|
||||
@@ -82,8 +82,8 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
IOHandle* handle = reinterpret_cast<IOHandle*>(fd);
|
||||
LOG_INFO("Connect: calling connect(%ld)\n", handle->fd());
|
||||
intptr_t result = NO_RETRY_EXPECTED(
|
||||
connect(handle->fd(), &addr.addr, SocketAddress::GetAddrLength(addr)));
|
||||
intptr_t result =
|
||||
NO_RETRY_EXPECTED(connect(handle->fd(), &addr.addr, addr.size));
|
||||
if ((result == 0) || (errno == EINPROGRESS)) {
|
||||
return reinterpret_cast<intptr_t>(handle);
|
||||
}
|
||||
@@ -166,8 +166,7 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
}
|
||||
|
||||
LOG_INFO("ServerSocket::CreateBindListen: calling bind(%ld)\n", fd);
|
||||
if (NO_RETRY_EXPECTED(
|
||||
bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
if (NO_RETRY_EXPECTED(bind(fd, &addr.addr, addr.size)) < 0) {
|
||||
LOG_ERR("ServerSocket::CreateBindListen: bind(%ld) failed\n", fd);
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
@@ -229,10 +228,9 @@ static bool IsTemporaryAcceptError(int error) {
|
||||
intptr_t ServerSocket::Accept(intptr_t fd) {
|
||||
IOHandle* listen_handle = reinterpret_cast<IOHandle*>(fd);
|
||||
intptr_t socket;
|
||||
struct sockaddr clientaddr;
|
||||
socklen_t addrlen = sizeof(clientaddr);
|
||||
RawAddr client_addr;
|
||||
LOG_INFO("ServerSocket::Accept: calling accept(%ld)\n", fd);
|
||||
socket = listen_handle->Accept(&clientaddr, &addrlen);
|
||||
socket = listen_handle->Accept(&client_addr);
|
||||
if (socket == -1) {
|
||||
if (IsTemporaryAcceptError(errno)) {
|
||||
// We need to signal to the caller that this is actually not an
|
||||
|
||||
+13
-20
@@ -43,8 +43,7 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
}
|
||||
|
||||
static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(fd, &addr.addr, addr.size));
|
||||
if ((result == 0) || (errno == EINPROGRESS)) {
|
||||
return fd;
|
||||
}
|
||||
@@ -65,8 +64,7 @@ intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
|
||||
if (fd < 0) {
|
||||
return fd;
|
||||
}
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(
|
||||
fd, (struct sockaddr*)&addr.un, SocketAddress::GetAddrLength(addr)));
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(fd, &addr.addr, addr.size));
|
||||
if (result == 0 || errno == EAGAIN) {
|
||||
return fd;
|
||||
}
|
||||
@@ -85,8 +83,8 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
VOID_NO_RETRY_EXPECTED(
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
intptr_t result =
|
||||
TEMP_FAILURE_RETRY(bind(fd, &source_addr.addr, source_addr.size));
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
@@ -102,15 +100,14 @@ intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
intptr_t result =
|
||||
TEMP_FAILURE_RETRY(bind(fd, &source_addr.addr, source_addr.size));
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
result = TEMP_FAILURE_RETRY(connect(fd, (struct sockaddr*)&addr.un,
|
||||
SocketAddress::GetAddrLength(addr)));
|
||||
result = TEMP_FAILURE_RETRY(connect(fd, &addr.addr, addr.size));
|
||||
if (result == 0 || errno == EAGAIN) {
|
||||
return fd;
|
||||
}
|
||||
@@ -170,8 +167,7 @@ intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NO_RETRY_EXPECTED(
|
||||
bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
if (NO_RETRY_EXPECTED(bind(fd, &addr.addr, addr.size)) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -199,8 +195,7 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
|
||||
}
|
||||
|
||||
if (NO_RETRY_EXPECTED(
|
||||
bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
if (NO_RETRY_EXPECTED(bind(fd, &addr.addr, addr.size)) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -226,8 +221,7 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog) {
|
||||
intptr_t fd = Create(addr);
|
||||
if (NO_RETRY_EXPECTED(bind(fd, (struct sockaddr*)&addr.un,
|
||||
SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
if (NO_RETRY_EXPECTED(bind(fd, &addr.addr, addr.size)) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -254,10 +248,9 @@ static bool IsTemporaryAcceptError(int error) {
|
||||
|
||||
intptr_t ServerSocket::Accept(intptr_t fd) {
|
||||
intptr_t socket;
|
||||
struct sockaddr clientaddr;
|
||||
socklen_t addrlen = sizeof(clientaddr);
|
||||
socket = TEMP_FAILURE_RETRY(
|
||||
accept4(fd, &clientaddr, &addrlen, SOCK_NONBLOCK | SOCK_CLOEXEC));
|
||||
RawAddr client_addr;
|
||||
socket = TEMP_FAILURE_RETRY(accept4(fd, &client_addr.addr, &client_addr.size,
|
||||
SOCK_NONBLOCK | SOCK_CLOEXEC));
|
||||
if (socket == -1) {
|
||||
if (IsTemporaryAcceptError(errno)) {
|
||||
// We need to signal to the caller that this is actually not an
|
||||
|
||||
+10
-15
@@ -53,8 +53,7 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
}
|
||||
|
||||
static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(fd, &addr.addr, addr.size));
|
||||
if ((result == 0) || (errno == EINPROGRESS)) {
|
||||
return fd;
|
||||
}
|
||||
@@ -90,8 +89,8 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
VOID_NO_RETRY_EXPECTED(
|
||||
setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)));
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
intptr_t result =
|
||||
TEMP_FAILURE_RETRY(bind(fd, &source_addr.addr, source_addr.size));
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
@@ -107,8 +106,8 @@ intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
return fd;
|
||||
}
|
||||
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
bind(fd, &source_addr.addr, SocketAddress::GetAddrLength(source_addr)));
|
||||
intptr_t result =
|
||||
TEMP_FAILURE_RETRY(bind(fd, &source_addr.addr, source_addr.size));
|
||||
if (result != 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
@@ -160,8 +159,7 @@ intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
|
||||
VOID_NO_RETRY_EXPECTED(
|
||||
setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &optval, sizeof(optval)));
|
||||
|
||||
if (NO_RETRY_EXPECTED(
|
||||
bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
if (NO_RETRY_EXPECTED(bind(fd, &addr.addr, addr.size)) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -204,8 +202,7 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &optval, sizeof(optval)));
|
||||
}
|
||||
|
||||
if (NO_RETRY_EXPECTED(
|
||||
bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
if (NO_RETRY_EXPECTED(bind(fd, &addr.addr, addr.size)) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -245,8 +242,7 @@ intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (NO_RETRY_EXPECTED(
|
||||
bind(fd, &addr.addr, SocketAddress::GetAddrLength(addr))) < 0) {
|
||||
if (NO_RETRY_EXPECTED(bind(fd, &addr.addr, addr.size)) < 0) {
|
||||
FDUtils::SaveErrorAndClose(fd);
|
||||
return -1;
|
||||
}
|
||||
@@ -270,9 +266,8 @@ bool ServerSocket::StartAccept(intptr_t fd) {
|
||||
|
||||
intptr_t ServerSocket::Accept(intptr_t fd) {
|
||||
intptr_t socket;
|
||||
struct sockaddr clientaddr;
|
||||
socklen_t addrlen = sizeof(clientaddr);
|
||||
socket = TEMP_FAILURE_RETRY(accept(fd, &clientaddr, &addrlen));
|
||||
RawAddr client_addr;
|
||||
socket = TEMP_FAILURE_RETRY(accept(fd, &client_addr.addr, &client_addr.size));
|
||||
if (socket == -1) {
|
||||
if (errno == EAGAIN) {
|
||||
// We need to signal to the caller that this is actually not an
|
||||
|
||||
+51
-42
@@ -68,8 +68,10 @@ static intptr_t Connect(intptr_t fd,
|
||||
ClientSocket* handle = reinterpret_cast<ClientSocket*>(fd);
|
||||
SOCKET s = handle->socket();
|
||||
|
||||
int status =
|
||||
bind(s, &bind_addr.addr, SocketAddress::GetAddrLength(bind_addr));
|
||||
// Note: unlike |connect| |ConnectEx| requires *bound* socket, so we must
|
||||
// manually bind() it to some local address before we can issue a connect
|
||||
// request to the remote address.
|
||||
int status = bind(s, &bind_addr.addr, bind_addr.size);
|
||||
if (status != NO_ERROR) {
|
||||
const int rc = WSAGetLastError();
|
||||
handle->mark_closed(); // Destructor asserts that socket is marked closed.
|
||||
@@ -80,9 +82,9 @@ static intptr_t Connect(intptr_t fd,
|
||||
}
|
||||
|
||||
auto buffer = OverlappedBuffer::AllocateConnectBuffer(handle);
|
||||
status = EventHandler::delegate()->connect_ex()(
|
||||
s, &addr.addr, SocketAddress::GetAddrLength(addr), nullptr, 0, nullptr,
|
||||
buffer->GetCleanOverlapped());
|
||||
status = EventHandler::delegate()->connect_ex()(s, &addr.addr, addr.size,
|
||||
nullptr, 0, nullptr,
|
||||
buffer->GetCleanOverlapped());
|
||||
if (status == TRUE) {
|
||||
handle->ConnectComplete();
|
||||
return fd;
|
||||
@@ -90,6 +92,7 @@ static intptr_t Connect(intptr_t fd,
|
||||
buffer.release(); // Ownership passed to event handler.
|
||||
return fd;
|
||||
}
|
||||
|
||||
const int rc = WSAGetLastError();
|
||||
// Cleanup in case of error.
|
||||
handle->Close();
|
||||
@@ -109,18 +112,23 @@ intptr_t Socket::CreateConnect(const RawAddr& addr) {
|
||||
bind_addr.ss.ss_family = addr.ss.ss_family;
|
||||
if (addr.ss.ss_family == AF_INET) {
|
||||
bind_addr.in.sin_addr.s_addr = INADDR_ANY;
|
||||
} else {
|
||||
bind_addr.size = sizeof(sockaddr_in);
|
||||
} else if (addr.ss.ss_family == AF_INET6) {
|
||||
bind_addr.in6.sin6_addr = in6addr_any;
|
||||
bind_addr.size = sizeof(sockaddr_in6);
|
||||
} else if (addr.ss.ss_family == AF_UNIX) {
|
||||
// Local address is an anonymous unix socket.
|
||||
bind_addr.size = sizeof(ADDRESS_FAMILY);
|
||||
} else {
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return Connect(fd, addr, bind_addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateUnixDomainConnect(const RawAddr& addr) {
|
||||
// TODO(21403): Support unix domain socket on Windows
|
||||
// https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return -1;
|
||||
return CreateConnect(addr);
|
||||
}
|
||||
|
||||
intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
@@ -135,8 +143,7 @@ intptr_t Socket::CreateBindConnect(const RawAddr& addr,
|
||||
|
||||
intptr_t Socket::CreateUnixDomainBindConnect(const RawAddr& addr,
|
||||
const RawAddr& source_addr) {
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return -1;
|
||||
return CreateBindConnect(addr, source_addr);
|
||||
}
|
||||
|
||||
intptr_t ServerSocket::Accept(intptr_t fd) {
|
||||
@@ -200,7 +207,7 @@ intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
status = bind(s, &addr.addr, SocketAddress::GetAddrLength(addr));
|
||||
status = bind(s, &addr.addr, addr.size);
|
||||
if (status == SOCKET_ERROR) {
|
||||
DWORD rc = WSAGetLastError();
|
||||
closesocket(s);
|
||||
@@ -215,29 +222,32 @@ intptr_t Socket::CreateBindDatagram(const RawAddr& addr,
|
||||
intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
intptr_t backlog,
|
||||
bool v6_only) {
|
||||
SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM, IPPROTO_TCP);
|
||||
SOCKET s = socket(addr.ss.ss_family, SOCK_STREAM,
|
||||
addr.ss.ss_family == AF_UNIX ? 0 : IPPROTO_TCP);
|
||||
if (s == INVALID_SOCKET) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
BOOL optval = true;
|
||||
int status =
|
||||
setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||
reinterpret_cast<const char*>(&optval), sizeof(optval));
|
||||
if (status == SOCKET_ERROR) {
|
||||
DWORD rc = WSAGetLastError();
|
||||
closesocket(s);
|
||||
SetLastError(rc);
|
||||
return -1;
|
||||
int status;
|
||||
if (addr.ss.ss_family != AF_UNIX) {
|
||||
BOOL optval = true;
|
||||
status = setsockopt(s, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
|
||||
reinterpret_cast<const char*>(&optval), sizeof(optval));
|
||||
if (status == SOCKET_ERROR) {
|
||||
DWORD rc = WSAGetLastError();
|
||||
closesocket(s);
|
||||
SetLastError(rc);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
if (addr.ss.ss_family == AF_INET6) {
|
||||
optval = v6_only;
|
||||
BOOL optval = v6_only;
|
||||
setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
reinterpret_cast<const char*>(&optval), sizeof(optval));
|
||||
}
|
||||
|
||||
status = bind(s, &addr.addr, SocketAddress::GetAddrLength(addr));
|
||||
status = bind(s, &addr.addr, addr.size);
|
||||
if (status == SOCKET_ERROR) {
|
||||
DWORD rc = WSAGetLastError();
|
||||
closesocket(s);
|
||||
@@ -245,20 +255,22 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
return -1;
|
||||
}
|
||||
|
||||
ListenSocket* listen_socket = new ListenSocket(s);
|
||||
ListenSocket* listen_socket = new ListenSocket(s, addr.ss.ss_family);
|
||||
|
||||
// Test for invalid socket port 65535 (some browsers disallow it).
|
||||
if ((SocketAddress::GetAddrPort(addr) == 0) &&
|
||||
(SocketBase::GetPort(reinterpret_cast<intptr_t>(listen_socket)) ==
|
||||
65535)) {
|
||||
// Don't close fd until we have created new. By doing that we ensure another
|
||||
// port.
|
||||
intptr_t new_s = CreateBindListen(addr, backlog, v6_only);
|
||||
DWORD rc = WSAGetLastError();
|
||||
closesocket(s);
|
||||
listen_socket->Release();
|
||||
SetLastError(rc);
|
||||
return new_s;
|
||||
if (addr.ss.ss_family != AF_UNIX) {
|
||||
// Test for invalid socket port 65535 (some browsers disallow it).
|
||||
if ((SocketAddress::GetAddrPort(addr) == 0) &&
|
||||
(SocketBase::GetPort(reinterpret_cast<intptr_t>(listen_socket)) ==
|
||||
65535)) {
|
||||
// Don't close fd until we have created new. By doing that we ensure
|
||||
// another port.
|
||||
intptr_t new_s = CreateBindListen(addr, backlog, v6_only);
|
||||
DWORD rc = WSAGetLastError();
|
||||
closesocket(s);
|
||||
listen_socket->Release();
|
||||
SetLastError(rc);
|
||||
return new_s;
|
||||
}
|
||||
}
|
||||
|
||||
status = listen(s, backlog > 0 ? backlog : SOMAXCONN);
|
||||
@@ -275,10 +287,7 @@ intptr_t ServerSocket::CreateBindListen(const RawAddr& addr,
|
||||
|
||||
intptr_t ServerSocket::CreateUnixDomainBindListen(const RawAddr& addr,
|
||||
intptr_t backlog) {
|
||||
// TODO(21403): Support unix domain socket on Windows
|
||||
// https://devblogs.microsoft.com/commandline/af_unix-comes-to-windows/
|
||||
SetLastError(ERROR_NOT_SUPPORTED);
|
||||
return -1;
|
||||
return CreateBindListen(addr, backlog);
|
||||
}
|
||||
|
||||
bool ServerSocket::StartAccept(intptr_t fd) {
|
||||
|
||||
@@ -84,7 +84,7 @@ void FUNCTION_NAME(SynchronousSocket_LookupRequest)(Dart_NativeArguments args) {
|
||||
error = Dart_ListSetAt(entry, 1, as_string);
|
||||
DART_CHECK_ERROR_AND_CLEANUP(error, addresses);
|
||||
|
||||
RawAddr raw = addr->addr();
|
||||
const auto& raw = addr->addr();
|
||||
Dart_Handle data = SocketAddress::ToTypedData(raw);
|
||||
DART_CHECK_ERROR_AND_CLEANUP(data, addresses);
|
||||
|
||||
@@ -301,7 +301,7 @@ void FUNCTION_NAME(SynchronousSocket_GetRemotePeer)(Dart_NativeArguments args) {
|
||||
Dart_ListSetAt(entry, 1, Dart_NewStringFromCString(addr->as_string()));
|
||||
DART_CHECK_ERROR_AND_CLEANUP(error, addr);
|
||||
|
||||
RawAddr raw = addr->addr();
|
||||
const auto& raw = addr->addr();
|
||||
error = Dart_ListSetAt(entry, 2, SocketAddress::ToTypedData(raw));
|
||||
DART_CHECK_ERROR_AND_CLEANUP(error, addr);
|
||||
|
||||
|
||||
@@ -32,8 +32,7 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
}
|
||||
|
||||
static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(fd, &addr.addr, addr.size));
|
||||
if (result == 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -32,8 +32,7 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
}
|
||||
|
||||
static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(fd, &addr.addr, addr.size));
|
||||
if (result == 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -35,8 +35,7 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
}
|
||||
|
||||
static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
intptr_t result = TEMP_FAILURE_RETRY(
|
||||
connect(fd, &addr.addr, SocketAddress::GetAddrLength(addr)));
|
||||
intptr_t result = TEMP_FAILURE_RETRY(connect(fd, &addr.addr, addr.size));
|
||||
if (result == 0) {
|
||||
return fd;
|
||||
}
|
||||
|
||||
@@ -23,8 +23,7 @@ static intptr_t Create(const RawAddr& addr) {
|
||||
|
||||
static intptr_t Connect(intptr_t fd, const RawAddr& addr) {
|
||||
SOCKET socket = static_cast<SOCKET>(fd);
|
||||
intptr_t result =
|
||||
connect(socket, &addr.addr, SocketAddress::GetAddrLength(addr));
|
||||
intptr_t result = connect(socket, &addr.addr, addr.size);
|
||||
return (result == SOCKET_ERROR) ? -1 : socket;
|
||||
}
|
||||
|
||||
@@ -43,8 +42,7 @@ intptr_t SynchronousSocket::Available(intptr_t fd) {
|
||||
intptr_t SynchronousSocket::GetPort(intptr_t fd) {
|
||||
SOCKET socket = static_cast<SOCKET>(fd);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (getsockname(socket, &raw.addr, &size) == SOCKET_ERROR) {
|
||||
if (getsockname(socket, &raw.addr, &raw.size) == SOCKET_ERROR) {
|
||||
return 0;
|
||||
}
|
||||
return SocketAddress::GetAddrPort(raw);
|
||||
@@ -53,15 +51,14 @@ intptr_t SynchronousSocket::GetPort(intptr_t fd) {
|
||||
SocketAddress* SynchronousSocket::GetRemotePeer(intptr_t fd, intptr_t* port) {
|
||||
SOCKET socket = static_cast<SOCKET>(fd);
|
||||
RawAddr raw;
|
||||
socklen_t size = sizeof(raw);
|
||||
if (getpeername(socket, &raw.addr, &size)) {
|
||||
if (getpeername(socket, &raw.addr, &raw.size)) {
|
||||
return nullptr;
|
||||
}
|
||||
*port = SocketAddress::GetAddrPort(raw);
|
||||
// Clear the port before calling WSAAddressToString as WSAAddressToString
|
||||
// includes the port in the formatted string.
|
||||
SocketAddress::SetAddrPort(&raw, 0);
|
||||
return new SocketAddress(&raw.addr);
|
||||
return new SocketAddress(raw);
|
||||
}
|
||||
|
||||
intptr_t SynchronousSocket::Read(intptr_t fd,
|
||||
|
||||
@@ -7,11 +7,15 @@ import 'dart:convert';
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:expect/expect.dart';
|
||||
import 'package:path/path.dart' as p;
|
||||
|
||||
import 'test_utils.dart' show withTempDir;
|
||||
|
||||
Future testAddress(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
var server = await ServerSocket.bind(address, 0);
|
||||
|
||||
var client = await Socket.connect(address, server.port);
|
||||
@@ -34,7 +38,10 @@ Future testAddress(String name) async {
|
||||
}
|
||||
|
||||
testBindShared(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
var socket = await ServerSocket.bind(address, 0, shared: true);
|
||||
Expect.isTrue(socket.port == 0);
|
||||
|
||||
@@ -46,7 +53,7 @@ testBindShared(String name) async {
|
||||
// Test relative path
|
||||
var path = name.substring(name.lastIndexOf('/') + 1);
|
||||
address = InternetAddress(
|
||||
'${name}/../${path}/sock',
|
||||
p.join(name, '..', path, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
|
||||
@@ -63,8 +70,11 @@ testBindShared(String name) async {
|
||||
await socket3.close();
|
||||
}
|
||||
|
||||
testBind(String name) async {
|
||||
final address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
Future<void> testBind(String name) async {
|
||||
final address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await ServerSocket.bind(address, 0, shared: false);
|
||||
Expect.isTrue(server.address.toString().contains(name));
|
||||
// Unix domain socket does not have a valid port number.
|
||||
@@ -87,7 +97,10 @@ testBind(String name) async {
|
||||
}
|
||||
|
||||
Future testListenCloseListenClose(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
ServerSocket socket = await ServerSocket.bind(address, 0, shared: true);
|
||||
ServerSocket socket2 = await ServerSocket.bind(
|
||||
address,
|
||||
@@ -124,12 +137,15 @@ Future testListenCloseListenClose(String name) async {
|
||||
}
|
||||
|
||||
Future testSourceAddressConnect(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
ServerSocket server = await ServerSocket.bind(address, 0);
|
||||
|
||||
var completer = Completer<void>();
|
||||
var localAddress = InternetAddress(
|
||||
'$name/local',
|
||||
p.join(name, 'local'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
server.listen((Socket socket) async {
|
||||
@@ -267,7 +283,10 @@ Future testExistingFile(String name) async {
|
||||
// Test that a leftover file(In case of previous process being killed and
|
||||
// finalizer doesn't clean up the file) will be cleaned up and bind() should
|
||||
// be able to bind to the socket.
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
// Create a file with the same name
|
||||
File(address.address).createSync();
|
||||
try {
|
||||
@@ -280,8 +299,19 @@ Future testExistingFile(String name) async {
|
||||
Expect.fail("bind should fail with existing file");
|
||||
}
|
||||
|
||||
bool isUnsupportedOperationError(e) {
|
||||
final msg = e.toString();
|
||||
return e is OSError &&
|
||||
(msg.contains('Operation not supported') ||
|
||||
msg.contains('unsupported option') ||
|
||||
msg.contains('Protocol not available'));
|
||||
}
|
||||
|
||||
Future testSetSockOpt(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
var server = await ServerSocket.bind(address, 0, shared: false);
|
||||
|
||||
var sub;
|
||||
@@ -303,7 +333,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.getRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -316,7 +346,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.getRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -329,7 +359,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.getRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -342,7 +372,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.getRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +385,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.getRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Protocol not available', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -368,7 +398,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.getRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -381,7 +411,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.getRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,7 +419,7 @@ Future testSetSockOpt(String name) async {
|
||||
try {
|
||||
socket.setOption(SocketOption.tcpNoDelay, true);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 5; i++) {
|
||||
@@ -401,7 +431,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.setRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,7 +444,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.setRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -427,7 +457,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.setRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -440,7 +470,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.setRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -453,7 +483,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.setRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Protocol not available', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -466,7 +496,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.setRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,7 +509,7 @@ Future testSetSockOpt(String name) async {
|
||||
);
|
||||
var result = socket.setRawOption(option);
|
||||
} catch (e) {
|
||||
Expect.contains('Operation not supported', e.toString());
|
||||
Expect.isTrue(isUnsupportedOperationError(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -488,7 +518,10 @@ Future testSetSockOpt(String name) async {
|
||||
}
|
||||
|
||||
Future testHttpServer(String name) async {
|
||||
var address = InternetAddress('$name/sock', type: InternetAddressType.unix);
|
||||
var address = InternetAddress(
|
||||
p.join(name, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
var httpServer = await HttpServer.bind(address, 0);
|
||||
|
||||
var sub;
|
||||
@@ -512,7 +545,7 @@ Future testFileMessage(String tempDirPath) async {
|
||||
final completer = Completer<bool>();
|
||||
|
||||
final address = InternetAddress(
|
||||
'$tempDirPath/sock',
|
||||
p.join(tempDirPath, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -553,7 +586,7 @@ Future testFileMessage(String tempDirPath) async {
|
||||
});
|
||||
});
|
||||
|
||||
final file = File('$tempDirPath/myfile.txt');
|
||||
final file = File(p.join(tempDirPath, 'myfile.txt'));
|
||||
final randomAccessFile = file.openSync(mode: FileMode.write);
|
||||
// Send a message with sample file.
|
||||
final socket = await RawSocket.connect(address, 0);
|
||||
@@ -593,7 +626,7 @@ Future testTooLargeControlMessage(String tempDirPath) async {
|
||||
}
|
||||
final completer = Completer<bool>();
|
||||
final address = InternetAddress(
|
||||
'$tempDirPath/sock',
|
||||
p.join(tempDirPath, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -610,7 +643,7 @@ Future testTooLargeControlMessage(String tempDirPath) async {
|
||||
});
|
||||
});
|
||||
|
||||
final file = File('$tempDirPath/myfile.txt');
|
||||
final file = File(p.join(tempDirPath, 'myfile.txt'));
|
||||
final randomAccessFile = file.openSync(mode: FileMode.write);
|
||||
// Send a message with sample file.
|
||||
final socket = await RawSocket.connect(address, 0);
|
||||
@@ -649,7 +682,7 @@ Future testFileMessageWithShortRead(String tempDirPath) async {
|
||||
final completer = Completer<bool>();
|
||||
|
||||
final address = InternetAddress(
|
||||
'$tempDirPath/sock',
|
||||
p.join(tempDirPath, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -694,7 +727,7 @@ Future testFileMessageWithShortRead(String tempDirPath) async {
|
||||
});
|
||||
});
|
||||
|
||||
final file = File('$tempDirPath/myfile.txt');
|
||||
final file = File(p.join(tempDirPath, 'myfile.txt'));
|
||||
final randomAccessFile = file.openSync(mode: FileMode.write);
|
||||
// Send a message with sample file.
|
||||
final socket = await RawSocket.connect(address, 0);
|
||||
@@ -765,7 +798,7 @@ Future testSocketMessage(String uniqueName) async {
|
||||
return;
|
||||
}
|
||||
final address = InternetAddress(
|
||||
'$uniqueName/sock',
|
||||
p.join(uniqueName, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -876,7 +909,7 @@ Future testStdioMessage(String tempDirPath, {bool caller = false}) async {
|
||||
}
|
||||
|
||||
final address = InternetAddress(
|
||||
'$tempDirPath/sock',
|
||||
p.join(tempDirPath, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -909,7 +942,7 @@ Future testStdioMessage(String tempDirPath, {bool caller = false}) async {
|
||||
});
|
||||
});
|
||||
|
||||
final file = File('$tempDirPath/myfile.txt');
|
||||
final file = File(p.join(tempDirPath, 'myfile.txt'));
|
||||
final randomAccessFile = file.openSync(mode: FileMode.write);
|
||||
// Send a message with sample file.
|
||||
var socket = await RawSocket.connect(address, 0);
|
||||
@@ -940,7 +973,7 @@ Future testReadPipeMessage(String uniqueName) async {
|
||||
return;
|
||||
}
|
||||
final address = InternetAddress(
|
||||
'$uniqueName/sock',
|
||||
p.join(uniqueName, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -1011,7 +1044,7 @@ Future testWritePipeMessage(String uniqueName) async {
|
||||
return;
|
||||
}
|
||||
final address = InternetAddress(
|
||||
'$uniqueName/sock',
|
||||
p.join(uniqueName, 'sock'),
|
||||
type: InternetAddressType.unix,
|
||||
);
|
||||
final server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -1080,26 +1113,32 @@ Future testWritePipeMessage(String uniqueName) async {
|
||||
}
|
||||
|
||||
Future testDeleteFile(String tempDirPath) async {
|
||||
if (!Platform.isMacOS && !Platform.isLinux && !Platform.isAndroid) {
|
||||
return;
|
||||
}
|
||||
final name = '$tempDirPath/sock';
|
||||
final name = p.join(tempDirPath, 'sock');
|
||||
final address = InternetAddress(name, type: InternetAddressType.unix);
|
||||
var server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
final file = File(name);
|
||||
Expect.isTrue(file.existsSync());
|
||||
Expect.isTrue(await file.exists());
|
||||
|
||||
bool sockExistsSync() {
|
||||
return FileSystemEntity.typeSync(name) != FileSystemEntityType.notFound;
|
||||
}
|
||||
|
||||
Future<bool> sockExists() async {
|
||||
return await FileSystemEntity.type(name) != FileSystemEntityType.notFound;
|
||||
}
|
||||
|
||||
Expect.isTrue(sockExistsSync());
|
||||
Expect.isTrue(await sockExists());
|
||||
file.deleteSync();
|
||||
Expect.isFalse(file.existsSync());
|
||||
Expect.isFalse(await file.exists());
|
||||
Expect.isFalse(sockExistsSync());
|
||||
Expect.isFalse(await sockExists());
|
||||
await server.close();
|
||||
|
||||
server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
Expect.isTrue(file.existsSync());
|
||||
Expect.isTrue(await file.exists());
|
||||
Expect.isTrue(sockExistsSync());
|
||||
Expect.isTrue(await sockExists());
|
||||
await file.delete();
|
||||
Expect.isFalse(file.existsSync());
|
||||
Expect.isFalse(await file.exists());
|
||||
Expect.isFalse(sockExistsSync());
|
||||
Expect.isFalse(await sockExists());
|
||||
await server.close();
|
||||
}
|
||||
|
||||
@@ -1107,7 +1146,7 @@ Future testFileStat(String tempDirPath) async {
|
||||
if (!Platform.isMacOS && !Platform.isLinux && !Platform.isAndroid) {
|
||||
return;
|
||||
}
|
||||
final name = '$tempDirPath/sock';
|
||||
final name = p.join(tempDirPath, 'sock');
|
||||
final address = InternetAddress(name, type: InternetAddressType.unix);
|
||||
var server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
FileStat fileStat = FileStat.statSync(name);
|
||||
@@ -1119,8 +1158,8 @@ Future testFileRename(String tempDirPath) async {
|
||||
if (!Platform.isLinux && !Platform.isAndroid) {
|
||||
return;
|
||||
}
|
||||
final name1 = '$tempDirPath/sock1';
|
||||
final name2 = '$tempDirPath/sock2';
|
||||
final name1 = p.join(tempDirPath, 'sock1');
|
||||
final name2 = p.join(tempDirPath, 'sock2');
|
||||
final address = InternetAddress(name1, type: InternetAddressType.unix);
|
||||
var server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
final file1 = File(name1);
|
||||
@@ -1137,8 +1176,8 @@ Future testFileCopy(String tempDirPath) async {
|
||||
if (!Platform.isMacOS && !Platform.isLinux && !Platform.isAndroid) {
|
||||
return;
|
||||
}
|
||||
final name1 = '$tempDirPath/sock1';
|
||||
final name2 = '$tempDirPath/sock2';
|
||||
final name1 = p.join(tempDirPath, 'sock1');
|
||||
final name2 = p.join(tempDirPath, 'sock2');
|
||||
final address = InternetAddress(name1, type: InternetAddressType.unix);
|
||||
final file1 = File(name1);
|
||||
var server = await RawServerSocket.bind(address, 0, shared: false);
|
||||
@@ -1226,7 +1265,10 @@ void main(List<String> args) async {
|
||||
});
|
||||
},
|
||||
(e, st) {
|
||||
if (Platform.isMacOS || Platform.isLinux || Platform.isAndroid) {
|
||||
if (Platform.isWindows ||
|
||||
Platform.isMacOS ||
|
||||
Platform.isLinux ||
|
||||
Platform.isAndroid) {
|
||||
Expect.fail("Unexpected exception $e is thrown:\n$st");
|
||||
} else {
|
||||
Expect.isTrue(e is SocketException);
|
||||
|
||||
Reference in New Issue
Block a user