// Copyright 2025 Google LLC // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "internal/platform/implementation/windows/socket_address.h" #include #include #include #include #include #include #include "absl/types/span.h" #include "internal/platform/logging.h" #include "internal/platform/service_address.h" namespace nearby::windows { SocketAddress::SocketAddress(const sockaddr_in& address) { std::memcpy(&address_, &address, sizeof(sockaddr_in)); address_.ss_family = AF_INET; } SocketAddress::SocketAddress(const sockaddr_in6& address) { std::memcpy(&address_, &address, sizeof(sockaddr_in6)); address_.ss_family = AF_INET6; } SocketAddress::SocketAddress(const sockaddr_storage& address) { DCHECK(address.ss_family == AF_INET || address.ss_family == AF_INET6); std::memcpy(&address_, &address, sizeof(sockaddr_storage)); } SocketAddress SocketAddress::ToMappedIPv6() const { if (address_.ss_family == AF_INET6) { return *this; } if (address_.ss_family != AF_INET) { LOG(ERROR) << "Unknown socket family: " << address_.ss_family; return SocketAddress(); } const sockaddr_in* v4_address = ipv4_address(); sockaddr_in6 v6_address; v6_address.sin6_port = v4_address->sin_port; v6_address.sin6_flowinfo = 0; v6_address.sin6_scope_id = 0; v6_address.sin6_addr.u.Word[0] = 0; v6_address.sin6_addr.u.Word[1] = 0; v6_address.sin6_addr.u.Word[2] = 0; v6_address.sin6_addr.u.Word[3] = 0; v6_address.sin6_addr.u.Word[4] = 0; v6_address.sin6_addr.u.Word[5] = 0xffff; v6_address.sin6_addr.u.Word[6] = v4_address->sin_addr.S_un.S_un_w.s_w1; v6_address.sin6_addr.u.Word[7] = v4_address->sin_addr.S_un.S_un_w.s_w2; return SocketAddress(v6_address); } bool SocketAddress::FromString(SocketAddress& address, std::string address_string, int port) { if (address_string.empty()) { address = SocketAddress(); address.set_port(port); return true; } // Try v4 address first. address.address_.ss_family = AF_INET; int sock_address_size = sizeof(sockaddr_storage); if (WSAStringToAddressA(address_string.data(), AF_INET, /*lpProtocolInfo=*/nullptr, reinterpret_cast(&address.address_), &sock_address_size) == 0) { address.set_port(port); return true; } address.address_.ss_family = AF_INET6; sock_address_size = sizeof(sockaddr_storage); if (WSAStringToAddressA(const_cast(address_string.data()), AF_INET6, /*lpProtocolInfo=*/nullptr, reinterpret_cast(&address.address_), &sock_address_size) == 0) { address.set_port(port); return true; } return false; } bool SocketAddress::FromBytes(SocketAddress& address, absl::Span address_bytes, int port) { // Must be either 4 or 16 bytes. if (address_bytes.size() != 4 && address_bytes.size() != 16) { // Invalid address bytes size. return false; } if (address_bytes.size() == 4) { address.address_.ss_family = AF_INET; sockaddr_in* v4_address = reinterpret_cast(&address.address_); std::memcpy(&v4_address->sin_addr, address_bytes.data(), sizeof(in_addr)); address.set_port(port); return true; } address.address_.ss_family = AF_INET6; sockaddr_in6* v6_address = reinterpret_cast(&address.address_); std::memcpy(&v6_address->sin6_addr, address_bytes.data(), sizeof(in6_addr)); address.set_port(port); return true; } bool SocketAddress::FromServiceAddress(SocketAddress& address, const ServiceAddress& service_address) { return FromBytes(address, service_address.address, service_address.port); } uint16_t SocketAddress::port() const { DCHECK(address_.ss_family == AF_INET || address_.ss_family == AF_INET6); if (address_.ss_family == AF_INET) { const sockaddr_in* v4_address = reinterpret_cast(&address_); return ntohs(v4_address->sin_port); } if (address_.ss_family == AF_INET6) { const sockaddr_in6* v6_address = reinterpret_cast(&address_); return ntohs(v6_address->sin6_port); } LOG(ERROR) << "Unknown socket family: " << address_.ss_family; return 0; } bool SocketAddress::set_port(uint16_t port) { DCHECK(address_.ss_family == AF_INET || address_.ss_family == AF_INET6); if (address_.ss_family == AF_INET) { sockaddr_in* v4_address = reinterpret_cast(&address_); v4_address->sin_port = htons(port); return true; } if (address_.ss_family == AF_INET6) { sockaddr_in6* v6_address = reinterpret_cast(&address_); v6_address->sin6_port = htons(port); return true; } LOG(ERROR) << "Unknown socket family: " << address_.ss_family; return false; } std::string SocketAddress::ToString() const { std::string address_string; DWORD size = INET6_ADDRSTRLEN; // Max IP address length. address_string.resize(size); if (WSAAddressToStringA( const_cast(reinterpret_cast(&address_)), sizeof(sockaddr_storage), /*lpProtocolInfo=*/nullptr, address_string.data(), &size) != 0) { LOG(ERROR) << __func__ << ": Cannot convert address to string: " << WSAGetLastError(); return ""; } // size includes the null terminator. address_string.resize(size - 1); return address_string; } bool SocketAddress::IsV6LinkLocal() const { if (address_.ss_family != AF_INET6) { return false; } const sockaddr_in6* v6_address = ipv6_address(); return IN6_IS_ADDR_LINKLOCAL(&v6_address->sin6_addr); } bool SocketAddress::IsV4LinkLocal() const { if (address_.ss_family != AF_INET) { return false; } const sockaddr_in* v4_address = ipv4_address(); return (v4_address->sin_addr.S_un.S_un_b.s_b1 == 169 && v4_address->sin_addr.S_un.S_un_b.s_b2 == 254); } bool SocketAddress::SetScopeId(uint32_t scope_id) { if (address_.ss_family != AF_INET6) { return false; } sockaddr_in6* v6_address = reinterpret_cast(&address_); v6_address->sin6_scope_id = scope_id; return true; } ServiceAddress SocketAddress::ToServiceAddress(uint16_t port) const { if (port == 0) { port = this->port(); } if (family() == AF_INET) { return ServiceAddress{ .address = {ipv4_address()->sin_addr.S_un.S_un_b.s_b1, ipv4_address()->sin_addr.S_un.S_un_b.s_b2, ipv4_address()->sin_addr.S_un.S_un_b.s_b3, ipv4_address()->sin_addr.S_un.S_un_b.s_b4}, .port = port, }; } return ServiceAddress{ .address = std::vector(ipv6_address()->sin6_addr.u.Byte, ipv6_address()->sin6_addr.u.Byte + 16), .port = port, }; } } // namespace nearby::windows