diff --git a/cpp/core_v2/internal/base_pcp_handler.h b/cpp/core_v2/internal/base_pcp_handler.h index a5411612..ec7213ff 100644 --- a/cpp/core_v2/internal/base_pcp_handler.h +++ b/cpp/core_v2/internal/base_pcp_handler.h @@ -164,6 +164,15 @@ class BasePcpHandler : public PcpHandler, // instance (but it can if implementation desires to do so). // BasePcpHandler will hold on to the shared_ptr. struct DiscoveredEndpoint { + DiscoveredEndpoint(std::string endpoint_id, std::string endpoint_name, + std::string service_id, + proto::connections::Medium medium) + : endpoint_id(std::move(endpoint_id)), + endpoint_name(std::move(endpoint_name)), + service_id(std::move(service_id)), + medium(medium) {} + virtual ~DiscoveredEndpoint() = default; + std::string endpoint_id; std::string endpoint_name; std::string service_id; diff --git a/cpp/core_v2/internal/base_pcp_handler_test.cc b/cpp/core_v2/internal/base_pcp_handler_test.cc index a5d9f8b6..882dbd5d 100644 --- a/cpp/core_v2/internal/base_pcp_handler_test.cc +++ b/cpp/core_v2/internal/base_pcp_handler_test.cc @@ -124,6 +124,10 @@ class MockContext { }; struct MockDiscoveredEndpoint : public MockPcpHandler::DiscoveredEndpoint { + MockDiscoveredEndpoint(DiscoveredEndpoint endpoint, MockContext context) + : DiscoveredEndpoint(std::move(endpoint)), + context(std::move(context)) {} + MockContext context; }; @@ -262,10 +266,10 @@ class BasePcpHandlerTest : public ::testing::Test { pcp_handler->OnEndpointFound( client, std::make_shared(MockDiscoveredEndpoint{ { - .endpoint_id = endpoint_id, - .endpoint_name = info.name, - .service_id = "service", - .medium = Medium::BLE, + endpoint_id, + info.name, + "service", + Medium::BLE, }, MockContext{flag}, })); diff --git a/cpp/core_v2/internal/bluetooth_device_name.cc b/cpp/core_v2/internal/bluetooth_device_name.cc index 724723db..8afd1737 100644 --- a/cpp/core_v2/internal/bluetooth_device_name.cc +++ b/cpp/core_v2/internal/bluetooth_device_name.cc @@ -34,9 +34,9 @@ BluetoothDeviceName::BluetoothDeviceName(Version version, Pcp pcp, version_ = version; pcp_ = pcp; - endpoint_id_ = endpoint_id; + endpoint_id_ = std::string(endpoint_id); service_id_hash_ = service_id_hash; - endpoint_name_ = endpoint_name; + endpoint_name_ = std::string(endpoint_name); } BluetoothDeviceName::BluetoothDeviceName( diff --git a/cpp/core_v2/internal/mediums/mediums.cc b/cpp/core_v2/internal/mediums/mediums.cc index ee2ea3bf..54b3a24f 100644 --- a/cpp/core_v2/internal/mediums/mediums.cc +++ b/cpp/core_v2/internal/mediums/mediums.cc @@ -16,6 +16,8 @@ WifiLan& Mediums::GetWifiLan() { return wifi_lan_; } +mediums::WebRtc& Mediums::GetWebRtc() { return webrtc_; } + } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core_v2/internal/mediums/mediums.h b/cpp/core_v2/internal/mediums/mediums.h index 193bb98b..4e6b07ec 100644 --- a/cpp/core_v2/internal/mediums/mediums.h +++ b/cpp/core_v2/internal/mediums/mediums.h @@ -3,9 +3,9 @@ #include "core_v2/internal/mediums/bluetooth_classic.h" #include "core_v2/internal/mediums/bluetooth_radio.h" +#include "core_v2/internal/mediums/webrtc.h" #include "core_v2/internal/mediums/wifi_lan.h" - namespace location { namespace nearby { namespace connections { @@ -25,6 +25,9 @@ class Mediums { // Returns a handle to the Wifi-Lan medium. WifiLan& GetWifiLan(); + // Returns a handle to the WebRtc medium. + mediums::WebRtc& GetWebRtc(); + private: // The order of declaration is critical for both construction and // destruction. @@ -37,6 +40,7 @@ class Mediums { BluetoothRadio bluetooth_radio_; BluetoothClassic bluetooth_classic_{bluetooth_radio_}; WifiLan wifi_lan_; + mediums::WebRtc webrtc_; }; } // namespace connections diff --git a/cpp/core_v2/internal/mediums/webrtc.cc b/cpp/core_v2/internal/mediums/webrtc.cc index 20e2f1af..32a4ec0e 100644 --- a/cpp/core_v2/internal/mediums/webrtc.cc +++ b/cpp/core_v2/internal/mediums/webrtc.cc @@ -111,14 +111,13 @@ WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id) { NEARBY_LOG(INFO, "Attempting to make a WebRTC connection to %s.", peer_id.GetId().c_str()); - std::shared_ptr> socket_future = - ListenForWebRtcSocketFuture(connection_flow_->GetDataChannel(), - AcceptedConnectionCallback()); + Future socket_future = ListenForWebRtcSocketFuture( + connection_flow_->GetDataChannel(), AcceptedConnectionCallback()); // The two devices have discovered each other, hence we have a timeout for // establishing the transport channel. ExceptionOr result = - socket_future->Get(kDataChannelTimeout); + socket_future.Get(kDataChannelTimeout); if (result.ok()) return result.result(); Disconnect(); @@ -149,18 +148,17 @@ void WebRtc::StopAcceptingConnections() { NEARBY_LOG(INFO, "Stopped accepting WebRTC connections"); } -std::shared_ptr> -WebRtc::ListenForWebRtcSocketFuture( - Future>* +Future WebRtc::ListenForWebRtcSocketFuture( + Future> data_channel_future, AcceptedConnectionCallback callback) { - auto socket_future = std::make_shared>(); + Future socket_future; auto data_channel_runnable = [this, socket_future, data_channel_future, - callback{std::move(callback)}]() { + callback{std::move(callback)}]() mutable { // The overall timeout of creating the socket and data channel is controlled // by the caller of this function. ExceptionOr> res = - data_channel_future->Get(); + data_channel_future.Get(); if (res.ok()) { WebRtcSocketWrapper wrapper = CreateWebRtcSocketWrapper(res.result()); callback.accepted_cb(wrapper); @@ -168,15 +166,15 @@ WebRtc::ListenForWebRtcSocketFuture( MutexLock lock(&mutex_); socket_ = wrapper; } - socket_future->Set(wrapper); + socket_future.Set(wrapper); } else { NEARBY_LOG(WARNING, "Failed to get WebRtcSocket."); - socket_future->Set(WebRtcSocketWrapper()); + socket_future.Set(WebRtcSocketWrapper()); } }; - data_channel_future->AddListener(std::move(data_channel_runnable), - &single_thread_executor_); + data_channel_future.AddListener(std::move(data_channel_runnable), + &single_thread_executor_); return socket_future; } diff --git a/cpp/core_v2/internal/mediums/webrtc.h b/cpp/core_v2/internal/mediums/webrtc.h index 0097d2f7..9781501f 100644 --- a/cpp/core_v2/internal/mediums/webrtc.h +++ b/cpp/core_v2/internal/mediums/webrtc.h @@ -74,8 +74,8 @@ class WebRtc { bool InitWebRtcFlow(Role role, const PeerId& self_id) ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); - std::shared_ptr> ListenForWebRtcSocketFuture( - Future>* + Future ListenForWebRtcSocketFuture( + Future> data_channel_future, AcceptedConnectionCallback callback); diff --git a/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc b/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc index 6da917b5..401cb0dc 100644 --- a/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc +++ b/cpp/core_v2/internal/mediums/webrtc/connection_flow.cc @@ -17,6 +17,8 @@ namespace nearby { namespace connections { namespace mediums { +constexpr absl::Duration ConnectionFlow::kTimeout; + namespace { // This is the same as the nearby data channel name. const char kDataChannelName[] = "dataChannel"; @@ -217,9 +219,9 @@ bool ConnectionFlow::OnRemoteIceCandidatesReceived( return true; } -Future>* +Future> ConnectionFlow::GetDataChannel() { - return &data_channel_future_; + return data_channel_future_; } bool ConnectionFlow::Close() { diff --git a/cpp/core_v2/internal/mediums/webrtc/connection_flow.h b/cpp/core_v2/internal/mediums/webrtc/connection_flow.h index 95776ea4..b1e76c41 100644 --- a/cpp/core_v2/internal/mediums/webrtc/connection_flow.h +++ b/cpp/core_v2/internal/mediums/webrtc/connection_flow.h @@ -87,7 +87,7 @@ class ConnectionFlow { std::vector> ice_candidates) ABSL_LOCKS_EXCLUDED(mutex_); // Get a future for the data channel. - Future>* GetDataChannel(); + Future> GetDataChannel(); // Close the peer connection and data channel. bool Close() ABSL_LOCKS_EXCLUDED(mutex_); diff --git a/cpp/core_v2/internal/mediums/webrtc/connection_flow_test.cc b/cpp/core_v2/internal/mediums/webrtc/connection_flow_test.cc index cca175bc..8087fec5 100644 --- a/cpp/core_v2/internal/mediums/webrtc/connection_flow_test.cc +++ b/cpp/core_v2/internal/mediums/webrtc/connection_flow_test.cc @@ -80,10 +80,10 @@ TEST(ConnectionFlowTest, SuccessfulOfferAnswerFlow) { // Retrieve Data Channels ExceptionOr> - offerer_channel = offerer->GetDataChannel()->Get(absl::Seconds(1)); + offerer_channel = offerer->GetDataChannel().Get(absl::Seconds(1)); EXPECT_TRUE(offerer_channel.ok()); ExceptionOr> - answerer_channel = answerer->GetDataChannel()->Get(absl::Seconds(1)); + answerer_channel = answerer->GetDataChannel().Get(absl::Seconds(1)); EXPECT_TRUE(answerer_channel.ok()); // Send message on data channel diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc b/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc index 126e193b..41d612d7 100644 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc +++ b/cpp/core_v2/internal/p2p_cluster_pcp_handler.cc @@ -1,7 +1,11 @@ #include "core_v2/internal/p2p_cluster_pcp_handler.h" +#include "core_v2/internal/base_pcp_handler.h" #include "core_v2/internal/bluetooth_endpoint_channel.h" +#include "core_v2/internal/mediums/webrtc/webrtc_socket_wrapper.h" +#include "core_v2/internal/webrtc_endpoint_channel.h" #include "core_v2/internal/wifi_lan_endpoint_channel.h" +#include "platform_v2/base/types.h" #include "platform_v2/public/crypto.h" #include "proto/connections_enums.pb.h" @@ -23,22 +27,24 @@ P2pClusterPcpHandler::P2pClusterPcpHandler( : BasePcpHandler(endpoint_manager, endpoint_channel_manager, pcp), bluetooth_radio_(mediums.GetBluetoothRadio()), bluetooth_medium_(mediums.GetBluetoothClassic()), - wifi_lan_medium_(mediums.GetWifiLan()) {} + wifi_lan_medium_(mediums.GetWifiLan()), + webrtc_medium_(mediums.GetWebRtc()) {} // Returns a vector or mediums sorted in order or decreasing priority for // all the supported mediums. -// NOTE: currently we only have BT, but eventually it will be more, and items -// will have to be sorted in the order of decreasing traffic bandwidth. -// Example: WiFi_LAN, BT, BLE +// Example: WiFi_LAN, WEB_RTC, BT, BLE std::vector P2pClusterPcpHandler::GetConnectionMediumsByPriority() { std::vector mediums; - if (bluetooth_medium_.IsAvailable()) { - mediums.push_back(proto::connections::BLUETOOTH); - } 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); + } return mediums; } @@ -52,16 +58,6 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( const std::string& local_endpoint_name, const ConnectionOptions& options) { std::vector mediums_started_successfully; - 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_name); - if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) { - NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: BT added"); - mediums_started_successfully.push_back(bluetooth_medium); - } - const ByteArray wifi_lan_hash = GenerateHash(service_id, WifiLanServiceInfo::kServiceIdHashLength); proto::connections::Medium wifi_lan_medium = @@ -73,6 +69,22 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( mediums_started_successfully.push_back(wifi_lan_medium); } + proto::connections::Medium webrtc_medium = StartListeningForWebRtcConnections( + client, service_id, local_endpoint_id, local_endpoint_name); + if (webrtc_medium != proto::connections::UNKNOWN_MEDIUM) { + mediums_started_successfully.push_back(webrtc_medium); + } + + 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_name); + if (bluetooth_medium != proto::connections::UNKNOWN_MEDIUM) { + NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: BT added"); + mediums_started_successfully.push_back(bluetooth_medium); + } + if (mediums_started_successfully.empty()) { NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartAdvertisingImpl: not started"); return { @@ -91,9 +103,13 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartAdvertisingImpl( } Status P2pClusterPcpHandler::StopAdvertisingImpl(ClientProxy* client) { - wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); bluetooth_medium_.TurnOffDiscoverability(); bluetooth_medium_.StopAcceptingConnections(client->GetAdvertisingServiceId()); + + webrtc_medium_.StopAcceptingConnections(); + + wifi_lan_medium_.StopAdvertising(client->GetAdvertisingServiceId()); + return {Status::kSuccess}; } @@ -163,10 +179,10 @@ P2pClusterPcpHandler::MakeBluetoothDeviceDiscoveredHandler( OnEndpointFound(client, std::make_shared(BluetoothEndpoint{ { - .endpoint_id = device_name.GetEndpointId(), - .endpoint_name = device_name.GetEndpointName(), - .service_id = service_id, - .medium = proto::connections::Medium::BLUETOOTH, + device_name.GetEndpointId(), + device_name.GetEndpointName(), + service_id, + proto::connections::Medium::BLUETOOTH, }, device, })); @@ -203,16 +219,15 @@ P2pClusterPcpHandler::MakeBluetoothDeviceLostHandler( "BT discovery handler (LOST) [client=%p, service=%s]: report " "to client", client, service_id.c_str()); - OnEndpointLost(client, - BluetoothEndpoint{ - { - .endpoint_id = device_name.GetEndpointId(), - .endpoint_name = device_name.GetEndpointName(), - .service_id = service_id, - .medium = proto::connections::Medium::BLUETOOTH, - }, - device, - }); + OnEndpointLost(client, BluetoothEndpoint{ + { + device_name.GetEndpointId(), + device_name.GetEndpointName(), + service_id, + proto::connections::Medium::BLUETOOTH, + }, + device, + }); }); }; } @@ -282,16 +297,15 @@ P2pClusterPcpHandler::MakeWifiLanServiceDiscoveredHandler( "service=%s; id=%s; name=%s", service_id.c_str(), service_name.GetEndpointId().c_str(), service_name.GetEndpointName().c_str()); - OnEndpointFound(client, - std::make_shared(WifiLanEndpoint{ - { - .endpoint_id = service_name.GetEndpointId(), - .endpoint_name = service_name.GetEndpointName(), - .service_id = service_id, - .medium = proto::connections::Medium::WIFI_LAN, - }, - service, - })); + OnEndpointFound(client, std::make_shared(WifiLanEndpoint{ + { + service_name.GetEndpointId(), + service_name.GetEndpointName(), + service_id, + proto::connections::Medium::WIFI_LAN, + }, + service, + })); }); }; } @@ -328,16 +342,15 @@ P2pClusterPcpHandler::MakeWifiLanServiceLostHandler( "WifiLan discovery handler (LOST) [client=%p, service=%s]: report " "to client", client, service_id.c_str()); - OnEndpointLost(client, - WifiLanEndpoint{ - { - .endpoint_id = service_name.GetEndpointId(), - .endpoint_name = service_name.GetEndpointName(), - .service_id = service_id, - .medium = proto::connections::Medium::WIFI_LAN, - }, - service, - }); + OnEndpointLost(client, WifiLanEndpoint{ + { + service_name.GetEndpointId(), + service_name.GetEndpointName(), + service_id, + proto::connections::Medium::WIFI_LAN, + }, + service, + }); }); }; } @@ -347,18 +360,6 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( const ConnectionOptions& options) { std::vector mediums_started_successfully; - proto::connections::Medium bluetooth_medium = StartBluetoothDiscovery( - { - .device_discovered_cb = - MakeBluetoothDeviceDiscoveredHandler(client, service_id), - .device_lost_cb = MakeBluetoothDeviceLostHandler(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); - } - proto::connections::Medium wifi_lan_medium = StartWifiLanDiscovery( { .service_discovered_cb = @@ -371,6 +372,18 @@ BasePcpHandler::StartOperationResult P2pClusterPcpHandler::StartDiscoveryImpl( mediums_started_successfully.push_back(wifi_lan_medium); } + proto::connections::Medium bluetooth_medium = StartBluetoothDiscovery( + { + .device_discovered_cb = + MakeBluetoothDeviceDiscoveredHandler(client, service_id), + .device_lost_cb = MakeBluetoothDeviceLostHandler(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); + } + if (mediums_started_successfully.empty()) { NEARBY_LOG(INFO, "P2pClusterPcpHandler::StartDiscoveryImpl: nothing added"); return { @@ -392,15 +405,35 @@ Status P2pClusterPcpHandler::StopDiscoveryImpl(ClientProxy* client) { BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::ConnectImpl( ClientProxy* client, BasePcpHandler::DiscoveredEndpoint* endpoint) { - BluetoothEndpoint* bluetooth_endpoint = - static_cast(endpoint); - if (bluetooth_endpoint) { - return BluetoothConnectImpl(client, bluetooth_endpoint); + if (!endpoint) { + return BasePcpHandler::ConnectImplResult{ + .status = {Status::kError}, + }; } - - WifiLanEndpoint* wifi_lan_endpoint = static_cast(endpoint); - if (wifi_lan_endpoint) { - return WifiLanConnectImpl(client, wifi_lan_endpoint); + switch (endpoint->medium) { + case proto::connections::Medium::BLUETOOTH: { + auto* bluetooth_endpoint = down_cast(endpoint); + if (bluetooth_endpoint) { + return BluetoothConnectImpl(client, bluetooth_endpoint); + } + break; + } + case proto::connections::Medium::WIFI_LAN: { + auto* wifi_lan_endpoint = down_cast(endpoint); + if (wifi_lan_endpoint) { + return WifiLanConnectImpl(client, wifi_lan_endpoint); + } + break; + } + case proto::connections::Medium::WEB_RTC: { + auto* webrtc_endpoint = down_cast(endpoint); + if (webrtc_endpoint) { + return WebRtcConnectImpl(client, webrtc_endpoint); + } + break; + } + default: + break; } return BasePcpHandler::ConnectImplResult{ @@ -654,6 +687,74 @@ BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WifiLanConnectImpl( }; } +proto::connections::Medium +P2pClusterPcpHandler::StartListeningForWebRtcConnections( + ClientProxy* client, const string& service_id, + const string& local_endpoint_id, const string& local_endpoint_name) { + if (!webrtc_medium_.IsAvailable()) { + return proto::connections::UNKNOWN_MEDIUM; + } + + if (!webrtc_medium_.IsAcceptingConnections()) { + mediums::PeerId self_id = CreatePeerIdFromAdvertisement( + service_id, local_endpoint_id, local_endpoint_name); + if (!webrtc_medium_.StartAcceptingConnections( + self_id, {[this, client, local_endpoint_name]( + mediums::WebRtcSocketWrapper socket) { + if (!socket.IsValid()) { + NEARBY_LOG(ERROR, "Invalid socket in accept callback: name=%s", + local_endpoint_name.c_str()); + return; + } + + RunOnPcpHandlerThread( + [this, client, socket = std::move(socket)]() { + string remote_device_name = "WebRtcSocket"; + auto channel = absl::make_unique( + remote_device_name, socket); + + OnIncomingConnection(client, remote_device_name, + std::move(channel), + proto::connections::WEB_RTC); + }); + }})) { + return proto::connections::UNKNOWN_MEDIUM; + } + } + + return proto::connections::WEB_RTC; +} + +BasePcpHandler::ConnectImplResult P2pClusterPcpHandler::WebRtcConnectImpl( + ClientProxy* client, WebRtcEndpoint* webrtc_endpoint) { + mediums::WebRtcSocketWrapper socket_wrapper = + webrtc_medium_.Connect(webrtc_endpoint->peer_id); + + if (!socket_wrapper.IsValid()) { + return BasePcpHandler::ConnectImplResult{.status = {Status::kError}}; + } + + auto channel = absl::make_unique( + webrtc_endpoint->endpoint_id, socket_wrapper); + + if (!channel) { + socket_wrapper.Close(); + return BasePcpHandler::ConnectImplResult{.status = {Status::kError}}; + } + + return BasePcpHandler::ConnectImplResult{ + .medium = proto::connections::Medium::WEB_RTC, + .status = {Status::kSuccess}, + .endpoint_channel = std::move(channel)}; +} + +mediums::PeerId P2pClusterPcpHandler::CreatePeerIdFromAdvertisement( + const std::string& service_id, const std::string& endpoint_id, + const std::string& endpoint_name) { + std::string seed = absl::StrCat(service_id, endpoint_id, endpoint_name); + return mediums::PeerId::FromSeed(ByteArray(seed)); +} + } // namespace connections } // namespace nearby } // namespace location diff --git a/cpp/core_v2/internal/p2p_cluster_pcp_handler.h b/cpp/core_v2/internal/p2p_cluster_pcp_handler.h index c1c5d19a..fc699aae 100644 --- a/cpp/core_v2/internal/p2p_cluster_pcp_handler.h +++ b/cpp/core_v2/internal/p2p_cluster_pcp_handler.h @@ -12,6 +12,8 @@ #include "core_v2/internal/endpoint_manager.h" #include "core_v2/internal/mediums/bluetooth_classic.h" #include "core_v2/internal/mediums/mediums.h" +#include "core_v2/internal/mediums/webrtc.h" +#include "core_v2/internal/mediums/webrtc/peer_id.h" #include "core_v2/internal/pcp.h" #include "core_v2/internal/wifi_lan_service_info.h" #include "core_v2/options.h" @@ -69,11 +71,24 @@ class P2pClusterPcpHandler : public BasePcpHandler { private: struct BluetoothEndpoint : public BasePcpHandler::DiscoveredEndpoint { + BluetoothEndpoint(DiscoveredEndpoint endpoint, BluetoothDevice device) + : DiscoveredEndpoint(std::move(endpoint)), + bluetooth_device(std::move(device)) {} + BluetoothDevice bluetooth_device; }; struct WifiLanEndpoint : public BasePcpHandler::DiscoveredEndpoint { + WifiLanEndpoint(DiscoveredEndpoint endpoint, WifiLanService service) + : DiscoveredEndpoint(std::move(endpoint)), + wifi_lan_service(std::move(service)) {} WifiLanService wifi_lan_service; }; + struct WebRtcEndpoint : public BasePcpHandler::DiscoveredEndpoint { + WebRtcEndpoint(DiscoveredEndpoint endpoint, mediums::PeerId peer_id) + : DiscoveredEndpoint(std::move(endpoint)), + peer_id(std::move(peer_id)) {} + mediums::PeerId peer_id; + }; using BluetoothDiscoveredDeviceCallback = BluetoothClassic::DiscoveredDeviceCallback; @@ -124,9 +139,21 @@ class P2pClusterPcpHandler : public BasePcpHandler { BasePcpHandler::ConnectImplResult WifiLanConnectImpl( ClientProxy* client, WifiLanEndpoint* endpoint); + // WebRtc + proto::connections::Medium StartListeningForWebRtcConnections( + ClientProxy* client, const std::string& service_id, + const std::string& local_endpoint_id, + const std::string& local_endpoint_name); + BasePcpHandler::ConnectImplResult WebRtcConnectImpl( + ClientProxy* client, WebRtcEndpoint* webrtc_endpoint); + mediums::PeerId CreatePeerIdFromAdvertisement(const string& service_id, + const string& endpoint_id, + const string& endpoint_name); + BluetoothRadio& bluetooth_radio_; BluetoothClassic& bluetooth_medium_; WifiLan& wifi_lan_medium_; + mediums::WebRtc& webrtc_medium_; }; } // namespace connections diff --git a/cpp/core_v2/internal/wifi_lan_service_info.cc b/cpp/core_v2/internal/wifi_lan_service_info.cc index 75fb5463..92496867 100644 --- a/cpp/core_v2/internal/wifi_lan_service_info.cc +++ b/cpp/core_v2/internal/wifi_lan_service_info.cc @@ -35,8 +35,8 @@ WifiLanServiceInfo::WifiLanServiceInfo(Version version, Pcp pcp, version_ = version; pcp_ = pcp; service_id_hash_ = service_id_hash; - endpoint_id_ = endpoint_id; - endpoint_name_ = endpoint_name; + endpoint_id_ = std::string(endpoint_id); + endpoint_name_ = std::string(endpoint_name); } WifiLanServiceInfo::WifiLanServiceInfo(absl::string_view service_info_string) { diff --git a/cpp/platform_v2/base/types.h b/cpp/platform_v2/base/types.h index 3ac71f9a..1cca5f3f 100644 --- a/cpp/platform_v2/base/types.h +++ b/cpp/platform_v2/base/types.h @@ -19,7 +19,8 @@ namespace nearby { template inline Derived down_cast(Base* value) { using DerivedType = typename std::remove_pointer::type; - static_assert(std::is_base_of::value); + static_assert(std::is_base_of::value, + "incompatible casting"); return static_cast(value); } diff --git a/cpp/platform_v2/public/atomic_reference.h b/cpp/platform_v2/public/atomic_reference.h index 049b9f31..66c40e9d 100644 --- a/cpp/platform_v2/public/atomic_reference.h +++ b/cpp/platform_v2/public/atomic_reference.h @@ -8,7 +8,6 @@ #include "platform_v2/api/platform.h" #include "platform_v2/public/mutex.h" #include "platform_v2/public/mutex_lock.h" -#include "absl/types/any.h" namespace location { namespace nearby { @@ -20,8 +19,7 @@ class AtomicReference; // Platform-based atomic type, for something convertible to std::uint32_t. template class AtomicReference, - void>> + std::is_trivially_copyable::value>> final { public: using Platform = api::ImplementationPlatform; @@ -42,9 +40,9 @@ class AtomicReference -class AtomicReference sizeof(std::uint32_t) || - !std::is_trivially_copyable_v), - void>> +class AtomicReference sizeof(std::uint32_t) || + !std::is_trivially_copyable::value)>> final { public: explicit AtomicReference(T value) { diff --git a/proto/mediums/BUILD b/proto/mediums/BUILD new file mode 100644 index 00000000..dcf12b59 --- /dev/null +++ b/proto/mediums/BUILD @@ -0,0 +1,95 @@ +load("//net/proto2/contrib/portable/cc:portable_proto_build_defs.bzl", "portable_proto_library") +load("//tools/build_defs/proto/cpp:cc_proto_library.bzl", "cc_proto_library") + +package(default_visibility = ["//visibility:public"]) + +proto_library( + name = "nfc_frames_proto", + srcs = [ + "nfc_frames.proto", + ], + cc_api_version = 2, +) + +java_lite_proto_library( + name = "nfc_frames_java_proto_lite", + visibility = ["//java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums:__subpackages__"], + deps = [":nfc_frames_proto"], +) + +proto_library( + name = "wifi_aware_frames_proto", + srcs = [ + "wifi_aware_frames.proto", + ], + cc_api_version = 2, +) + +java_lite_proto_library( + name = "wifi_aware_frames_java_proto_lite", + visibility = [ + "//java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums:__subpackages__", + "//javatests/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums:__subpackages__", + ], + deps = [":wifi_aware_frames_proto"], +) + +proto_library( + name = "ble_frames_proto", + srcs = [ + "ble_frames.proto", + ], + cc_api_version = 2, +) + +java_lite_proto_library( + name = "ble_frames_java_proto_lite", + visibility = [ + "//java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums:__subpackages__", + "//javatests/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums:__subpackages__", + ], + deps = [":ble_frames_proto"], +) + +proto_library( + name = "web_rtc_signaling_frames_proto", + srcs = [ + "web_rtc_signaling_frames.proto", + ], + cc_api_version = 2, +) + +cc_proto_library( + name = "web_rtc_signaling_frames_cc_proto", + visibility = ["//location/nearby/connections:__subpackages__"], + deps = [":web_rtc_signaling_frames_proto"], +) + +java_lite_proto_library( + name = "web_rtc_signaling_frames_java_proto_lite", + strict_deps = 0, + visibility = [ + "//java/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums:__subpackages__", + "//javatests/com/google/android/gmscore/integ/modules/nearby/src/com/google/android/gms/nearby/mediums:__subpackages__", + ], + deps = [":web_rtc_signaling_frames_proto"], +) + +portable_proto_library( + name = "ble_frames_portable_proto", + config = ":ble_frames_portable_proto_config", + copts = [ + "-DGOOGLE_PROTOBUF_NO_RTTI=1", + ], + header_outs = [ + "ble_frames.pb.h", + ], + proto_deps = [ + ":ble_frames_proto", + ], +) + +filegroup( + name = "ble_frames_portable_proto_config", + srcs = ["ble_frames_portable_proto_config.asciipb"], +) diff --git a/proto/mediums/ble_frames.proto b/proto/mediums/ble_frames.proto new file mode 100644 index 00000000..d4f6b21c --- /dev/null +++ b/proto/mediums/ble_frames.proto @@ -0,0 +1,40 @@ +syntax = "proto2"; + +package location.nearby.mediums; + +option optimize_for = LITE_RUNTIME; +option java_outer_classname = "BleFramesProto"; +option java_package = "com.google.location.nearby.mediums.proto"; +option objc_class_prefix = "GNCM"; + +// This should map exactly to BleAdvertisement's socket versions. +// TODO(alexanderkang): Make BleAdvertisement reference this proto. +// https://cs.corp.google.com/piper///depot/google3/java/com/google/android/gmscore/dev/modules/nearby/src/com/google/android/gms/nearby/mediums/bluetoothlowenergy/BleAdvertisement.java?l=57&cl=CS&rcl=214509192 +enum SocketVersion { + UNKNOWN_SOCKET_VERSION = 0; + V1 = 1; + V2 = 2; +} + +message SocketControlFrame { + enum ControlFrameType { + UNKNOWN_CONTROL_FRAME_TYPE = 0; + INTRODUCTION = 1; + DISCONNECTION = 2; + } + + optional ControlFrameType type = 1; + + // Exactly one of the following fields will be set. + optional IntroductionFrame introduction = 2; + optional DisconnectionFrame disconnection = 3; +} + +message IntroductionFrame { + optional bytes service_id_hash = 1; + optional SocketVersion socket_version = 2; +} + +message DisconnectionFrame { + optional bytes service_id_hash = 1; +} diff --git a/proto/mediums/ble_frames_portable_proto_config.asciipb b/proto/mediums/ble_frames_portable_proto_config.asciipb new file mode 100644 index 00000000..73e7564b --- /dev/null +++ b/proto/mediums/ble_frames_portable_proto_config.asciipb @@ -0,0 +1,7 @@ +optimize_mode: LITE_RUNTIME + +allowed_enum: "location.nearby.mediums.proto.SocketVersion" +allowed_message: "location.nearby.mediums.proto.SocketControlFrame" +allowed_enum: "location.nearby.mediums.proto.SocketControlFrame.ControlFrameType" +allowed_message: "location.nearby.mediums.proto.IntroductionFrame" +allowed_message: "location.nearby.mediums.proto.DisconnectionFrame" diff --git a/proto/mediums/nfc_frames.proto b/proto/mediums/nfc_frames.proto new file mode 100644 index 00000000..b3622715 --- /dev/null +++ b/proto/mediums/nfc_frames.proto @@ -0,0 +1,29 @@ +syntax = "proto2"; + +package location.nearby.mediums; + +option optimize_for = LITE_RUNTIME; +option java_outer_classname = "NfcFramesProto"; +option java_package = "com.google.location.nearby.mediums.proto"; + +// The data to be sent to scanning devices from advertising devices during +// adveritising. +message AdvertisementData { + // The tag in the advertisement. + optional bytes tag = 1; + + // A public key associated with the advertisement. + optional bytes public_key = 2; +} + +// The data to be sent to advertisers from scanning device during discovery. +message AdvertisementRequest { + // Service id of the scanning device. + optional string service_id = 1; + + // Endpoint id of the scanning device. + optional string endpoint_id = 2; + + // Public key from the scanning device. + optional bytes public_key = 3; +} diff --git a/proto/mediums/web_rtc_signaling_frames.proto b/proto/mediums/web_rtc_signaling_frames.proto new file mode 100644 index 00000000..028c474d --- /dev/null +++ b/proto/mediums/web_rtc_signaling_frames.proto @@ -0,0 +1,94 @@ +syntax = "proto2"; + +package location.nearby.mediums; + +option optimize_for = LITE_RUNTIME; +option java_outer_classname = "WebRtcSignalingFramesProto"; +option java_package = "com.google.location.nearby.mediums.proto"; + +message WebRtcSignalingFrame { + enum FrameType { + UNKNOWN_FRAME_TYPE = 0; + OFFER_TYPE = 1; + ANSWER_TYPE = 2; + ICE_CANDIDATES_TYPE = 3; + READY_FOR_SIGNALING_POKE_TYPE = 4; + } + + optional PeerId sender_id = 1; + + optional FrameType type = 2; + + oneof Frame { + Offer offer = 3; + Answer answer = 4; + IceCandidates ice_candidates = 5; + ReadyForSignalingPoke ready_for_signaling_poke = 6; + } +} + +// The id of the peer who sent the signaling frame. +message PeerId { + optional string id = 1; +} + +// https://en.wikipedia.org/wiki/Session_Description_Protocol +// SDP (Session Description Protocol) is the standard describing a peer-to-peer +// connection. SDP contains the codec, source address, and timing information of +// audio and video. An example message is: +// v=0 +// t=0 0 +// a=group:BUNDLE data +// a=msid-semantic: WMS +// m=application 9 DTLS/SCTP 5000 +// c=IN IP4 0.0.0.0 +// b=AS:30 +// a=ice-ufrag:zaEf +// a=ice-pwd:w9+RrqMj1RbC++15mNcRoRG5 +// a=ice-options:trickle renomination +// a=fingerprint:sha-256 +// B3:FE:B9:E1:F4:58:F6:05:A7:0D:3C:E6:E5:0A:44:A0:88:F4:50:90:41:D6:2E:A3:84:D8:C5:0C:40:2E:DB:6D +// a=setup:active +// a=mid:data +// a=sctpmap:5000 webrtc-datachannel 1024 +// a=candidate:1 1 UDP 2130706431 10.0.1.1 8998 typ host +// a=candidate:2 1 UDP 1694498815 192.0.2.3 45664 typ srflx raddr +message SessionDescription { + // See the SDP example above. + optional string description = 1; +} + +// https://en.wikipedia.org/wiki/Interactive_Connectivity_Establishment +// https://www.slideshare.net/saghul/ice-4414037 +// An example message contains: +// sdp_mid = data +// sdp_m_line_index = 0 +// sdp = candidate:198238137 1 udp 2122262783 +// 620:0:1000:fd1f:1cc5:76e0:78ba:6c54 41539 typ host generation 0 ufrag kq7J +// network-id 4 network-cost 10: +message IceCandidate { + // See the lines beginning with a=candidate in the SDP example above. + optional string sdp = 1; + // For valid values, see https://tools.ietf.org/html/rfc4566 -> Media Types + // This ID uniquely identifies a given media stream with which the candidate + // is associated. Example: data + optional string sdp_mid = 2; + // A zero-based index of the m-line describing the media associated with the + // candidate. Example: 0 + optional int32 sdp_m_line_index = 3; +} + +message IceCandidates { + repeated IceCandidate ice_candidates = 1; +} + +message Offer { + optional SessionDescription session_description = 1; +} + +message Answer { + optional SessionDescription session_description = 1; +} + +// Sent from answerer->offerer once the answerer is ready to receive the offer. +message ReadyForSignalingPoke {} diff --git a/proto/mediums/wifi_aware_frames.proto b/proto/mediums/wifi_aware_frames.proto new file mode 100644 index 00000000..766b8cc0 --- /dev/null +++ b/proto/mediums/wifi_aware_frames.proto @@ -0,0 +1,48 @@ +syntax = "proto2"; + +package location.nearby.mediums; + +option optimize_for = LITE_RUNTIME; +option java_outer_classname = "WifiAwareFramesProto"; +option java_package = "com.google.location.nearby.mediums.proto"; + +message WifiAwareFrame { + enum FrameType { + UNKNOWN_FRAME_TYPE = 0; + HOST_NETWORK = 1; + NETWORK_AVAILABLE = 2; + IP_AVAILABLE = 3; + CANCELLATION = 4; + } + optional FrameType type = 1; + + // Exactly one of the following fields will be set. + optional HostNetworkFrame host_network = 2; + optional NetworkAvailableFrame network_available = 3; + optional IpAvailableFrame ip_available = 4; + optional CancellationFrame cancellation = 7; + + // The id of each frame. + optional int32 frame_id = 5; + + // A byte array of size 2. It is the id and comparable token of a WifiAware + // endpoint session. + optional bytes session_id = 6; +} + +message HostNetworkFrame {} + +message NetworkAvailableFrame {} + +message IpAvailableFrame { + // NOTE: We use string here, rather than int. This is because the WiFi Aware + // ip address has a network interface appended to the end. It looks like + // 'fe80::a321:2935:9b2d:d7e7%aware_data0', where the %aware_data0 at the end + // lets Android know which type of network this address is associated with. + // If this information is lost, we won't be able to connect to the remote + // device's ServerSocket. + optional string ip_address = 1; + optional int32 port = 2; +} + +message CancellationFrame {} diff --git a/script/oss.py b/script/oss.py index cd0199d8..4b621b0f 100755 --- a/script/oss.py +++ b/script/oss.py @@ -42,6 +42,7 @@ HEADLINE = 1 PARTIAL = 2 FULL = 3 + def has_copyright(lines, max_lookup=3): pos = 0 result = MISSING @@ -65,6 +66,7 @@ def has_copyright(lines, max_lookup=3): return FULL + def add_copyright(lines, prefix, offset): new_lines = lines[0:offset] if offset: @@ -78,6 +80,7 @@ def add_copyright(lines, prefix, offset): new_lines.extend(lines[offset:]) return new_lines + def copy_files_to_oss_project(src_root, dst_root): shutil.rmtree(dst_root + "/cpp", ignore_errors=True) shutil.rmtree(dst_root + "/proto", ignore_errors=True) @@ -87,6 +90,8 @@ def copy_files_to_oss_project(src_root, dst_root): shutil.copytree(src_root + "/connections/core/", dst_root + "/cpp/core/") shutil.copytree(src_root + "/connections/core_v2/", dst_root + "/cpp/core_v2/") shutil.copytree(src_root + "/connections/proto/", dst_root + "/proto/connections/") + shutil.copytree(src_root + "/mediums/proto/", dst_root + "/proto/mediums/") + def detect_file_copy_header_options(fname, lines): if not lines: @@ -102,6 +107,7 @@ def detect_file_copy_header_options(fname, lines): return ("#", 1) return None + def post_process_oss_files(path, args): modified_total = 0 top_level = True @@ -203,6 +209,7 @@ def post_process_oss_files(path, args): return modified_total + def main(): parser = argparse.ArgumentParser('Opensource Nearby Release Tool') parser.add_argument('target', action='store', type=str, nargs="+", default=[]) @@ -232,5 +239,6 @@ def main(): total += post_process_oss_files(dst, args) print("Total modified: {} files".format(total)) + if __name__ == "__main__": sys.exit(main())