diff --git a/Package.swift b/Package.swift index 1b8bd4a9..d517a10a 100644 --- a/Package.swift +++ b/Package.swift @@ -486,6 +486,7 @@ let package = Package( "internal/platform/count_down_latch_test.cc", "internal/platform/pipe_test.cc", "internal/platform/uuid_test.cc", + "internal/platform/wifi_lan_connection_info_test.cc", "internal/platform/wifi_direct_test.cc", "internal/platform/wifi_hotspot_test.cc", "internal/platform/wifi_lan_test.cc", diff --git a/internal/device.h b/internal/device.h index dca34fc0..5f49c509 100644 --- a/internal/device.h +++ b/internal/device.h @@ -21,6 +21,7 @@ #include "absl/strings/string_view.h" #include "absl/types/variant.h" #include "internal/platform/bluetooth_connection_info.h" +#include "internal/platform/wifi_lan_connection_info.h" namespace location { namespace nearby { @@ -42,7 +43,8 @@ class NearbyDevice { virtual absl::string_view GetEndpointInfo() const = 0; // We will be adding more ConnectionInfo types to this variant as they are // implemented. - virtual std::vector> + virtual std::vector< + absl::variant> GetConnectionInfos() const = 0; virtual Type GetType() const { return Type::kUnknownDevice; } }; diff --git a/internal/platform/BUILD b/internal/platform/BUILD index d4a87284..6bf27d4a 100644 --- a/internal/platform/BUILD +++ b/internal/platform/BUILD @@ -146,10 +146,12 @@ cc_library( name = "connection_info", srcs = [ "bluetooth_connection_info.cc", + "wifi_lan_connection_info.cc", ], hdrs = [ "bluetooth_connection_info.h", "connection_info.h", + "wifi_lan_connection_info.h", ], defines = ["NO_WEBRTC"], visibility = [ @@ -159,7 +161,9 @@ cc_library( "//presence:__subpackages__", ], deps = [ - "//internal/platform:base", + ":base", + "@com_google_absl//absl/status", + "@com_google_absl//absl/status:statusor", "@com_google_absl//absl/strings", ], ) @@ -442,6 +446,7 @@ cc_test( "uuid_test.cc", "wifi_direct_test.cc", "wifi_hotspot_test.cc", + "wifi_lan_connection_info_test.cc", "wifi_lan_test.cc", "wifi_test.cc", "wifi_utils_test.cc", @@ -461,6 +466,7 @@ cc_test( "//internal/platform/implementation/g3", # build_cleaner: keep "//internal/proto:credential_cc_proto", "@com_github_protobuf_matchers//protobuf-matchers", + "@com_google_absl//absl/status", "@com_google_absl//absl/strings", "@com_google_absl//absl/synchronization", "@com_google_absl//absl/time", diff --git a/internal/platform/connection_info.h b/internal/platform/connection_info.h index 48fc6796..52a6c9db 100644 --- a/internal/platform/connection_info.h +++ b/internal/platform/connection_info.h @@ -24,6 +24,7 @@ class ConnectionInfo { enum class MediumType { kUnknown = 0, kBluetooth = 1, + kWifiLan = 2, }; virtual ~ConnectionInfo() = default; virtual MediumType GetMediumType() const = 0; diff --git a/internal/platform/wifi_lan_connection_info.cc b/internal/platform/wifi_lan_connection_info.cc new file mode 100644 index 00000000..f8f16af3 --- /dev/null +++ b/internal/platform/wifi_lan_connection_info.cc @@ -0,0 +1,55 @@ +// Copyright 2022 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/wifi_lan_connection_info.h" + +#include + +#include "absl/status/status.h" +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { + +ByteArray WifiLanConnectionInfo::ToBytes() const { + return ByteArray(absl::StrCat(std::to_string(GetWifiLanConnectionInfoType()), + ip_address_, port_, bssid_)); +} + +absl::StatusOr WifiLanConnectionInfo::FromBytes( + ByteArray bytes) { + // IPV4/IPV6 indicator size are both 1 + int ip_size = 1; + absl::string_view serial = bytes.AsStringView(); + if (serial.length() != + ip_size + kIpv4AddressLength + kPortLength + kBssidLength && + serial.length() != + ip_size + kIpv6AddressLength + kPortLength + kBssidLength) { + return absl::InvalidArgumentError("Bad byte array length"); + } + size_t proc; + int type = std::stoi(std::string(serial.substr(0, ip_size)), &proc); + if (proc != ip_size) { + return absl::InvalidArgumentError("Could not determine IPV4 or IPV6"); + } + int ip_length = type == kIpv4 ? kIpv4AddressLength : kIpv6AddressLength; + absl::string_view ip = serial.substr(ip_size, ip_length); + absl::string_view port = serial.substr(ip_size + ip_length, kPortLength); + absl::string_view bssid = serial.substr(ip_size + ip_length + kPortLength); + return WifiLanConnectionInfo(ip, port, bssid); +} + +} // namespace nearby +} // namespace location diff --git a/internal/platform/wifi_lan_connection_info.h b/internal/platform/wifi_lan_connection_info.h new file mode 100644 index 00000000..ab490951 --- /dev/null +++ b/internal/platform/wifi_lan_connection_info.h @@ -0,0 +1,87 @@ +// Copyright 2022 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_WIFI_LAN_CONNECTION_INFO_H_ +#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_WIFI_LAN_CONNECTION_INFO_H_ + +#include +#include + +#include "absl/status/statusor.h" +#include "absl/strings/string_view.h" +#include "internal/platform/byte_array.h" +#include "internal/platform/connection_info.h" + +namespace location { +namespace nearby { + +constexpr int kIpv4AddressLength = 4; +constexpr int kIpv6AddressLength = 16; +constexpr int kPortLength = 2; +constexpr int kBssidLength = 6; + +class WifiLanConnectionInfo : public ConnectionInfo { + public: + enum WifiLanConnectionInfoType { + kUnknown = 0, + kIpv4 = 1, + kIpv6 = 2, + }; + WifiLanConnectionInfo(absl::string_view ip_address, absl::string_view port) + : ip_address_(ip_address), port_(port), bssid_("") { + port_.resize(kPortLength); + bssid_.resize(kBssidLength); + } + WifiLanConnectionInfo(absl::string_view ip_address, absl::string_view port, + absl::string_view bssid) + : ip_address_(ip_address), port_(port), bssid_(std::string(bssid)) { + port_.resize(kPortLength); + bssid_.resize(kBssidLength); + } + static absl::StatusOr FromBytes(ByteArray bytes); + MediumType GetMediumType() const override { return MediumType::kWifiLan; } + ByteArray ToBytes() const override; + ByteArray GetIpAddress() const { return ByteArray(ip_address_); } + ByteArray GetPort() const { return ByteArray(port_); } + ByteArray GetBssid() const { return ByteArray(bssid_); } + WifiLanConnectionInfoType GetWifiLanConnectionInfoType() const { + if (ip_address_.size() == kIpv6AddressLength) { + return kIpv6; + } else if (ip_address_.size() == kIpv4AddressLength) { + return kIpv4; + } + return kUnknown; + } + + private: + std::string ip_address_; + std::string port_; + std::string bssid_; +}; + +inline bool operator==(const WifiLanConnectionInfo& a, + const WifiLanConnectionInfo& b) { + return a.GetIpAddress() == b.GetIpAddress() && a.GetPort() == b.GetPort() && + a.GetBssid() == b.GetBssid(); +} + +inline bool operator!=(const WifiLanConnectionInfo& a, + const WifiLanConnectionInfo& b) { + return !(a == b); +} + +} // namespace nearby +} // namespace location + +#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_WIFI_LAN_CONNECTION_INFO_H_ diff --git a/internal/platform/wifi_lan_connection_info_test.cc b/internal/platform/wifi_lan_connection_info_test.cc new file mode 100644 index 00000000..c4461682 --- /dev/null +++ b/internal/platform/wifi_lan_connection_info_test.cc @@ -0,0 +1,140 @@ +// Copyright 2022 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/wifi_lan_connection_info.h" + +#include + +#include "gmock/gmock.h" +#include "protobuf-matchers/protocol-buffer-matchers.h" +#include "gtest/gtest.h" +#include "absl/status/status.h" +#include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" + +namespace location { +namespace nearby { +namespace { + +constexpr absl::string_view kIpv4Addr = "\x4C\x8B\x1D\xCE"; +constexpr absl::string_view kIpv6Addr = + "\x4C\x8B\x1D\xCE\x4C\x8B\x1D\xCE\x4C\x8B\x1D\xCE\x4C\x8B\x1D\xCE"; +constexpr absl::string_view kPort = "\x56\x78"; +constexpr absl::string_view kBssid = "\x0A\x1B\x2C\x34\x58\x7E"; + +using ::testing::status::StatusIs; + +TEST(WifiLanConnectionInfoTest, TestMediumType) { + WifiLanConnectionInfo info(kIpv4Addr, kPort); + EXPECT_EQ(info.GetMediumType(), WifiLanConnectionInfo::MediumType::kWifiLan); +} + +TEST(WifiLanConnectionInfoTest, TestGetMembers) { + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid); + EXPECT_EQ(info.GetIpAddress().AsStringView(), kIpv4Addr); + EXPECT_EQ(info.GetPort().AsStringView(), kPort); + EXPECT_EQ(info.GetBssid().AsStringView(), kBssid); +} + +TEST(WifiLanConnectionInfoTest, TestIpv4ToBytes) { + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid); + ByteArray expected( + absl::StrCat(std::to_string(info.GetWifiLanConnectionInfoType()), + kIpv4Addr, kPort, kBssid)); + EXPECT_EQ(info.ToBytes(), expected); +} + +TEST(WifiLanConnectionInfoTest, TestFromBytesIpv4) { + ByteArray expected = ByteArray(absl::StrCat( + std::to_string(WifiLanConnectionInfo::kIpv4), kIpv4Addr, kPort, kBssid)); + ASSERT_OK(WifiLanConnectionInfo::FromBytes(expected)); + WifiLanConnectionInfo info = + WifiLanConnectionInfo::FromBytes(expected).value(); + EXPECT_EQ(info.GetIpAddress().AsStringView(), kIpv4Addr); + EXPECT_EQ(info.GetPort().AsStringView(), kPort); + EXPECT_EQ(info.GetBssid().AsStringView(), kBssid); +} + +TEST(WifiLanConnectionInfoTest, TestFromBytesIpv6) { + ByteArray expected = ByteArray(absl::StrCat( + std::to_string(WifiLanConnectionInfo::kIpv6), kIpv6Addr, kPort, kBssid)); + ASSERT_OK(WifiLanConnectionInfo::FromBytes(expected)); + WifiLanConnectionInfo info = + WifiLanConnectionInfo::FromBytes(expected).value(); + EXPECT_EQ(info.GetIpAddress().AsStringView(), kIpv6Addr); + EXPECT_EQ(info.GetPort().AsStringView(), kPort); + EXPECT_EQ(info.GetBssid().AsStringView(), kBssid); +} + +TEST(WifiLanConnectionInfoTest, TestToFromBytesIpv4) { + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid); + ByteArray serialized = info.ToBytes(); + WifiLanConnectionInfo result = + WifiLanConnectionInfo::FromBytes(serialized).value(); + EXPECT_EQ(result, info); +} + +TEST(WifiLanConnectionInfoTest, TestToFromBytesIpv6) { + WifiLanConnectionInfo info(kIpv6Addr, kPort, kBssid); + ByteArray serialized = info.ToBytes(); + WifiLanConnectionInfo result = + WifiLanConnectionInfo::FromBytes(serialized).value(); + EXPECT_EQ(result, info); +} + +TEST(WifiLanConnectionInfoTest, TestCopy) { + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid); + WifiLanConnectionInfo copy(info); + EXPECT_EQ(info, copy); +} + +TEST(WifiLanConnectionInfoTest, TestEquals) { + WifiLanConnectionInfo info(kIpv4Addr, kPort, kBssid); + WifiLanConnectionInfo info2(kIpv4Addr, kPort, kBssid); + EXPECT_EQ(info, info2); +} + +TEST(WifiLanConnectionInfoTest, TestShortBssid) { + std::string shortBssid = "\x0A\x1B\x2C"; + std::string extended("\x0A\x1B\x2C\0\0\0", kBssidLength); + WifiLanConnectionInfo info(kIpv4Addr, kPort, shortBssid); + EXPECT_EQ(info.GetBssid().size(), kBssidLength); + // Value-initialized so there will be 3 0x0 characters + EXPECT_EQ(info.GetBssid().AsStringView(), extended); +} + +TEST(WifiLanConnectionInfoTest, TestLongBssid) { + std::string longBssid = absl::StrCat(kBssid, "\x68\x42\x35"); + WifiLanConnectionInfo info(kIpv4Addr, kPort, longBssid); + EXPECT_EQ(info.GetBssid().size(), kBssidLength); + EXPECT_EQ(info.GetBssid().AsStringView(), kBssid); +} + +TEST(WifiLanConnectionInfoTest, TestBadBytesLength) { + WifiLanConnectionInfo info(kIpv4Addr, kPort); + ByteArray serialized = info.ToBytes(); + ByteArray modified_short(std::string( + serialized.AsStringView().substr(0, kIpv4AddressLength + kPortLength))); + ByteArray modified_long(absl::StrCat(serialized.AsStringView(), kPort)); + EXPECT_THAT(WifiLanConnectionInfo::FromBytes(modified_short), + StatusIs(absl::StatusCode::kInvalidArgument)); + EXPECT_THAT(WifiLanConnectionInfo::FromBytes(ByteArray()), + StatusIs(absl::StatusCode::kInvalidArgument)); + EXPECT_THAT(WifiLanConnectionInfo::FromBytes(modified_long), + StatusIs(absl::StatusCode::kInvalidArgument)); +} + +} // namespace +} // namespace nearby +} // namespace location diff --git a/presence/presence_device.cc b/presence/presence_device.cc index 52695234..533de492 100644 --- a/presence/presence_device.cc +++ b/presence/presence_device.cc @@ -20,6 +20,7 @@ #include "internal/crypto/random.h" #include "internal/platform/bluetooth_connection_info.h" #include "internal/platform/implementation/system_clock.h" +#include "internal/platform/wifi_lan_connection_info.h" #include "presence/device_motion.h" namespace nearby { @@ -45,7 +46,8 @@ PresenceDevice::PresenceDevice(DeviceMotion device_motion, endpoint_id_ = GenerateRandomEndpointId(); } -std::vector> +std::vector> PresenceDevice::GetConnectionInfos() const { location::nearby::BluetoothConnectionInfo bluetooth_connection_info( location::nearby::ByteArray(device_metadata_.bluetooth_mac_address()), diff --git a/presence/presence_device.h b/presence/presence_device.h index 75d03423..d0a9b00f 100644 --- a/presence/presence_device.h +++ b/presence/presence_device.h @@ -23,6 +23,7 @@ #include "absl/types/variant.h" #include "internal/device.h" #include "internal/platform/bluetooth_connection_info.h" +#include "internal/platform/wifi_lan_connection_info.h" #include "internal/proto/device_metadata.pb.h" #include "presence/device_motion.h" @@ -47,7 +48,8 @@ class PresenceDevice : public location::nearby::NearbyDevice { return NearbyDevice::Type::kPresenceDevice; } // Add more medium ConnectionInfos as we introduce them. - std::vector> + std::vector> GetConnectionInfos() const override; DeviceMotion GetDeviceMotion() const { return device_motion_; } DeviceMetadata GetMetadata() const { return device_metadata_; }