Fix Socket remoteAddress obtaining on Win32 #51778

Closes https://github.com/dart-lang/sdk/pull/51981

GitOrigin-RevId: de22efdd25a716b6c7eac086e2cb12e8793554f5
Change-Id: If1d8247f7e0188c47c19e19f33732a56493d21d8
Bug: https://github.com/dart-lang/sdk/issues/51778
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/294220
Reviewed-by: Alexander Aprelev <aam@google.com>
Commit-Queue: Brian Quinlan <bquinlan@google.com>
Reviewed-by: Brian Quinlan <bquinlan@google.com>
This commit is contained in:
Mihail Slobodyanuk
2023-06-07 19:32:49 +00:00
committed by Commit Queue
parent 884be01ec3
commit a4b25027fe
4 changed files with 79 additions and 18 deletions
+55 -11
View File
@@ -13,6 +13,7 @@
#include <mswsock.h> // NOLINT
#include <winsock2.h> // NOLINT
#include <ws2tcpip.h> // NOLINT
#include <utility>
#include "bin/builtin.h"
#include "bin/dartutils.h"
@@ -33,6 +34,14 @@ namespace bin {
static constexpr int kBufferSize = 64 * 1024;
static constexpr int kStdOverlappedBufferSize = 16 * 1024;
static constexpr int kMaxUDPPackageLength = 64 * 1024;
// For AcceptEx there needs to be buffer storage for address
// information for two addresses (local and remote address). The
// AcceptEx documentation says: "This value must be at least 16
// bytes more than the maximum address length for the transport
// protocol in use."
static constexpr int kAcceptExAddressAdditionalBytes = 16;
static constexpr int kAcceptExAddressStorageSize =
sizeof(SOCKADDR_STORAGE) + kAcceptExAddressAdditionalBytes;
OverlappedBuffer* OverlappedBuffer::AllocateBuffer(int buffer_size,
Operation operation) {
@@ -455,17 +464,21 @@ bool ListenSocket::LoadAcceptEx() {
return (status != SOCKET_ERROR);
}
bool ListenSocket::LoadGetAcceptExSockaddrs() {
// Load the GetAcceptExSockaddrs function into memory using WSAIoctl.
GUID guid_get_accept_ex_sockaddrs = WSAID_GETACCEPTEXSOCKADDRS;
DWORD bytes;
int status =
WSAIoctl(socket(), SIO_GET_EXTENSION_FUNCTION_POINTER,
&guid_get_accept_ex_sockaddrs,
sizeof(guid_get_accept_ex_sockaddrs), &GetAcceptExSockaddrs_,
sizeof(GetAcceptExSockaddrs_), &bytes, nullptr, nullptr);
return (status != SOCKET_ERROR);
}
bool ListenSocket::IssueAccept() {
MonitorLocker ml(&monitor_);
// For AcceptEx there needs to be buffer storage for address
// information for two addresses (local and remote address). The
// AcceptEx documentation says: "This value must be at least 16
// bytes more than the maximum address length for the transport
// protocol in use."
const int kAcceptExAddressAdditionalBytes = 16;
const int kAcceptExAddressStorageSize =
sizeof(SOCKADDR_STORAGE) + kAcceptExAddressAdditionalBytes;
OverlappedBuffer* buffer =
OverlappedBuffer::AllocateAcceptBuffer(2 * kAcceptExAddressStorageSize);
DWORD received;
@@ -498,8 +511,25 @@ void ListenSocket::AcceptComplete(OverlappedBuffer* buffer,
int rc = setsockopt(buffer->client(), SOL_SOCKET, SO_UPDATE_ACCEPT_CONTEXT,
reinterpret_cast<char*>(&s), sizeof(s));
if (rc == NO_ERROR) {
// getpeername() returns incorrect results when used with a socket that
// was accepted using overlapped I/O. AcceptEx includes the remote
// address in its result so retrieve it using GetAcceptExSockaddrs and
// save it.
LPSOCKADDR local_addr;
int local_addr_length;
LPSOCKADDR remote_addr;
int remote_addr_length;
GetAcceptExSockaddrs_(
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);
// Insert the accepted socket into the list.
ClientSocket* client_socket = new ClientSocket(buffer->client());
ClientSocket* client_socket = new ClientSocket(
buffer->client(),
std::move(std::unique_ptr<RawAddr>(raw_remote_addr)));
client_socket->mark_connected();
client_socket->CreateCompletionPort(completion_port);
if (accepted_head_ == nullptr) {
@@ -557,8 +587,9 @@ void ListenSocket::DoClose() {
}
// To finish resetting the state of the ListenSocket back to what it was
// before EnsureInitialized was called, we have to reset the AcceptEx_
// function pointer.
// and GetAcceptExSockaddrs_ function pointers.
AcceptEx_ = nullptr;
GetAcceptExSockaddrs_ = nullptr;
}
bool ListenSocket::CanAccept() {
@@ -601,7 +632,12 @@ void ListenSocket::EnsureInitialized(
ASSERT(event_handler_ == nullptr);
event_handler_ = event_handler;
CreateCompletionPort(event_handler_->completion_port());
LoadAcceptEx();
bool isLoaded = LoadAcceptEx();
ASSERT(isLoaded);
}
if (GetAcceptExSockaddrs_ == nullptr) {
bool isLoaded = LoadGetAcceptExSockaddrs();
ASSERT(isLoaded);
}
}
@@ -977,6 +1013,14 @@ bool ClientSocket::IsClosed() {
return connected_ && closed_ && !HasPendingRead() && !HasPendingWrite();
}
bool ClientSocket::PopulateRemoteAddr(RawAddr& addr) {
if (!remote_addr_) {
return false;
}
addr = *remote_addr_;
return true;
}
bool DatagramSocket::IssueSendTo(struct sockaddr* sa, socklen_t sa_len) {
MonitorLocker ml(&monitor_);
ASSERT(completion_port_ != INVALID_HANDLE_VALUE);
+16 -3
View File
@@ -12,9 +12,12 @@
#include <mswsock.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <memory>
#include <utility>
#include "bin/builtin.h"
#include "bin/reference_counting.h"
#include "bin/socket_base.h"
#include "bin/thread.h"
namespace dart {
@@ -387,6 +390,7 @@ class ListenSocket : public DescriptorInfoMultipleMixin<SocketHandle> {
explicit ListenSocket(intptr_t s)
: DescriptorInfoMultipleMixin(s, true),
AcceptEx_(nullptr),
GetAcceptExSockaddrs_(nullptr),
pending_accept_count_(0),
accepted_head_(nullptr),
accepted_tail_(nullptr),
@@ -418,8 +422,10 @@ class ListenSocket : public DescriptorInfoMultipleMixin<SocketHandle> {
private:
bool LoadAcceptEx();
bool LoadGetAcceptExSockaddrs();
LPFN_ACCEPTEX AcceptEx_;
LPFN_GETACCEPTEXSOCKADDRS GetAcceptExSockaddrs_;
// The number of asynchronous `IssueAccept` operations which haven't completed
// yet.
@@ -440,12 +446,14 @@ class ListenSocket : public DescriptorInfoMultipleMixin<SocketHandle> {
// Information on connected sockets.
class ClientSocket : public DescriptorInfoSingleMixin<SocketHandle> {
public:
explicit ClientSocket(intptr_t s)
explicit ClientSocket(intptr_t s,
std::unique_ptr<RawAddr> remote_addr = nullptr)
: DescriptorInfoSingleMixin(s, true),
DisconnectEx_(nullptr),
next_(nullptr),
connected_(false),
closed_(false) {
closed_(false),
remote_addr_(std::move(remote_addr)) {
LoadDisconnectEx();
type_ = kClientSocket;
}
@@ -465,13 +473,17 @@ class ClientSocket : public DescriptorInfoSingleMixin<SocketHandle> {
virtual bool IssueWrite();
void IssueDisconnect();
void DisconnectComplete(OverlappedBuffer* buffer);
void ConnectComplete(OverlappedBuffer* buffer);
virtual void EnsureInitialized(EventHandlerImplementation* event_handler);
virtual void DoClose();
virtual bool IsClosed();
// If `ClientSocket` was constructed with a `remote_addr`, populate `addr`
// with that value and return `true`. Otherwise leave `addr` untouched and
// return `false`.
bool PopulateRemoteAddr(RawAddr& addr);
ClientSocket* next() { return next_; }
void set_next(ClientSocket* next) { next_ = next; }
@@ -491,6 +503,7 @@ class ClientSocket : public DescriptorInfoSingleMixin<SocketHandle> {
ClientSocket* next_;
bool connected_;
bool closed_;
std::unique_ptr<RawAddr> remote_addr_;
#if defined(DEBUG)
static intptr_t disconnecting_;
+8 -3
View File
@@ -188,9 +188,14 @@ SocketAddress* SocketBase::GetRemotePeer(intptr_t fd, intptr_t* port) {
ASSERT(reinterpret_cast<Handle*>(fd)->is_socket());
SocketHandle* socket_handle = reinterpret_cast<SocketHandle*>(fd);
RawAddr raw;
socklen_t size = sizeof(raw);
if (getpeername(socket_handle->socket(), &raw.addr, &size)) {
return nullptr;
if (socket_handle->is_client_socket() &&
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)) {
return nullptr;
}
}
*port = SocketAddress::GetAddrPort(raw);
// Clear the port before calling WSAAddressToString as WSAAddressToString
-1
View File
@@ -42,7 +42,6 @@ io/socket_upgrade_to_secure_test: Skip # Issue 27638
[ $system == windows ]
io/process_sync_test: Pass, Timeout # Issue 24596
io/sleep_test: Pass, Fail # Issue 25757
io/socket_info_ipv6_test: Skip
verbose_gc_to_bmu_test: Skip
[ $arch == arm && $mode == release && $runtime == dart_precompiled && $system == android ]