mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 15:16:12 -04:00
1868 lines
81 KiB
C++
1868 lines
81 KiB
C++
// Copyright 2021 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 "connections/implementation/p2p_cluster_pcp_handler.h"
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "absl/functional/bind_front.h"
|
|
#include "absl/strings/escaping.h"
|
|
#include "connections/implementation/base_pcp_handler.h"
|
|
#include "connections/implementation/ble_advertisement.h"
|
|
#include "connections/implementation/ble_endpoint_channel.h"
|
|
#include "connections/implementation/ble_v2_endpoint_channel.h"
|
|
#include "connections/implementation/bluetooth_endpoint_channel.h"
|
|
#include "connections/implementation/bwu_manager.h"
|
|
#include "connections/implementation/mediums/utils.h"
|
|
#include "connections/implementation/webrtc_endpoint_channel.h"
|
|
#include "connections/implementation/wifi_lan_endpoint_channel.h"
|
|
#include "internal/platform/crypto.h"
|
|
#include "internal/platform/nsd_service_info.h"
|
|
#include "internal/platform/types.h"
|
|
#include "proto/connections_enums.pb.h"
|
|
|
|
namespace location {
|
|
namespace nearby {
|
|
namespace connections {
|
|
|
|
ByteArray P2pClusterPcpHandler::GenerateHash(const std::string& source,
|
|
size_t size) {
|
|
return Utils::Sha256Hash(source, size);
|
|
}
|
|
|
|
bool P2pClusterPcpHandler::ShouldAdvertiseBluetoothMacOverBle(
|
|
PowerLevel power_level) {
|
|
return power_level == PowerLevel::kHighPower;
|
|
}
|
|
|
|
bool P2pClusterPcpHandler::ShouldAcceptBluetoothConnections(
|
|
const AdvertisingOptions& advertising_options) {
|
|
return advertising_options.enable_bluetooth_listening;
|
|
}
|
|
|
|
P2pClusterPcpHandler::P2pClusterPcpHandler(
|
|
Mediums* mediums, EndpointManager* endpoint_manager,
|
|
EndpointChannelManager* endpoint_channel_manager, BwuManager* bwu_manager,
|
|
InjectedBluetoothDeviceStore& injected_bluetooth_device_store, Pcp pcp)
|
|
: BasePcpHandler(mediums, endpoint_manager, endpoint_channel_manager,
|
|
bwu_manager, pcp),
|
|
bluetooth_radio_(mediums->GetBluetoothRadio()),
|
|
bluetooth_medium_(mediums->GetBluetoothClassic()),
|
|
ble_medium_(mediums->GetBle()),
|
|
ble_v2_medium_(mediums->GetBleV2()),
|
|
wifi_lan_medium_(mediums->GetWifiLan()),
|
|
wifi_hotspot_medium_(mediums->GetWifiHotspot()),
|
|
webrtc_medium_(mediums->GetWebRtc()),
|
|
injected_bluetooth_device_store_(injected_bluetooth_device_store) {}
|
|
|
|
// Returns a vector or mediums sorted in order or decreasing priority for
|
|
// all the supported mediums.
|
|
// Example: WiFi_LAN, WEB_RTC, BT, BLE
|
|
std::vector<proto::connections::Medium>
|
|
P2pClusterPcpHandler::GetConnectionMediumsByPriority() {
|
|
std::vector<proto::connections::Medium> mediums;
|
|
if (wifi_lan_medium_.IsAvailable()) {
|
|
mediums.push_back(proto::connections::WIFI_LAN);
|
|
}
|
|
if (webrtc_medium_.IsAvailable()) {
|
|
mediums.push_back(proto::connections::WEB_RTC);
|
|
}
|
|
if (bluetooth_medium_.IsAvailable()) {
|
|
mediums.push_back(proto::connections::BLUETOOTH);
|
|
}
|
|
if (FeatureFlags::GetInstance().GetFlags().support_ble_v2) {
|
|
if (ble_v2_medium_.IsAvailable()) {
|
|
mediums.push_back(proto::connections::BLE);
|
|
}
|
|
} else {
|
|
if (ble_medium_.IsAvailable()) {
|
|
mediums.push_back(proto::connections::BLE);
|
|
}
|
|
}
|
|
|
|
return mediums;
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::GetDefaultUpgradeMedium() {
|
|
return proto::connections::WIFI_LAN;
|
|
}
|
|
|
|
BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl(
|
|
ClientProxy* client, const std::string& service_id,
|
|
const std::string& local_endpoint_id, const ByteArray& local_endpoint_info,
|
|
const AdvertisingOptions& advertising_options) {
|
|
std::vector<proto::connections::Medium> mediums_started_successfully;
|
|
|
|
WebRtcState web_rtc_state{WebRtcState::kUnconnectable};
|
|
|
|
if (advertising_options.allowed.wifi_lan) {
|
|
proto::connections::Medium wifi_lan_medium =
|
|
StartWifiLanAdvertising(client, service_id, local_endpoint_id,
|
|
local_endpoint_info, web_rtc_state);
|
|
if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "P2pClusterPcpHandler::StartAdvertisingImpl: WifiLan added";
|
|
mediums_started_successfully.push_back(wifi_lan_medium);
|
|
}
|
|
}
|
|
|
|
if (advertising_options.allowed.bluetooth) {
|
|
const ByteArray bluetooth_hash =
|
|
GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength);
|
|
proto::connections::Medium bluetooth_medium = StartBluetoothAdvertising(
|
|
client, service_id, bluetooth_hash, local_endpoint_id,
|
|
local_endpoint_info, web_rtc_state);
|
|
if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: BT added");
|
|
mediums_started_successfully.push_back(bluetooth_medium);
|
|
bluetooth_classic_advertiser_client_id_ = client->GetClientId();
|
|
}
|
|
}
|
|
|
|
if (advertising_options.allowed.ble) {
|
|
if (FeatureFlags::GetInstance().GetFlags().support_ble_v2) {
|
|
proto::connections::Medium ble_v2_medium = StartBleV2Advertising(
|
|
client, service_id, local_endpoint_id, local_endpoint_info,
|
|
advertising_options, web_rtc_state);
|
|
if (ble_v2_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "P2pClusterPcpHandler::StartAdvertisingImpl: Ble added";
|
|
mediums_started_successfully.push_back(ble_v2_medium);
|
|
}
|
|
} else {
|
|
proto::connections::Medium ble_medium = StartBleAdvertising(
|
|
client, service_id, local_endpoint_id, local_endpoint_info,
|
|
advertising_options, web_rtc_state);
|
|
if (ble_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "P2pClusterPcpHandler::StartAdvertisingImpl: Ble added";
|
|
mediums_started_successfully.push_back(ble_medium);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mediums_started_successfully.empty()) {
|
|
NEARBY_LOGS(ERROR) << "Failed StartAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< ") for client=" << client->GetClientId();
|
|
return {
|
|
.status = {Status::kBluetoothError},
|
|
};
|
|
}
|
|
|
|
// The rest of the operations for startAdvertising() will continue
|
|
// asynchronously via
|
|
// IncomingBluetoothConnectionProcessor.onIncomingBluetoothConnection(), so
|
|
// leave it to that to signal any errors that may occur.
|
|
return {
|
|
.status = {Status::kSuccess},
|
|
.mediums = std::move(mediums_started_successfully),
|
|
};
|
|
}
|
|
|
|
Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) {
|
|
if (client->GetClientId() == bluetooth_classic_advertiser_client_id_) {
|
|
bluetooth_medium_.TurnOffDiscoverability();
|
|
bluetooth_classic_advertiser_client_id_ = 0;
|
|
} else {
|
|
NEARBY_LOGS(INFO) << "Skipped BT TurnOffDiscoverability for client="
|
|
<< client->GetClientId()
|
|
<< ", client that turned on discoverability is "
|
|
<< bluetooth_classic_advertiser_client_id_;
|
|
}
|
|
|
|
bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
|
|
|
if (FeatureFlags::GetInstance().GetFlags().support_ble_v2) {
|
|
ble_v2_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
|
ble_v2_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
|
} else {
|
|
ble_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
|
ble_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
|
}
|
|
|
|
wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId());
|
|
wifi_lan_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId());
|
|
|
|
return {Status::kSuccess};
|
|
}
|
|
|
|
bool P2pClusterPcpHandler::IsRecognizedBluetoothEndpoint(
|
|
const std::string& name_string, const std::string& service_id,
|
|
const BluetoothDeviceName& name) const {
|
|
if (!name.IsValid()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< name_string
|
|
<< " doesn't conform to the BluetoothDeviceName format, discarding.";
|
|
return false;
|
|
}
|
|
|
|
if (name.GetPcp() != GetPcp()) {
|
|
NEARBY_LOGS(INFO) << name_string << " doesn't match on Pcp; expected "
|
|
<< PcpToStrategy(GetPcp()).GetName() << ", found "
|
|
<< PcpToStrategy(name.GetPcp()).GetName();
|
|
return false;
|
|
}
|
|
|
|
ByteArray expected_service_id_hash =
|
|
GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength);
|
|
|
|
if (name.GetServiceIdHash() != expected_service_id_hash) {
|
|
NEARBY_LOGS(INFO) << name_string
|
|
<< " doesn't match on expected service_id_hash; expected "
|
|
<< absl::BytesToHexString(expected_service_id_hash.data())
|
|
<< ", found "
|
|
<< absl::BytesToHexString(name.GetServiceIdHash().data());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler(
|
|
ClientProxy* client, const std::string& service_id,
|
|
BluetoothDevice device) {
|
|
RunOnPcpHandlerThread(
|
|
"p2p-bt-device-discovered",
|
|
[this, client, service_id, device]()
|
|
RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering()) {
|
|
NEARBY_LOGS(WARNING) << "Skipping discovery of BluetoothDevice "
|
|
<< device.GetName()
|
|
<< " because we are no longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the Bluetooth device name.
|
|
const std::string device_name_string = device.GetName();
|
|
BluetoothDeviceName device_name(device_name_string);
|
|
|
|
// Make sure the Bluetooth device name points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id,
|
|
device_name)) {
|
|
NEARBY_LOGS(INFO) << "Found unrecognized BluetoothDeviceName "
|
|
<< device_name_string;
|
|
return;
|
|
}
|
|
|
|
// Report the discovered endpoint to the client.
|
|
NEARBY_LOGS(INFO)
|
|
<< "Found BluetoothDeviceName " << device_name_string
|
|
<< " (with endpoint_id=" << device_name.GetEndpointId()
|
|
<< " and endpoint_info="
|
|
<< absl::BytesToHexString(device_name.GetEndpointInfo().data())
|
|
<< ").";
|
|
OnEndpointFound(
|
|
client,
|
|
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
|
|
{device_name.GetEndpointId(), device_name.GetEndpointInfo(),
|
|
service_id, proto::connections::Medium::BLUETOOTH,
|
|
device_name.GetWebRtcState()},
|
|
device,
|
|
}));
|
|
});
|
|
}
|
|
|
|
void P2pClusterPcpHandler::BluetoothNameChangedHandler(
|
|
ClientProxy* client, const std::string& service_id,
|
|
BluetoothDevice device) {
|
|
RunOnPcpHandlerThread(
|
|
"p2p-bt-name-changed",
|
|
[this, client, service_id, device]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Ignoring lost BluetoothDevice " << device.GetName()
|
|
<< " because Connections is no longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the Bluetooth device name.
|
|
const std::string device_name_string = device.GetName();
|
|
BluetoothDeviceName device_name(device_name_string);
|
|
NEARBY_LOGS(INFO) << "BT discovery handler (CHANGED) [client_id="
|
|
<< client->GetClientId()
|
|
<< ", service_id=" << service_id
|
|
<< "]: processing new name " << device_name_string;
|
|
|
|
// By this point, the BluetoothDevice passed to us has a different name
|
|
// than what we may have discovered before. We need to iterate over the
|
|
// found BluetoothEndpoints and compare their addresses to see the
|
|
// devices are the same. We are not guaranteed to discover a match,
|
|
// since the old name may not have been formatted for Nearby
|
|
// Connections.
|
|
for (auto endpoint :
|
|
GetDiscoveredEndpoints(proto::connections::Medium::BLUETOOTH)) {
|
|
BluetoothEndpoint* bluetoothEndpoint =
|
|
static_cast<BluetoothEndpoint*>(endpoint);
|
|
NEARBY_LOGS(INFO)
|
|
<< "BT discovery handler (CHANGED) [client_id="
|
|
<< client->GetClientId() << ", service_id=" << service_id
|
|
<< "]: comparing MAC addresses with existing endpoint "
|
|
<< bluetoothEndpoint->bluetooth_device.GetName()
|
|
<< ". They have MAC address "
|
|
<< bluetoothEndpoint->bluetooth_device.GetMacAddress()
|
|
<< " and the new endpoint has MAC address "
|
|
<< device.GetMacAddress();
|
|
if (bluetoothEndpoint->bluetooth_device.GetMacAddress() ==
|
|
device.GetMacAddress()) {
|
|
// Report the BluetoothEndpoint as lost to the client.
|
|
NEARBY_LOGS(INFO) << "Reporting lost BluetoothDevice "
|
|
<< bluetoothEndpoint->bluetooth_device.GetName()
|
|
<< ", due to device name change.";
|
|
OnEndpointLost(client, *endpoint);
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Make sure the Bluetooth device name points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id,
|
|
device_name)) {
|
|
NEARBY_LOGS(INFO) << "Found unrecognized BluetoothDeviceName "
|
|
<< device_name_string;
|
|
return;
|
|
}
|
|
|
|
// Report the discovered endpoint to the client.
|
|
NEARBY_LOGS(INFO) << "Found BluetoothDeviceName " << device_name_string
|
|
<< " (with endpoint_id="
|
|
<< device_name.GetEndpointId()
|
|
<< " and endpoint_info="
|
|
<< absl::BytesToHexString(
|
|
device_name.GetEndpointInfo().data())
|
|
<< ").";
|
|
OnEndpointFound(
|
|
client,
|
|
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
|
|
{device_name.GetEndpointId(), device_name.GetEndpointInfo(),
|
|
service_id, proto::connections::Medium::BLUETOOTH,
|
|
device_name.GetWebRtcState()},
|
|
device,
|
|
}));
|
|
});
|
|
}
|
|
|
|
void P2pClusterPcpHandler::BluetoothDeviceLostHandler(
|
|
ClientProxy* client, const std::string& service_id,
|
|
BluetoothDevice& device) {
|
|
const std::string& device_name_string = device.GetName();
|
|
RunOnPcpHandlerThread(
|
|
"p2p-bt-device-lost", [this, client, service_id,
|
|
device_name_string]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Ignoring lost BluetoothDevice " << device_name_string
|
|
<< " because Connections is no "
|
|
"longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the Bluetooth device name.
|
|
BluetoothDeviceName device_name(device_name_string);
|
|
|
|
// Make sure the Bluetooth device name points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedBluetoothEndpoint(device_name_string, service_id,
|
|
device_name))
|
|
return;
|
|
|
|
// Report the BluetoothEndpoint as lost to the client.
|
|
NEARBY_LOGS(INFO) << "Processing lost BluetoothDeviceName "
|
|
<< device_name_string;
|
|
OnEndpointLost(client, DiscoveredEndpoint{
|
|
device_name.GetEndpointId(),
|
|
device_name.GetEndpointInfo(), service_id,
|
|
proto::connections::Medium::BLUETOOTH,
|
|
WebRtcState::kUndefined});
|
|
});
|
|
}
|
|
|
|
bool P2pClusterPcpHandler::IsRecognizedBleEndpoint(
|
|
const std::string& service_id,
|
|
const BleAdvertisement& advertisement) const {
|
|
if (!advertisement.IsValid()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "BleAdvertisement doesn't conform to the format, discarding.";
|
|
return false;
|
|
}
|
|
|
|
if (advertisement.GetVersion() != kBleAdvertisementVersion) {
|
|
NEARBY_LOGS(INFO) << "BleAdvertisement has an unknown version; expected "
|
|
<< static_cast<int>(kBleAdvertisementVersion)
|
|
<< ", found "
|
|
<< static_cast<int>(advertisement.GetVersion());
|
|
return false;
|
|
}
|
|
|
|
if (advertisement.GetPcp() != GetPcp()) {
|
|
NEARBY_LOGS(INFO) << "BleAdvertisement doesn't match on Pcp; expected "
|
|
<< PcpToStrategy(GetPcp()).GetName() << ", found "
|
|
<< PcpToStrategy(advertisement.GetPcp()).GetName();
|
|
return false;
|
|
}
|
|
|
|
// Check ServiceId for normal advertisement.
|
|
// ServiceIdHash is empty for fast advertisement.
|
|
if (!advertisement.IsFastAdvertisement()) {
|
|
ByteArray expected_service_id_hash =
|
|
GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength);
|
|
|
|
if (advertisement.GetServiceIdHash() != expected_service_id_hash) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "BleAdvertisement doesn't match on expected service_id_hash; "
|
|
"expected "
|
|
<< absl::BytesToHexString(expected_service_id_hash.data())
|
|
<< ", found "
|
|
<< absl::BytesToHexString(advertisement.GetServiceIdHash().data());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void P2pClusterPcpHandler::BlePeripheralDiscoveredHandler(
|
|
ClientProxy* client, BlePeripheral& peripheral,
|
|
const std::string& service_id, const ByteArray& advertisement_bytes,
|
|
bool fast_advertisement) {
|
|
RunOnPcpHandlerThread(
|
|
"p2p-ble-device-discovered",
|
|
[this, client, &peripheral, service_id, advertisement_bytes,
|
|
fast_advertisement]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering() || stop_.Get()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Skipping discovery of BleAdvertisement header "
|
|
<< absl::BytesToHexString(advertisement_bytes.data())
|
|
<< " because we are no longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the BLE advertisement bytes.
|
|
BleAdvertisement advertisement(fast_advertisement, advertisement_bytes);
|
|
|
|
// Make sure the BLE advertisement points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedBleEndpoint(service_id, advertisement)) return;
|
|
|
|
// Store all the state we need to be able to re-create a BleEndpoint
|
|
// in BlePeripheralLostHandler, since that isn't privy to
|
|
// the bytes of the ble advertisement itself.
|
|
found_ble_endpoints_.emplace(
|
|
peripheral.GetName(),
|
|
BleEndpointState(advertisement.GetEndpointId(),
|
|
advertisement.GetEndpointInfo()));
|
|
|
|
// Report the discovered endpoint to the client.
|
|
NEARBY_LOGS(INFO) << "Found BleAdvertisement "
|
|
<< absl::BytesToHexString(advertisement_bytes.data())
|
|
<< " (with endpoint_id="
|
|
<< advertisement.GetEndpointId()
|
|
<< ", and endpoint_info="
|
|
<< absl::BytesToHexString(
|
|
advertisement.GetEndpointInfo().data())
|
|
<< ").",
|
|
OnEndpointFound(client,
|
|
std::make_shared<BleEndpoint>(BleEndpoint{
|
|
{advertisement.GetEndpointId(),
|
|
advertisement.GetEndpointInfo(), service_id,
|
|
proto::connections::Medium::BLE,
|
|
advertisement.GetWebRtcState()},
|
|
peripheral,
|
|
}));
|
|
|
|
// Make sure we can connect to this device via Classic Bluetooth.
|
|
std::string remote_bluetooth_mac_address =
|
|
advertisement.GetBluetoothMacAddress();
|
|
if (remote_bluetooth_mac_address.empty()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "No Bluetooth Classic MAC address found in advertisement.";
|
|
return;
|
|
}
|
|
|
|
BluetoothDevice remote_bluetooth_device =
|
|
bluetooth_medium_.GetRemoteDevice(remote_bluetooth_mac_address);
|
|
if (!remote_bluetooth_device.IsValid()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "A valid Bluetooth device could not be derived from the MAC "
|
|
"address "
|
|
<< remote_bluetooth_mac_address;
|
|
return;
|
|
}
|
|
|
|
OnEndpointFound(client,
|
|
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
|
|
{
|
|
advertisement.GetEndpointId(),
|
|
advertisement.GetEndpointInfo(),
|
|
service_id,
|
|
proto::connections::Medium::BLUETOOTH,
|
|
advertisement.GetWebRtcState(),
|
|
},
|
|
remote_bluetooth_device,
|
|
}));
|
|
});
|
|
}
|
|
|
|
void P2pClusterPcpHandler::BlePeripheralLostHandler(
|
|
ClientProxy* client, BlePeripheral& peripheral,
|
|
const std::string& service_id) {
|
|
std::string peripheral_name = peripheral.GetName();
|
|
NEARBY_LOG(INFO, "Ble: [LOST, SCHED] peripheral_name=%s",
|
|
peripheral_name.c_str());
|
|
RunOnPcpHandlerThread(
|
|
"p2p-ble-device-lost",
|
|
[this, client, service_id, &peripheral]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering() || stop_.Get()) {
|
|
NEARBY_LOGS(WARNING) << "Ignoring lost BlePeripheral because we are "
|
|
"no longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Remove this BlePeripheral from found_ble_endpoints_, and
|
|
// report the endpoint as lost to the client.
|
|
auto item = found_ble_endpoints_.find(peripheral.GetName());
|
|
if (item != found_ble_endpoints_.end()) {
|
|
BleEndpointState ble_endpoint_state(item->second);
|
|
found_ble_endpoints_.erase(item);
|
|
|
|
// Report the discovered endpoint to the client.
|
|
NEARBY_LOGS(INFO)
|
|
<< "Lost BleEndpoint for BlePeripheral " << peripheral.GetName()
|
|
<< " (with endpoint_id=" << ble_endpoint_state.endpoint_id
|
|
<< " and endpoint_info="
|
|
<< absl::BytesToHexString(ble_endpoint_state.endpoint_info.data())
|
|
<< ").";
|
|
OnEndpointLost(client, DiscoveredEndpoint{
|
|
ble_endpoint_state.endpoint_id,
|
|
ble_endpoint_state.endpoint_info,
|
|
service_id,
|
|
proto::connections::Medium::BLE,
|
|
WebRtcState::kUndefined,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
bool P2pClusterPcpHandler::IsRecognizedBleV2Endpoint(
|
|
absl::string_view service_id, const BleAdvertisement& advertisement) const {
|
|
if (!advertisement.IsValid()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "BleAdvertisement doesn't conform to the format, discarding.";
|
|
return false;
|
|
}
|
|
|
|
if (advertisement.GetVersion() != kBleAdvertisementVersion) {
|
|
NEARBY_LOGS(INFO) << "BleAdvertisement has an unknown version; expected "
|
|
<< static_cast<int>(kBleAdvertisementVersion)
|
|
<< ", found "
|
|
<< static_cast<int>(advertisement.GetVersion());
|
|
return false;
|
|
}
|
|
|
|
if (advertisement.GetPcp() != GetPcp()) {
|
|
NEARBY_LOGS(INFO) << "BleAdvertisement doesn't match on Pcp; expected "
|
|
<< PcpToStrategy(GetPcp()).GetName() << ", found "
|
|
<< PcpToStrategy(advertisement.GetPcp()).GetName();
|
|
return false;
|
|
}
|
|
|
|
// Check ServiceId for normal advertisement.
|
|
// ServiceIdHash is empty for fast advertisement.
|
|
if (!advertisement.IsFastAdvertisement()) {
|
|
ByteArray expected_service_id_hash = GenerateHash(
|
|
std::string(service_id), BleAdvertisement::kServiceIdHashLength);
|
|
|
|
if (advertisement.GetServiceIdHash() != expected_service_id_hash) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "BleAdvertisement doesn't match on expected service_id_hash; "
|
|
"expected "
|
|
<< absl::BytesToHexString(expected_service_id_hash.data())
|
|
<< ", found "
|
|
<< absl::BytesToHexString(advertisement.GetServiceIdHash().data());
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void P2pClusterPcpHandler::BleV2PeripheralDiscoveredHandler(
|
|
ClientProxy* client, BleV2Peripheral peripheral,
|
|
const std::string& service_id, const ByteArray& advertisement_bytes,
|
|
bool fast_advertisement) {
|
|
// TODO(edwinwu): Move the lambda to a named function.
|
|
RunOnPcpHandlerThread(
|
|
"p2p-ble-peripheral-discovered",
|
|
[this, client, peripheral = std::move(peripheral), service_id,
|
|
advertisement_bytes, fast_advertisement]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering() || stop_.Get()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Skipping discovery of BleAdvertisement header "
|
|
<< absl::BytesToHexString(advertisement_bytes.data())
|
|
<< " because we are no longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the BLE advertisement bytes.
|
|
BleAdvertisement advertisement(fast_advertisement, advertisement_bytes);
|
|
|
|
// Make sure the BLE advertisement points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedBleV2Endpoint(service_id, advertisement)) return;
|
|
|
|
// Report the discovered endpoint to the client.
|
|
// BleV2EndpointState ble_endpoint_state(/*ble=*/true, /*l2cap=*/false,
|
|
// /*bt=alse*/false);
|
|
BleV2EndpointState ble_endpoint_state;
|
|
ByteArray peripheral_id = peripheral.GetId();
|
|
found_endpoints_in_ble_discover_cb_.insert(
|
|
{peripheral_id, ble_endpoint_state});
|
|
|
|
ble_endpoint_state.ble = true;
|
|
found_endpoints_in_ble_discover_cb_[peripheral_id] = ble_endpoint_state;
|
|
NEARBY_LOGS(INFO) << "Found BleAdvertisement "
|
|
<< absl::BytesToHexString(advertisement_bytes.data())
|
|
<< " (with endpoint_id="
|
|
<< advertisement.GetEndpointId()
|
|
<< ", and endpoint_info="
|
|
<< absl::BytesToHexString(
|
|
advertisement.GetEndpointInfo().data())
|
|
<< ").";
|
|
OnEndpointFound(
|
|
client,
|
|
std::make_shared<BleV2Endpoint>(BleV2Endpoint{
|
|
{advertisement.GetEndpointId(), advertisement.GetEndpointInfo(),
|
|
service_id, proto::connections::Medium::BLE,
|
|
advertisement.GetWebRtcState()},
|
|
std::move(peripheral),
|
|
}));
|
|
|
|
// Make sure we can connect to this device via Classic Bluetooth.
|
|
std::string remote_bluetooth_mac_address =
|
|
advertisement.GetBluetoothMacAddress();
|
|
if (remote_bluetooth_mac_address.empty()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "No Bluetooth Classic MAC address found in advertisement.";
|
|
return;
|
|
}
|
|
|
|
BluetoothDevice remote_bluetooth_device =
|
|
bluetooth_medium_.GetRemoteDevice(remote_bluetooth_mac_address);
|
|
if (!remote_bluetooth_device.IsValid()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "A valid Bluetooth device could not be derived from the MAC "
|
|
"address "
|
|
<< remote_bluetooth_mac_address;
|
|
return;
|
|
}
|
|
|
|
ble_endpoint_state.bt = true;
|
|
found_endpoints_in_ble_discover_cb_[peripheral_id] = ble_endpoint_state;
|
|
OnEndpointFound(client,
|
|
std::make_shared<BluetoothEndpoint>(BluetoothEndpoint{
|
|
{
|
|
advertisement.GetEndpointId(),
|
|
advertisement.GetEndpointInfo(),
|
|
service_id,
|
|
proto::connections::Medium::BLUETOOTH,
|
|
advertisement.GetWebRtcState(),
|
|
},
|
|
remote_bluetooth_device,
|
|
}));
|
|
});
|
|
}
|
|
|
|
// TODO(b/222392304): More test coverage.
|
|
void P2pClusterPcpHandler::BleV2PeripheralLostHandler(
|
|
ClientProxy* client, BleV2Peripheral peripheral,
|
|
const std::string& service_id, const ByteArray& advertisement_bytes,
|
|
bool fast_advertisement) {
|
|
RunOnPcpHandlerThread(
|
|
"p2p-ble-peripheral-lost",
|
|
[this, client, service_id, peripheral = std::move(peripheral),
|
|
advertisement_bytes, fast_advertisement]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering() || stop_.Get()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Ignoring lost BlePeripheral "
|
|
<< absl::BytesToHexString(peripheral.GetId().data())
|
|
<< " because we are no longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the BLE advertisement bytes.
|
|
BleAdvertisement advertisement(fast_advertisement, advertisement_bytes);
|
|
|
|
// Make sure the BLE advertisement points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedBleV2Endpoint(service_id, advertisement)) return;
|
|
|
|
// Remove this BlePeripheral from found_ble_endpoints_, and
|
|
// report the endpoint as lost to the client.
|
|
auto const item =
|
|
found_endpoints_in_ble_discover_cb_.find(peripheral.GetId());
|
|
if (item == found_endpoints_in_ble_discover_cb_.end()) {
|
|
return;
|
|
}
|
|
BleV2EndpointState ble_endpoint_state(item->second);
|
|
found_endpoints_in_ble_discover_cb_.erase(item);
|
|
|
|
if (ble_endpoint_state.ble) {
|
|
// Report the lost endpoint to the client.
|
|
NEARBY_LOGS(INFO)
|
|
<< "Lost BleEndpoint for BlePeripheral "
|
|
<< absl::BytesToHexString(peripheral.GetId().data())
|
|
<< " (with endpoint_id=" << advertisement.GetEndpointId()
|
|
<< " and endpoint_info="
|
|
<< absl::BytesToHexString(advertisement.GetEndpointInfo().data())
|
|
<< ").";
|
|
OnEndpointLost(client, DiscoveredEndpoint{
|
|
advertisement.GetEndpointId(),
|
|
advertisement.GetEndpointInfo(),
|
|
service_id,
|
|
proto::connections::Medium::BLE,
|
|
WebRtcState::kUndefined,
|
|
});
|
|
}
|
|
if (ble_endpoint_state.bt) {
|
|
// Report the lost endpoint to the client.
|
|
NEARBY_LOGS(INFO)
|
|
<< "Lost BluetoothEndpoint for BlePeripheral "
|
|
<< absl::BytesToHexString(peripheral.GetId().data())
|
|
<< " (with endpoint_id=" << advertisement.GetEndpointId()
|
|
<< " and endpoint_info="
|
|
<< absl::BytesToHexString(advertisement.GetEndpointInfo().data())
|
|
<< ").";
|
|
OnEndpointLost(client, DiscoveredEndpoint{
|
|
advertisement.GetEndpointId(),
|
|
advertisement.GetEndpointInfo(),
|
|
service_id,
|
|
proto::connections::Medium::BLUETOOTH,
|
|
WebRtcState::kUndefined,
|
|
});
|
|
}
|
|
});
|
|
}
|
|
|
|
bool P2pClusterPcpHandler::IsRecognizedWifiLanEndpoint(
|
|
const std::string& service_id,
|
|
const WifiLanServiceInfo& wifi_lan_service_info) const {
|
|
if (!wifi_lan_service_info.IsValid()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "WifiLanServiceInfo doesn't conform to the format, discarding.";
|
|
return false;
|
|
}
|
|
|
|
if (wifi_lan_service_info.GetPcp() != GetPcp()) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "WifiLanServiceInfo doesn't match on Pcp; expected "
|
|
<< PcpToStrategy(GetPcp()).GetName() << ", found "
|
|
<< PcpToStrategy(wifi_lan_service_info.GetPcp()).GetName();
|
|
return false;
|
|
}
|
|
|
|
ByteArray expected_service_id_hash =
|
|
GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength);
|
|
|
|
if (wifi_lan_service_info.GetServiceIdHash() != expected_service_id_hash) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "WifiLanServiceInfo doesn't match on expected service_id_hash; "
|
|
"expected "
|
|
<< absl::BytesToHexString(expected_service_id_hash.data()) << ", found "
|
|
<< absl::BytesToHexString(
|
|
wifi_lan_service_info.GetServiceIdHash().data());
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
void P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler(
|
|
ClientProxy* client, NsdServiceInfo service_info,
|
|
const std::string& service_id) {
|
|
RunOnPcpHandlerThread(
|
|
"p2p-wifi-service-discovered",
|
|
[this, client, service_id, service_info]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering()) {
|
|
NEARBY_LOGS(WARNING) << "Skipping discovery of NsdServiceInfo "
|
|
<< service_info.GetServiceName()
|
|
<< " because we are no longer discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the WifiLanServiceInfo.
|
|
WifiLanServiceInfo wifi_lan_service_info(service_info);
|
|
// Make sure the WifiLan service name points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedWifiLanEndpoint(service_id, wifi_lan_service_info)) {
|
|
return;
|
|
}
|
|
|
|
// Report the discovered endpoint to the client.
|
|
NEARBY_LOGS(INFO) << "Found NsdServiceInfo "
|
|
<< service_info.GetServiceName()
|
|
<< " (with endpoint_id="
|
|
<< wifi_lan_service_info.GetEndpointId()
|
|
<< "and endpoint_info="
|
|
<< absl::BytesToHexString(
|
|
wifi_lan_service_info.GetEndpointInfo().data())
|
|
<< ").";
|
|
OnEndpointFound(client,
|
|
std::make_shared<WifiLanEndpoint>(WifiLanEndpoint{
|
|
{
|
|
wifi_lan_service_info.GetEndpointId(),
|
|
wifi_lan_service_info.GetEndpointInfo(),
|
|
service_id,
|
|
proto::connections::Medium::WIFI_LAN,
|
|
wifi_lan_service_info.GetWebRtcState(),
|
|
},
|
|
service_info,
|
|
}));
|
|
});
|
|
}
|
|
|
|
void P2pClusterPcpHandler::WifiLanServiceLostHandler(
|
|
ClientProxy* client, NsdServiceInfo service_info,
|
|
const std::string& service_id) {
|
|
NEARBY_LOGS(INFO) << "WifiLan: [LOST, SCHED] service_info=" << &service_info
|
|
<< ", service_name=" << service_info.GetServiceName();
|
|
RunOnPcpHandlerThread(
|
|
"p2p-wifi-service-lost",
|
|
[this, client, service_id, service_info]() RUN_ON_PCP_HANDLER_THREAD() {
|
|
// Make sure we are still discovering before proceeding.
|
|
if (!client->IsDiscovering()) {
|
|
NEARBY_LOGS(WARNING) << "Ignoring lost NsdServiceInfo "
|
|
<< service_info.GetServiceName()
|
|
<< " because we are no longer "
|
|
"discovering.";
|
|
return;
|
|
}
|
|
|
|
// Parse the WifiLanServiceInfo.
|
|
WifiLanServiceInfo wifi_lan_service_info(service_info);
|
|
|
|
// Make sure the WifiLan service name points to a valid
|
|
// endpoint we're discovering.
|
|
if (!IsRecognizedWifiLanEndpoint(service_id, wifi_lan_service_info))
|
|
return;
|
|
|
|
// Report the lost endpoint to the client.
|
|
NEARBY_LOGS(INFO) << "Lost NsdServiceInfo "
|
|
<< service_info.GetServiceName()
|
|
<< " (with endpoint_id="
|
|
<< wifi_lan_service_info.GetEndpointId()
|
|
<< " and endpoint_info="
|
|
<< absl::BytesToHexString(
|
|
wifi_lan_service_info.GetEndpointInfo().data())
|
|
<< ").";
|
|
OnEndpointLost(client, DiscoveredEndpoint{
|
|
wifi_lan_service_info.GetEndpointId(),
|
|
wifi_lan_service_info.GetEndpointInfo(),
|
|
service_id,
|
|
proto::connections::Medium::WIFI_LAN,
|
|
WebRtcState::kUndefined,
|
|
});
|
|
});
|
|
}
|
|
|
|
BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl(
|
|
ClientProxy* client, const std::string& service_id,
|
|
const DiscoveryOptions& discovery_options) {
|
|
// If this is an out-of-band connection, do not start actual discovery, since
|
|
// this connection is intended to be completed via InjectEndpointImpl().
|
|
if (discovery_options.is_out_of_band_connection) {
|
|
return {.status = {Status::kSuccess},
|
|
.mediums = discovery_options.allowed.GetMediums(true)};
|
|
}
|
|
|
|
std::vector<proto::connections::Medium> mediums_started_successfully;
|
|
|
|
if (discovery_options.allowed.wifi_lan) {
|
|
proto::connections::Medium wifi_lan_medium = StartWifiLanDiscovery(
|
|
{
|
|
.service_discovered_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::WifiLanServiceDiscoveredHandler, this,
|
|
client),
|
|
.service_lost_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::WifiLanServiceLostHandler, this, client),
|
|
},
|
|
client, service_id);
|
|
if (wifi_lan_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "P2pClusterPcpHandler::StartDiscoveryImpl: WifiLan added";
|
|
mediums_started_successfully.push_back(wifi_lan_medium);
|
|
}
|
|
}
|
|
|
|
if (discovery_options.allowed.bluetooth) {
|
|
proto::connections::Medium bluetooth_medium = StartBluetoothDiscovery(
|
|
{
|
|
.device_discovered_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::BluetoothDeviceDiscoveredHandler, this,
|
|
client, service_id),
|
|
.device_name_changed_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::BluetoothNameChangedHandler, this,
|
|
client, service_id),
|
|
.device_lost_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::BluetoothDeviceLostHandler, this, client,
|
|
service_id),
|
|
},
|
|
client, service_id);
|
|
if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: BT added");
|
|
mediums_started_successfully.push_back(bluetooth_medium);
|
|
bluetooth_classic_discoverer_client_id_ = client->GetClientId();
|
|
}
|
|
}
|
|
|
|
if (discovery_options.allowed.ble) {
|
|
if (FeatureFlags::GetInstance().GetFlags().support_ble_v2) {
|
|
proto::connections::Medium ble_v2_medium = StartBleV2Scanning(
|
|
{
|
|
.peripheral_discovered_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::BleV2PeripheralDiscoveredHandler, this,
|
|
client),
|
|
.peripheral_lost_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::BleV2PeripheralLostHandler, this,
|
|
client),
|
|
},
|
|
client, service_id, discovery_options);
|
|
if (ble_v2_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "P2pClusterPcpHandler::StartDiscoveryImpl: Ble added.";
|
|
mediums_started_successfully.push_back(ble_v2_medium);
|
|
}
|
|
} else {
|
|
proto::connections::Medium ble_medium = StartBleScanning(
|
|
{
|
|
.peripheral_discovered_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::BlePeripheralDiscoveredHandler, this,
|
|
client),
|
|
.peripheral_lost_cb = absl::bind_front(
|
|
&P2pClusterPcpHandler::BlePeripheralLostHandler, this,
|
|
client),
|
|
},
|
|
client, service_id,
|
|
discovery_options.fast_advertisement_service_uuid);
|
|
if (ble_medium != proto::connections::UNKNOWN_MEDIUM) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "P2pClusterPcpHandler::StartDiscoveryImpl: Ble added.";
|
|
mediums_started_successfully.push_back(ble_medium);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mediums_started_successfully.empty()) {
|
|
NEARBY_LOGS(ERROR)
|
|
<< "Failed StartDiscovery() for client=" << client->GetClientId()
|
|
<< " because we couldn't scan on Bluetooth, BLE, or WifiLan for "
|
|
"service_id="
|
|
<< service_id;
|
|
return {
|
|
.status = {Status::kBluetoothError},
|
|
};
|
|
}
|
|
|
|
return {
|
|
.status = {Status::kSuccess},
|
|
.mediums = std::move(mediums_started_successfully),
|
|
};
|
|
}
|
|
|
|
Status P2pClusterPcpHandler::StopDiscoveryImpl(ClientProxy* client) {
|
|
wifi_lan_medium_.StopDiscovery(client->GetDiscoveryServiceId());
|
|
if (client->GetClientId() == bluetooth_classic_discoverer_client_id_) {
|
|
bluetooth_medium_.StopDiscovery();
|
|
bluetooth_classic_discoverer_client_id_ = 0;
|
|
} else {
|
|
NEARBY_LOGS(INFO) << "Skipped BT StopDiscovery for client="
|
|
<< client->GetClientId()
|
|
<< ", client that started discovery is "
|
|
<< bluetooth_classic_discoverer_client_id_;
|
|
}
|
|
|
|
if (FeatureFlags::GetInstance().GetFlags().support_ble_v2) {
|
|
ble_v2_medium_.StopScanning(client->GetDiscoveryServiceId());
|
|
} else {
|
|
ble_medium_.StopScanning(client->GetDiscoveryServiceId());
|
|
}
|
|
return {Status::kSuccess};
|
|
}
|
|
|
|
Status P2pClusterPcpHandler::InjectEndpointImpl(
|
|
ClientProxy* client, const std::string& service_id,
|
|
const OutOfBandConnectionMetadata& metadata) {
|
|
NEARBY_LOGS(INFO) << "InjectEndpoint.";
|
|
// Bluetooth is the only supported out-of-band connection medium.
|
|
if (metadata.medium != Medium::BLUETOOTH) {
|
|
NEARBY_LOGS(WARNING) << "InjectEndpointImpl: Only Bluetooth is supported.";
|
|
return {Status::kError};
|
|
}
|
|
|
|
BluetoothDevice remote_bluetooth_device =
|
|
injected_bluetooth_device_store_.CreateInjectedBluetoothDevice(
|
|
metadata.remote_bluetooth_mac_address, metadata.endpoint_id,
|
|
metadata.endpoint_info,
|
|
GenerateHash(service_id, BluetoothDeviceName::kServiceIdHashLength),
|
|
GetPcp());
|
|
|
|
if (!remote_bluetooth_device.IsValid()) {
|
|
NEARBY_LOG(WARNING, "InjectEndpointImpl: Invalid parameters.");
|
|
return {Status::kError};
|
|
}
|
|
|
|
BluetoothDeviceDiscoveredHandler(client, service_id, remote_bluetooth_device);
|
|
return {Status::kSuccess};
|
|
}
|
|
|
|
BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::ConnectImpl(
|
|
ClientProxy* client, BasePcpHandler::DiscoveredEndpoint* endpoint) {
|
|
if (!endpoint) {
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.status = {Status::kError},
|
|
};
|
|
}
|
|
switch (endpoint->medium) {
|
|
case proto::connections::Medium::BLUETOOTH: {
|
|
auto* bluetooth_endpoint = down_cast<BluetoothEndpoint*>(endpoint);
|
|
if (bluetooth_endpoint) {
|
|
return BluetoothConnectImpl(client, bluetooth_endpoint);
|
|
}
|
|
break;
|
|
}
|
|
case proto::connections::Medium::BLE: {
|
|
if (FeatureFlags::GetInstance().GetFlags().support_ble_v2) {
|
|
auto* ble_v2_endpoint = down_cast<BleV2Endpoint*>(endpoint);
|
|
if (ble_v2_endpoint) {
|
|
return BleV2ConnectImpl(client, ble_v2_endpoint);
|
|
}
|
|
|
|
} else {
|
|
auto* ble_endpoint = down_cast<BleEndpoint*>(endpoint);
|
|
if (ble_endpoint) {
|
|
return BleConnectImpl(client, ble_endpoint);
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
case proto::connections::Medium::WIFI_LAN: {
|
|
auto* wifi_lan_endpoint = down_cast<WifiLanEndpoint*>(endpoint);
|
|
if (wifi_lan_endpoint) {
|
|
return WifiLanConnectImpl(client, wifi_lan_endpoint);
|
|
}
|
|
break;
|
|
}
|
|
case proto::connections::Medium::WEB_RTC: {
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.status = {Status::kError},
|
|
};
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartBluetoothAdvertising(
|
|
ClientProxy* client, const std::string& service_id,
|
|
const ByteArray& service_id_hash, const std::string& local_endpoint_id,
|
|
const ByteArray& local_endpoint_info, WebRtcState web_rtc_state) {
|
|
// Start listening for connections before advertising in case a connection
|
|
// request comes in very quickly.
|
|
NEARBY_LOG(
|
|
INFO,
|
|
"P2pClusterPcpHandler::StartBluetoothAdvertising: service=%s: start",
|
|
service_id.c_str());
|
|
if (!bluetooth_medium_.IsAcceptingConnections(service_id)) {
|
|
if (!bluetooth_radio_.Enable() ||
|
|
!bluetooth_medium_.StartAcceptingConnections(
|
|
service_id, {.accepted_cb = [this, client, local_endpoint_info](
|
|
const std::string& service_id,
|
|
BluetoothSocket socket) {
|
|
if (!socket.IsValid()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Invalid socket in accept callback("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId();
|
|
return;
|
|
}
|
|
RunOnPcpHandlerThread(
|
|
"p2p-bt-on-incoming-connection",
|
|
[this, client, local_endpoint_info, service_id,
|
|
socket = std::move(socket)]()
|
|
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
|
std::string remote_device_name =
|
|
socket.GetRemoteDevice().GetName();
|
|
auto channel =
|
|
std::make_unique<BluetoothEndpointChannel>(
|
|
service_id, /*channel_name=*/remote_device_name,
|
|
socket);
|
|
ByteArray remote_device_info{remote_device_name};
|
|
|
|
OnIncomingConnection(
|
|
client, remote_device_info, std::move(channel),
|
|
proto::connections::Medium::BLUETOOTH);
|
|
});
|
|
}})) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In StartBluetoothAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to start listening for incoming Bluetooth "
|
|
"connections to service_id="
|
|
<< service_id;
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO)
|
|
<< "In StartBluetoothAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started listening for incoming Bluetooth connections to "
|
|
"service_id="
|
|
<< service_id;
|
|
}
|
|
|
|
// Generate a BluetoothDeviceName with which to become Bluetooth discoverable.
|
|
// TODO(b/169550050): Implement UWBAddress.
|
|
std::string device_name(BluetoothDeviceName(
|
|
kBluetoothDeviceNameVersion, GetPcp(), local_endpoint_id, service_id_hash,
|
|
local_endpoint_info, ByteArray{}, web_rtc_state));
|
|
if (device_name.empty()) {
|
|
NEARBY_LOGS(WARNING) << "In StartBluetoothAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to generate BluetoothDeviceName {version="
|
|
<< static_cast<int>(kBluetoothDeviceNameVersion)
|
|
<< ", pcp=" << PcpToStrategy(GetPcp()).GetName()
|
|
<< ", endpoint_id=" << local_endpoint_id
|
|
<< ", service_id_hash="
|
|
<< absl::BytesToHexString(service_id_hash.data())
|
|
<< ", endpoint_info="
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "}.";
|
|
bluetooth_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO) << "In StartBluetoothAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " generated BluetoothDeviceName " << device_name
|
|
<< " with service_id=" << service_id;
|
|
|
|
// Become Bluetooth discoverable.
|
|
if (!bluetooth_medium_.TurnOnDiscoverability(device_name)) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "In StartBluetoothAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " couldn't start Bluetooth advertising with BluetoothDeviceName "
|
|
<< device_name;
|
|
bluetooth_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO)
|
|
<< "In StartBluetoothAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started Bluetooth advertising with BluetoothDeviceName "
|
|
<< device_name;
|
|
return proto::connections::BLUETOOTH;
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartBluetoothDiscovery(
|
|
BluetoothDiscoveredDeviceCallback callback, ClientProxy* client,
|
|
const std::string& service_id) {
|
|
if (bluetooth_radio_.Enable() &&
|
|
bluetooth_medium_.StartDiscovery(std::move(callback))) {
|
|
NEARBY_LOGS(INFO) << "In StartBluetoothDiscovery(), client="
|
|
<< client->GetClientId()
|
|
<< " started scanning for Bluetooth for service_id="
|
|
<< service_id;
|
|
return proto::connections::BLUETOOTH;
|
|
} else {
|
|
NEARBY_LOGS(INFO) << "In StartBluetoothDiscovery(), client="
|
|
<< client->GetClientId()
|
|
<< " couldn't start scanning on Bluetooth for service_id="
|
|
<< service_id;
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
}
|
|
|
|
BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BluetoothConnectImpl(
|
|
ClientProxy* client, BluetoothEndpoint* endpoint) {
|
|
NEARBY_LOGS(VERBOSE) << "Client " << client->GetClientId()
|
|
<< " is attempting to connect to endpoint(id="
|
|
<< endpoint->endpoint_id << ") over Bluetooth Classic.";
|
|
BluetoothDevice& device = endpoint->bluetooth_device;
|
|
|
|
BluetoothSocket bluetooth_socket = bluetooth_medium_.Connect(
|
|
device, endpoint->service_id,
|
|
client->GetCancellationFlag(endpoint->endpoint_id));
|
|
if (!bluetooth_socket.IsValid()) {
|
|
NEARBY_LOGS(ERROR)
|
|
<< "In BluetoothConnectImpl(), failed to connect to Bluetooth device "
|
|
<< device.GetName() << " for endpoint(id=" << endpoint->endpoint_id
|
|
<< ").";
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.status = {Status::kBluetoothError},
|
|
};
|
|
}
|
|
|
|
auto channel = std::make_unique<BluetoothEndpointChannel>(
|
|
endpoint->service_id, /*channel_name=*/endpoint->endpoint_id,
|
|
bluetooth_socket);
|
|
NEARBY_LOGS(VERBOSE) << "Client" << client->GetClientId()
|
|
<< " created Bluetooth endpoint channel to endpoint(id="
|
|
<< endpoint->endpoint_id << ").";
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.medium = proto::connections::Medium::BLUETOOTH,
|
|
.status = {Status::kSuccess},
|
|
.endpoint_channel = std::move(channel),
|
|
};
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartBleAdvertising(
|
|
ClientProxy* client, const std::string& service_id,
|
|
const std::string& local_endpoint_id, const ByteArray& local_endpoint_info,
|
|
const AdvertisingOptions& advertising_options, WebRtcState web_rtc_state) {
|
|
bool fast_advertisement =
|
|
!advertising_options.fast_advertisement_service_uuid.empty();
|
|
PowerLevel power_level = advertising_options.low_power
|
|
? PowerLevel::kLowPower
|
|
: PowerLevel::kHighPower;
|
|
|
|
// Start listening for connections before advertising in case a connection
|
|
// request comes in very quickly. BLE allows connecting over BLE itself, as
|
|
// well as advertising the Bluetooth MAC address to allow connecting over
|
|
// Bluetooth Classic.
|
|
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id="
|
|
<< service_id << " : start";
|
|
if (!ble_medium_.IsAcceptingConnections(service_id)) {
|
|
if (!bluetooth_radio_.Enable() ||
|
|
!ble_medium_.StartAcceptingConnections(
|
|
service_id, {.accepted_cb = [this, client, local_endpoint_info](
|
|
BleSocket socket,
|
|
const std::string& service_id) {
|
|
if (!socket.IsValid()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Invalid socket in accept callback("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId();
|
|
return;
|
|
}
|
|
RunOnPcpHandlerThread(
|
|
"p2p-ble-on-incoming-connection",
|
|
[this, client, local_endpoint_info, service_id,
|
|
socket = std::move(socket)]()
|
|
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
|
std::string remote_peripheral_name =
|
|
socket.GetRemotePeripheral().GetName();
|
|
auto channel = std::make_unique<BleEndpointChannel>(
|
|
service_id,
|
|
/*channel_name=*/remote_peripheral_name, socket);
|
|
ByteArray remote_peripheral_info =
|
|
socket.GetRemotePeripheral().GetAdvertisementBytes(
|
|
service_id);
|
|
|
|
OnIncomingConnection(client, remote_peripheral_info,
|
|
std::move(channel),
|
|
proto::connections::Medium::BLE);
|
|
});
|
|
}})) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to start accepting for incoming BLE connections to "
|
|
"service_id="
|
|
<< service_id;
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO)
|
|
<< "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started accepting for incoming BLE connections to service_id="
|
|
<< service_id;
|
|
}
|
|
|
|
if (ShouldAdvertiseBluetoothMacOverBle(power_level) ||
|
|
ShouldAcceptBluetoothConnections(advertising_options)) {
|
|
if (bluetooth_medium_.IsAvailable() &&
|
|
!bluetooth_medium_.IsAcceptingConnections(service_id)) {
|
|
if (!bluetooth_radio_.Enable() ||
|
|
!bluetooth_medium_.StartAcceptingConnections(
|
|
service_id, {.accepted_cb = [this, client, local_endpoint_info](
|
|
const std::string& service_id,
|
|
BluetoothSocket socket) {
|
|
if (!socket.IsValid()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In BT StartAcceptingConnections.accepted_cb("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< ": Invalid socket in accept callback.";
|
|
return;
|
|
}
|
|
RunOnPcpHandlerThread(
|
|
"p2p-bt-on-incoming-connection",
|
|
[this, client, local_endpoint_info, service_id,
|
|
socket = std::move(socket)]()
|
|
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
|
std::string remote_device_name =
|
|
socket.GetRemoteDevice().GetName();
|
|
auto channel =
|
|
std::make_unique<BluetoothEndpointChannel>(
|
|
service_id,
|
|
/*channel_name=*/remote_device_name, socket);
|
|
ByteArray remote_device_info{remote_device_name};
|
|
|
|
OnIncomingConnection(
|
|
client, remote_device_info, std::move(channel),
|
|
proto::connections::Medium::BLUETOOTH);
|
|
});
|
|
}})) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In BT StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to start accepting for incoming BLE connections to "
|
|
"service_id="
|
|
<< service_id;
|
|
ble_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO)
|
|
<< "In BT StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started accepting for incoming BLE connections to service_id="
|
|
<< service_id;
|
|
}
|
|
}
|
|
|
|
NEARBY_LOGS(INFO) << "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " start to generate BleAdvertisement with service_id="
|
|
<< service_id
|
|
<< ", local endpoint_id=" << local_endpoint_id;
|
|
// Generate a BleAdvertisement. If a fast advertisement service UUID was
|
|
// provided, create a fast BleAdvertisement.
|
|
ByteArray advertisement_bytes;
|
|
// TODO(b/169550050): Implement UWBAddress.
|
|
if (fast_advertisement) {
|
|
advertisement_bytes = ByteArray(
|
|
BleAdvertisement(kBleAdvertisementVersion, GetPcp(), local_endpoint_id,
|
|
local_endpoint_info, ByteArray{}));
|
|
} else {
|
|
const ByteArray service_id_hash =
|
|
GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength);
|
|
std::string bluetooth_mac_address;
|
|
if (bluetooth_medium_.IsAvailable() &&
|
|
ShouldAdvertiseBluetoothMacOverBle(power_level))
|
|
bluetooth_mac_address = bluetooth_medium_.GetMacAddress();
|
|
|
|
advertisement_bytes = ByteArray(
|
|
BleAdvertisement(kBleAdvertisementVersion, GetPcp(), service_id_hash,
|
|
local_endpoint_id, local_endpoint_info,
|
|
bluetooth_mac_address, ByteArray{}, web_rtc_state));
|
|
}
|
|
if (advertisement_bytes.Empty()) {
|
|
NEARBY_LOGS(WARNING) << "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to create an advertisement.";
|
|
ble_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
|
|
NEARBY_LOGS(INFO) << "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " generated BleAdvertisement with service_id="
|
|
<< service_id;
|
|
|
|
if (!ble_medium_.StartAdvertising(
|
|
service_id, advertisement_bytes,
|
|
advertising_options.fast_advertisement_service_uuid)) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " couldn't start BLE Advertising with BleAdvertisement "
|
|
<< absl::BytesToHexString(advertisement_bytes.data());
|
|
ble_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO) << "In startBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started BLE Advertising with BleAdvertisement "
|
|
<< absl::BytesToHexString(advertisement_bytes.data());
|
|
return proto::connections::BLE;
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartBleScanning(
|
|
BleDiscoveredPeripheralCallback callback, ClientProxy* client,
|
|
const std::string& service_id,
|
|
const std::string& fast_advertisement_service_uuid) {
|
|
if (bluetooth_radio_.Enable() &&
|
|
ble_medium_.StartScanning(service_id, fast_advertisement_service_uuid,
|
|
std::move(callback))) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "In StartBleScanning(), client=" << client->GetClientId()
|
|
<< " started scanning for BLE advertisements for service_id="
|
|
<< service_id;
|
|
return proto::connections::BLE;
|
|
} else {
|
|
NEARBY_LOGS(INFO) << "In StartBleScanning(), client="
|
|
<< client->GetClientId()
|
|
<< " couldn't start scanning on BLE for service_id="
|
|
<< service_id;
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
}
|
|
|
|
BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleConnectImpl(
|
|
ClientProxy* client, BleEndpoint* endpoint) {
|
|
NEARBY_LOGS(VERBOSE) << "Client " << client->GetClientId()
|
|
<< " is attempting to connect to endpoint(id="
|
|
<< endpoint->endpoint_id << ") over BLE.";
|
|
|
|
BlePeripheral& peripheral = endpoint->ble_peripheral;
|
|
|
|
BleSocket ble_socket =
|
|
ble_medium_.Connect(peripheral, endpoint->service_id,
|
|
client->GetCancellationFlag(endpoint->endpoint_id));
|
|
if (!ble_socket.IsValid()) {
|
|
NEARBY_LOGS(ERROR)
|
|
<< "In BleConnectImpl(), failed to connect to BLE device "
|
|
<< peripheral.GetName() << " for endpoint(id=" << endpoint->endpoint_id
|
|
<< ").";
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.status = {Status::kBleError},
|
|
};
|
|
}
|
|
|
|
auto channel = std::make_unique<BleEndpointChannel>(
|
|
endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, ble_socket);
|
|
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.medium = proto::connections::Medium::BLE,
|
|
.status = {Status::kSuccess},
|
|
.endpoint_channel = std::move(channel),
|
|
};
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartBleV2Advertising(
|
|
ClientProxy* client, const std::string& service_id,
|
|
const std::string& local_endpoint_id, const ByteArray& local_endpoint_info,
|
|
const AdvertisingOptions& advertising_options, WebRtcState web_rtc_state) {
|
|
// Start listening for connections before advertising in case a connection
|
|
// request comes in very quickly. BLE allows connecting over BLE itself, as
|
|
// well as advertising the Bluetooth MAC address to allow connecting over
|
|
// Bluetooth Classic.
|
|
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartBleAdvertising: service_id="
|
|
<< service_id << " : start";
|
|
// TODO(edwinwu): Move the lambda to a named function.
|
|
if (!ble_v2_medium_.IsAcceptingConnections(service_id)) {
|
|
if (!bluetooth_radio_.Enable() ||
|
|
!ble_v2_medium_.StartAcceptingConnections(
|
|
service_id, {.accepted_cb = [this, client, local_endpoint_info](
|
|
BleV2Socket socket,
|
|
const std::string& service_id) {
|
|
if (!socket.IsValid()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Invalid socket in accept callback("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId();
|
|
return;
|
|
}
|
|
RunOnPcpHandlerThread(
|
|
"p2p-ble-on-incoming-connection",
|
|
[this, client, local_endpoint_info, service_id,
|
|
socket = std::move(socket)]()
|
|
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
|
ByteArray remote_peripheral_info =
|
|
socket.GetRemotePeripheral().GetId();
|
|
auto channel = std::make_unique<BleV2EndpointChannel>(
|
|
service_id, std::string(remote_peripheral_info),
|
|
socket);
|
|
|
|
OnIncomingConnection(client, remote_peripheral_info,
|
|
std::move(channel),
|
|
proto::connections::Medium::BLE);
|
|
});
|
|
}})) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to start accepting for incoming BLE connections to "
|
|
"service_id="
|
|
<< service_id;
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO)
|
|
<< "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started accepting for incoming BLE connections to service_id="
|
|
<< service_id;
|
|
}
|
|
|
|
PowerLevel power_level = advertising_options.low_power
|
|
? PowerLevel::kLowPower
|
|
: PowerLevel::kHighPower;
|
|
if (ShouldAdvertiseBluetoothMacOverBle(power_level) ||
|
|
ShouldAcceptBluetoothConnections(advertising_options)) {
|
|
if (bluetooth_medium_.IsAvailable() &&
|
|
!bluetooth_medium_.IsAcceptingConnections(service_id)) {
|
|
if (!bluetooth_radio_.Enable() ||
|
|
!bluetooth_medium_.StartAcceptingConnections(
|
|
service_id, {.accepted_cb = [this, client, local_endpoint_info](
|
|
const std::string& service_id,
|
|
BluetoothSocket socket) {
|
|
if (!socket.IsValid()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In BT StartAcceptingConnections.accepted_cb("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< ": Invalid socket in accept callback.";
|
|
return;
|
|
}
|
|
RunOnPcpHandlerThread(
|
|
"p2p-bt-on-incoming-connection",
|
|
[this, client, local_endpoint_info, service_id,
|
|
socket = std::move(socket)]()
|
|
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
|
std::string remote_device_name =
|
|
socket.GetRemoteDevice().GetName();
|
|
auto channel =
|
|
std::make_unique<BluetoothEndpointChannel>(
|
|
service_id, remote_device_name, socket);
|
|
ByteArray remote_device_info{remote_device_name};
|
|
|
|
OnIncomingConnection(
|
|
client, remote_device_info, std::move(channel),
|
|
proto::connections::Medium::BLUETOOTH);
|
|
});
|
|
}})) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In BT StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to start accepting for incoming BLE connections to "
|
|
"service_id="
|
|
<< service_id;
|
|
ble_v2_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO)
|
|
<< "In BT StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started accepting for incoming BLE connections to service_id="
|
|
<< service_id;
|
|
}
|
|
}
|
|
|
|
NEARBY_LOGS(INFO) << "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " start to generate BleAdvertisement with service_id="
|
|
<< service_id
|
|
<< ", local endpoint_id=" << local_endpoint_id;
|
|
// Generate a BleAdvertisement. If a fast advertisement service UUID was
|
|
// provided, create a fast BleAdvertisement.
|
|
ByteArray advertisement_bytes;
|
|
bool fast_advertisement =
|
|
!advertising_options.fast_advertisement_service_uuid.empty();
|
|
if (fast_advertisement) {
|
|
advertisement_bytes = ByteArray(
|
|
BleAdvertisement(kBleAdvertisementVersion, GetPcp(), local_endpoint_id,
|
|
local_endpoint_info, /*uwb_address=*/ByteArray{}));
|
|
} else {
|
|
const ByteArray service_id_hash =
|
|
GenerateHash(service_id, BleAdvertisement::kServiceIdHashLength);
|
|
std::string bluetooth_mac_address;
|
|
if (bluetooth_medium_.IsAvailable() &&
|
|
ShouldAdvertiseBluetoothMacOverBle(power_level))
|
|
bluetooth_mac_address = bluetooth_medium_.GetMacAddress();
|
|
|
|
advertisement_bytes = ByteArray(BleAdvertisement(
|
|
kBleAdvertisementVersion, GetPcp(), service_id_hash, local_endpoint_id,
|
|
local_endpoint_info, bluetooth_mac_address, /*uwb_address=*/ByteArray{},
|
|
web_rtc_state));
|
|
}
|
|
if (advertisement_bytes.Empty()) {
|
|
NEARBY_LOGS(WARNING) << "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to create an advertisement.";
|
|
ble_v2_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
|
|
NEARBY_LOGS(INFO) << "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " generated BleAdvertisement with service_id="
|
|
<< service_id;
|
|
|
|
if (!ble_v2_medium_.StartAdvertising(
|
|
service_id, advertisement_bytes, power_level,
|
|
!advertising_options.fast_advertisement_service_uuid.empty())) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In StartBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " couldn't start BLE Advertising with BleAdvertisement "
|
|
<< absl::BytesToHexString(advertisement_bytes.data());
|
|
ble_v2_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO) << "In startBleAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started BLE Advertising with BleAdvertisement "
|
|
<< absl::BytesToHexString(advertisement_bytes.data());
|
|
return proto::connections::BLE;
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartBleV2Scanning(
|
|
BleV2DiscoveredPeripheralCallback callback, ClientProxy* client,
|
|
const std::string& service_id, const DiscoveryOptions& discovery_options) {
|
|
PowerLevel power_level = discovery_options.low_power ? PowerLevel::kLowPower
|
|
: PowerLevel::kHighPower;
|
|
if (bluetooth_radio_.Enable() &&
|
|
ble_v2_medium_.StartScanning(service_id, power_level,
|
|
std::move(callback))) {
|
|
NEARBY_LOGS(INFO)
|
|
<< "In StartBleScanning(), client=" << client->GetClientId()
|
|
<< " started scanning for BLE advertisements for service_id="
|
|
<< service_id;
|
|
return proto::connections::BLE;
|
|
}
|
|
NEARBY_LOGS(INFO) << "In StartBleScanning(), client=" << client->GetClientId()
|
|
<< " couldn't start scanning on BLE for service_id="
|
|
<< service_id;
|
|
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
|
|
BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::BleV2ConnectImpl(
|
|
ClientProxy* client, BleV2Endpoint* endpoint) {
|
|
NEARBY_LOGS(VERBOSE) << "Client " << client->GetClientId()
|
|
<< " is attempting to connect to endpoint(id="
|
|
<< endpoint->endpoint_id << ") over BLE.";
|
|
|
|
BleV2Peripheral& peripheral = endpoint->ble_peripheral;
|
|
|
|
BleV2Socket ble_socket = ble_v2_medium_.Connect(
|
|
endpoint->service_id, peripheral,
|
|
client->GetCancellationFlag(endpoint->endpoint_id));
|
|
if (!ble_socket.IsValid()) {
|
|
NEARBY_LOGS(ERROR)
|
|
<< "In BleConnectImpl(), failed to connect to BLE device "
|
|
<< absl::BytesToHexString(peripheral.GetId().data())
|
|
<< " for endpoint(id=" << endpoint->endpoint_id << ").";
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.status = {Status::kBleError},
|
|
};
|
|
}
|
|
|
|
auto channel = std::make_unique<BleV2EndpointChannel>(
|
|
endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, ble_socket);
|
|
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.medium = proto::connections::Medium::BLE,
|
|
.status = {Status::kSuccess},
|
|
.endpoint_channel = std::move(channel),
|
|
};
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartWifiLanAdvertising(
|
|
ClientProxy* client, const std::string& service_id,
|
|
const std::string& local_endpoint_id, const ByteArray& local_endpoint_info,
|
|
WebRtcState web_rtc_state) {
|
|
// Start listening for connections before advertising in case a connection
|
|
// request comes in very quickly.
|
|
NEARBY_LOGS(INFO) << "P2pClusterPcpHandler::StartWifiLanAdvertising: service="
|
|
<< service_id << ": start";
|
|
if (!wifi_lan_medium_.IsAcceptingConnections(service_id)) {
|
|
if (!wifi_lan_medium_.StartAcceptingConnections(
|
|
service_id,
|
|
{.accepted_cb = [this, client, local_endpoint_info,
|
|
local_endpoint_id](const std::string& service_id,
|
|
WifiLanSocket socket) {
|
|
if (!socket.IsValid()) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "Invalid socket in accept callback("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId();
|
|
return;
|
|
}
|
|
RunOnPcpHandlerThread(
|
|
"p2p-wifi-on-incoming-connection",
|
|
[this, client, local_endpoint_id, local_endpoint_info,
|
|
service_id, socket = std::move(socket)]()
|
|
RUN_ON_PCP_HANDLER_THREAD() mutable {
|
|
std::string remote_service_name = local_endpoint_id;
|
|
auto channel = std::make_unique<WifiLanEndpointChannel>(
|
|
service_id, /*channel_name=*/remote_service_name,
|
|
socket);
|
|
ByteArray remote_service_name_byte{remote_service_name};
|
|
|
|
OnIncomingConnection(
|
|
client, remote_service_name_byte,
|
|
std::move(channel),
|
|
proto::connections::Medium::WIFI_LAN);
|
|
});
|
|
}})) {
|
|
NEARBY_LOGS(WARNING)
|
|
<< "In StartWifiLanAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to start listening for incoming WifiLan connections "
|
|
"to service_id="
|
|
<< service_id;
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " started listening for incoming WifiLan connections "
|
|
"to service_id = "
|
|
<< service_id;
|
|
}
|
|
|
|
// Generate a WifiLanServiceInfo with which to become WifiLan discoverable.
|
|
// TODO(b/169550050): Implement UWBAddress.
|
|
const ByteArray service_id_hash =
|
|
GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength);
|
|
WifiLanServiceInfo service_info{kWifiLanServiceInfoVersion,
|
|
GetPcp(),
|
|
local_endpoint_id,
|
|
service_id_hash,
|
|
local_endpoint_info,
|
|
ByteArray{},
|
|
web_rtc_state};
|
|
NsdServiceInfo nsd_service_info(service_info);
|
|
if (!nsd_service_info.IsValid()) {
|
|
NEARBY_LOGS(WARNING) << "In StartWifiLanAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " failed to generate WifiLanServiceInfo {version="
|
|
<< static_cast<int>(kWifiLanServiceInfoVersion)
|
|
<< ", pcp=" << PcpToStrategy(GetPcp()).GetName()
|
|
<< ", endpoint_id=" << local_endpoint_id
|
|
<< ", service_id_hash="
|
|
<< absl::BytesToHexString(service_id_hash.data())
|
|
<< ", endpoint_info="
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "}.";
|
|
wifi_lan_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " generated WifiLanServiceInfo "
|
|
<< nsd_service_info.GetServiceName()
|
|
<< " with service_id=" << service_id;
|
|
|
|
if (!wifi_lan_medium_.StartAdvertising(service_id, nsd_service_info)) {
|
|
NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " couldn't advertise with WifiLanServiceInfo "
|
|
<< nsd_service_info.GetServiceName();
|
|
wifi_lan_medium_.StopAcceptingConnections(service_id);
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
NEARBY_LOGS(INFO) << "In StartWifiLanAdvertising("
|
|
<< absl::BytesToHexString(local_endpoint_info.data())
|
|
<< "), client=" << client->GetClientId()
|
|
<< " advertised with WifiLanServiceInfo "
|
|
<< nsd_service_info.GetServiceName();
|
|
return proto::connections::WIFI_LAN;
|
|
}
|
|
|
|
proto::connections::Medium P2pClusterPcpHandler::StartWifiLanDiscovery(
|
|
WifiLanDiscoveredServiceCallback callback, ClientProxy* client,
|
|
const std::string& service_id) {
|
|
if (wifi_lan_medium_.StartDiscovery(service_id, std::move(callback))) {
|
|
NEARBY_LOGS(INFO) << "In StartWifiLanDiscovery(), client="
|
|
<< client->GetClientId()
|
|
<< " started scanning for Wifi devices for service_id="
|
|
<< service_id;
|
|
return proto::connections::WIFI_LAN;
|
|
} else {
|
|
NEARBY_LOGS(INFO) << "In StartWifiLanDiscovery(), client="
|
|
<< client->GetClientId()
|
|
<< " couldn't start scanning on Wifi for service_id="
|
|
<< service_id;
|
|
return proto::connections::UNKNOWN_MEDIUM;
|
|
}
|
|
}
|
|
|
|
BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl(
|
|
ClientProxy* client, WifiLanEndpoint* endpoint) {
|
|
NEARBY_LOGS(INFO) << "Client " << client->GetClientId()
|
|
<< " is attempting to connect to endpoint(id="
|
|
<< endpoint->endpoint_id << ") over WifiLan.";
|
|
WifiLanSocket socket = wifi_lan_medium_.Connect(
|
|
endpoint->service_id, endpoint->service_info,
|
|
client->GetCancellationFlag(endpoint->endpoint_id));
|
|
NEARBY_LOGS(ERROR) << "In WifiLanConnectImpl(), connect to service "
|
|
<< " socket=" << &socket.GetImpl()
|
|
<< " for endpoint(id=" << endpoint->endpoint_id << ").";
|
|
if (!socket.IsValid()) {
|
|
NEARBY_LOGS(ERROR)
|
|
<< "In WifiLanConnectImpl(), failed to connect to service "
|
|
<< endpoint->service_info.GetServiceName()
|
|
<< " for endpoint(id=" << endpoint->endpoint_id << ").";
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.status = {Status::kWifiLanError},
|
|
};
|
|
}
|
|
|
|
auto channel = std::make_unique<WifiLanEndpointChannel>(
|
|
endpoint->service_id, /*channel_name=*/endpoint->endpoint_id, socket);
|
|
NEARBY_LOGS(INFO) << "Client " << client->GetClientId()
|
|
<< " created WifiLan endpoint channel to endpoint(id="
|
|
<< endpoint->endpoint_id << ").";
|
|
return BasePcpHandler::ConnectImplResult{
|
|
.medium = proto::connections::Medium::WIFI_LAN,
|
|
.status = {Status::kSuccess},
|
|
.endpoint_channel = std::move(channel),
|
|
};
|
|
}
|
|
|
|
} // namespace connections
|
|
} // namespace nearby
|
|
} // namespace location
|