Improve usabilty of ServiceAddress.

PiperOrigin-RevId: 842439675
This commit is contained in:
Francis Tsui
2025-12-09 16:22:25 -08:00
committed by Copybara-Service
parent 4652aef48c
commit 63f943aaed
10 changed files with 308 additions and 8 deletions
+1
View File
@@ -427,6 +427,7 @@ let package = Package(
"internal/platform/borrowable_test.cc",
"internal/platform/implementation/windows/http_loader_test.cc",
"internal/platform/blocking_queue_stream_test.cc",
"internal/platform/service_address_test.cc",
"internal/network/utils_test.cc",
"internal/network/url_test.cc",
"internal/network/http_response_test.cc",
+15
View File
@@ -42,6 +42,7 @@ cc_library(
"base64_utils.cc",
"input_stream.cc",
"prng.cc",
"service_address.cc",
],
hdrs = [
"base64_utils.h",
@@ -59,6 +60,7 @@ cc_library(
"payload_id.h",
"prng.h",
"runnable.h",
"service_address.h",
"socket.h",
"types.h",
"wifi_credential.h",
@@ -70,6 +72,7 @@ cc_library(
"//connections:partners",
],
deps = [
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"//internal/platform/implementation:wifi_utils",
"//proto:connections_enums_cc_proto",
"@com_google_absl//absl/base:core_headers",
@@ -80,6 +83,7 @@ cc_library(
"@com_google_absl//absl/status",
"@com_google_absl//absl/status:statusor",
"@com_google_absl//absl/strings",
"@com_google_absl//absl/strings:str_format",
"@com_google_absl//absl/synchronization",
"@com_google_absl//absl/time",
],
@@ -606,3 +610,14 @@ cc_test(
"@com_google_googletest//:gtest_main",
],
)
cc_test(
name = "service_address_test",
srcs = ["service_address_test.cc"],
deps = [
":base",
"//connections/implementation/proto:offline_wire_formats_cc_proto",
"@com_github_protobuf_matchers//protobuf-matchers",
"@com_google_googletest//:gtest_main",
],
)
@@ -354,6 +354,7 @@ cc_library(
"//:__subpackages__",
],
deps = [
"//internal/platform:base",
"//internal/platform:logging",
"@com_google_absl//absl/types:span",
],
@@ -23,6 +23,7 @@
#include "absl/types/span.h"
#include "internal/platform/logging.h"
#include "internal/platform/service_address.h"
namespace nearby::windows {
@@ -149,6 +150,11 @@ bool SocketAddress::FromBytes(SocketAddress& address,
return true;
}
bool SocketAddress::FromServiceAddress(SocketAddress& address,
const ServiceAddress& service_address) {
return FromBytes(address, service_address.address, service_address.port);
}
int SocketAddress::port() const {
DCHECK(address_.ss_family == AF_INET || address_.ss_family == AF_INET6);
if (address_.ss_family == AF_INET) {
@@ -23,6 +23,7 @@
#include <string>
#include "absl/types/span.h"
#include "internal/platform/service_address.h"
namespace nearby::windows {
@@ -63,6 +64,9 @@ class SocketAddress {
static bool FromBytes(SocketAddress& address,
absl::Span<const char> address_bytes, int port = 0);
static bool FromServiceAddress(SocketAddress& address,
const ServiceAddress& service_address);
// Returns true if dual stack support has been enabled.
bool dual_stack() const { return dual_stack_; }
@@ -15,6 +15,7 @@
#include "internal/platform/implementation/windows/socket_address.h"
#include "gtest/gtest.h"
#include "internal/platform/service_address.h"
namespace nearby::windows {
namespace {
@@ -201,5 +202,58 @@ TEST(SocketAddressTest, IPv6LinkLocalFail) {
EXPECT_FALSE(address.IsV6LinkLocal());
}
TEST(SocketAddressTest, FromServiceAddressIPv4) {
SocketAddress address;
ServiceAddress service_address = {
.address = {192, 168, 1, 1},
.port = 8080,
};
EXPECT_TRUE(SocketAddress::FromServiceAddress(address, service_address));
EXPECT_EQ(address.ToString(), "192.168.1.1:8080");
EXPECT_EQ(address.port(), 8080);
}
TEST(SocketAddressTest, FromServiceAddressIPv4DualStack) {
SocketAddress address(/*dual_stack=*/true);
ServiceAddress service_address = {
.address = {192, 168, 1, 1},
.port = 8080,
};
EXPECT_TRUE(SocketAddress::FromServiceAddress(address, service_address));
EXPECT_EQ(address.ToString(), "[::ffff:192.168.1.1]:8080");
EXPECT_EQ(address.port(), 8080);
}
TEST(SocketAddressTest, FromServiceAddressIPv6) {
SocketAddress address(/*dual_stack=*/true);
ServiceAddress service_address = {
.address = {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x4d, 0xb2, 0xb3, 0x5c, 0x22,
0x03, 0x98, 0xa1},
.port = 8080,
};
EXPECT_TRUE(SocketAddress::FromServiceAddress(address, service_address));
EXPECT_EQ(address.ToString(), "[fe80::4db2:b35c:2203:98a1]:8080");
EXPECT_EQ(address.port(), 8080);
}
TEST(SocketAddressTest, FromServiceAddressIPv6NoDualStack) {
SocketAddress address;
ServiceAddress service_address = {
.address = {0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0x4d, 0xb2, 0xb3, 0x5c, 0x22,
0x03, 0x98, 0xa1},
.port = 8080,
};
EXPECT_FALSE(SocketAddress::FromServiceAddress(address, service_address));
}
TEST(SocketAddressTest, FromServiceAddressInvalidAddress) {
SocketAddress address;
ServiceAddress service_address = {
.address = {192, 168, 1},
.port = 8080,
};
EXPECT_FALSE(SocketAddress::FromServiceAddress(address, service_address));
}
} // namespace
} // namespace nearby::windows
+45
View File
@@ -0,0 +1,45 @@
// 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/service_address.h"
#include <string>
#include "connections/implementation/proto/offline_wire_formats.pb.h"
namespace nearby {
void ServiceAddressToProto(
const ServiceAddress& service_address,
location::nearby::connections::ServiceAddress& proto) {
proto.set_ip_address(std::string(service_address.address.begin(),
service_address.address.end()));
proto.set_port(service_address.port);
}
bool ServiceAddressFromProto(
const location::nearby::connections::ServiceAddress& proto,
ServiceAddress& service_address) {
// Address must be either 4 or 16 bytes and port must be set.
if ((proto.ip_address().size() != 16 && proto.ip_address().size() != 4) ||
proto.port() == 0) {
return false;
}
service_address.address = {proto.ip_address().begin(),
proto.ip_address().end()};
service_address.port = proto.port();
return true;
}
} // namespace nearby
+59
View File
@@ -0,0 +1,59 @@
// 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.
#ifndef THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_SERVICE_ADDRESS_H_
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_SERVICE_ADDRESS_H_
#include <cstdint>
#include <string>
#include <vector>
#include "absl/strings/str_format.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
#include "internal/platform/implementation/wifi_utils.h"
namespace nearby {
struct ServiceAddress {
// IP address in MSB-first order.
// IPv4 address is 4 bytes, and IPv6 address is 16 bytes.
std::vector<char> address;
uint16_t port;
bool operator==(const ServiceAddress& other) const = default;
};
// Support logging of ServiceAddress.
template <typename Sink>
void AbslStringify(Sink& sink, const ServiceAddress& service_address) {
absl::Format(
&sink, "[%s]:%d",
WifiUtils::GetHumanReadableIpAddress(std::string(
service_address.address.begin(), service_address.address.end())),
service_address.port);
}
void ServiceAddressToProto(
const ServiceAddress& service_address,
location::nearby::connections::ServiceAddress& proto);
// Returns false is proto address does not contain an IPv4 or IPv6 address, or
// if the proto port is 0.
bool ServiceAddressFromProto(
const location::nearby::connections::ServiceAddress& proto,
ServiceAddress& service_address);
} // namespace nearby
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_SERVICE_ADDRESS_H_
+122
View File
@@ -0,0 +1,122 @@
// 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/service_address.h"
#include <string>
#include <vector>
#include "gtest/gtest.h"
#include "connections/implementation/proto/offline_wire_formats.pb.h"
namespace nearby {
namespace {
using ProtoServiceAddress = ::location::nearby::connections::ServiceAddress;
TEST(ServiceAddressTest, IPv4ServiceAddressToProto) {
ServiceAddress service_address = {
.address = {127, 0, 0, 1},
.port = 8080,
};
ProtoServiceAddress proto;
ServiceAddressToProto(service_address, proto);
EXPECT_EQ(proto.ip_address(), std::string("\x7f\0\0\1", 4));
EXPECT_EQ(proto.port(), 8080);
}
TEST(ServiceAddressTest, IPv4ServiceAddressFromProto) {
ProtoServiceAddress proto;
proto.set_ip_address(std::string("\x7f\0\0\1", 4));
proto.set_port(8080);
ServiceAddress service_address;
EXPECT_TRUE(ServiceAddressFromProto(proto, service_address));
EXPECT_EQ(service_address.address, std::vector<char>({127, 0, 0, 1}));
EXPECT_EQ(service_address.port, 8080);
}
TEST(ServiceAddressTest, IPv6ServiceAddressToProto) {
ServiceAddress service_address = {
.address = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
.port = 8080,
};
ProtoServiceAddress proto;
ServiceAddressToProto(service_address, proto);
EXPECT_EQ(proto.ip_address(),
std::string("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 16));
EXPECT_EQ(proto.port(), 8080);
}
TEST(ServiceAddressTest, IPv6ServiceAddressFromProto) {
ProtoServiceAddress proto;
proto.set_ip_address(std::string("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 16));
proto.set_port(8080);
ServiceAddress service_address;
EXPECT_TRUE(ServiceAddressFromProto(proto, service_address));
EXPECT_EQ(
service_address.address,
std::vector<char>({0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1}));
EXPECT_EQ(service_address.port, 8080);
}
TEST(ServiceAddressTest, ServiceAddressFromProtoInvalidAddress) {
ProtoServiceAddress proto;
proto.set_ip_address(std::string("\x7f\0\0", 3));
proto.set_port(8080);
ServiceAddress service_address;
EXPECT_FALSE(ServiceAddressFromProto(proto, service_address));
}
TEST(ServiceAddressTest, ServiceAddressFromProtoInvalidPort) {
ProtoServiceAddress proto;
proto.set_ip_address(std::string("\x7f\0\0\1", 4));
proto.set_port(0);
ServiceAddress service_address;
EXPECT_FALSE(ServiceAddressFromProto(proto, service_address));
}
TEST(ServiceAddressTest, ServiceAddressEquality) {
ServiceAddress service_address1 = {
.address = {127, 0, 0, 1},
.port = 8080,
};
ServiceAddress service_address2 = {
.address = {127, 0, 0, 1},
.port = 8080,
};
ServiceAddress service_address3 = {
.address = {127, 0, 0, 2},
.port = 8080,
};
ServiceAddress service_address4 = {
.address = {127, 0, 0, 1},
.port = 8081,
};
ServiceAddress service_address5 = {
.address = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
.port = 8080,
};
ServiceAddress service_address6 = {
.address = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1},
.port = 8080,
};
EXPECT_EQ(service_address1, service_address2);
EXPECT_NE(service_address1, service_address3);
EXPECT_NE(service_address1, service_address4);
EXPECT_NE(service_address1, service_address5);
EXPECT_EQ(service_address5, service_address6);
}
} // namespace
} // namespace nearby
+1 -8
View File
@@ -15,22 +15,15 @@
#ifndef PLATFORM_BASE_WIFI_CREDENTIAL_H_
#define PLATFORM_BASE_WIFI_CREDENTIAL_H_
#include <cstdint>
#include <string>
#include <utility>
#include <vector>
#include "internal/platform/service_address.h"
#include "proto/connections_enums.pb.h"
namespace nearby {
struct ServiceAddress {
// IP address in MSB-first order.
// IPv4 address is 4 bytes, and IPv6 address is 16 bytes.
std::vector<char> address;
uint16_t port;
};
// Credentials for the currently-hosted Wifi hotspot (if any)
// Class HotspotCredentials is copyable & movable
class HotspotCredentials {