Commit 46f1ab02 authored by Richard Knoll's avatar Richard Knoll Committed by Commit Bot

Implement browser side of WebRtc service

This adds the host implementation of the WebRtc service in the browser
process. It implements a new SendMessageDelegate that can send Unido
messages via the WebRtc service running in a sandboxed process.

- The service is launched in SharingServiceHost::BindService with
  SandboxType::kUtility
- SharingWebRtcConnectionHost handles sending / receiving data in
  plaintext as of now, with a follow-up CL adding encryption:
  https://crrev.com/c/2011925
- Signaling of WebRTC is done via FCM messages and passed through
  WebRtcSignallingHostFCM to and from the service

Bug: 1031144
Change-Id: I44884b5debdf3001b82c32e467b07bc0de87c938
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1995660
Commit-Queue: Richard Knoll <knollr@chromium.org>
Reviewed-by: default avatarAlex Gough <ajgo@chromium.org>
Reviewed-by: default avatarHimanshu Jaju <himanshujaju@chromium.org>
Cr-Commit-Position: refs/heads/master@{#735095}
parent 63b2822b
...@@ -1568,8 +1568,6 @@ jumbo_static_library("browser") { ...@@ -1568,8 +1568,6 @@ jumbo_static_library("browser") {
"sharing/click_to_call/click_to_call_message_handler_android.h", "sharing/click_to_call/click_to_call_message_handler_android.h",
"sharing/click_to_call/feature.cc", "sharing/click_to_call/feature.cc",
"sharing/click_to_call/feature.h", "sharing/click_to_call/feature.h",
"sharing/fake_device_info.cc",
"sharing/fake_device_info.h",
"sharing/features.cc", "sharing/features.cc",
"sharing/features.h", "sharing/features.h",
"sharing/ping_message_handler.cc", "sharing/ping_message_handler.cc",
...@@ -3558,6 +3556,16 @@ jumbo_static_library("browser") { ...@@ -3558,6 +3556,16 @@ jumbo_static_library("browser") {
"sharing/sharing_ui_controller.h", "sharing/sharing_ui_controller.h",
"sharing/webrtc/ice_config_fetcher.cc", "sharing/webrtc/ice_config_fetcher.cc",
"sharing/webrtc/ice_config_fetcher.h", "sharing/webrtc/ice_config_fetcher.h",
"sharing/webrtc/sharing_mojo_service.cc",
"sharing/webrtc/sharing_mojo_service.h",
"sharing/webrtc/sharing_service_host.cc",
"sharing/webrtc/sharing_service_host.h",
"sharing/webrtc/sharing_webrtc_connection_host.cc",
"sharing/webrtc/sharing_webrtc_connection_host.h",
"sharing/webrtc/webrtc_message_handler.cc",
"sharing/webrtc/webrtc_message_handler.h",
"sharing/webrtc/webrtc_signalling_host_fcm.cc",
"sharing/webrtc/webrtc_signalling_host_fcm.h",
"signin/signin_promo.cc", "signin/signin_promo.cc",
"signin/signin_promo.h", "signin/signin_promo.h",
"signin/signin_ui_util.cc", "signin/signin_ui_util.cc",
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/fake_sharing_handler_registry.h"
#include "base/logging.h"
#include "chrome/browser/sharing/sharing_message_handler.h"
FakeSharingHandlerRegistry::FakeSharingHandlerRegistry() = default;
FakeSharingHandlerRegistry::~FakeSharingHandlerRegistry() = default;
SharingMessageHandler* FakeSharingHandlerRegistry::GetSharingHandler(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
auto it = handler_map_.find(payload_case);
return it != handler_map_.end() ? it->second : nullptr;
}
void FakeSharingHandlerRegistry::RegisterSharingHandler(
std::unique_ptr<SharingMessageHandler> handler,
chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
NOTIMPLEMENTED();
}
void FakeSharingHandlerRegistry::UnregisterSharingHandler(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
NOTIMPLEMENTED();
}
void FakeSharingHandlerRegistry::SetSharingHandler(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case,
SharingMessageHandler* handler) {
handler_map_[payload_case] = handler;
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SHARING_FAKE_SHARING_HANDLER_REGISTRY_H_
#define CHROME_BROWSER_SHARING_FAKE_SHARING_HANDLER_REGISTRY_H_
#include <map>
#include "chrome/browser/sharing/sharing_handler_registry.h"
class FakeSharingHandlerRegistry : public SharingHandlerRegistry {
public:
FakeSharingHandlerRegistry();
FakeSharingHandlerRegistry(const FakeSharingHandlerRegistry&) = delete;
FakeSharingHandlerRegistry& operator=(const FakeSharingHandlerRegistry&) =
delete;
~FakeSharingHandlerRegistry() override;
// SharingHandlerRegistry:
SharingMessageHandler* GetSharingHandler(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case)
override;
void RegisterSharingHandler(
std::unique_ptr<SharingMessageHandler> handler,
chrome_browser_sharing::SharingMessage::PayloadCase payload_case)
override;
void UnregisterSharingHandler(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case)
override;
void SetSharingHandler(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case,
SharingMessageHandler* handler);
private:
std::map<chrome_browser_sharing::SharingMessage::PayloadCase,
SharingMessageHandler*>
handler_map_;
};
#endif // CHROME_BROWSER_SHARING_FAKE_SHARING_HANDLER_REGISTRY_H_
...@@ -12,23 +12,32 @@ package chrome_browser_sharing; ...@@ -12,23 +12,32 @@ package chrome_browser_sharing;
// Required in Chrome. // Required in Chrome.
option optimize_for = LITE_RUNTIME; option optimize_for = LITE_RUNTIME;
// Used to send offer and answer for signalling process of webRTC. // Used to send an initial offer to a remote device as part of the signalling
message SignallingMessage { // mechanism of WebRTC.
// Required. message PeerConnectionOfferMessage {
string session_description_message = 1; // required
string sdp = 1;
// Required.
string session_type = 2;
} }
// Used to exchange ice candidate messages between peers for webRTC connection. // Used to send the answer to a received offer as part of the signalling
message IceCandidateMessage { // mechanism of WebRTC.
// Required. message PeerConnectionAnswerMessage {
string sdp_message = 1; // required
string sdp = 1;
}
// Required. // Represents an ICE candidate for a WebRTC connection.
int32 sdp_mline_index = 2; message PeerConnectionIceCandidate {
// required
string candidate = 1;
// required
string sdp_mid = 2;
// required
int32 sdp_mline_index = 3;
}
// Required. // Used to exchange ice candidate messages between peers for WebRTC connection.
string sdp_mid = 3; message PeerConnectionIceCandidatesMessage {
} // required
\ No newline at end of file repeated PeerConnectionIceCandidate ice_candidates = 1;
}
...@@ -30,8 +30,8 @@ enum MessageType { ...@@ -30,8 +30,8 @@ enum MessageType {
SHARED_CLIPBOARD_MESSAGE = 4; SHARED_CLIPBOARD_MESSAGE = 4;
SMS_FETCH_REQUEST = 5; SMS_FETCH_REQUEST = 5;
REMOTE_COPY_MESSAGE = 6; REMOTE_COPY_MESSAGE = 6;
SIGNALLING_MESSAGE = 7; PEER_CONNECTION_OFFER_MESSAGE = 7;
ICE_CANDIDATE_MESSAGE = 8; PEER_CONNECTION_ICE_CANDIDATES_MESSAGE = 8;
DISCOVERY_REQUEST = 9; DISCOVERY_REQUEST = 9;
WEB_RTC_SIGNALING_FRAME = 10; WEB_RTC_SIGNALING_FRAME = 10;
} }
...@@ -50,8 +50,9 @@ message SharingMessage { ...@@ -50,8 +50,9 @@ message SharingMessage {
SharedClipboardMessage shared_clipboard_message = 5; SharedClipboardMessage shared_clipboard_message = 5;
SmsFetchRequest sms_fetch_request = 8; SmsFetchRequest sms_fetch_request = 8;
RemoteCopyMessage remote_copy_message = 9; RemoteCopyMessage remote_copy_message = 9;
SignallingMessage signalling_message = 10; PeerConnectionOfferMessage peer_connection_offer_message = 10;
IceCandidateMessage ice_candidate_message = 11; PeerConnectionIceCandidatesMessage peer_connection_ice_candidates_message =
11;
DiscoveryRequest discovery_request = 13; DiscoveryRequest discovery_request = 13;
WebRtcSignalingMessage web_rtc_signaling_frame = 14; WebRtcSignalingMessage web_rtc_signaling_frame = 14;
} }
...@@ -92,7 +93,7 @@ message ResponseMessage { ...@@ -92,7 +93,7 @@ message ResponseMessage {
// Payload of the response, contains one of the messages below. required. // Payload of the response, contains one of the messages below. required.
oneof payload { oneof payload {
SmsFetchResponse sms_fetch_response = 1; SmsFetchResponse sms_fetch_response = 1;
SignallingMessage signalling_message_response = 2; PeerConnectionAnswerMessage peer_connection_answer_message_response = 2;
DiscoveryResponse discovery_response = 3; DiscoveryResponse discovery_response = 3;
} }
} }
...@@ -151,3 +152,13 @@ message WebRtcSignalingMessage { ...@@ -151,3 +152,13 @@ message WebRtcSignalingMessage {
// required // required
bytes web_rtc_signaling_frame = 1; bytes web_rtc_signaling_frame = 1;
} }
// Message for sending data between devices using webRTC.
message WebRtcMessage {
// Randomly generated guid. Required for messages other than AckMessage.
string message_guid = 1;
// The actual SharingMessage to be sent across the two remote devices.
// Required.
SharingMessage message = 2;
}
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include <memory> #include <memory>
#include "chrome/browser/sharing/fake_sharing_handler_registry.h"
#include "chrome/browser/sharing/features.h" #include "chrome/browser/sharing/features.h"
#include "chrome/browser/sharing/sharing_constants.h" #include "chrome/browser/sharing/sharing_constants.h"
#include "chrome/browser/sharing/sharing_fcm_handler.h" #include "chrome/browser/sharing/sharing_fcm_handler.h"
...@@ -38,39 +39,6 @@ const char kFCMToken[] = "test_vapid_fcm_token"; ...@@ -38,39 +39,6 @@ const char kFCMToken[] = "test_vapid_fcm_token";
const char kP256dh[] = "test_p256_dh"; const char kP256dh[] = "test_p256_dh";
const char kAuthSecret[] = "test_auth_secret"; const char kAuthSecret[] = "test_auth_secret";
class FakeSharingHandlerRegistry : public SharingHandlerRegistry {
public:
FakeSharingHandlerRegistry() = default;
~FakeSharingHandlerRegistry() override = default;
SharingMessageHandler* GetSharingHandler(
SharingMessage::PayloadCase payload_case) override {
auto it = handler_map_.find(payload_case);
return it != handler_map_.end() ? it->second : nullptr;
}
void SetSharingHandler(SharingMessage::PayloadCase payload_case,
SharingMessageHandler* handler) {
handler_map_[payload_case] = handler;
}
void RegisterSharingHandler(
std::unique_ptr<SharingMessageHandler> handler,
chrome_browser_sharing::SharingMessage::PayloadCase payload_case)
override {
NOTIMPLEMENTED();
}
void UnregisterSharingHandler(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case)
override {
NOTIMPLEMENTED();
}
private:
std::map<SharingMessage::PayloadCase, SharingMessageHandler*> handler_map_;
};
class MockSharingMessageHandler : public SharingMessageHandler { class MockSharingMessageHandler : public SharingMessageHandler {
public: public:
MockSharingMessageHandler() = default; MockSharingMessageHandler() = default;
......
...@@ -20,6 +20,8 @@ ...@@ -20,6 +20,8 @@
#include "chrome/browser/sharing/sms/sms_fetch_request_handler.h" #include "chrome/browser/sharing/sms/sms_fetch_request_handler.h"
#else #else
#include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h" #include "chrome/browser/sharing/shared_clipboard/shared_clipboard_message_handler_desktop.h"
#include "chrome/browser/sharing/webrtc/sharing_service_host.h"
#include "chrome/browser/sharing/webrtc/webrtc_message_handler.h"
#endif // defined(OS_ANDROID) #endif // defined(OS_ANDROID)
#if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \ #if defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || \
...@@ -33,7 +35,8 @@ SharingHandlerRegistryImpl::SharingHandlerRegistryImpl( ...@@ -33,7 +35,8 @@ SharingHandlerRegistryImpl::SharingHandlerRegistryImpl(
SharingDeviceRegistration* sharing_device_registration, SharingDeviceRegistration* sharing_device_registration,
SharingMessageSender* message_sender, SharingMessageSender* message_sender,
SharingDeviceSource* device_source, SharingDeviceSource* device_source,
content::SmsFetcher* sms_fetcher) { content::SmsFetcher* sms_fetcher,
SharingServiceHost* sharing_service_host) {
AddSharingHandler(std::make_unique<PingMessageHandler>(), AddSharingHandler(std::make_unique<PingMessageHandler>(),
{chrome_browser_sharing::SharingMessage::kPingMessage}); {chrome_browser_sharing::SharingMessage::kPingMessage});
...@@ -79,6 +82,17 @@ SharingHandlerRegistryImpl::SharingHandlerRegistryImpl( ...@@ -79,6 +82,17 @@ SharingHandlerRegistryImpl::SharingHandlerRegistryImpl(
} }
#endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) || #endif // defined(OS_WIN) || defined(OS_MACOSX) || defined(OS_LINUX) ||
// defined(OS_CHROMEOS) // defined(OS_CHROMEOS)
#if !defined(OS_ANDROID)
if (sharing_device_registration->IsPeerConnectionSupported()) {
sharing_service_host->SetSharingHandlerRegistry(this);
AddSharingHandler(
std::make_unique<WebRtcMessageHandler>(sharing_service_host),
{chrome_browser_sharing::SharingMessage::kPeerConnectionOfferMessage,
chrome_browser_sharing::SharingMessage::
kPeerConnectionIceCandidatesMessage});
}
#endif // !defined(OS_ANDROID)
} }
SharingHandlerRegistryImpl::~SharingHandlerRegistryImpl() = default; SharingHandlerRegistryImpl::~SharingHandlerRegistryImpl() = default;
......
...@@ -20,6 +20,7 @@ class SharingDeviceRegistration; ...@@ -20,6 +20,7 @@ class SharingDeviceRegistration;
class SharingDeviceSource; class SharingDeviceSource;
class SharingMessageSender; class SharingMessageSender;
class Profile; class Profile;
class SharingServiceHost;
// Interface for handling incoming SharingMessage. // Interface for handling incoming SharingMessage.
class SharingHandlerRegistryImpl : public SharingHandlerRegistry { class SharingHandlerRegistryImpl : public SharingHandlerRegistry {
...@@ -29,7 +30,8 @@ class SharingHandlerRegistryImpl : public SharingHandlerRegistry { ...@@ -29,7 +30,8 @@ class SharingHandlerRegistryImpl : public SharingHandlerRegistry {
SharingDeviceRegistration* sharing_device_registration, SharingDeviceRegistration* sharing_device_registration,
SharingMessageSender* message_sender, SharingMessageSender* message_sender,
SharingDeviceSource* device_source, SharingDeviceSource* device_source,
content::SmsFetcher* sms_fetcher); content::SmsFetcher* sms_fetcher,
SharingServiceHost* sharing_service_host);
~SharingHandlerRegistryImpl() override; ~SharingHandlerRegistryImpl() override;
// Gets SharingMessageHandler registered for |payload_case|. // Gets SharingMessageHandler registered for |payload_case|.
......
...@@ -49,7 +49,7 @@ class SharingHandlerRegistryImplTest : public testing::Test { ...@@ -49,7 +49,7 @@ class SharingHandlerRegistryImplTest : public testing::Test {
return std::make_unique<SharingHandlerRegistryImpl>( return std::make_unique<SharingHandlerRegistryImpl>(
/*profile=*/nullptr, &sharing_device_registration_, /*profile=*/nullptr, &sharing_device_registration_,
/*message_sender=*/nullptr, /*device_source=*/nullptr, /*message_sender=*/nullptr, /*device_source=*/nullptr,
/*sms_fetcher=*/nullptr); /*sms_fetcher=*/nullptr, /*sharing_service_host=*/nullptr);
} }
protected: protected:
......
...@@ -53,6 +53,7 @@ class SharingMessageSender { ...@@ -53,6 +53,7 @@ class SharingMessageSender {
// Delegate type used to send a message. // Delegate type used to send a message.
enum class DelegateType { enum class DelegateType {
kFCM, kFCM,
kWebRtc,
}; };
SharingMessageSender( SharingMessageSender(
......
...@@ -94,10 +94,11 @@ chrome_browser_sharing::MessageType SharingPayloadCaseToMessageType( ...@@ -94,10 +94,11 @@ chrome_browser_sharing::MessageType SharingPayloadCaseToMessageType(
return chrome_browser_sharing::SMS_FETCH_REQUEST; return chrome_browser_sharing::SMS_FETCH_REQUEST;
case chrome_browser_sharing::SharingMessage::kRemoteCopyMessage: case chrome_browser_sharing::SharingMessage::kRemoteCopyMessage:
return chrome_browser_sharing::REMOTE_COPY_MESSAGE; return chrome_browser_sharing::REMOTE_COPY_MESSAGE;
case chrome_browser_sharing::SharingMessage::kSignallingMessage: case chrome_browser_sharing::SharingMessage::kPeerConnectionOfferMessage:
return chrome_browser_sharing::SIGNALLING_MESSAGE; return chrome_browser_sharing::PEER_CONNECTION_OFFER_MESSAGE;
case chrome_browser_sharing::SharingMessage::kIceCandidateMessage: case chrome_browser_sharing::SharingMessage::
return chrome_browser_sharing::ICE_CANDIDATE_MESSAGE; kPeerConnectionIceCandidatesMessage:
return chrome_browser_sharing::PEER_CONNECTION_ICE_CANDIDATES_MESSAGE;
case chrome_browser_sharing::SharingMessage::kDiscoveryRequest: case chrome_browser_sharing::SharingMessage::kDiscoveryRequest:
return chrome_browser_sharing::DISCOVERY_REQUEST; return chrome_browser_sharing::DISCOVERY_REQUEST;
case chrome_browser_sharing::SharingMessage::kWebRtcSignalingFrame: case chrome_browser_sharing::SharingMessage::kWebRtcSignalingFrame:
...@@ -231,6 +232,9 @@ void LogSharingMessageAckTime(chrome_browser_sharing::MessageType message_type, ...@@ -231,6 +232,9 @@ void LogSharingMessageAckTime(chrome_browser_sharing::MessageType message_type,
case chrome_browser_sharing::MessageType::PING_MESSAGE: case chrome_browser_sharing::MessageType::PING_MESSAGE:
case chrome_browser_sharing::MessageType::CLICK_TO_CALL_MESSAGE: case chrome_browser_sharing::MessageType::CLICK_TO_CALL_MESSAGE:
case chrome_browser_sharing::MessageType::SHARED_CLIPBOARD_MESSAGE: case chrome_browser_sharing::MessageType::SHARED_CLIPBOARD_MESSAGE:
case chrome_browser_sharing::MessageType::PEER_CONNECTION_OFFER_MESSAGE:
case chrome_browser_sharing::MessageType::
PEER_CONNECTION_ICE_CANDIDATES_MESSAGE:
base::UmaHistogramMediumTimes(suffixed_name, time); base::UmaHistogramMediumTimes(suffixed_name, time);
base::UmaHistogramMediumTimes(platform_suffixed_name, time); base::UmaHistogramMediumTimes(platform_suffixed_name, time);
break; break;
......
...@@ -79,6 +79,7 @@ void SharingService::SendMessageToDevice( ...@@ -79,6 +79,7 @@ void SharingService::SendMessageToDevice(
base::TimeDelta response_timeout, base::TimeDelta response_timeout,
chrome_browser_sharing::SharingMessage message, chrome_browser_sharing::SharingMessage message,
SharingMessageSender::ResponseCallback callback) { SharingMessageSender::ResponseCallback callback) {
// TODO(knollr): Select between kFCM and kWebRtc.
message_sender_->SendMessageToDevice( message_sender_->SendMessageToDevice(
device, response_timeout, std::move(message), device, response_timeout, std::move(message),
SharingMessageSender::DelegateType::kFCM, std::move(callback)); SharingMessageSender::DelegateType::kFCM, std::move(callback));
......
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
#include <memory> #include <memory>
#include "base/memory/singleton.h" #include "base/memory/singleton.h"
#include "build/build_config.h"
#include "chrome/browser/gcm/gcm_profile_service_factory.h" #include "chrome/browser/gcm/gcm_profile_service_factory.h"
#include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h" #include "chrome/browser/gcm/instance_id/instance_id_profile_service_factory.h"
#include "chrome/browser/profiles/profile.h" #include "chrome/browser/profiles/profile.h"
...@@ -34,6 +35,11 @@ ...@@ -34,6 +35,11 @@
#include "components/sync_device_info/local_device_info_provider.h" #include "components/sync_device_info/local_device_info_provider.h"
#include "content/public/browser/browser_context.h" #include "content/public/browser/browser_context.h"
#include "content/public/browser/sms_fetcher.h" #include "content/public/browser/sms_fetcher.h"
#include "content/public/browser/storage_partition.h"
#if !defined(OS_ANDROID)
#include "chrome/browser/sharing/webrtc/sharing_service_host.h"
#endif // !defined(OS_ANDROID)
namespace { namespace {
constexpr char kServiceName[] = "SharingService"; constexpr char kServiceName[] = "SharingService";
...@@ -51,6 +57,33 @@ void CleanEncryptionInfoWithoutAuthorizedEntity(gcm::GCMDriver* gcm_driver) { ...@@ -51,6 +57,33 @@ void CleanEncryptionInfoWithoutAuthorizedEntity(gcm::GCMDriver* gcm_driver) {
/*callback=*/base::DoNothing()); /*callback=*/base::DoNothing());
} }
// Creates a new SharingServiceHost and registers it with the
// |sharing_message_sender| to send messages via WebRTC.
// Returns nullptr if WebRTC sending is not available on this device.
SharingServiceHost* MaybeRegisterSharingServiceHost(
SharingMessageSender* sharing_message_sender,
content::BrowserContext* context) {
#if defined(OS_ANDROID)
// Sending via WebRTC is not supported on Android.
return nullptr;
#else
auto url_loader_factory =
content::BrowserContext::GetDefaultStoragePartition(context)
->GetURLLoaderFactoryForBrowserProcess();
auto sharing_service_host = std::make_unique<SharingServiceHost>(
sharing_message_sender, url_loader_factory);
// Get pointer as |sharing_message_sender| takes ownership.
SharingServiceHost* sharing_service_host_ptr = sharing_service_host.get();
sharing_message_sender->RegisterSendDelegate(
SharingMessageSender::DelegateType::kWebRtc,
std::move(sharing_service_host));
return sharing_service_host_ptr;
#endif // !defined(OS_ANDROID)
}
} // namespace } // namespace
// static // static
...@@ -116,22 +149,26 @@ KeyedService* SharingServiceFactory::BuildServiceInstanceFor( ...@@ -116,22 +149,26 @@ KeyedService* SharingServiceFactory::BuildServiceInstanceFor(
profile->GetPrefs(), sync_prefs.get(), instance_id_service->driver(), profile->GetPrefs(), sync_prefs.get(), instance_id_service->driver(),
vapid_key_manager.get()); vapid_key_manager.get());
auto sharing_message_sender = std::make_unique<SharingMessageSender>(
sync_prefs.get(), local_device_info_provider);
auto fcm_sender = std::make_unique<SharingFCMSender>( auto fcm_sender = std::make_unique<SharingFCMSender>(
gcm_driver, sync_prefs.get(), vapid_key_manager.get(), gcm_driver, sync_prefs.get(), vapid_key_manager.get(),
local_device_info_provider); local_device_info_provider);
SharingFCMSender* fcm_sender_ptr = fcm_sender.get(); SharingFCMSender* fcm_sender_ptr = fcm_sender.get();
auto sharing_message_sender = std::make_unique<SharingMessageSender>(
sync_prefs.get(), local_device_info_provider);
sharing_message_sender->RegisterSendDelegate( sharing_message_sender->RegisterSendDelegate(
SharingMessageSender::DelegateType::kFCM, std::move(fcm_sender)); SharingMessageSender::DelegateType::kFCM, std::move(fcm_sender));
SharingServiceHost* sharing_service_host_ptr =
MaybeRegisterSharingServiceHost(sharing_message_sender.get(), context);
auto device_source = std::make_unique<SharingDeviceSourceSync>( auto device_source = std::make_unique<SharingDeviceSourceSync>(
sync_service, local_device_info_provider, device_info_tracker, sync_service, local_device_info_provider, device_info_tracker,
sync_prefs.get()); sync_prefs.get());
auto handler_registry = std::make_unique<SharingHandlerRegistryImpl>( auto handler_registry = std::make_unique<SharingHandlerRegistryImpl>(
profile, sharing_device_registration.get(), sharing_message_sender.get(), profile, sharing_device_registration.get(), sharing_message_sender.get(),
device_source.get(), sms_fetcher); device_source.get(), sms_fetcher, sharing_service_host_ptr);
auto fcm_handler = std::make_unique<SharingFCMHandler>( auto fcm_handler = std::make_unique<SharingFCMHandler>(
gcm_driver, fcm_sender_ptr, sync_prefs.get(), handler_registry.get()); gcm_driver, fcm_sender_ptr, sync_prefs.get(), handler_registry.get());
......
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/webrtc/sharing_mojo_service.h"
#include "content/public/browser/service_process_host.h"
namespace sharing {
mojo::PendingRemote<mojom::Sharing> LaunchSharing() {
mojo::PendingRemote<mojom::Sharing> remote;
content::ServiceProcessHost::Launch<mojom::Sharing>(
remote.InitWithNewPipeAndPassReceiver(),
content::ServiceProcessHost::Options()
.WithSandboxType(service_manager::SandboxType::kUtility)
.WithDisplayName("Sharing Service")
.Pass());
return remote;
}
} // namespace sharing
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SHARING_WEBRTC_SHARING_MOJO_SERVICE_H_
#define CHROME_BROWSER_SHARING_WEBRTC_SHARING_MOJO_SERVICE_H_
#include "chrome/services/sharing/public/mojom/sharing.mojom.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
namespace sharing {
// Launches a new instance of the Sharing service in an isolated, sandboxed
// process, and returns a remote interface to control the service. The lifetime
// of the process is tied to that of the Remote. May be called from any thread.
mojo::PendingRemote<mojom::Sharing> LaunchSharing();
} // namespace sharing
#endif // CHROME_BROWSER_SHARING_WEBRTC_SHARING_MOJO_SERVICE_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/webrtc/sharing_service_host.h"
#include "base/callback.h"
#include "base/guid.h"
#include "chrome/browser/sharing/webrtc/sharing_mojo_service.h"
#include "chrome/browser/sharing/webrtc/sharing_webrtc_connection_host.h"
#include "chrome/browser/sharing/webrtc/webrtc_signalling_host_fcm.h"
#include "content/public/browser/network_context_client_base.h"
#include "content/public/browser/network_service_instance.h"
#include "content/public/browser/service_process_host.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/self_owned_receiver.h"
#include "services/network/public/cpp/shared_url_loader_factory.h"
#include "services/network/public/mojom/network_service.mojom.h"
#include "services/network/public/mojom/p2p.mojom.h"
#include "services/network/public/mojom/p2p_trusted.mojom.h"
#include "url/gurl.h"
namespace {
// static
std::unique_ptr<syncer::DeviceInfo> CreateDeviceInfo(
const std::string& device_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info) {
return std::make_unique<syncer::DeviceInfo>(
device_guid, /*client_name=*/std::string(),
/*chrome_version=*/std::string(), /*sync_user_agent=*/std::string(),
/*device_type=*/sync_pb::SyncEnums::TYPE_UNSET,
/*signin_scoped_device_id=*/std::string(),
/*hardware_info=*/base::SysInfo::HardwareInfo(),
/*last_updated_timestamp=*/base::Time(),
/*send_tab_to_self_receiving_enabled=*/true,
syncer::DeviceInfo::SharingInfo(target_info, /*sender_id_target_info=*/{},
/*enabled_features=*/{}));
}
template <typename T>
struct MojoPipe {
mojo::PendingRemote<T> remote;
mojo::PendingReceiver<T> receiver{remote.InitWithNewPipeAndPassReceiver()};
};
// static
// This is called from the sandboxed process after sending a message.
void OnMessageSent(
SharingMessageSender::SendMessageDelegate::SendMessageCallback callback,
std::string message_guid,
sharing::mojom::SendMessageResult result) {
switch (result) {
case sharing::mojom::SendMessageResult::kSuccess:
std::move(callback).Run(SharingSendMessageResult::kSuccessful,
message_guid);
break;
case sharing::mojom::SendMessageResult::kError:
std::move(callback).Run(SharingSendMessageResult::kInternalError,
base::nullopt);
break;
}
}
} // namespace
struct SharingWebRtcMojoPipes {
MojoPipe<sharing::mojom::SignallingSender> signalling_sender;
MojoPipe<sharing::mojom::SignallingReceiver> signalling_receiver;
MojoPipe<sharing::mojom::SharingWebRtcConnectionDelegate> delegate;
MojoPipe<sharing::mojom::SharingWebRtcConnection> connection;
MojoPipe<network::mojom::P2PTrustedSocketManagerClient> socket_manager_client;
MojoPipe<network::mojom::P2PTrustedSocketManager> trusted_socket_manager;
MojoPipe<network::mojom::P2PSocketManager> socket_manager;
MojoPipe<network::mojom::MdnsResponder> mdns_responder;
};
SharingServiceHost::SharingServiceHost(
SharingMessageSender* message_sender,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory)
: message_sender_(message_sender),
ice_config_fetcher_(url_loader_factory) {}
SharingServiceHost::~SharingServiceHost() = default;
void SharingServiceHost::DoSendMessageToDevice(
const syncer::DeviceInfo& device,
base::TimeDelta time_to_live,
chrome_browser_sharing::SharingMessage message,
SendMessageCallback callback) {
chrome_browser_sharing::WebRtcMessage webrtc_message;
std::string message_guid = base::GenerateGUID();
webrtc_message.mutable_message()->Swap(&message);
webrtc_message.set_message_guid(message_guid);
// TODO(crbug.com/1044539): support multiple messages over the same connection
// or queue messages instead of rejecting them here.
auto connection_iter = connections_.find(device.guid());
if (connection_iter != connections_.end()) {
std::move(callback).Run(SharingSendMessageResult::kInternalError,
std::string());
return;
}
// Remote device must have a valid sharing_info.
if (!device.sharing_info()) {
std::move(callback).Run(SharingSendMessageResult::kInternalError,
std::string());
return;
}
GetConnection(device.guid(), device.sharing_info()->vapid_target_info)
->SendMessage(std::move(webrtc_message),
base::BindOnce(&OnMessageSent, std::move(callback),
std::move(message_guid)));
}
void SharingServiceHost::OnPeerConnectionClosed(
const std::string& device_guid) {
connections_.erase(device_guid);
if (connections_.empty())
sharing_utility_service_.reset();
}
// |callback| will be called from the sandboxed process with the remote answer.
void SharingServiceHost::OnOfferReceived(
const std::string& device_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
const std::string& offer,
base::OnceCallback<void(const std::string&)> callback) {
GetConnection(device_guid, target_info)
->OnOfferReceived(offer, std::move(callback));
}
void SharingServiceHost::OnIceCandidatesReceived(
const std::string& device_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates) {
GetConnection(device_guid, target_info)
->OnIceCandidatesReceived(std::move(ice_candidates));
}
void SharingServiceHost::SetSharingHandlerRegistry(
SharingHandlerRegistry* handler_registry) {
handler_registry_ = handler_registry;
}
SharingWebRtcConnectionHost* SharingServiceHost::GetConnection(
const std::string& device_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info) {
auto connection_iter = connections_.find(device_guid);
if (connection_iter != connections_.end())
return connection_iter->second.get();
auto pipes = std::make_unique<SharingWebRtcMojoPipes>();
auto signalling_host = std::make_unique<WebRtcSignallingHostFCM>(
std::move(pipes->signalling_sender.receiver),
std::move(pipes->signalling_receiver.remote), message_sender_,
CreateDeviceInfo(device_guid, target_info));
// base::Unretained is safe as the connection is owned by |this|.
auto result = connections_.emplace(
device_guid,
std::make_unique<SharingWebRtcConnectionHost>(
std::move(signalling_host), handler_registry_,
CreateDeviceInfo(device_guid, target_info),
base::BindOnce(&SharingServiceHost::OnPeerConnectionClosed,
base::Unretained(this)),
std::move(pipes->delegate.receiver),
std::move(pipes->connection.remote),
std::move(pipes->socket_manager_client.receiver),
std::move(pipes->trusted_socket_manager.remote)));
DCHECK(result.second);
GetNetworkContext()->CreateP2PSocketManager(
std::move(pipes->socket_manager_client.remote),
std::move(pipes->trusted_socket_manager.receiver),
std::move(pipes->socket_manager.receiver));
GetNetworkContext()->CreateMdnsResponder(
std::move(pipes->mdns_responder.receiver));
ice_config_fetcher_.GetIceServers(
base::BindOnce(&SharingServiceHost::OnIceServersReceived,
weak_ptr_factory_.GetWeakPtr(), std::move(pipes)));
return result.first->second.get();
}
void SharingServiceHost::OnIceServersReceived(
std::unique_ptr<SharingWebRtcMojoPipes> pipes,
std::vector<sharing::mojom::IceServerPtr> ice_servers) {
if (!sharing_utility_service_) {
sharing_utility_service_.Bind(sharing::LaunchSharing());
sharing_utility_service_.reset_on_disconnect();
}
sharing_utility_service_->CreateSharingWebRtcConnection(
std::move(pipes->signalling_sender.remote),
std::move(pipes->signalling_receiver.receiver),
std::move(pipes->delegate.remote), std::move(pipes->connection.receiver),
std::move(pipes->socket_manager.remote),
std::move(pipes->mdns_responder.remote), std::move(ice_servers));
}
network::mojom::NetworkContext* SharingServiceHost::GetNetworkContext() {
if (network_context_ && network_context_.is_connected())
return network_context_.get();
network_context_.reset();
network::mojom::NetworkContextParamsPtr context_params =
network::mojom::NetworkContextParams::New();
context_params->user_agent = "";
context_params->accept_language = "en-us,en";
content::GetNetworkService()->CreateNetworkContext(
network_context_.BindNewPipeAndPassReceiver(), std::move(context_params));
mojo::PendingRemote<network::mojom::NetworkContextClient> client_remote;
mojo::MakeSelfOwnedReceiver(
std::make_unique<content::NetworkContextClientBase>(),
client_remote.InitWithNewPipeAndPassReceiver());
network_context_->SetClient(std::move(client_remote));
return network_context_.get();
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SHARING_WEBRTC_SHARING_SERVICE_HOST_H_
#define CHROME_BROWSER_SHARING_WEBRTC_SHARING_SERVICE_HOST_H_
#include <string>
#include <unordered_map>
#include "base/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/optional.h"
#include "chrome/browser/sharing/proto/sharing_message.pb.h"
#include "chrome/browser/sharing/sharing_message_sender.h"
#include "chrome/browser/sharing/sharing_send_message_result.h"
#include "chrome/browser/sharing/webrtc/ice_config_fetcher.h"
#include "chrome/services/sharing/public/mojom/sharing.mojom.h"
#include "chrome/services/sharing/public/mojom/webrtc.mojom.h"
#include "components/sync_device_info/device_info.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/network_context.mojom.h"
namespace network {
class SharedURLLoaderFactory;
} // namespace network
class SharingHandlerRegistry;
class SharingWebRtcConnectionHost;
struct SharingWebRtcMojoPipes;
// Connects to the Sharing service running in a sandboxed process and manages
// active WebRTC connections. This object is owned by the |message_sender|.
class SharingServiceHost : public SharingMessageSender::SendMessageDelegate {
public:
using SendMessageCallback =
base::OnceCallback<void(SharingSendMessageResult,
base::Optional<std::string>)>;
SharingServiceHost(
SharingMessageSender* message_sender,
scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory);
SharingServiceHost(const SharingServiceHost&) = delete;
SharingServiceHost& operator=(const SharingServiceHost&) = delete;
~SharingServiceHost() override;
// SharingMessageSender::SendMessageDelegate:
void DoSendMessageToDevice(const syncer::DeviceInfo& device,
base::TimeDelta time_to_live,
chrome_browser_sharing::SharingMessage message,
SendMessageCallback callback) override;
void OnOfferReceived(const std::string& device_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
const std::string& offer,
base::OnceCallback<void(const std::string&)> callback);
void OnIceCandidatesReceived(
const std::string& device_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates);
void SetSharingHandlerRegistry(SharingHandlerRegistry* handler_registry);
private:
void OnPeerConnectionClosed(const std::string& device_guid);
SharingWebRtcConnectionHost* GetConnection(
const std::string& device_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info);
void OnIceServersReceived(
std::unique_ptr<SharingWebRtcMojoPipes> pipes,
std::vector<sharing::mojom::IceServerPtr> ice_servers);
network::mojom::NetworkContext* GetNetworkContext();
// Owned by the SharingService KeyedService and owns |this|.
SharingMessageSender* message_sender_;
IceConfigFetcher ice_config_fetcher_;
mojo::Remote<sharing::mojom::Sharing> sharing_utility_service_;
mojo::Remote<network::mojom::NetworkContext> network_context_;
// Map of device_guid to SharingWebRtcConnectionHost containing all currently
// active connections.
std::unordered_map<std::string, std::unique_ptr<SharingWebRtcConnectionHost>>
connections_;
// Will be set when a message handler for this is registered. Owned by the
// SharingService KeyedService.
SharingHandlerRegistry* handler_registry_ = nullptr;
base::WeakPtrFactory<SharingServiceHost> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_SHARING_WEBRTC_SHARING_SERVICE_HOST_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/webrtc/sharing_webrtc_connection_host.h"
#include <memory>
#include "base/callback.h"
#include "base/logging.h"
#include "base/time/time.h"
#include "chrome/browser/sharing/sharing_handler_registry.h"
#include "chrome/browser/sharing/sharing_message_handler.h"
#include "chrome/browser/sharing/sharing_metrics.h"
#include "chrome/browser/sharing/webrtc/webrtc_signalling_host_fcm.h"
namespace {
bool IsValidSharingWebRtcPayloadCase(
chrome_browser_sharing::SharingMessage::PayloadCase payload_case) {
// WebRTC signalling messages should only be received via FCM.
return payload_case != chrome_browser_sharing::SharingMessage::
kPeerConnectionOfferMessage &&
payload_case != chrome_browser_sharing::SharingMessage::
kPeerConnectionIceCandidatesMessage;
}
} // namespace
SharingWebRtcConnectionHost::SharingWebRtcConnectionHost(
std::unique_ptr<WebRtcSignallingHostFCM> signalling_host,
SharingHandlerRegistry* handler_registry,
std::unique_ptr<syncer::DeviceInfo> device_info,
base::OnceCallback<void(const std::string&)> on_closed,
mojo::PendingReceiver<sharing::mojom::SharingWebRtcConnectionDelegate>
delegate,
mojo::PendingRemote<sharing::mojom::SharingWebRtcConnection> connection,
mojo::PendingReceiver<network::mojom::P2PTrustedSocketManagerClient>
socket_manager_client,
mojo::PendingRemote<network::mojom::P2PTrustedSocketManager> socket_manager)
: signalling_host_(std::move(signalling_host)),
handler_registry_(handler_registry),
device_info_(std::move(device_info)),
on_closed_(std::move(on_closed)),
delegate_(this, std::move(delegate)),
connection_(std::move(connection)),
socket_manager_client_(this, std::move(socket_manager_client)),
socket_manager_(std::move(socket_manager)) {
// TODO(crbug.com/1044926): start timer that force closes the connection?
delegate_.set_disconnect_handler(
base::BindOnce(&SharingWebRtcConnectionHost::OnConnectionClosing,
weak_ptr_factory_.GetWeakPtr()));
connection_.set_disconnect_handler(
base::BindOnce(&SharingWebRtcConnectionHost::OnConnectionClosing,
weak_ptr_factory_.GetWeakPtr()));
socket_manager_client_.set_disconnect_handler(
base::BindOnce(&SharingWebRtcConnectionHost::OnConnectionClosed,
weak_ptr_factory_.GetWeakPtr()));
socket_manager_.set_disconnect_handler(
base::BindOnce(&SharingWebRtcConnectionHost::OnConnectionClosed,
weak_ptr_factory_.GetWeakPtr()));
}
SharingWebRtcConnectionHost::~SharingWebRtcConnectionHost() = default;
void SharingWebRtcConnectionHost::OnMessageReceived(
const std::vector<uint8_t>& message) {
// TODO(crbug.com/1045408): hook this up to a fuzzer.
// TODO(crbug.com/1045406): decrypt |message|.
chrome_browser_sharing::WebRtcMessage sharing_message;
if (!sharing_message.ParseFromArray(message.data(), message.size())) {
// TODO(crbug.com/1021984): replace this with UMA metrics
LOG(ERROR) << "Could not parse Sharing message received via WebRTC!";
return;
}
auto payload_case = sharing_message.message().payload_case();
if (!IsValidSharingWebRtcPayloadCase(payload_case)) {
// TODO(crbug.com/1021984): replace this with UMA metrics
LOG(ERROR) << "Unexpected payload case from WebRTC: " << payload_case;
return;
}
auto* handler = handler_registry_->GetSharingHandler(payload_case);
if (!handler) {
// TODO(crbug.com/1021984): replace this with UMA metrics
LOG(ERROR) << "No sharing handler for payload_case " << payload_case;
return;
}
std::string original_message_id = sharing_message.message_guid();
chrome_browser_sharing::MessageType original_message_type =
SharingPayloadCaseToMessageType(sharing_message.message().payload_case());
handler->OnMessage(
std::move(sharing_message.message()),
base::BindOnce(&SharingWebRtcConnectionHost::OnMessageHandled,
weak_ptr_factory_.GetWeakPtr(), original_message_id,
original_message_type));
}
void SharingWebRtcConnectionHost::OnMessageHandled(
const std::string& original_message_id,
chrome_browser_sharing::MessageType original_message_type,
std::unique_ptr<chrome_browser_sharing::ResponseMessage> response) {
if (original_message_type ==
chrome_browser_sharing::MessageType::ACK_MESSAGE) {
OnConnectionClosing();
return;
}
chrome_browser_sharing::WebRtcMessage message;
auto* sharing_message = message.mutable_message();
auto* ack_message = sharing_message->mutable_ack_message();
ack_message->set_original_message_id(original_message_id);
if (response)
ack_message->set_allocated_response_message(response.release());
SendMessage(std::move(message),
base::BindOnce(&SharingWebRtcConnectionHost::OnAckSent,
weak_ptr_factory_.GetWeakPtr()));
}
void SharingWebRtcConnectionHost::OnAckSent(
sharing::mojom::SendMessageResult result) {
OnConnectionClosing();
}
void SharingWebRtcConnectionHost::OnConnectionClosing() {
connection_.reset();
delegate_.reset();
}
void SharingWebRtcConnectionHost::OnConnectionClosed() {
if (on_closed_)
std::move(on_closed_).Run(device_info_->guid());
}
void SharingWebRtcConnectionHost::SendMessage(
chrome_browser_sharing::WebRtcMessage message,
sharing::mojom::SharingWebRtcConnection::SendMessageCallback callback) {
std::vector<uint8_t> serialized_message(message.ByteSize());
if (!message.SerializeToArray(serialized_message.data(),
serialized_message.size())) {
std::move(callback).Run(sharing::mojom::SendMessageResult::kError);
return;
}
// TODO(crbug.com/1045406): encrypt |serialized_message|.
connection_->SendMessage(serialized_message, std::move(callback));
}
void SharingWebRtcConnectionHost::OnOfferReceived(
const std::string& offer,
base::OnceCallback<void(const std::string&)> callback) {
signalling_host_->OnOfferReceived(offer, std::move(callback));
}
void SharingWebRtcConnectionHost::OnIceCandidatesReceived(
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates) {
signalling_host_->OnIceCandidatesReceived(std::move(ice_candidates));
}
void SharingWebRtcConnectionHost::InvalidSocketPortRangeRequested() {
// TODO(crbug.com/1021984): Add metrics for this.
}
void SharingWebRtcConnectionHost::DumpPacket(
const std::vector<uint8_t>& packet_header,
uint64_t packet_length,
bool incoming) {
NOTIMPLEMENTED();
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SHARING_WEBRTC_SHARING_WEBRTC_CONNECTION_HOST_H_
#define CHROME_BROWSER_SHARING_WEBRTC_SHARING_WEBRTC_CONNECTION_HOST_H_
#include <cstdint>
#include <memory>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/sharing/proto/sharing_message.pb.h"
#include "chrome/browser/sharing/sharing_message_sender.h"
#include "chrome/browser/sharing/sharing_send_message_result.h"
#include "chrome/services/sharing/public/mojom/webrtc.mojom.h"
#include "components/sync_device_info/device_info.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/network/public/mojom/mdns_responder.mojom.h"
#include "services/network/public/mojom/network_context.mojom.h"
#include "services/network/public/mojom/p2p.mojom.h"
#include "services/network/public/mojom/p2p_trusted.mojom.h"
class SharingHandlerRegistry;
class WebRtcSignallingHostFCM;
// Host endpoint of a SharingWebRtcConnection. This class runs in the browser
// process and communicates with the SharingWebRtcConnection in a sandboxed
// process. This bridges Sharing messages via a WebRTC connection to another
// browser instance running on a remote device.
class SharingWebRtcConnectionHost
: public sharing::mojom::SharingWebRtcConnectionDelegate,
public network::mojom::P2PTrustedSocketManagerClient {
public:
SharingWebRtcConnectionHost(
std::unique_ptr<WebRtcSignallingHostFCM> signalling_host,
SharingHandlerRegistry* handler_registry,
std::unique_ptr<syncer::DeviceInfo> device_info,
base::OnceCallback<void(const std::string&)> on_closed,
mojo::PendingReceiver<sharing::mojom::SharingWebRtcConnectionDelegate>
delegate,
mojo::PendingRemote<sharing::mojom::SharingWebRtcConnection> connection,
mojo::PendingReceiver<network::mojom::P2PTrustedSocketManagerClient>
socket_manager_client,
mojo::PendingRemote<network::mojom::P2PTrustedSocketManager>
socket_manager);
SharingWebRtcConnectionHost(const SharingWebRtcConnectionHost&) = delete;
SharingWebRtcConnectionHost& operator=(const SharingWebRtcConnectionHost&) =
delete;
~SharingWebRtcConnectionHost() override;
// sharing::mojom::SharingWebRtcConnectionDelegate:
void OnMessageReceived(const std::vector<uint8_t>& message) override;
void SendMessage(
chrome_browser_sharing::WebRtcMessage message,
sharing::mojom::SharingWebRtcConnection::SendMessageCallback callback);
void OnOfferReceived(const std::string& offer,
base::OnceCallback<void(const std::string&)> callback);
void OnIceCandidatesReceived(
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates);
private:
void OnMessageHandled(
const std::string& original_message_id,
chrome_browser_sharing::MessageType original_message_type,
std::unique_ptr<chrome_browser_sharing::ResponseMessage> response);
void OnAckSent(sharing::mojom::SendMessageResult result);
void OnConnectionClosing();
void OnConnectionClosed();
// network::mojom::P2PTrustedSocketManagerClient:
void InvalidSocketPortRangeRequested() override;
void DumpPacket(const std::vector<uint8_t>& packet_header,
uint64_t packet_length,
bool incoming) override;
std::unique_ptr<WebRtcSignallingHostFCM> signalling_host_;
// Owned by the SharingService KeyedService and must outlive |this|.
SharingHandlerRegistry* handler_registry_;
std::unique_ptr<syncer::DeviceInfo> device_info_;
base::OnceCallback<void(const std::string&)> on_closed_;
mojo::Receiver<sharing::mojom::SharingWebRtcConnectionDelegate> delegate_;
mojo::Remote<sharing::mojom::SharingWebRtcConnection> connection_;
mojo::Receiver<network::mojom::P2PTrustedSocketManagerClient>
socket_manager_client_;
mojo::Remote<network::mojom::P2PTrustedSocketManager> socket_manager_;
base::WeakPtrFactory<SharingWebRtcConnectionHost> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_SHARING_WEBRTC_SHARING_WEBRTC_CONNECTION_HOST_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/webrtc/sharing_webrtc_connection_host.h"
#include "base/bind_helpers.h"
#include "base/test/bind_test_util.h"
#include "chrome/browser/sharing/fake_device_info.h"
#include "chrome/browser/sharing/fake_sharing_handler_registry.h"
#include "chrome/browser/sharing/proto/sharing_message.pb.h"
#include "chrome/browser/sharing/sharing_message_handler.h"
#include "chrome/browser/sharing/webrtc/webrtc_signalling_host_fcm.h"
#include "chrome/services/sharing/public/mojom/webrtc.mojom.h"
#include "content/public/test/browser_task_environment.h"
#include "services/network/public/mojom/p2p_trusted.mojom.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class MockSharingMojoService : public sharing::mojom::SharingWebRtcConnection,
public network::mojom::P2PTrustedSocketManager {
public:
MockSharingMojoService() = default;
~MockSharingMojoService() override = default;
// sharing::mojom::SharingWebRtcConnection:
MOCK_METHOD2(SendMessage,
void(const std::vector<uint8_t>&, SendMessageCallback));
// network::mojom::P2PTrustedSocketManager:
void StartRtpDump(bool incoming, bool outgoing) override {}
void StopRtpDump(bool incoming, bool outgoing) override {}
mojo::Remote<sharing::mojom::SharingWebRtcConnectionDelegate> delegate;
mojo::Receiver<sharing::mojom::SharingWebRtcConnection> connection{this};
mojo::Remote<network::mojom::P2PTrustedSocketManagerClient>
socket_manager_client;
mojo::Receiver<network::mojom::P2PTrustedSocketManager> socket_manager{this};
};
class MockSignallingHost : public WebRtcSignallingHostFCM {
public:
MockSignallingHost()
: WebRtcSignallingHostFCM(
mojo::PendingReceiver<sharing::mojom::SignallingSender>(),
mojo::PendingRemote<sharing::mojom::SignallingReceiver>(),
/*message_sender=*/nullptr,
CreateFakeDeviceInfo("id", "name")) {}
~MockSignallingHost() override = default;
// WebRtcSignallingHostFCM:
MOCK_METHOD2(SendOffer, void(const std::string&, SendOfferCallback));
MOCK_METHOD1(SendIceCandidates,
void(std::vector<sharing::mojom::IceCandidatePtr>));
MOCK_METHOD2(OnOfferReceived, void(const std::string&, SendOfferCallback));
MOCK_METHOD1(OnIceCandidatesReceived,
void(std::vector<sharing::mojom::IceCandidatePtr>));
};
class MockSharingMessageHandler : public SharingMessageHandler {
public:
MockSharingMessageHandler() = default;
~MockSharingMessageHandler() override = default;
// SharingMessageHandler:
MOCK_METHOD2(OnMessage,
void(chrome_browser_sharing::SharingMessage, DoneCallback));
};
chrome_browser_sharing::WebRtcMessage CreateMessage() {
chrome_browser_sharing::WebRtcMessage message;
message.set_message_guid("guid");
chrome_browser_sharing::SharingMessage* sharing_message =
message.mutable_message();
chrome_browser_sharing::SharedClipboardMessage* shared_clipboard_message =
sharing_message->mutable_shared_clipboard_message();
shared_clipboard_message->set_text("text");
return message;
}
chrome_browser_sharing::WebRtcMessage CreateAckMessage() {
chrome_browser_sharing::WebRtcMessage message;
chrome_browser_sharing::SharingMessage* sharing_message =
message.mutable_message();
chrome_browser_sharing::AckMessage* ack_message =
sharing_message->mutable_ack_message();
ack_message->set_original_message_id("original_message_id");
return message;
}
std::vector<uint8_t> SerializeMessage(
const chrome_browser_sharing::WebRtcMessage& message) {
std::vector<uint8_t> serialized_message(message.ByteSize());
message.SerializeToArray(serialized_message.data(),
serialized_message.size());
return serialized_message;
}
} // namespace
class SharingWebRtcConnectionHostTest : public testing::Test {
public:
SharingWebRtcConnectionHostTest() {
handler_registry_.SetSharingHandler(
chrome_browser_sharing::SharingMessage::kSharedClipboardMessage,
&message_handler_);
handler_registry_.SetSharingHandler(
chrome_browser_sharing::SharingMessage::kAckMessage,
&ack_message_handler_);
auto signalling_host = std::make_unique<MockSignallingHost>();
signalling_host_ = signalling_host.get();
host_ = std::make_unique<SharingWebRtcConnectionHost>(
std::move(signalling_host), &handler_registry_,
CreateFakeDeviceInfo("id", "name"),
base::BindOnce(&SharingWebRtcConnectionHostTest::ConnectionClosed,
base::Unretained(this)),
mock_service_.delegate.BindNewPipeAndPassReceiver(),
mock_service_.connection.BindNewPipeAndPassRemote(),
mock_service_.socket_manager_client.BindNewPipeAndPassReceiver(),
mock_service_.socket_manager.BindNewPipeAndPassRemote());
}
MOCK_METHOD1(ConnectionClosed, void(const std::string&));
void ExpectOnMessage(MockSharingMessageHandler* handler) {
EXPECT_CALL(*handler, OnMessage(testing::_, testing::_))
.WillOnce(testing::Invoke(
[&](const chrome_browser_sharing::SharingMessage& message,
SharingMessageHandler::DoneCallback done_callback) {
std::move(done_callback).Run(/*response=*/nullptr);
}));
}
void ExpectSendMessage() {
EXPECT_CALL(mock_service_, SendMessage(testing::_, testing::_))
.WillOnce(testing::Invoke(
[&](const std::vector<uint8_t>& data,
sharing::mojom::SharingWebRtcConnection::SendMessageCallback
callback) {
std::move(callback).Run(
sharing::mojom::SendMessageResult::kSuccess);
}));
}
protected:
content::BrowserTaskEnvironment task_environment_;
MockSharingMessageHandler message_handler_;
MockSharingMessageHandler ack_message_handler_;
MockSharingMojoService mock_service_;
FakeSharingHandlerRegistry handler_registry_;
MockSignallingHost* signalling_host_;
std::unique_ptr<SharingWebRtcConnectionHost> host_;
};
TEST_F(SharingWebRtcConnectionHostTest, OnMessageReceived) {
EXPECT_TRUE(mock_service_.delegate.is_connected());
// Expect the message handler to be called.
ExpectOnMessage(&message_handler_);
// Expect that an Ack message is sent after the message handler is done.
ExpectSendMessage();
// Expect that sending the Ack message closes the connection.
base::RunLoop run_loop;
mock_service_.delegate.set_disconnect_handler(run_loop.QuitClosure());
host_->OnMessageReceived(SerializeMessage(CreateMessage()));
run_loop.Run();
EXPECT_FALSE(mock_service_.delegate.is_connected());
}
TEST_F(SharingWebRtcConnectionHostTest, OnAckMessageReceived) {
EXPECT_TRUE(mock_service_.delegate.is_connected());
// Expect the Ack message handler to be called.
ExpectOnMessage(&ack_message_handler_);
// Expect that handling the Ack message closes the connection.
base::RunLoop run_loop;
mock_service_.delegate.set_disconnect_handler(run_loop.QuitClosure());
host_->OnMessageReceived(SerializeMessage(CreateAckMessage()));
run_loop.Run();
EXPECT_FALSE(mock_service_.delegate.is_connected());
}
TEST_F(SharingWebRtcConnectionHostTest, SendMessage) {
// Expect the message to be sent to the service.
ExpectSendMessage();
base::RunLoop run_loop;
host_->SendMessage(
CreateMessage(),
base::BindLambdaForTesting([&](sharing::mojom::SendMessageResult result) {
EXPECT_EQ(sharing::mojom::SendMessageResult::kSuccess, result);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(SharingWebRtcConnectionHostTest, OnOfferReceived) {
EXPECT_CALL(*signalling_host_, OnOfferReceived("offer", testing::_))
.WillOnce(testing::Invoke(
[&](const std::string& offer,
base::OnceCallback<void(const std::string&)> callback) {
EXPECT_EQ("offer", offer);
std::move(callback).Run("answer");
}));
base::RunLoop run_loop;
host_->OnOfferReceived(
"offer", base::BindLambdaForTesting([&](const std::string& answer) {
EXPECT_EQ("answer", answer);
run_loop.Quit();
}));
run_loop.Run();
}
TEST_F(SharingWebRtcConnectionHostTest, OnIceCandidatesReceived) {
base::RunLoop run_loop;
EXPECT_CALL(*signalling_host_, OnIceCandidatesReceived(testing::_))
.WillOnce(testing::Invoke(
[&](std::vector<sharing::mojom::IceCandidatePtr> ice_candidates) {
EXPECT_EQ(1u, ice_candidates.size());
run_loop.Quit();
}));
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates;
ice_candidates.push_back(sharing::mojom::IceCandidate::New());
host_->OnIceCandidatesReceived(std::move(ice_candidates));
run_loop.Run();
}
TEST_F(SharingWebRtcConnectionHostTest, ConnectionClosed) {
base::RunLoop run_loop;
EXPECT_CALL(*this, ConnectionClosed(testing::_))
.WillOnce(testing::Invoke(
[&](const std::string& device_guid) { run_loop.Quit(); }));
// Expect the connection to force close if the network service connection is
// lost. This also happens if the Sharing service closes the connection.
mock_service_.socket_manager.reset();
run_loop.Run();
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/webrtc/webrtc_message_handler.h"
#include <memory>
#include <utility>
#include "chrome/browser/sharing/webrtc/sharing_service_host.h"
namespace {
std::vector<sharing::mojom::IceCandidatePtr> GetIceCandidates(
const chrome_browser_sharing::PeerConnectionIceCandidatesMessage& message) {
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates;
for (const auto& candidate : message.ice_candidates()) {
ice_candidates.push_back(sharing::mojom::IceCandidate::New(
candidate.candidate(), candidate.sdp_mid(),
candidate.sdp_mline_index()));
}
return ice_candidates;
}
} // namespace
WebRtcMessageHandler::WebRtcMessageHandler(
SharingServiceHost* sharing_service_host)
: sharing_service_host_(sharing_service_host) {
DCHECK(sharing_service_host_);
}
WebRtcMessageHandler::~WebRtcMessageHandler() = default;
void WebRtcMessageHandler::OnMessage(
chrome_browser_sharing::SharingMessage message,
SharingMessageHandler::DoneCallback done_callback) {
// Do not accept the message if we did not get a valid target info.
if (!message.has_fcm_channel_configuration()) {
// TODO(crbug.com/1021984): replace this with UMA metrics
LOG(ERROR) << "Discarding message without fcm channel info";
return;
}
const chrome_browser_sharing::FCMChannelConfiguration&
fcm_channel_configuration = message.fcm_channel_configuration();
syncer::DeviceInfo::SharingTargetInfo target_info{
fcm_channel_configuration.vapid_fcm_token(),
fcm_channel_configuration.vapid_p256dh(),
fcm_channel_configuration.vapid_auth_secret()};
if (message.has_peer_connection_offer_message()) {
HandleOfferMessage(message.sender_guid(), target_info,
message.peer_connection_offer_message(),
std::move(done_callback));
return;
}
if (message.has_peer_connection_ice_candidates_message()) {
HandleIceCandidatesMessage(message.sender_guid(), target_info,
message.peer_connection_ice_candidates_message(),
std::move(done_callback));
return;
}
NOTREACHED();
}
void WebRtcMessageHandler::HandleOfferMessage(
const std::string& sender_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
const chrome_browser_sharing::PeerConnectionOfferMessage& message,
SharingMessageHandler::DoneCallback done_callback) {
sharing_service_host_->OnOfferReceived(
sender_guid, target_info, message.sdp(),
base::BindOnce(&ReplyWithAnswer, std::move(done_callback)));
}
// This is called from the sandboxed process with the received answer.
void WebRtcMessageHandler::ReplyWithAnswer(
SharingMessageHandler::DoneCallback done_callback,
const std::string& answer) {
auto response = std::make_unique<chrome_browser_sharing::ResponseMessage>();
response->mutable_peer_connection_answer_message_response()->set_sdp(answer);
std::move(done_callback).Run(std::move(response));
}
void WebRtcMessageHandler::HandleIceCandidatesMessage(
const std::string& sender_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
const chrome_browser_sharing::PeerConnectionIceCandidatesMessage& message,
SharingMessageHandler::DoneCallback done_callback) {
sharing_service_host_->OnIceCandidatesReceived(sender_guid, target_info,
GetIceCandidates(message));
std::move(done_callback).Run(/*response=*/nullptr);
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SHARING_WEBRTC_WEBRTC_MESSAGE_HANDLER_H_
#define CHROME_BROWSER_SHARING_WEBRTC_WEBRTC_MESSAGE_HANDLER_H_
#include <string>
#include "chrome/browser/sharing/proto/peer_connection_messages.pb.h"
#include "chrome/browser/sharing/proto/sharing_message.pb.h"
#include "chrome/browser/sharing/sharing_message_handler.h"
#include "components/sync_device_info/device_info.h"
class SharingServiceHost;
// Handles WebRTC specific Sharing messages received via FCM that implement the
// signalling part of the WebRTC communication between two browser instances.
// Relays incoming messages to the |sharing_service_host|.
// This object is owned by the SharingHandlerRegistryImpl which is owned by the
// SharingService KeyedService.
class WebRtcMessageHandler : public SharingMessageHandler {
public:
explicit WebRtcMessageHandler(SharingServiceHost* sharing_service_host);
WebRtcMessageHandler(const WebRtcMessageHandler&) = delete;
WebRtcMessageHandler& operator=(const WebRtcMessageHandler&) = delete;
~WebRtcMessageHandler() override;
// SharingMessageHandler implementation:
void OnMessage(chrome_browser_sharing::SharingMessage message,
SharingMessageHandler::DoneCallback done_callback) override;
private:
void HandleOfferMessage(
const std::string& sender_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
const chrome_browser_sharing::PeerConnectionOfferMessage& message,
SharingMessageHandler::DoneCallback done_callback);
static void ReplyWithAnswer(SharingMessageHandler::DoneCallback done_callback,
const std::string& answer);
void HandleIceCandidatesMessage(
const std::string& sender_guid,
const syncer::DeviceInfo::SharingTargetInfo& target_info,
const chrome_browser_sharing::PeerConnectionIceCandidatesMessage& message,
SharingMessageHandler::DoneCallback done_callback);
// Owned by the SharingService KeyedService and must outlive |this|.
SharingServiceHost* sharing_service_host_;
};
#endif // CHROME_BROWSER_SHARING_WEBRTC_WEBRTC_MESSAGE_HANDLER_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/webrtc/webrtc_signalling_host_fcm.h"
#include <memory>
#include "base/callback.h"
#include "base/time/time.h"
#include "chrome/browser/sharing/features.h"
#include "chrome/browser/sharing/sharing_metrics.h"
WebRtcSignallingHostFCM::WebRtcSignallingHostFCM(
mojo::PendingReceiver<sharing::mojom::SignallingSender> signalling_sender,
mojo::PendingRemote<sharing::mojom::SignallingReceiver> signalling_receiver,
SharingMessageSender* message_sender,
std::unique_ptr<syncer::DeviceInfo> device_info)
: message_sender_(message_sender),
device_info_(std::move(device_info)),
signalling_sender_(this, std::move(signalling_sender)),
signalling_receiver_(std::move(signalling_receiver)) {
DCHECK(device_info_);
}
WebRtcSignallingHostFCM::~WebRtcSignallingHostFCM() = default;
void WebRtcSignallingHostFCM::SendOffer(const std::string& offer,
SendOfferCallback callback) {
chrome_browser_sharing::SharingMessage sharing_message;
sharing_message.mutable_peer_connection_offer_message()->set_sdp(offer);
message_sender_->SendMessageToDevice(
*device_info_,
base::TimeDelta::FromSeconds(kSharingMessageTTLSeconds.Get()),
std::move(sharing_message), SharingMessageSender::DelegateType::kFCM,
base::BindOnce(&WebRtcSignallingHostFCM::OnOfferSent,
weak_ptr_factory_.GetWeakPtr(), std::move(callback)));
}
void WebRtcSignallingHostFCM::OnOfferSent(
SendOfferCallback callback,
SharingSendMessageResult result,
std::unique_ptr<chrome_browser_sharing::ResponseMessage> response) {
if (result != SharingSendMessageResult::kSuccessful || !response ||
!response->has_peer_connection_answer_message_response()) {
std::move(callback).Run(std::string());
return;
}
std::move(callback).Run(
response->peer_connection_answer_message_response().sdp());
}
void WebRtcSignallingHostFCM::SendIceCandidates(
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates) {
if (ice_candidates.empty())
return;
chrome_browser_sharing::SharingMessage sharing_message;
auto* mutable_ice_candidates =
sharing_message.mutable_peer_connection_ice_candidates_message()
->mutable_ice_candidates();
for (const auto& ice_candidate : ice_candidates) {
chrome_browser_sharing::PeerConnectionIceCandidate ice_candidate_entry;
ice_candidate_entry.set_candidate(ice_candidate->candidate);
ice_candidate_entry.set_sdp_mid(ice_candidate->sdp_mid);
ice_candidate_entry.set_sdp_mline_index(ice_candidate->sdp_mline_index);
mutable_ice_candidates->Add(std::move(ice_candidate_entry));
}
message_sender_->SendMessageToDevice(
*device_info_,
base::TimeDelta::FromSeconds(kSharingMessageTTLSeconds.Get()),
std::move(sharing_message), SharingMessageSender::DelegateType::kFCM,
base::BindOnce([](SharingSendMessageResult result,
std::unique_ptr<chrome_browser_sharing::ResponseMessage>
response) {
if (result != SharingSendMessageResult::kSuccessful) {
// TODO(crbug.com/1021984): replace this with UMA metrics
LOG(ERROR) << "Error sending Ice Candidate";
return;
}
}));
}
void WebRtcSignallingHostFCM::OnOfferReceived(
const std::string& offer,
base::OnceCallback<void(const std::string&)> callback) {
signalling_receiver_->OnOfferReceived(offer, std::move(callback));
}
void WebRtcSignallingHostFCM::OnIceCandidatesReceived(
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates) {
signalling_receiver_->OnIceCandidatesReceived(std::move(ice_candidates));
}
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SHARING_WEBRTC_WEBRTC_SIGNALLING_HOST_FCM_H_
#define CHROME_BROWSER_SHARING_WEBRTC_WEBRTC_SIGNALLING_HOST_FCM_H_
#include <memory>
#include <string>
#include <vector>
#include "base/callback_forward.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/sharing/sharing_message_sender.h"
#include "chrome/services/sharing/public/mojom/webrtc.mojom.h"
#include "components/sync_device_info/device_info.h"
#include "mojo/public/cpp/bindings/pending_receiver.h"
#include "mojo/public/cpp/bindings/pending_remote.h"
#include "mojo/public/cpp/bindings/receiver.h"
#include "mojo/public/cpp/bindings/remote.h"
// Handles the signalling part of a WebRTC connection via FCM. The signalling
// messages are sent via the |message_sender| to |device_info| through FCM.
class WebRtcSignallingHostFCM : public sharing::mojom::SignallingSender {
public:
WebRtcSignallingHostFCM(
mojo::PendingReceiver<sharing::mojom::SignallingSender> signalling_sender,
mojo::PendingRemote<sharing::mojom::SignallingReceiver>
signalling_receiver,
SharingMessageSender* message_sender,
std::unique_ptr<syncer::DeviceInfo> device_info);
WebRtcSignallingHostFCM(const WebRtcSignallingHostFCM&) = delete;
WebRtcSignallingHostFCM& operator=(const WebRtcSignallingHostFCM&) = delete;
~WebRtcSignallingHostFCM() override;
// sharing::mojom::SignallingSender:
void SendOffer(const std::string& offer, SendOfferCallback callback) override;
void SendIceCandidates(
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates) override;
virtual void OnOfferReceived(
const std::string& offer,
base::OnceCallback<void(const std::string&)> callback);
virtual void OnIceCandidatesReceived(
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates);
private:
void OnOfferSent(
SendOfferCallback callback,
SharingSendMessageResult result,
std::unique_ptr<chrome_browser_sharing::ResponseMessage> response);
SharingMessageSender* message_sender_;
std::unique_ptr<syncer::DeviceInfo> device_info_;
mojo::Receiver<sharing::mojom::SignallingSender> signalling_sender_;
mojo::Remote<sharing::mojom::SignallingReceiver> signalling_receiver_;
base::WeakPtrFactory<WebRtcSignallingHostFCM> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_SHARING_WEBRTC_WEBRTC_SIGNALLING_HOST_FCM_H_
// Copyright 2020 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/sharing/webrtc/webrtc_signalling_host_fcm.h"
#include "base/test/bind_test_util.h"
#include "chrome/browser/sharing/fake_device_info.h"
#include "chrome/browser/sharing/proto/sharing_message.pb.h"
#include "chrome/browser/sharing/sharing_message_sender.h"
#include "chrome/browser/sharing/sharing_send_message_result.h"
#include "chrome/services/sharing/public/mojom/webrtc.mojom.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace {
class MockSharingMessageSender : public SharingMessageSender {
public:
MockSharingMessageSender()
: SharingMessageSender(
/*sync_prefs=*/nullptr,
/*local_device_info_provider=*/nullptr) {}
MockSharingMessageSender(const MockSharingMessageSender&) = delete;
MockSharingMessageSender& operator=(const MockSharingMessageSender&) = delete;
~MockSharingMessageSender() override = default;
MOCK_METHOD5(SendMessageToDevice,
void(const syncer::DeviceInfo&,
base::TimeDelta,
chrome_browser_sharing::SharingMessage,
DelegateType,
ResponseCallback));
};
class MockSignallingService : public sharing::mojom::SignallingReceiver {
public:
MockSignallingService() = default;
MockSignallingService(const MockSignallingService&) = delete;
MockSignallingService& operator=(const MockSignallingService&) = delete;
~MockSignallingService() override = default;
// sharing::mojom::SignallingReceiver:
MOCK_METHOD2(OnOfferReceived,
void(const std::string&, OnOfferReceivedCallback));
MOCK_METHOD1(OnIceCandidatesReceived,
void(std::vector<sharing::mojom::IceCandidatePtr>));
mojo::Remote<sharing::mojom::SignallingSender> signalling_sender;
mojo::Receiver<sharing::mojom::SignallingReceiver> signalling_receiver{this};
};
class WebRtcSignallingHostFCMTest : public testing::Test {
public:
WebRtcSignallingHostFCMTest() = default;
void RespondWith(
SharingSendMessageResult result,
std::unique_ptr<chrome_browser_sharing::ResponseMessage> response) {
next_result_ = result;
next_response_ = std::move(response);
EXPECT_CALL(message_sender_,
SendMessageToDevice(testing::_, testing::_, testing::_,
SharingMessageSender::DelegateType::kFCM,
testing::_))
.WillOnce(testing::Invoke(
[&](const syncer::DeviceInfo& device_info,
base::TimeDelta response_timeout,
chrome_browser_sharing::SharingMessage message,
SharingMessageSender::DelegateType delegate_type,
SharingMessageSender::ResponseCallback callback) {
std::move(callback).Run(next_result_, std::move(next_response_));
}));
}
std::string SendOfferSync(const std::string& offer) {
std::string result;
base::RunLoop run_loop;
signalling_host_.SendOffer(
offer, base::BindLambdaForTesting([&](const std::string& response) {
result = response;
run_loop.Quit();
}));
run_loop.Run();
return result;
}
protected:
content::BrowserTaskEnvironment task_environment_;
MockSharingMessageSender message_sender_;
MockSignallingService signalling_service_;
WebRtcSignallingHostFCM signalling_host_{
signalling_service_.signalling_sender.BindNewPipeAndPassReceiver(),
signalling_service_.signalling_receiver.BindNewPipeAndPassRemote(),
&message_sender_, CreateFakeDeviceInfo("id", "name")};
private:
SharingSendMessageResult next_result_;
std::unique_ptr<chrome_browser_sharing::ResponseMessage> next_response_;
};
} // namespace
TEST_F(WebRtcSignallingHostFCMTest, SendOffer_Success) {
auto answer = std::make_unique<chrome_browser_sharing::ResponseMessage>();
answer->mutable_peer_connection_answer_message_response()->set_sdp("answer");
RespondWith(SharingSendMessageResult::kSuccessful, std::move(answer));
EXPECT_EQ("answer", SendOfferSync("offer"));
}
TEST_F(WebRtcSignallingHostFCMTest, SendOffer_NoAnswer) {
auto answer = std::make_unique<chrome_browser_sharing::ResponseMessage>();
RespondWith(SharingSendMessageResult::kSuccessful, std::move(answer));
EXPECT_EQ("", SendOfferSync("offer"));
}
TEST_F(WebRtcSignallingHostFCMTest, SendOffer_NoResponse) {
RespondWith(SharingSendMessageResult::kSuccessful, nullptr);
EXPECT_EQ("", SendOfferSync("offer"));
}
TEST_F(WebRtcSignallingHostFCMTest, SendIceCandidates_Empty) {
EXPECT_CALL(
message_sender_,
SendMessageToDevice(testing::_, testing::_, testing::_,
SharingMessageSender::DelegateType::kFCM, testing::_))
.Times(0);
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates;
signalling_host_.SendIceCandidates(std::move(ice_candidates));
}
TEST_F(WebRtcSignallingHostFCMTest, SendIceCandidates_Success) {
chrome_browser_sharing::PeerConnectionIceCandidate ice_candidate;
ice_candidate.set_candidate("candidate");
ice_candidate.set_sdp_mid("sdp_mid");
ice_candidate.set_sdp_mline_index(3);
base::RunLoop run_loop;
chrome_browser_sharing::SharingMessage sent_message;
EXPECT_CALL(
message_sender_,
SendMessageToDevice(testing::_, testing::_, testing::_,
SharingMessageSender::DelegateType::kFCM, testing::_))
.WillOnce(
testing::Invoke([&](const syncer::DeviceInfo& device_info,
base::TimeDelta response_timeout,
chrome_browser_sharing::SharingMessage message,
SharingMessageSender::DelegateType delegate_type,
SharingMessageSender::ResponseCallback callback) {
sent_message = std::move(message);
std::move(callback).Run(SharingSendMessageResult::kSuccessful,
nullptr);
run_loop.Quit();
}));
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates;
ice_candidates.push_back(sharing::mojom::IceCandidate::New(
ice_candidate.candidate(), ice_candidate.sdp_mid(),
ice_candidate.sdp_mline_index()));
signalling_host_.SendIceCandidates(std::move(ice_candidates));
run_loop.Run();
ASSERT_TRUE(sent_message.has_peer_connection_ice_candidates_message());
const auto& ice_message =
sent_message.peer_connection_ice_candidates_message();
ASSERT_EQ(1, ice_message.ice_candidates_size());
const auto& ice_candidate_sent = ice_message.ice_candidates(0);
EXPECT_EQ(ice_candidate.candidate(), ice_candidate_sent.candidate());
EXPECT_EQ(ice_candidate.sdp_mid(), ice_candidate_sent.sdp_mid());
EXPECT_EQ(ice_candidate.sdp_mline_index(),
ice_candidate_sent.sdp_mline_index());
}
TEST_F(WebRtcSignallingHostFCMTest, OnOfferReceived) {
EXPECT_CALL(signalling_service_, OnOfferReceived("offer", testing::_))
.WillOnce(testing::Invoke(
[&](const std::string& offer,
base::OnceCallback<void(const std::string&)> callback) {
EXPECT_EQ("offer", offer);
std::move(callback).Run("answer");
}));
base::RunLoop run_loop;
auto callback = base::BindLambdaForTesting([&](const std::string& answer) {
EXPECT_EQ("answer", answer);
run_loop.Quit();
});
signalling_host_.OnOfferReceived("offer", std::move(callback));
run_loop.Run();
}
TEST_F(WebRtcSignallingHostFCMTest, OnIceCandidatesReceived) {
base::RunLoop run_loop;
EXPECT_CALL(signalling_service_, OnIceCandidatesReceived(testing::_))
.WillOnce(testing::Invoke(
[&](std::vector<sharing::mojom::IceCandidatePtr> ice_candidates) {
EXPECT_EQ(1u, ice_candidates.size());
run_loop.Quit();
}));
std::vector<sharing::mojom::IceCandidatePtr> ice_candidates;
ice_candidates.push_back(sharing::mojom::IceCandidate::New());
signalling_host_.OnIceCandidatesReceived(std::move(ice_candidates));
run_loop.Run();
}
...@@ -3351,6 +3351,10 @@ test("unit_tests") { ...@@ -3351,6 +3351,10 @@ test("unit_tests") {
"../browser/sessions/restore_on_startup_policy_handler_unittest.cc", "../browser/sessions/restore_on_startup_policy_handler_unittest.cc",
"../browser/sessions/session_common_utils_unittest.cc", "../browser/sessions/session_common_utils_unittest.cc",
"../browser/sharing/ack_message_handler_unittest.cc", "../browser/sharing/ack_message_handler_unittest.cc",
"../browser/sharing/fake_device_info.cc",
"../browser/sharing/fake_device_info.h",
"../browser/sharing/fake_sharing_handler_registry.cc",
"../browser/sharing/fake_sharing_handler_registry.h",
"../browser/sharing/mock_sharing_service.cc", "../browser/sharing/mock_sharing_service.cc",
"../browser/sharing/mock_sharing_service.h", "../browser/sharing/mock_sharing_service.h",
"../browser/sharing/sharing_device_registration_unittest.cc", "../browser/sharing/sharing_device_registration_unittest.cc",
...@@ -3521,6 +3525,8 @@ test("unit_tests") { ...@@ -3521,6 +3525,8 @@ test("unit_tests") {
if (!is_android) { if (!is_android) {
sources += [ sources += [
"../browser/profiles/profile_avatar_icon_util_unittest.cc", "../browser/profiles/profile_avatar_icon_util_unittest.cc",
"../browser/sharing/webrtc/sharing_webrtc_connection_host_unittest.cc",
"../browser/sharing/webrtc/webrtc_signalling_host_fcm_unittest.cc",
"../browser/storage/storage_notification_service_unittest.cc", "../browser/storage/storage_notification_service_unittest.cc",
"../browser/tab_contents/form_interaction_tab_helper_unittest.cc", "../browser/tab_contents/form_interaction_tab_helper_unittest.cc",
"../browser/ui/autofill/payments/autofill_dialog_models_unittest.cc", "../browser/ui/autofill/payments/autofill_dialog_models_unittest.cc",
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment