Enable password for AWDL upgrade

PiperOrigin-RevId: 759226149
This commit is contained in:
Guogang Li
2025-05-15 11:22:45 -07:00
committed by Copybara-Service
parent 0a64440528
commit 9853d62532
9 changed files with 258 additions and 115 deletions
+34 -7
View File
@@ -21,6 +21,7 @@
#include "absl/functional/bind_front.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/str_format.h"
#include "absl/strings/string_view.h"
#include "absl/time/time.h"
#include "connections/implementation/awdl_endpoint_channel.h"
#include "connections/implementation/base_bwu_handler.h"
@@ -35,6 +36,7 @@
#include "internal/platform/byte_array.h"
#include "internal/platform/count_down_latch.h"
#include "internal/platform/expected.h"
#include "internal/platform/implementation/psk_info.h"
#include "internal/platform/logging.h"
#include "internal/platform/nsd_service_info.h"
@@ -46,6 +48,8 @@ using ::location::nearby::proto::connections::OperationResultCode;
constexpr absl::Duration kAwdlDiscoveryTimeout = absl::Seconds(5);
constexpr int kServiceNameLength = 8;
constexpr int kPasswordLength = 16;
constexpr absl::string_view kPskIdentity = "AwdlUpgradeMedium";
} // namespace
AwdlBwuHandler::AwdlBwuHandler(
@@ -68,7 +72,8 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel(
const UpgradePathInfo::AwdlCredentials& awdl_credentials =
upgrade_path_info.awdl_credentials();
if (!awdl_credentials.has_service_name() ||
!awdl_credentials.has_service_type()) {
!awdl_credentials.has_service_type() ||
!awdl_credentials.has_password()) {
LOG(ERROR) << "Failed to upgrade AWDL due to invalid credentials.";
return {
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL)};
@@ -76,16 +81,23 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel(
std::string service_name = awdl_credentials.service_name();
std::string service_type = awdl_credentials.service_type();
std::string password = awdl_credentials.password();
LOG(INFO) << "Attempting to connect to "
<< "AWDL (service_name:" << service_name
<< ", service_type:" << service_type << ") for endpoint "
<< endpoint_id;
<< ", service_type:" << service_type
<< ", has password:" << (password.empty() ? "false" : "true")
<< ") for endpoint " << endpoint_id;
NsdServiceInfo nsd_service_info{};
nsd_service_info.SetServiceName(service_name);
nsd_service_info.SetServiceType(service_type);
api::PskInfo psk_info = {
.identity = std::string(kPskIdentity),
.password = password,
};
LOG(INFO) << "Start to discover the AWDL service "
"(service_name:"
<< service_name << ", service_type:" << service_type
@@ -134,7 +146,7 @@ AwdlBwuHandler::CreateUpgradedEndpointChannel(
<< ") for endpoint " << endpoint_id;
ErrorOr<AwdlSocket> socket_result =
awdl_medium_.Connect(upgrade_service_id, nsd_service_info,
awdl_medium_.Connect(upgrade_service_id, nsd_service_info, psk_info,
client->GetCancellationFlag(endpoint_id));
if (socket_result.has_error()) {
LOG(ERROR) << "Failed to connect to the AWDL service (service_name:"
@@ -174,8 +186,12 @@ ByteArray AwdlBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
ClientProxy* client, const std::string& upgrade_service_id,
const std::string& endpoint_id) {
if (!awdl_medium_.IsAcceptingConnections(upgrade_service_id)) {
api::PskInfo psk_info = {
.identity = std::string(kPskIdentity),
.password = GeneratePassword(),
};
if (!awdl_medium_.StartAcceptingConnections(
upgrade_service_id,
upgrade_service_id, psk_info,
absl::bind_front(&AwdlBwuHandler::OnIncomingAwdlConnection, this,
client))) {
LOG(ERROR) << "Failed to initiate the AWDL upgrade for "
@@ -211,11 +227,13 @@ ByteArray AwdlBwuHandler::HandleInitializeUpgradedMediumForEndpoint(
awdl_medium_.GetCredentials(upgrade_service_id);
std::string service_name = credential.service_name;
std::string service_type = credential.service_type;
std::string password = credential.password;
LOG(INFO) << "Retrieved AWDL credentials. service_name: " << service_name
<< " and service_type: " << service_type;
<< " and service_type: " << service_type
<< " and has password: " << (password.empty() ? "false" : "true");
return parser::ForBwuAwdlPathAvailable(service_name, service_type);
return parser::ForBwuAwdlPathAvailable(service_name, service_type, password);
}
void AwdlBwuHandler::HandleRevertInitiatorStateForService(
@@ -266,5 +284,14 @@ std::string AwdlBwuHandler::GenerateServiceName() {
return service_name_string;
}
std::string AwdlBwuHandler::GeneratePassword() {
std::string password_string;
ByteArray ramdon_bytes = Utils::GenerateRandomBytes(kPasswordLength);
for (auto byte : std::string(ramdon_bytes)) {
absl::StrAppend(&password_string, absl::StrFormat("%02X", byte));
}
return password_string;
}
} // namespace connections
} // namespace nearby
@@ -79,6 +79,7 @@ class AwdlBwuHandler : public BaseBwuHandler {
std::string GenerateServiceType(const std::string& service_id);
std::string GenerateServiceName();
std::string GeneratePassword();
Mediums& mediums_;
Awdl& awdl_medium_{mediums_.GetAwdl()};
+1 -1
View File
@@ -109,7 +109,7 @@ BwuManager::BwuManager(
config_.allow_upgrade_to.wifi_lan = true;
config_.allow_upgrade_to.wifi_hotspot = true;
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableDct)) {
config_package_nearby::nearby_connections_feature::kEnableAwdl)) {
config_.allow_upgrade_to.awdl = true;
}
}
+154 -103
View File
@@ -16,6 +16,7 @@
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <utility>
@@ -30,6 +31,7 @@
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/expected.h"
#include "internal/platform/implementation/psk_info.h"
#include "internal/platform/implementation/wifi_utils.h"
#include "internal/platform/logging.h"
#include "internal/platform/mutex_lock.h"
@@ -217,74 +219,22 @@ bool Awdl::IsDiscoveringLocked(const std::string& service_id) {
ErrorOr<bool> Awdl::StartAcceptingConnections(
const std::string& service_id, AcceptedConnectionCallback callback) {
MutexLock lock(&mutex_);
return InternalStartAcceptingConnections(service_id, std::nullopt,
std::move(callback));
}
if (service_id.empty()) {
LOG(INFO) << "Refusing to start accepting Awdl connections; "
"service_id is empty.";
return {Error(OperationResultCode::NEARBY_LOCAL_CLIENT_STATE_WRONG)};
ErrorOr<bool> Awdl::StartAcceptingConnections(
const std::string& service_id, const api::PskInfo& psk_info,
AcceptedConnectionCallback callback) {
MutexLock lock(&mutex_);
ErrorOr<bool> result = InternalStartAcceptingConnections(service_id, psk_info,
std::move(callback));
if (result.has_value() && result.value()) {
listening_info_.Add(service_id, psk_info);
}
if (!IsAvailableLocked()) {
LOG(INFO) << "Can't start accepting Awdl connections [service_id="
<< service_id << "]; Awdl not available.";
return {Error(
OperationResultCode::MEDIUM_UNAVAILABLE_WIFI_AWARE_NOT_AVAILABLE)};
}
if (IsAcceptingConnectionsLocked(service_id)) {
LOG(INFO) << "Refusing to start accepting Awdl connections [service="
<< service_id
<< "]; Awdl server is already in-progress with the same name.";
return {Error(OperationResultCode::
CLIENT_DUPLICATE_ACCEPTING_LAN_CONNECTION_REQUEST)};
}
auto port_range = medium_.GetDynamicPortRange();
// Generate an exact port here on server socket; if platform doesn't provide
// range of port then assign 0 to let platform decide it.
int port = 0;
if (port_range.has_value() &&
(port_range->first > 0 && port_range->first <= 65535 &&
port_range->second > 0 && port_range->second <= 65535 &&
port_range->first <= port_range->second)) {
port = GeneratePort(service_id, port_range.value());
}
AwdlServerSocket server_socket = medium_.ListenForService(port);
if (!server_socket.IsValid()) {
LOG(INFO) << "Failed to start accepting Awdl connections for service_id="
<< service_id;
return {Error(OperationResultCode::
CLIENT_CANCELLATION_WIFI_LAN_SERVER_SOCKET_CREATION)};
}
// Mark the fact that there's an in-progress Awdl server accepting
// connections.
auto owned_server_socket =
server_sockets_.insert({service_id, std::move(server_socket)})
.first->second;
// Start the accept loop on a dedicated thread - this stays alive and
// listening for new incoming connections until StopAcceptingConnections() is
// invoked.
accept_loops_runner_.Execute(
"awdl-accept",
[callback = std::move(callback),
server_socket = std::move(owned_server_socket), service_id]() mutable {
while (true) {
AwdlSocket client_socket = server_socket.Accept();
if (!client_socket.IsValid()) {
server_socket.Close();
break;
}
LOG(INFO) << "Accepted connection for " << service_id;
if (callback) {
LOG(INFO) << "Call back triggered for physical socket.";
callback(service_id, std::move(client_socket));
}
}
});
return {true};
return result;
}
bool Awdl::StopAcceptingConnections(const std::string& service_id) {
@@ -303,6 +253,8 @@ bool Awdl::StopAcceptingConnections(const std::string& service_id) {
return false;
}
listening_info_.Remove(service_id);
// Closing the AwdlServerSocket will kick off the suicide of the thread
// in accept_loops_thread_pool_ that blocks on AwdlServerSocket.accept().
// That may take some time to complete, but there's no particular reason to
@@ -341,45 +293,16 @@ ErrorOr<AwdlSocket> Awdl::Connect(const std::string& service_id,
const NsdServiceInfo& service_info,
CancellationFlag* cancellation_flag) {
MutexLock lock(&mutex_);
// Socket to return. To allow for NRVO to work, it has to be a single object.
AwdlSocket socket;
return InternalConnect(service_id, service_info, std::nullopt,
cancellation_flag);
}
if (service_id.empty()) {
LOG(INFO) << "Refusing to create client Awdl socket because "
"service_id is empty.";
return {Error(OperationResultCode::NEARBY_LOCAL_CLIENT_STATE_WRONG)};
}
if (!IsAvailableLocked()) {
LOG(INFO) << "Can't create client Awdl socket [service_id=" << service_id
<< "]; Awdl isn't available.";
return {Error(OperationResultCode::MEDIUM_UNAVAILABLE_LAN_NOT_AVAILABLE)};
}
if (cancellation_flag->Cancelled()) {
LOG(INFO) << "Can't create client Awdl socket due to cancel.";
return {Error(OperationResultCode::
CLIENT_CANCELLATION_CANCEL_LAN_OUTGOING_CONNECTION)};
}
if (service_info.GetServiceName().empty() ||
service_info.GetServiceType().empty()) {
LOG(INFO) << "Can't create client Awdl socket due to invalid service "
"information.";
return {
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL)};
}
socket = medium_.ConnectToService(service_info, cancellation_flag);
if (!socket.IsValid()) {
LOG(INFO) << "Failed to Connect via Awdl [service_id=" << service_id << "]";
return {Error(
OperationResultCode::CONNECTIVITY_LAN_CLIENT_SOCKET_CREATION_FAILURE)};
}
LOG(INFO) << "Successfully connected via Awdl [service_id=" << service_id
<< "]";
return socket;
ErrorOr<AwdlSocket> Awdl::Connect(const std::string& service_id,
const NsdServiceInfo& service_info,
const api::PskInfo& psk_info,
CancellationFlag* cancellation_flag) {
MutexLock lock(&mutex_);
return InternalConnect(service_id, service_info, psk_info, cancellation_flag);
}
Awdl::AwdlCredential Awdl::GetCredentials(const std::string& service_id) {
@@ -393,6 +316,12 @@ Awdl::AwdlCredential Awdl::GetCredentials(const std::string& service_id) {
}
credential.service_name = service_info->GetServiceName();
credential.service_type = service_info->GetServiceType();
api::PskInfo* psk_info = listening_info_.GetPskInfo(service_id);
if (psk_info == nullptr) {
return credential;
}
credential.password = psk_info->password;
return credential;
}
@@ -422,5 +351,127 @@ int Awdl::GeneratePort(const std::string& service_id,
(uint_of_service_id_hash % (port_range.second - port_range.first));
}
ErrorOr<bool> Awdl::InternalStartAcceptingConnections(
const std::string& service_id, const std::optional<api::PskInfo>& psk_info,
AcceptedConnectionCallback callback) {
if (service_id.empty()) {
LOG(INFO) << "Refusing to start accepting Awdl connections; "
"service_id is empty.";
return {Error(OperationResultCode::NEARBY_LOCAL_CLIENT_STATE_WRONG)};
}
if (!IsAvailableLocked()) {
LOG(INFO) << "Can't start accepting Awdl connections [service_id="
<< service_id << "]; Awdl not available.";
return {Error(
OperationResultCode::MEDIUM_UNAVAILABLE_WIFI_AWARE_NOT_AVAILABLE)};
}
if (IsAcceptingConnectionsLocked(service_id)) {
LOG(INFO) << "Refusing to start accepting Awdl connections [service="
<< service_id
<< "]; Awdl server is already in-progress with the same name.";
return {Error(OperationResultCode::
CLIENT_DUPLICATE_ACCEPTING_LAN_CONNECTION_REQUEST)};
}
auto port_range = medium_.GetDynamicPortRange();
// Generate an exact port here on server socket; if platform doesn't provide
// range of port then assign 0 to let platform decide it.
int port = 0;
if (port_range.has_value() &&
(port_range->first > 0 && port_range->first <= 65535 &&
port_range->second > 0 && port_range->second <= 65535 &&
port_range->first <= port_range->second)) {
port = GeneratePort(service_id, port_range.value());
}
AwdlServerSocket server_socket =
psk_info.has_value() ? medium_.ListenForService(*psk_info, port)
: medium_.ListenForService(port);
if (!server_socket.IsValid()) {
LOG(INFO) << "Failed to start accepting Awdl connections for service_id="
<< service_id;
return {Error(OperationResultCode::
CLIENT_CANCELLATION_WIFI_LAN_SERVER_SOCKET_CREATION)};
}
// Mark the fact that there's an in-progress Awdl server accepting
// connections.
auto owned_server_socket =
server_sockets_.insert({service_id, std::move(server_socket)})
.first->second;
// Start the accept loop on a dedicated thread - this stays alive and
// listening for new incoming connections until StopAcceptingConnections() is
// invoked.
accept_loops_runner_.Execute(
"awdl-accept",
[callback = std::move(callback),
server_socket = std::move(owned_server_socket), service_id]() mutable {
while (true) {
AwdlSocket client_socket = server_socket.Accept();
if (!client_socket.IsValid()) {
server_socket.Close();
break;
}
LOG(INFO) << "Accepted connection for " << service_id;
if (callback) {
LOG(INFO) << "Call back triggered for physical socket.";
callback(service_id, std::move(client_socket));
}
}
});
return {true};
}
ErrorOr<AwdlSocket> Awdl::InternalConnect(
const std::string& service_id, const NsdServiceInfo& service_info,
const std::optional<api::PskInfo>& psk_info,
CancellationFlag* cancellation_flag) {
// Socket to return. To allow for NRVO to work, it has to be a single object.
AwdlSocket socket;
if (service_id.empty()) {
LOG(INFO) << "Refusing to create client Awdl socket because "
"service_id is empty.";
return {Error(OperationResultCode::NEARBY_LOCAL_CLIENT_STATE_WRONG)};
}
if (!IsAvailableLocked()) {
LOG(INFO) << "Can't create client Awdl socket [service_id=" << service_id
<< "]; Awdl isn't available.";
return {Error(OperationResultCode::MEDIUM_UNAVAILABLE_LAN_NOT_AVAILABLE)};
}
if (cancellation_flag->Cancelled()) {
LOG(INFO) << "Can't create client Awdl socket due to cancel.";
return {Error(OperationResultCode::
CLIENT_CANCELLATION_CANCEL_LAN_OUTGOING_CONNECTION)};
}
if (service_info.GetServiceName().empty() ||
service_info.GetServiceType().empty()) {
LOG(INFO) << "Can't create client Awdl socket due to invalid service "
"information.";
return {
Error(OperationResultCode::CONNECTIVITY_WIFI_LAN_INVALID_CREDENTIAL)};
}
socket =
psk_info.has_value()
? medium_.ConnectToService(service_info, *psk_info, cancellation_flag)
: medium_.ConnectToService(service_info, cancellation_flag);
if (!socket.IsValid()) {
LOG(INFO) << "Failed to Connect via Awdl [service_id=" << service_id << "]";
return {Error(
OperationResultCode::CONNECTIVITY_LAN_CLIENT_SOCKET_CREATION_FAILURE)};
}
LOG(INFO) << "Successfully connected via Awdl [service_id=" << service_id
<< "]";
return socket;
}
} // namespace connections
} // namespace nearby
+59
View File
@@ -16,6 +16,7 @@
#define CORE_INTERNAL_MEDIUMS_AWDL_H_
#include <cstdint>
#include <optional>
#include <string>
#include <utility>
@@ -30,6 +31,7 @@
#include "internal/platform/cancellation_flag.h"
#include "internal/platform/exception.h"
#include "internal/platform/expected.h"
#include "internal/platform/implementation/psk_info.h"
#include "internal/platform/multi_thread_executor.h"
#include "internal/platform/mutex.h"
#include "internal/platform/nsd_service_info.h"
@@ -48,6 +50,7 @@ class Awdl {
struct AwdlCredential {
std::string service_name;
std::string service_type;
std::string password;
};
Awdl() = default;
@@ -89,6 +92,13 @@ class Awdl {
AcceptedConnectionCallback callback)
ABSL_LOCKS_EXCLUDED(mutex_);
// Starts a worker thread, creates a PSK-based Awdl socket, associates it with
// a service id.
ErrorOr<bool> StartAcceptingConnections(const std::string& service_id,
const api::PskInfo& psk_info,
AcceptedConnectionCallback callback)
ABSL_LOCKS_EXCLUDED(mutex_);
// Closes socket corresponding to a service id.
bool StopAcceptingConnections(const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_);
@@ -105,6 +115,17 @@ class Awdl {
CancellationFlag* cancellation_flag)
ABSL_LOCKS_EXCLUDED(mutex_);
// Establishes connection to PSK-based Awdl service that was might be started
// on another service with StartAcceptingConnections() using the same
// service_id. Blocks until connection is established, or server-side is
// terminated. Returns socket instance. On success, AwdlSocket.IsValid()
// return true.
ErrorOr<AwdlSocket> Connect(const std::string& service_id,
const NsdServiceInfo& service_info,
const api::PskInfo& psk_info,
CancellationFlag* cancellation_flag)
ABSL_LOCKS_EXCLUDED(mutex_);
// Gets ip address + port for remote services on the network to identify and
// connect to this service.
//
@@ -137,6 +158,28 @@ class Awdl {
absl::flat_hash_map<std::string, NsdServiceInfo> nsd_service_infos;
};
struct ListeningInfo {
bool IsEmpty() const { return psk_infos.empty(); }
void Clear() { psk_infos.clear(); }
void Add(const std::string& service_id, const api::PskInfo& psk_info) {
psk_infos.insert({service_id, psk_info});
}
void Remove(const std::string& service_id) { psk_infos.erase(service_id); }
bool Existed(const std::string& service_id) const {
return psk_infos.contains(service_id);
}
api::PskInfo* GetPskInfo(const std::string& service_id) {
const auto& it = psk_infos.find(service_id);
if (it == psk_infos.end()) {
return nullptr;
}
return &it->second;
}
absl::flat_hash_map<std::string, api::PskInfo> psk_infos;
};
struct DiscoveringInfo {
bool Empty() const { return service_ids.empty(); }
void Clear() { service_ids.clear(); }
@@ -175,10 +218,26 @@ class Awdl {
int GeneratePort(const std::string& service_id,
std::pair<std::int32_t, std::int32_t> port_range);
// Internal version of StartAcceptingConnections that is called by the
// public methods.
ErrorOr<bool> InternalStartAcceptingConnections(
const std::string& service_id,
const std::optional<api::PskInfo>& psk_info,
AcceptedConnectionCallback callback)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Internal version of Connect that is called by the public methods.
ErrorOr<AwdlSocket> InternalConnect(
const std::string& service_id, const NsdServiceInfo& service_info,
const std::optional<api::PskInfo>& psk_info,
CancellationFlag* cancellation_flag)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
mutable Mutex mutex_;
AwdlMedium medium_ ABSL_GUARDED_BY(mutex_);
AdvertisingInfo advertising_info_ ABSL_GUARDED_BY(mutex_);
DiscoveringInfo discovering_info_ ABSL_GUARDED_BY(mutex_);
ListeningInfo listening_info_ ABSL_GUARDED_BY(mutex_);
// A thread pool dedicated to running all the accept loops from
// StartAcceptingConnections().
+3 -1
View File
@@ -306,7 +306,8 @@ ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address,
}
ByteArray ForBwuAwdlPathAvailable(const std::string& service_name,
const std::string& service_type) {
const std::string& service_type,
const std::string& password) {
OfflineFrame frame;
frame.set_version(OfflineFrame::V1);
@@ -321,6 +322,7 @@ ByteArray ForBwuAwdlPathAvailable(const std::string& service_name,
auto* awdl_socket = upgrade_path_info->mutable_awdl_credentials();
awdl_socket->set_service_name(service_name);
awdl_socket->set_service_type(service_type);
awdl_socket->set_password(password);
return ToBytes(std::move(frame));
}
+2 -1
View File
@@ -83,7 +83,8 @@ ByteArray ForBwuWifiHotspotPathAvailable(const std::string& ssid,
ByteArray ForBwuWifiLanPathAvailable(const std::string& ip_address,
std::int32_t port);
ByteArray ForBwuAwdlPathAvailable(const std::string& service_name,
const std::string& service_type);
const std::string& service_type,
const std::string& password);
ByteArray ForBwuWifiAwarePathAvailable(const std::string& service_id,
const std::string& service_info,
const std::string& password,
@@ -445,11 +445,13 @@ TEST(OfflineFramesTest, CanGenerateBwuAwdlPathAvailable) {
awdl_credentials: <
service_name: "service_name"
service_type: "nearby_upgrade"
password: "password"
>
>
>
>)pb";
ByteArray bytes = ForBwuAwdlPathAvailable("service_name", "nearby_upgrade");
ByteArray bytes =
ForBwuAwdlPathAvailable("service_name", "nearby_upgrade", "password");
auto response = FromBytes(bytes);
ASSERT_TRUE(response.ok());
OfflineFrame message = response.result();
@@ -33,7 +33,7 @@ std::vector<location::nearby::proto::connections::Medium>
P2pPointToPointPcpHandler::GetConnectionMediumsByPriority() {
std::vector<location::nearby::proto::connections::Medium> mediums;
if (NearbyFlags::GetInstance().GetBoolFlag(
config_package_nearby::nearby_connections_feature::kEnableDct)) {
config_package_nearby::nearby_connections_feature::kEnableAwdl)) {
if (mediums_->GetAwdl().IsAvailable()) {
mediums.push_back(location::nearby::proto::connections::AWDL);
}