diff --git a/CHANGELOG.md b/CHANGELOG.md index 6859482a490..695b91ee207 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/runtime/bin/eventhandler_fuchsia.cc b/runtime/bin/eventhandler_fuchsia.cc index 7ca7c6e92f8..880627dac76 100644 --- a/runtime/bin/eventhandler_fuchsia.cc +++ b/runtime/bin/eventhandler_fuchsia.cc @@ -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); diff --git a/runtime/bin/eventhandler_fuchsia.h b/runtime/bin/eventhandler_fuchsia.h index d9a381a34c0..64c05e19e67 100644 --- a/runtime/bin/eventhandler_fuchsia.h +++ b/runtime/bin/eventhandler_fuchsia.h @@ -26,6 +26,7 @@ namespace dart { namespace bin { class DescriptorInfo; +struct RawAddr; class IOHandle : public ReferenceCounted { public: @@ -46,7 +47,7 @@ class IOHandle : public ReferenceCounted { // 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. diff --git a/runtime/bin/eventhandler_win.cc b/runtime/bin/eventhandler_win.cc index c7dc55f63ad..e38c02e4249 100644 --- a/runtime/bin/eventhandler_win.cc +++ b/runtime/bin/eventhandler_win.cc @@ -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(GetBufferStart() + GetBufferSize()); - *from_len_addr_ = sizeof(struct sockaddr_storage); - from_ = reinterpret_cast(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(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::AllocateBuffer( } std::unique_ptr 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::AllocateReadBuffer( @@ -129,7 +126,7 @@ std::unique_ptr 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 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 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(); + 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(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(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 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. diff --git a/runtime/bin/eventhandler_win.h b/runtime/bin/eventhandler_win.h index 9f54c6e9a90..fe106de55e5 100644 --- a/runtime/bin/eventhandler_win.h +++ b/runtime/bin/eventhandler_win.h @@ -47,7 +47,9 @@ class OverlappedBuffer { kConnect }; - static std::unique_ptr AllocateAcceptBuffer(Handle* handle); + static std::unique_ptr AllocateAcceptBuffer( + Handle* handle, + ADDRESS_FAMILY sa_family); static std::unique_ptr AllocateReadBuffer(Handle* handle, int buffer_size); static std::unique_ptr AllocateRecvFromBuffer( @@ -86,9 +88,7 @@ class OverlappedBuffer { SOCKET client() const { return client_; } char* GetBufferStart() { return reinterpret_cast(&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, 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, public DescriptorInfoBase { std::unique_ptr buffer); virtual bool IssueSendToLocked(MonitorLocker* ml, std::unique_ptr 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 { 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 { 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 { class ClientSocket : public DescriptorInfoSingleMixin { public: explicit ClientSocket(intptr_t s, - std::unique_ptr remote_addr = nullptr) + std::unique_ptr&& remote_addr = nullptr) : DescriptorInfoSingleMixin(s, kClientSocket), next_(nullptr), connected_(false), @@ -508,8 +505,7 @@ class DatagramSocket : public DescriptorInfoSingleMixin { private: virtual bool IssueSendToLocked(MonitorLocker* ml, std::unique_ptr buffer, - sockaddr* sa, - socklen_t sa_len); + const RawAddr& addr); DISALLOW_COPY_AND_ASSIGN(DatagramSocket); }; diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc index e9d9431302a..7c076e92853 100644 --- a/runtime/bin/file_win.cc +++ b/runtime/bin/file_win.cc @@ -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, diff --git a/runtime/bin/socket.cc b/runtime/bin/socket.cc index 1d14d428468..3aa6793bdd4 100644 --- a/runtime/bin/socket.cc +++ b/runtime/bin/socket.cc @@ -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(&addr), 0, sizeof(RawAddr)); if (len == sizeof(in_addr)) { addr.in.sin_family = AF_INET; + addr.size = sizeof(sockaddr_in); memmove(reinterpret_cast(&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(&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( - 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); diff --git a/runtime/bin/socket.h b/runtime/bin/socket.h index 9a53d51774d..224afa560b2 100644 --- a/runtime/bin/socket.h +++ b/runtime/bin/socket.h @@ -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; diff --git a/runtime/bin/socket_base.cc b/runtime/bin/socket_base.cc index c69b544b85c..eca54f2e625 100644 --- a/runtime/bin/socket_base.cc +++ b/runtime/bin/socket_base.cc @@ -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(addr), 0, sizeof(RawAddr)); if (len == sizeof(in_addr)) { addr->in.sin_family = AF_INET; + addr->size = sizeof(sockaddr_in); memmove(reinterpret_cast(&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(&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); } diff --git a/runtime/bin/socket_base.h b/runtime/bin/socket_base.h index af60b2416ad..904b73ac0b0 100644 --- a/runtime/bin/socket_base.h +++ b/runtime/bin/socket_base.h @@ -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); diff --git a/runtime/bin/socket_base_fuchsia.cc b/runtime/bin/socket_base_fuchsia.cc index 1d6002866d4..3456e8c47a5 100644 --- a/runtime/bin/socket_base_fuchsia.cc +++ b/runtime/bin/socket_base_fuchsia.cc @@ -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(sa), - as_string_, INET6_ADDRSTRLEN)) { + if (!SocketBase::FormatNumericAddress(addr, as_string_, + kMaxAddressStringLength)) { as_string_[0] = 0; } - socklen_t salen = GetAddrLength(*reinterpret_cast(sa)); - memmove(reinterpret_cast(&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(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(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* SocketBase::LookupAddress(const char* host, AddressList* addresses = new AddressList(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* 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++; } } diff --git a/runtime/bin/socket_base_linux.cc b/runtime/bin/socket_base_linux.cc index 570f03b23d2..24f8e067055 100644 --- a/runtime/bin/socket_base_linux.cc +++ b/runtime/bin/socket_base_linux.cc @@ -87,7 +87,7 @@ AddressList* SocketBase::LookupAddress(const char* host, AddressList* addresses = new AddressList(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; } diff --git a/runtime/bin/socket_base_macos.cc b/runtime/bin/socket_base_macos.cc index 9250f788d78..f229ff0b83a 100644 --- a/runtime/bin/socket_base_macos.cc +++ b/runtime/bin/socket_base_macos.cc @@ -78,7 +78,7 @@ AddressList* SocketBase::LookupAddress(const char* host, AddressList* addresses = new AddressList(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++; } } diff --git a/runtime/bin/socket_base_posix.cc b/runtime/bin/socket_base_posix.cc index 3838e6d11ee..629c307d1d6 100644 --- a/runtime/bin/socket_base_posix.cc +++ b/runtime/bin/socket_base_posix.cc @@ -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(sa), - as_string_, INET6_ADDRSTRLEN)) { + if (!SocketBase::FormatNumericAddress(addr, as_string_, + kMaxAddressStringLength)) { as_string_[0] = 0; } } - socklen_t salen = - GetAddrLength(*reinterpret_cast(sa), unnamed_unix_socket); - memmove(reinterpret_cast(&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* 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++; } } diff --git a/runtime/bin/socket_base_win.cc b/runtime/bin/socket_base_win.cc index 966dada4de8..5ff60467b0d 100644 --- a/runtime/bin/socket_base_win.cc +++ b/runtime/bin/socket_base_win.cc @@ -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(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(&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(addr); - wchar_t* waddress = reinterpret_cast( - 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(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(fd); RawAddr& raw = const_cast(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(fd)->is_socket()); SocketHandle* socket_handle = reinterpret_cast(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(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* 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* 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(&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(&mreq), sizeof(mreq)) == 0; } diff --git a/runtime/bin/socket_fuchsia.cc b/runtime/bin/socket_fuchsia.cc index 885ec97063d..33ff9f81d69 100644 --- a/runtime/bin/socket_fuchsia.cc +++ b/runtime/bin/socket_fuchsia.cc @@ -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(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(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(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 diff --git a/runtime/bin/socket_linux.cc b/runtime/bin/socket_linux.cc index 99fa9754f15..cbd00abcbbd 100644 --- a/runtime/bin/socket_linux.cc +++ b/runtime/bin/socket_linux.cc @@ -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 diff --git a/runtime/bin/socket_macos.cc b/runtime/bin/socket_macos.cc index 6aa863f5a35..64bc0c7e25a 100644 --- a/runtime/bin/socket_macos.cc +++ b/runtime/bin/socket_macos.cc @@ -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 diff --git a/runtime/bin/socket_win.cc b/runtime/bin/socket_win.cc index a64dceeb390..06572149247 100644 --- a/runtime/bin/socket_win.cc +++ b/runtime/bin/socket_win.cc @@ -68,8 +68,10 @@ static intptr_t Connect(intptr_t fd, ClientSocket* handle = reinterpret_cast(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(&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(&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(&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(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(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) { diff --git a/runtime/bin/sync_socket.cc b/runtime/bin/sync_socket.cc index 00d3ec4160f..a3a47d1caa5 100644 --- a/runtime/bin/sync_socket.cc +++ b/runtime/bin/sync_socket.cc @@ -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); diff --git a/runtime/bin/sync_socket_fuchsia.cc b/runtime/bin/sync_socket_fuchsia.cc index 2775e5bce72..ac83d7a2cac 100644 --- a/runtime/bin/sync_socket_fuchsia.cc +++ b/runtime/bin/sync_socket_fuchsia.cc @@ -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; } diff --git a/runtime/bin/sync_socket_linux.cc b/runtime/bin/sync_socket_linux.cc index 9c27088c74a..d0e9619ce65 100644 --- a/runtime/bin/sync_socket_linux.cc +++ b/runtime/bin/sync_socket_linux.cc @@ -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; } diff --git a/runtime/bin/sync_socket_macos.cc b/runtime/bin/sync_socket_macos.cc index 83535b85d2e..6172b9a64c3 100644 --- a/runtime/bin/sync_socket_macos.cc +++ b/runtime/bin/sync_socket_macos.cc @@ -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; } diff --git a/runtime/bin/sync_socket_win.cc b/runtime/bin/sync_socket_win.cc index d09ae0da65e..020504f7b1e 100644 --- a/runtime/bin/sync_socket_win.cc +++ b/runtime/bin/sync_socket_win.cc @@ -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(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(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(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, diff --git a/tests/standalone/io/unix_socket_test.dart b/tests/standalone/io/unix_socket_test.dart index 10ac7079b9d..b59431c69ef 100644 --- a/tests/standalone/io/unix_socket_test.dart +++ b/tests/standalone/io/unix_socket_test.dart @@ -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 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(); 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(); 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(); 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(); 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 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 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);