mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Add IPv6 dual stack support to NearbyServerSocket.
PiperOrigin-RevId: 820274866
This commit is contained in:
committed by
Copybara-Service
parent
4c37f90965
commit
98c2b17752
@@ -252,6 +252,7 @@ cc_library(
|
||||
deps = [
|
||||
":crypto", # build_cleaner: keep
|
||||
":network_info",
|
||||
":socket_address",
|
||||
":string_utils",
|
||||
":types",
|
||||
"//connections/implementation/flags:connections_flags",
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <string>
|
||||
|
||||
#include "internal/platform/implementation/windows/nearby_client_socket.h"
|
||||
#include "internal/platform/implementation/windows/socket_address.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby::windows {
|
||||
@@ -42,66 +43,77 @@ NearbyServerSocket::~NearbyServerSocket() {
|
||||
}
|
||||
}
|
||||
|
||||
bool NearbyServerSocket::Listen(const std::string& ip_address, int port) {
|
||||
bool NearbyServerSocket::Listen(const std::string& ip_address, int port,
|
||||
bool dual_stack) {
|
||||
VLOG(1) << "Listen to socket at " << ip_address << ":" << port;
|
||||
LOG(INFO) << "Server socket dual stack support: " << dual_stack;
|
||||
if (!is_socket_initiated_) {
|
||||
LOG(ERROR) << "Windows socket is not initiated.";
|
||||
return false;
|
||||
}
|
||||
|
||||
socket_ = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
socket_ = socket(dual_stack ? AF_INET6 :AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
if (socket_ == INVALID_SOCKET) {
|
||||
LOG(ERROR) << "Failed to create socket.";
|
||||
return false;
|
||||
}
|
||||
|
||||
BOOL flag = TRUE;
|
||||
if (setsockopt(/*s=*/socket_, /*level=*/SOL_SOCKET, /*optname=*/SO_KEEPALIVE,
|
||||
/*optval=*/(const char*)&flag,
|
||||
/*optlen=*/sizeof(flag)) == SOCKET_ERROR) {
|
||||
if (setsockopt(socket_, SOL_SOCKET, SO_KEEPALIVE,
|
||||
reinterpret_cast<const char*>(&flag),
|
||||
sizeof(flag)) == SOCKET_ERROR) {
|
||||
LOG(WARNING) << "Failed to set SO_KEEPALIVE with error "
|
||||
<< WSAGetLastError();
|
||||
}
|
||||
|
||||
struct sockaddr_in serv_addr;
|
||||
serv_addr.sin_family = AF_INET;
|
||||
serv_addr.sin_port = htons(port);
|
||||
if (ip_address.empty()) {
|
||||
serv_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
} else {
|
||||
serv_addr.sin_addr.s_addr = inet_addr(ip_address.c_str());
|
||||
if (dual_stack) {
|
||||
// On Windows dual stack is not the default.
|
||||
// https://learn.microsoft.com/en-us/windows/win32/winsock/dual-stack-sockets#creating-a-dual-stack-socket
|
||||
DWORD v6_only = 0;
|
||||
if (setsockopt(socket_, IPPROTO_IPV6, IPV6_V6ONLY,
|
||||
reinterpret_cast<const char*>(&v6_only),
|
||||
sizeof(v6_only)) == SOCKET_ERROR) {
|
||||
LOG(WARNING) << "Failed to set IPV6_V6ONLY with error "
|
||||
<< WSAGetLastError();
|
||||
}
|
||||
}
|
||||
SocketAddress serv_address(dual_stack);
|
||||
if (!SocketAddress::FromString(serv_address, ip_address, port)) {
|
||||
LOG(ERROR) << "Failed to parse address " << ip_address << ":" << port;
|
||||
return false;
|
||||
}
|
||||
// Set REUSEADDR if a specific port is needed.
|
||||
if (port != 0) {
|
||||
BOOL flag = TRUE;
|
||||
if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR, (const char*)&flag,
|
||||
if (setsockopt(socket_, SOL_SOCKET, SO_REUSEADDR,
|
||||
reinterpret_cast<const char*>(&flag),
|
||||
sizeof(flag)) == SOCKET_ERROR) {
|
||||
LOG(WARNING) << "Failed to set SO_REUSEADDR with error "
|
||||
<< WSAGetLastError();
|
||||
}
|
||||
}
|
||||
|
||||
if (bind(/*s=*/socket_, /*addr=*/(struct sockaddr*)&serv_addr,
|
||||
/*namelen=*/sizeof(serv_addr)) == SOCKET_ERROR) {
|
||||
if (bind(socket_, serv_address.address(), sizeof(sockaddr_storage)) ==
|
||||
SOCKET_ERROR) {
|
||||
LOG(ERROR) << "Failed to bind socket with error " << WSAGetLastError();
|
||||
closesocket(socket_);
|
||||
return false;
|
||||
}
|
||||
|
||||
sockaddr_in local_address;
|
||||
int address_length = sizeof(local_address);
|
||||
if (getsockname(/*s=*/socket_, (/*name=*/SOCKADDR*)&local_address,
|
||||
/*namelen=*/&address_length) == SOCKET_ERROR) {
|
||||
SocketAddress local_address(dual_stack);
|
||||
int address_length = sizeof(sockaddr_storage);
|
||||
if (getsockname(socket_, local_address.address(), &address_length) ==
|
||||
SOCKET_ERROR) {
|
||||
LOG(ERROR) << "Failed to get socket name with error " << WSAGetLastError();
|
||||
closesocket(socket_);
|
||||
return false;
|
||||
}
|
||||
|
||||
port_ = ntohs(local_address.sin_port);
|
||||
port_ = local_address.port();
|
||||
|
||||
VLOG(1) << "Bound to " << ip_address << ":" << port_;
|
||||
VLOG(1) << "Bound to " << local_address.ToString();
|
||||
|
||||
if (::listen(/*s=*/socket_, /*backlog=*/SOMAXCONN) == SOCKET_ERROR) {
|
||||
if (::listen(socket_, /*backlog=*/SOMAXCONN) == SOCKET_ERROR) {
|
||||
LOG(ERROR) << "Failed to listen socket with error " << WSAGetLastError();
|
||||
closesocket(socket_);
|
||||
return false;
|
||||
@@ -111,28 +123,24 @@ bool NearbyServerSocket::Listen(const std::string& ip_address, int port) {
|
||||
}
|
||||
|
||||
std::unique_ptr<NearbyClientSocket> NearbyServerSocket::Accept() {
|
||||
VLOG(1) << "Accept is called on NearbyServerSocket.";
|
||||
LOG(INFO) << "Accept is called on NearbyServerSocket.";
|
||||
if (!is_socket_initiated_) {
|
||||
LOG(WARNING) << "Windows socket is not initiated";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
sockaddr_in peer_address;
|
||||
int peer_address_length = sizeof(peer_address);
|
||||
SocketAddress peer_address;
|
||||
int peer_address_length = sizeof(sockaddr_storage);
|
||||
|
||||
SOCKET client_socket =
|
||||
accept(/*s=*/socket_, /*addr=*/(SOCKADDR*)&peer_address,
|
||||
/*addrlen=*/&peer_address_length);
|
||||
SOCKET client_socket = accept(socket_, peer_address.address(),
|
||||
/*addrlen=*/&peer_address_length);
|
||||
if (client_socket == INVALID_SOCKET) {
|
||||
LOG(ERROR) << "Failed to accept socket with error: " << WSAGetLastError();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
char client_ip[INET_ADDRSTRLEN];
|
||||
inet_ntop(AF_INET, &(peer_address.sin_addr), client_ip, INET_ADDRSTRLEN);
|
||||
int client_port = ntohs(peer_address.sin_port);
|
||||
|
||||
LOG(INFO) << "Accepted remote device " << client_ip << ":" << client_port;
|
||||
LOG(INFO) << "Accepted remote device.";
|
||||
VLOG(1) << "Remote device address: " << peer_address.ToString();
|
||||
return std::make_unique<NearbyClientSocket>(client_socket);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ class NearbyServerSocket {
|
||||
NearbyServerSocket();
|
||||
~NearbyServerSocket();
|
||||
|
||||
bool Listen(const std::string& ip_address, int port);
|
||||
bool Listen(const std::string& ip_address, int port, bool dual_stack = false);
|
||||
std::unique_ptr<NearbyClientSocket> Accept();
|
||||
bool Close();
|
||||
|
||||
|
||||
@@ -40,6 +40,7 @@ SocketAddress::SocketAddress(const sockaddr_in6& address) : dual_stack_(true) {
|
||||
|
||||
SocketAddress::SocketAddress(const sockaddr_storage& address)
|
||||
: dual_stack_(true) {
|
||||
DCHECK(address.ss_family == AF_INET || address.ss_family == AF_INET6);
|
||||
std::memcpy(&address_, &address, sizeof(sockaddr_storage));
|
||||
ToMappedIPv6();
|
||||
}
|
||||
@@ -72,7 +73,7 @@ void SocketAddress::ToMappedIPv6() {
|
||||
}
|
||||
|
||||
bool SocketAddress::FromString(SocketAddress& address,
|
||||
const std::string& address_string, int port) {
|
||||
std::string address_string, int port) {
|
||||
if (address_string.empty()) {
|
||||
if (address.dual_stack_) {
|
||||
address.address_.ss_family = AF_INET6;
|
||||
@@ -95,7 +96,7 @@ bool SocketAddress::FromString(SocketAddress& address,
|
||||
// Try v4 address first.
|
||||
address.address_.ss_family = AF_INET;
|
||||
int sock_address_size = sizeof(sockaddr_storage);
|
||||
if (WSAStringToAddressA(const_cast<char*>(address_string.data()), AF_INET,
|
||||
if (WSAStringToAddressA(address_string.data(), AF_INET,
|
||||
/*lpProtocolInfo=*/nullptr,
|
||||
reinterpret_cast<sockaddr*>(&address.address_),
|
||||
&sock_address_size) == 0) {
|
||||
|
||||
@@ -37,6 +37,8 @@ class SocketAddress {
|
||||
}
|
||||
explicit SocketAddress(const sockaddr_in& address, bool dual_stack = false);
|
||||
explicit SocketAddress(const sockaddr_in6& address);
|
||||
// This constructor assumes dual_stack is enabled, and will convert IPv4
|
||||
// addresses to mapped IPv6 addresses.
|
||||
explicit SocketAddress(const sockaddr_storage& address);
|
||||
|
||||
~SocketAddress() = default;
|
||||
@@ -46,8 +48,8 @@ class SocketAddress {
|
||||
// If dual_stack is enabled, an IPv4 string will be returned as a mapped IPv6
|
||||
// address (e.g. [::ffff:192.0.2.1]).
|
||||
// Use empty `address_string` to create and unspecified address ie. ADDR_ANY.
|
||||
static bool FromString(SocketAddress& address,
|
||||
const std::string& address_string, int port = 0);
|
||||
static bool FromString(SocketAddress& address, std::string address_string,
|
||||
int port = 0);
|
||||
|
||||
// `Returns port in host byte order.
|
||||
int port() const;
|
||||
@@ -56,12 +58,10 @@ class SocketAddress {
|
||||
|
||||
std::string ToString() const;
|
||||
|
||||
const sockaddr_in* v4_address() const {
|
||||
return reinterpret_cast<const sockaddr_in*>(&address_);
|
||||
}
|
||||
const sockaddr_in6* v6_address() const {
|
||||
return reinterpret_cast<const sockaddr_in6*>(&address_);
|
||||
}
|
||||
// Returns a pointer to the internal sockaddr_storage.
|
||||
// This can be used to modify the address directly. However, the dual_stack
|
||||
// state is not honored, ie. it will not convert IPv4 addresses to mapped IPv6
|
||||
// addresses.
|
||||
sockaddr* address() {
|
||||
return reinterpret_cast<sockaddr*>(&address_);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user