Merge pull request #26 from hai007/cl-345608764

Roll forward to Cl/345608764
This commit is contained in:
hai007
2020-12-03 22:54:40 -08:00
committed by GitHub
22 changed files with 511 additions and 252 deletions
+1 -1
View File
@@ -21,7 +21,7 @@ cc_library(
"core.h", "core.h",
], ],
visibility = [ visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections:__subpackages__", "//googlemac/iPhone/Shared/Nearby/Connections_v2:__subpackages__",
], ],
deps = [ deps = [
":core_types", ":core_types",
@@ -259,6 +259,11 @@ std::string BaseEndpointChannel::GetType() const {
std::string BaseEndpointChannel::GetName() const { return channel_name_; } std::string BaseEndpointChannel::GetName() const { return channel_name_; }
int BaseEndpointChannel::GetMaxTransmitPacketSize() const {
// Return default value if the medium never define it's chunk size.
return kDefaultMaxTransmitPacketSize;
}
void BaseEndpointChannel::EnableEncryption( void BaseEndpointChannel::EnableEncryption(
std::shared_ptr<EncryptionContext> context) { std::shared_ptr<EncryptionContext> context) {
MutexLock crypto_lock(&crypto_mutex_); MutexLock crypto_lock(&crypto_mutex_);
@@ -62,6 +62,10 @@ class BaseEndpointChannel : public EndpointChannel {
// Returns the name of the EndpointChannel. // Returns the name of the EndpointChannel.
std::string GetName() const override; std::string GetName() const override;
// Returns the maximum supported transmit packet size(MTU) for the underlying
// transport.
int GetMaxTransmitPacketSize() const override;
// Enables encryption on the EndpointChannel. // Enables encryption on the EndpointChannel.
// Should be called after connection is accepted by both parties, and // Should be called after connection is accepted by both parties, and
// before entering data phase, where Payloads may be exchanged. // before entering data phase, where Payloads may be exchanged.
@@ -92,6 +96,9 @@ class BaseEndpointChannel : public EndpointChannel {
// Used to sanity check that our frame sizes are reasonable. // Used to sanity check that our frame sizes are reasonable.
static constexpr std::int32_t kMaxAllowedReadBytes = 1048576; // 1MB static constexpr std::int32_t kMaxAllowedReadBytes = 1048576; // 1MB
// The default maximum transmit unit/packet size.
static constexpr int kDefaultMaxTransmitPacketSize = 65536; // 64 KB
bool IsEncryptionEnabledLocked() const bool IsEncryptionEnabledLocked() const
ABSL_EXCLUSIVE_LOCKS_REQUIRED(crypto_mutex_); ABSL_EXCLUSIVE_LOCKS_REQUIRED(crypto_mutex_);
void UnblockPausedWriter() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_); void UnblockPausedWriter() ABSL_EXCLUSIVE_LOCKS_REQUIRED(is_paused_mutex_);
@@ -47,6 +47,10 @@ proto::connections::Medium BleEndpointChannel::GetMedium() const {
return proto::connections::Medium::BLE; return proto::connections::Medium::BLE;
} }
int BleEndpointChannel::GetMaxTransmitPacketSize() const {
return kDefaultBleMaxTransmitPacketSize;
}
void BleEndpointChannel::CloseImpl() { void BleEndpointChannel::CloseImpl() {
auto status = ble_socket_.Close(); auto status = ble_socket_.Close();
if (!status.Ok()) { if (!status.Ok()) {
+4
View File
@@ -30,7 +30,11 @@ class BleEndpointChannel final : public BaseEndpointChannel {
proto::connections::Medium GetMedium() const override; proto::connections::Medium GetMedium() const override;
int GetMaxTransmitPacketSize() const override;
private: private:
static constexpr int kDefaultBleMaxTransmitPacketSize = 512; // 512 bytes
void CloseImpl() override; void CloseImpl() override;
BleSocket ble_socket_; BleSocket ble_socket_;
@@ -47,6 +47,10 @@ proto::connections::Medium BluetoothEndpointChannel::GetMedium() const {
return proto::connections::Medium::BLUETOOTH; return proto::connections::Medium::BLUETOOTH;
} }
int BluetoothEndpointChannel::GetMaxTransmitPacketSize() const {
return kDefaultBTMaxTransmitPacketSize;
}
void BluetoothEndpointChannel::CloseImpl() { void BluetoothEndpointChannel::CloseImpl() {
auto status = bluetooth_socket_.Close(); auto status = bluetooth_socket_.Close();
if (!status.Ok()) { if (!status.Ok()) {
@@ -33,7 +33,11 @@ class BluetoothEndpointChannel final : public BaseEndpointChannel {
proto::connections::Medium GetMedium() const override; proto::connections::Medium GetMedium() const override;
int GetMaxTransmitPacketSize() const override;
private: private:
static constexpr int kDefaultBTMaxTransmitPacketSize = 1980; // 990 * 2 Bytes
void CloseImpl() override; void CloseImpl() override;
BluetoothSocket bluetooth_socket_; BluetoothSocket bluetooth_socket_;
@@ -54,6 +54,7 @@ class FakeEndpointChannel : public EndpointChannel {
std::string GetType() const override { return "fake-channel-type"; } std::string GetType() const override { return "fake-channel-type"; }
std::string GetName() const override { return "fake-channel"; } std::string GetName() const override { return "fake-channel"; }
Medium GetMedium() const override { return Medium::BLE; } Medium GetMedium() const override { return Medium::BLE; }
int GetMaxTransmitPacketSize() const override { return 512; }
void EnableEncryption(std::shared_ptr<EncryptionContext> context) override {} void EnableEncryption(std::shared_ptr<EncryptionContext> context) override {}
void DisableEncryption() override {} void DisableEncryption() override {}
bool IsPaused() const override { return false; } bool IsPaused() const override { return false; }
+4
View File
@@ -56,6 +56,10 @@ class EndpointChannel {
// Returns the analytics enum representing the medium of this EndpointChannel. // Returns the analytics enum representing the medium of this EndpointChannel.
virtual proto::connections::Medium GetMedium() const = 0; virtual proto::connections::Medium GetMedium() const = 0;
// Returns the maximum supported transmit packet size(MTU) for the underlying
// transport.
virtual int GetMaxTransmitPacketSize() const = 0;
// Enables encryption on the EndpointChannel. // Enables encryption on the EndpointChannel.
virtual void EnableEncryption(std::shared_ptr<EncryptionContext> context) = 0; virtual void EnableEncryption(std::shared_ptr<EncryptionContext> context) = 0;
+20 -10
View File
@@ -417,16 +417,14 @@ void EndpointManager::UnregisterEndpoint(ClientProxy* client,
latch.Await(); latch.Await();
} }
// Designed to run asynchronously. It is called from IO thread pools, and int EndpointManager::GetMaxTransmitPacketSize(const std::string& endpoint_id) {
// jobs in these pools may be waited for from the EndpointManager thread. If we std::shared_ptr<EndpointChannel> channel =
// allow synchronous behavior here it will cause a live lock. channel_manager_->GetChannelForEndpoint(endpoint_id);
void EndpointManager::DiscardEndpoint(ClientProxy* client, if (channel == nullptr) {
const std::string& endpoint_id) { return 0;
RunOnEndpointManagerThread([this, client, endpoint_id]() { }
RemoveEndpoint(client, endpoint_id,
/*notify=*/ return channel->GetMaxTransmitPacketSize();
client->IsConnectedToEndpoint(endpoint_id));
});
} }
std::vector<std::string> EndpointManager::SendPayloadChunk( std::vector<std::string> EndpointManager::SendPayloadChunk(
@@ -441,6 +439,18 @@ std::vector<std::string> EndpointManager::SendPayloadChunk(
/*packet_type=*/"DATA"); /*packet_type=*/"DATA");
} }
// Designed to run asynchronously. It is called from IO thread pools, and
// jobs in these pools may be waited for from the EndpointManager thread. If we
// allow synchronous behavior here it will cause a live lock.
void EndpointManager::DiscardEndpoint(ClientProxy* client,
const std::string& endpoint_id) {
RunOnEndpointManagerThread([this, client, endpoint_id]() {
RemoveEndpoint(client, endpoint_id,
/*notify=*/
client->IsConnectedToEndpoint(endpoint_id));
});
}
std::vector<std::string> EndpointManager::SendControlMessage( std::vector<std::string> EndpointManager::SendControlMessage(
const PayloadTransferFrame::PayloadHeader& header, const PayloadTransferFrame::PayloadHeader& header,
const PayloadTransferFrame::ControlMessage& control, const PayloadTransferFrame::ControlMessage& control,
+4
View File
@@ -112,6 +112,10 @@ class EndpointManager {
// this case, we do not notify the client of onDisconnected(). // this case, we do not notify the client of onDisconnected().
void UnregisterEndpoint(ClientProxy* client, const std::string& endpoint_id); void UnregisterEndpoint(ClientProxy* client, const std::string& endpoint_id);
// Returns the maximum supported transmit packet size(MTU) for the underlying
// transport.
int GetMaxTransmitPacketSize(const std::string& endpoint_id);
// Returns the list of endpoints to which sending this chunk failed. // Returns the list of endpoints to which sending this chunk failed.
// //
// Invoked from the PayloadManager's sendPayload() method. // Invoked from the PayloadManager's sendPayload() method.
@@ -54,6 +54,7 @@ class MockEndpointChannel : public EndpointChannel {
MOCK_METHOD(std::string, GetType, (), (const override)); MOCK_METHOD(std::string, GetType, (), (const override));
MOCK_METHOD(std::string, GetName, (), (const override)); MOCK_METHOD(std::string, GetName, (), (const override));
MOCK_METHOD(Medium, GetMedium, (), (const override)); MOCK_METHOD(Medium, GetMedium, (), (const override));
MOCK_METHOD(int, GetMaxTransmitPacketSize, (), (const override));
MOCK_METHOD(void, EnableEncryption, MOCK_METHOD(void, EnableEncryption,
(std::shared_ptr<EncryptionContext> context), (override)); (std::shared_ptr<EncryptionContext> context), (override));
MOCK_METHOD(void, DisableEncryption, (), (override)); MOCK_METHOD(void, DisableEncryption, (), (override));
+3 -1
View File
@@ -63,8 +63,10 @@ class InternalPayload {
// byte blobs for sending across a hard boundary (like the other side of // byte blobs for sending across a hard boundary (like the other side of
// a Binder, or another device altogether). // a Binder, or another device altogether).
// //
// @param chunk_size The preferred size of the next chunk. Depending on
// payload type, the provided size may be ignored.
// @return The next chunk from the Payload, or null if we've reached the end. // @return The next chunk from the Payload, or null if we've reached the end.
virtual ByteArray DetachNextChunk() = 0; virtual ByteArray DetachNextChunk(int chunk_size) = 0;
// Adds the next chunk that comprises the Payload to which this object is // Adds the next chunk that comprises the Payload to which this object is
// bound. // bound.
+10 -13
View File
@@ -22,6 +22,7 @@
#include "platform/base/exception.h" #include "platform/base/exception.h"
#include "platform/public/condition_variable.h" #include "platform/public/condition_variable.h"
#include "platform/public/file.h" #include "platform/public/file.h"
#include "platform/public/logging.h"
#include "platform/public/mutex.h" #include "platform/public/mutex.h"
#include "platform/public/pipe.h" #include "platform/public/pipe.h"
#include "absl/memory/memory.h" #include "absl/memory/memory.h"
@@ -47,7 +48,7 @@ class BytesInternalPayload : public InternalPayload {
// Relinquishes ownership of the payload_; retrieves and returns the stored // Relinquishes ownership of the payload_; retrieves and returns the stored
// ByteArray. // ByteArray.
ByteArray DetachNextChunk() override { ByteArray DetachNextChunk(int chunk_size) override {
if (detached_only_chunk_) { if (detached_only_chunk_) {
return {}; return {};
} }
@@ -80,11 +81,11 @@ class OutgoingStreamInternalPayload : public InternalPayload {
std::int64_t GetTotalSize() const override { return -1; } std::int64_t GetTotalSize() const override { return -1; }
ByteArray DetachNextChunk() override { ByteArray DetachNextChunk(int chunk_size) override {
InputStream* input_stream = payload_.AsStream(); InputStream* input_stream = payload_.AsStream();
if (!input_stream) return {}; if (!input_stream) return {};
ExceptionOr<ByteArray> bytes_read = input_stream->Read(kChunkSize); ExceptionOr<ByteArray> bytes_read = input_stream->Read(chunk_size);
if (!bytes_read.ok()) { if (!bytes_read.ok()) {
input_stream->Close(); input_stream->Close();
return {}; return {};
@@ -93,8 +94,8 @@ class OutgoingStreamInternalPayload : public InternalPayload {
ByteArray scoped_bytes_read = std::move(bytes_read.result()); ByteArray scoped_bytes_read = std::move(bytes_read.result());
if (scoped_bytes_read.Empty()) { if (scoped_bytes_read.Empty()) {
// TODO(reznor): logger.atVerbose().log("No more data for outgoing payload NEARBY_LOGS(INFO) << "No more data for outgoing payload " << this
// %s, closing InputStream.", this); << ", closing InputStream.";
input_stream->Close(); input_stream->Close();
return {}; return {};
@@ -113,9 +114,6 @@ class OutgoingStreamInternalPayload : public InternalPayload {
InputStream* stream = payload_.AsStream(); InputStream* stream = payload_.AsStream();
if (stream) stream->Close(); if (stream) stream->Close();
} }
private:
static constexpr std::int64_t kChunkSize = Pipe::kChunkSize;
}; };
class IncomingStreamInternalPayload : public InternalPayload { class IncomingStreamInternalPayload : public InternalPayload {
@@ -129,7 +127,7 @@ class IncomingStreamInternalPayload : public InternalPayload {
std::int64_t GetTotalSize() const override { return -1; } std::int64_t GetTotalSize() const override { return -1; }
ByteArray DetachNextChunk() override { return {}; } ByteArray DetachNextChunk(int chunk_size) override { return {}; }
Exception AttachNextChunk(const ByteArray& chunk) override { Exception AttachNextChunk(const ByteArray& chunk) override {
if (chunk.Empty()) { if (chunk.Empty()) {
@@ -158,11 +156,11 @@ class OutgoingFileInternalPayload : public InternalPayload {
std::int64_t GetTotalSize() const override { return total_size_; } std::int64_t GetTotalSize() const override { return total_size_; }
ByteArray DetachNextChunk() override { ByteArray DetachNextChunk(int chunk_size) override {
InputFile* file = payload_.AsFile(); InputFile* file = payload_.AsFile();
if (!file) return {}; if (!file) return {};
ExceptionOr<ByteArray> bytes_read = file->Read(kChunkSize); ExceptionOr<ByteArray> bytes_read = file->Read(chunk_size);
if (!bytes_read.ok()) { if (!bytes_read.ok()) {
return {}; return {};
} }
@@ -190,7 +188,6 @@ class OutgoingFileInternalPayload : public InternalPayload {
private: private:
std::int64_t total_size_; std::int64_t total_size_;
static constexpr std::int64_t kChunkSize = 64 * 1024;
}; };
class IncomingFileInternalPayload : public InternalPayload { class IncomingFileInternalPayload : public InternalPayload {
@@ -207,7 +204,7 @@ class IncomingFileInternalPayload : public InternalPayload {
std::int64_t GetTotalSize() const override { return total_size_; } std::int64_t GetTotalSize() const override { return total_size_; }
ByteArray DetachNextChunk() override { return {}; } ByteArray DetachNextChunk(int chunk_size) override { return {}; }
Exception AttachNextChunk(const ByteArray& chunk) override { Exception AttachNextChunk(const ByteArray& chunk) override {
if (chunk.Empty()) { if (chunk.Empty()) {
+339 -181
View File
@@ -26,6 +26,7 @@
#include "platform/public/logging.h" #include "platform/public/logging.h"
#include "platform/public/mutex_lock.h" #include "platform/public/mutex_lock.h"
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h" #include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
#include "absl/container/flat_hash_map.h"
#include "absl/strings/str_cat.h" #include "absl/strings/str_cat.h"
#include "absl/time/time.h" #include "absl/time/time.h"
#include "webrtc/api/jsep.h" #include "webrtc/api/jsep.h"
@@ -53,7 +54,23 @@ WebRtc::~WebRtc() {
restart_receive_messages_executor_.Shutdown(); restart_receive_messages_executor_.Shutdown();
single_thread_executor_.Shutdown(); single_thread_executor_.Shutdown();
Disconnect(); // Disconnect will also erase the connection info from map. Use a separate
// set to save the connection ids to avoid the iterator violation issue.
absl::flat_hash_set<std::string> connection_ids;
for (auto& item : accepting_map_) {
connection_ids.emplace(item.first);
}
for (const auto& connection_id : connection_ids) {
Disconnect(Role::kOfferer, connection_id);
}
connection_ids.clear();
for (auto& item : connecting_map_) {
connection_ids.emplace(item.first);
}
for (const auto& connection_id : connection_ids) {
Disconnect(Role::kAnswerer, connection_id);
}
connection_ids.clear();
} }
const std::string WebRtc::GetDefaultCountryCode() { const std::string WebRtc::GetDefaultCountryCode() {
@@ -64,8 +81,9 @@ bool WebRtc::IsAvailable() { return medium_.IsValid(); }
bool WebRtc::IsAcceptingConnections(const std::string& service_id) { bool WebRtc::IsAcceptingConnections(const std::string& service_id) {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
// TODO(hais): refractor the implementation with maps. ConnectionInfo* connection_info =
return role_ == Role::kOfferer; GetConnectionInfo(Role::kOfferer, service_id);
return connection_info && connection_info->self_id.IsValid();
} }
bool WebRtc::StartAcceptingConnections(const std::string& service_id, bool WebRtc::StartAcceptingConnections(const std::string& service_id,
@@ -73,10 +91,9 @@ bool WebRtc::StartAcceptingConnections(const std::string& service_id,
const LocationHint& location_hint, const LocationHint& location_hint,
AcceptedConnectionCallback callback) { AcceptedConnectionCallback callback) {
if (!IsAvailable()) { if (!IsAvailable()) {
{ MutexLock lock(&mutex_);
MutexLock lock(&mutex_); LogAndDisconnect(Role::kOfferer, service_id,
LogAndDisconnect("WebRTC is not available for data transfer."); "WebRTC is not available for data transfer.");
}
return false; return false;
} }
@@ -84,35 +101,36 @@ bool WebRtc::StartAcceptingConnections(const std::string& service_id,
NEARBY_LOG(WARNING, "Already accepting WebRTC connections."); NEARBY_LOG(WARNING, "Already accepting WebRTC connections.");
return false; return false;
} }
{ {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
if (role_ != Role::kNone) { accepting_map_.emplace(service_id,
NEARBY_LOG(WARNING, ConnectionInfo{.socket = WebRtcSocketWrapper()});
"Cannot start accepting WebRTC connections, current role %d", ConnectionInfo* connection_info = &accepting_map_[service_id];
role_); if (!InitWebRtcFlow(Role::kOfferer, self_id, location_hint, service_id))
return false; return false;
}
if (!InitWebRtcFlow(Role::kOfferer, self_id, location_hint)) return false; connection_info->restart_receive_messages_alarm = CancelableAlarm(
restart_receive_messages_alarm_ = CancelableAlarm(
"restart_receiving_messages_webrtc", "restart_receiving_messages_webrtc",
std::bind(&WebRtc::RestartReceiveMessages, this, location_hint, std::bind(&WebRtc::RestartReceiveMessages, this, location_hint,
service_id), service_id),
kRestartReceiveMessagesDuration, &restart_receive_messages_executor_); kRestartReceiveMessagesDuration, &restart_receive_messages_executor_);
SessionDescriptionWrapper offer = connection_flow_->CreateOffer(); SessionDescriptionWrapper offer =
pending_local_offer_ = webrtc_frames::EncodeOffer(self_id, offer.GetSdp()); connection_info->connection_flow->CreateOffer();
if (!SetLocalSessionDescription(std::move(offer))) { connection_info->pending_local_offer =
webrtc_frames::EncodeOffer(self_id, offer.GetSdp());
if (!SetLocalSessionDescription(std::move(offer), Role::kOfferer,
service_id)) {
return false; return false;
} }
// There is no timeout set for the future returned since we do not know how // There is no timeout set for the future returned since we do not know how
// much time it will take for the two devices to discover each other before // much time it will take for the two devices to discover each other before
// the actual transport can begin. // the actual transport can begin.
ListenForWebRtcSocketFuture(connection_flow_->GetDataChannel(), ListenForWebRtcSocketFuture(
std::move(callback)); Role::kOfferer, service_id,
connection_info->connection_flow->GetDataChannel(),
std::move(callback));
NEARBY_LOG(INFO, "Started listening for WebRtc connections as %s", NEARBY_LOG(INFO, "Started listening for WebRtc connections as %s",
self_id.GetId().c_str()); self_id.GetId().c_str());
} }
@@ -123,31 +141,38 @@ bool WebRtc::StartAcceptingConnections(const std::string& service_id,
WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id, WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id,
const LocationHint& location_hint) { const LocationHint& location_hint) {
if (!IsAvailable()) { if (!IsAvailable()) {
Disconnect(); Disconnect(Role::kAnswerer, peer_id.GetId());
return WebRtcSocketWrapper(); return WebRtcSocketWrapper();
} }
{ {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
if (role_ != Role::kNone) { if (connecting_map_.contains(peer_id.GetId())) {
NEARBY_LOG( NEARBY_LOG(
WARNING, ERROR,
"Cannot connect with WebRtc because we are already acting as %d", "Cannot connect with WebRtc because we are already connecting.");
role_);
return WebRtcSocketWrapper(); return WebRtcSocketWrapper();
} }
connecting_map_.emplace(peer_id.GetId(),
peer_id_ = peer_id; ConnectionInfo{.socket = WebRtcSocketWrapper()});
if (!InitWebRtcFlow(Role::kAnswerer, PeerId::FromRandom(), location_hint)) { ConnectionInfo* connection_info = &connecting_map_[peer_id.GetId()];
connection_info->peer_id = peer_id;
if (!InitWebRtcFlow(Role::kAnswerer, PeerId::FromRandom(), location_hint,
peer_id.GetId())) {
return WebRtcSocketWrapper(); return WebRtcSocketWrapper();
} }
} }
NEARBY_LOG(INFO, "Attempting to make a WebRTC connection to %s.", NEARBY_LOG(ERROR, "Attempting to make a WebRTC connection to %s.",
peer_id.GetId().c_str()); peer_id.GetId().c_str());
Future<WebRtcSocketWrapper> socket_future;
Future<WebRtcSocketWrapper> socket_future = ListenForWebRtcSocketFuture( {
connection_flow_->GetDataChannel(), AcceptedConnectionCallback()); MutexLock lock(&mutex_);
socket_future = ListenForWebRtcSocketFuture(
Role::kAnswerer, peer_id.GetId(),
connecting_map_[peer_id.GetId()].connection_flow->GetDataChannel(),
AcceptedConnectionCallback());
}
// The two devices have discovered each other, hence we have a timeout for // The two devices have discovered each other, hence we have a timeout for
// establishing the transport channel. // establishing the transport channel.
@@ -158,13 +183,19 @@ WebRtcSocketWrapper WebRtc::Connect(const PeerId& peer_id,
socket_future.Get(kDataChannelTimeout); socket_future.Get(kDataChannelTimeout);
if (result.ok()) return result.result(); if (result.ok()) return result.result();
Disconnect(); Disconnect(Role::kAnswerer, peer_id.GetId());
return WebRtcSocketWrapper(); return WebRtcSocketWrapper();
} }
bool WebRtc::SetLocalSessionDescription(SessionDescriptionWrapper sdp) { bool WebRtc::SetLocalSessionDescription(SessionDescriptionWrapper sdp,
if (!connection_flow_->SetLocalSessionDescription(std::move(sdp))) { Role role,
LogAndDisconnect("Unable to set local session description"); const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return false;
if (!connection_info->connection_flow->SetLocalSessionDescription(
std::move(sdp))) {
LogAndDisconnect(role, connection_id,
"Unable to set local session description");
return false; return false;
} }
@@ -182,28 +213,35 @@ void WebRtc::StopAcceptingConnections(const std::string& service_id) {
{ {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
ShutdownSignaling(); ShutdownSignaling(Role::kOfferer, service_id);
} }
NEARBY_LOG(INFO, "Stopped accepting WebRTC connections"); NEARBY_LOG(INFO, "Stopped accepting WebRTC connections");
} }
Future<WebRtcSocketWrapper> WebRtc::ListenForWebRtcSocketFuture( Future<WebRtcSocketWrapper> WebRtc::ListenForWebRtcSocketFuture(
const Role& role, const std::string& connection_id,
Future<rtc::scoped_refptr<webrtc::DataChannelInterface>> Future<rtc::scoped_refptr<webrtc::DataChannelInterface>>
data_channel_future, data_channel_future,
AcceptedConnectionCallback callback) { AcceptedConnectionCallback callback) {
Future<WebRtcSocketWrapper> socket_future; Future<WebRtcSocketWrapper> socket_future;
auto data_channel_runnable = [this, socket_future, data_channel_future, auto data_channel_runnable = [this, role, connection_id, socket_future,
data_channel_future,
callback{std::move(callback)}]() mutable { callback{std::move(callback)}]() mutable {
// The overall timeout of creating the socket and data channel is controlled // The overall timeout of creating the socket and data channel is controlled
// by the caller of this function. // by the caller of this function.
ExceptionOr<rtc::scoped_refptr<webrtc::DataChannelInterface>> res = ExceptionOr<rtc::scoped_refptr<webrtc::DataChannelInterface>> res =
data_channel_future.Get(); data_channel_future.Get();
if (res.ok()) { if (res.ok()) {
WebRtcSocketWrapper wrapper = CreateWebRtcSocketWrapper(res.result()); WebRtcSocketWrapper wrapper =
CreateWebRtcSocketWrapper(role, connection_id, res.result());
callback.accepted_cb(wrapper); callback.accepted_cb(wrapper);
{ {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
socket_ = wrapper; ConnectionInfo* connection_info =
GetConnectionInfo(role, connection_id);
if (connection_info) {
connection_info->socket = wrapper;
}
} }
socket_future.Set(wrapper); socket_future.Set(wrapper);
} else { } else {
@@ -219,274 +257,370 @@ Future<WebRtcSocketWrapper> WebRtc::ListenForWebRtcSocketFuture(
} }
WebRtcSocketWrapper WebRtc::CreateWebRtcSocketWrapper( WebRtcSocketWrapper WebRtc::CreateWebRtcSocketWrapper(
const Role& role, const std::string& connection_id,
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) { rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel) {
if (data_channel == nullptr) { if (data_channel == nullptr) {
return WebRtcSocketWrapper(); return WebRtcSocketWrapper();
} }
auto socket = std::make_unique<WebRtcSocket>("WebRtcSocket", data_channel); auto socket = std::make_unique<WebRtcSocket>("WebRtcSocket", data_channel);
socket->SetOnSocketClosedListener( socket->SetOnSocketClosedListener({[this, role, connection_id]() {
{[this]() { OffloadFromSignalingThread([this]() { Disconnect(); }); }}); OffloadFromSignalingThread(
[this, role, connection_id]() { Disconnect(role, connection_id); });
}});
return WebRtcSocketWrapper(std::move(socket)); return WebRtcSocketWrapper(std::move(socket));
} }
bool WebRtc::InitWebRtcFlow(Role role, const PeerId& self_id, bool WebRtc::InitWebRtcFlow(const Role& role, const PeerId& self_id,
const LocationHint& location_hint) { const LocationHint& location_hint,
role_ = role; const std::string& connection_id) {
self_id_ = self_id; ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return false;
connection_info->self_id = self_id;
if (connection_flow_) { if (connection_info->connection_flow) {
LogAndShutdownSignaling( LogAndShutdownSignaling(
role, connection_id,
"Tried to initialize WebRTC without shutting down the previous " "Tried to initialize WebRTC without shutting down the previous "
"connection"); "connection");
return false; return false;
} }
if (signaling_messenger_) { if (connection_info->signaling_messenger) {
LogAndShutdownSignaling( LogAndShutdownSignaling(
role, connection_id,
"Tried to initialize WebRTC without shutting down signaling messenger"); "Tried to initialize WebRTC without shutting down signaling messenger");
return false; return false;
} }
connection_info->signaling_messenger =
medium_.GetSignalingMessenger(self_id.GetId(), location_hint);
auto signaling_message_callback = std::bind(
[this](ByteArray message, Role role, const std::string& connection_id) {
OffloadFromSignalingThread([this, message{std::move(message)},
role{role},
connection_id{connection_id}]() {
ProcessSignalingMessage(role, connection_id, message);
});
},
std::placeholders::_1, role, connection_id);
signaling_messenger_ = if (!connection_info->signaling_messenger->IsValid() ||
medium_.GetSignalingMessenger(self_id_.GetId(), location_hint); !connection_info->signaling_messenger->StartReceivingMessages(
auto signaling_message_callback = [this](ByteArray message) {
OffloadFromSignalingThread([this, message{std::move(message)}]() {
ProcessSignalingMessage(message);
});
};
if (!signaling_messenger_->IsValid() ||
!signaling_messenger_->StartReceivingMessages(
signaling_message_callback)) { signaling_message_callback)) {
DisconnectLocked(); LogAndDisconnect(role, connection_id,
"Could not receive from signaling messenger.");
return false; return false;
} }
if (role_ == Role::kAnswerer && if (role == Role::kAnswerer &&
!signaling_messenger_->SendMessage( !connection_info->signaling_messenger->SendMessage(
peer_id_.GetId(), connection_info->peer_id.GetId(),
webrtc_frames::EncodeReadyForSignalingPoke(self_id))) { webrtc_frames::EncodeReadyForSignalingPoke(self_id))) {
LogAndDisconnect(absl::StrCat("Could not send signaling poke to peer ", LogAndDisconnect(Role::kAnswerer, connection_info->peer_id.GetId(),
peer_id_.GetId())); absl::StrCat("Could not send signaling poke to peer ",
connection_info->peer_id.GetId()));
return false; return false;
} }
connection_flow_ = ConnectionFlow::Create(GetLocalIceCandidateListener(), connection_info->connection_flow = ConnectionFlow::Create(
GetDataChannelListener(), medium_); GetLocalIceCandidateListener(role, connection_id),
if (!connection_flow_) return false; GetDataChannelListener(role, connection_id), medium_);
if (!connection_info->connection_flow) {
LogAndDisconnect(role, connection_id, "Failed to create connection flow");
return false;
}
return true; return true;
} }
void WebRtc::OnLocalIceCandidate( void WebRtc::OnLocalIceCandidate(
const Role& role, const std::string& connection_id,
const webrtc::IceCandidateInterface* local_ice_candidate) { const webrtc::IceCandidateInterface* local_ice_candidate) {
::location::nearby::mediums::IceCandidate ice_candidate = ::location::nearby::mediums::IceCandidate ice_candidate =
webrtc_frames::EncodeIceCandidate(*local_ice_candidate); webrtc_frames::EncodeIceCandidate(*local_ice_candidate);
OffloadFromSignalingThread([this, ice_candidate{std::move(ice_candidate)}]() { OffloadFromSignalingThread([this, ice_candidate{std::move(ice_candidate)},
role{role}, connection_id{connection_id}]() {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
if (IsSignaling()) { ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
signaling_messenger_->SendMessage( if (IsSignaling(role, connection_id)) {
peer_id_.GetId(), webrtc_frames::EncodeIceCandidates( if (connection_info && connection_info->signaling_messenger) {
self_id_, {std::move(ice_candidate)})); connection_info->signaling_messenger->SendMessage(
connection_info->peer_id.GetId(),
webrtc_frames::EncodeIceCandidates(connection_info->self_id,
{std::move(ice_candidate)}));
} else {
connection_info->pending_local_ice_candidates.push_back(
std::move(ice_candidate));
}
} else { } else {
pending_local_ice_candidates_.push_back(std::move(ice_candidate)); connection_info->pending_local_ice_candidates.push_back(
std::move(ice_candidate));
} }
}); });
} }
LocalIceCandidateListener WebRtc::GetLocalIceCandidateListener() { LocalIceCandidateListener WebRtc::GetLocalIceCandidateListener(
return {std::bind(&WebRtc::OnLocalIceCandidate, this, std::placeholders::_1)}; const Role& role, const std::string& connection_id) {
return {std::bind(&WebRtc::OnLocalIceCandidate, this, role, connection_id,
std::placeholders::_1)};
} }
void WebRtc::OnDataChannelClosed() { void WebRtc::OnDataChannelClosed(const Role& role,
OffloadFromSignalingThread([this]() { const std::string& connection_id) {
OffloadFromSignalingThread([this, role, connection_id]() {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
LogAndDisconnect("WebRTC data channel closed"); LogAndDisconnect(role, connection_id, "WebRTC data channel closed");
}); });
} }
void WebRtc::OnDataChannelMessageReceived(const ByteArray& message) { void WebRtc::OnDataChannelMessageReceived(const Role& role,
OffloadFromSignalingThread([this, message]() { const std::string& connection_id,
MutexLock lock(&mutex_); const ByteArray& message) {
if (!socket_.IsValid()) { OffloadFromSignalingThread([this, role, connection_id, message]() {
LogAndDisconnect("Received a data channel message without a socket"); {
return; MutexLock lock(&mutex_);
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return;
if (!connection_info->socket.IsValid()) {
LogAndDisconnect(role, connection_id,
"Received a data channel message without a socket");
return;
}
connection_info->socket.NotifyDataChannelMsgReceived(message);
} }
socket_.NotifyDataChannelMsgReceived(message);
}); });
} }
void WebRtc::OnDataChannelBufferedAmountChanged() { void WebRtc::OnDataChannelBufferedAmountChanged(
OffloadFromSignalingThread([this]() { const Role& role, const std::string& connection_id) {
MutexLock lock(&mutex_); OffloadFromSignalingThread([this, role, connection_id]() {
if (!socket_.IsValid()) { {
LogAndDisconnect("Data channel buffer changed without a socket"); MutexLock lock(&mutex_);
return; ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return;
if (!connection_info->socket.IsValid()) {
LogAndDisconnect(role, connection_id,
"Data channel buffer changed without a socket");
return;
}
connection_info->socket.NotifyDataChannelBufferedAmountChanged();
} }
socket_.NotifyDataChannelBufferedAmountChanged();
}); });
} }
DataChannelListener WebRtc::GetDataChannelListener() { DataChannelListener WebRtc::GetDataChannelListener(
const Role& role, const std::string& connection_id) {
return { return {
.data_channel_closed_cb = std::bind(&WebRtc::OnDataChannelClosed, this), .data_channel_closed_cb =
.data_channel_message_received_cb = std::bind( std::bind(&WebRtc::OnDataChannelClosed, this, role, connection_id),
&WebRtc::OnDataChannelMessageReceived, this, std::placeholders::_1), .data_channel_message_received_cb =
std::bind(&WebRtc::OnDataChannelMessageReceived, this, role,
connection_id, std::placeholders::_1),
.data_channel_buffered_amount_changed_cb = .data_channel_buffered_amount_changed_cb =
std::bind(&WebRtc::OnDataChannelBufferedAmountChanged, this), std::bind(&WebRtc::OnDataChannelBufferedAmountChanged, this, role,
connection_id),
}; };
} }
bool WebRtc::IsSignaling() { bool WebRtc::IsSignaling(const Role& role, const std::string& connection_id) {
return (role_ != Role::kNone && self_id_.IsValid() && peer_id_.IsValid()); ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return false;
return (connection_info->self_id.IsValid() &&
connection_info->peer_id.IsValid());
} }
void WebRtc::ProcessSignalingMessage(const ByteArray& message) { void WebRtc::ProcessSignalingMessage(const Role& role,
const std::string& connection_id,
const ByteArray& message) {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (!connection_info) return;
if (!connection_flow_) { if (!connection_info->connection_flow) {
LogAndDisconnect("Received WebRTC frame before signaling was started"); LogAndDisconnect(role, connection_id,
"Received WebRTC frame before signaling was started");
return; return;
} }
location::nearby::mediums::WebRtcSignalingFrame frame; location::nearby::mediums::WebRtcSignalingFrame frame;
if (!frame.ParseFromString(std::string(message))) { if (!frame.ParseFromString(std::string(message))) {
LogAndDisconnect("Failed to parse signaling message"); LogAndDisconnect(role, connection_id, "Failed to parse signaling message");
return; return;
} }
if (!frame.has_sender_id()) { if (!frame.has_sender_id()) {
LogAndDisconnect("Invalid WebRTC frame: Sender ID is missing"); LogAndDisconnect(role, connection_id,
"Invalid WebRTC frame: Sender ID is missing");
return; return;
} }
if (frame.has_ready_for_signaling_poke() && !peer_id_.IsValid()) { if (frame.has_ready_for_signaling_poke() &&
peer_id_ = PeerId(frame.sender_id().id()); !connection_info->peer_id.IsValid()) {
connection_info->peer_id = PeerId(frame.sender_id().id());
NEARBY_LOG(INFO, "Peer %s is ready for signaling", NEARBY_LOG(INFO, "Peer %s is ready for signaling",
peer_id_.GetId().c_str()); connection_info->peer_id.GetId().c_str());
} }
if (!IsSignaling()) { if (!IsSignaling(role, connection_id)) {
NEARBY_LOG(INFO, NEARBY_LOG(INFO,
"Ignoring WebRTC frame: we are not currently listening for " "Ignoring WebRTC frame: we are not currently listening for "
"signaling messages"); "signaling messages");
return; return;
} }
if (frame.sender_id().id() != peer_id_.GetId()) { if (frame.sender_id().id() != connection_info->peer_id.GetId()) {
NEARBY_LOG( NEARBY_LOG(
INFO, "Ignoring WebRTC frame: we are only listening for another peer."); INFO, "Ignoring WebRTC frame: we are only listening for another peer.");
return; return;
} }
if (frame.has_ready_for_signaling_poke()) { if (frame.has_ready_for_signaling_poke()) {
SendOfferAndIceCandidatesToPeer(); SendOfferAndIceCandidatesToPeer(connection_id);
} else if (frame.has_offer()) { } else if (frame.has_offer()) {
connection_flow_->OnOfferReceived( DCHECK(role == Role::kAnswerer);
connection_info->connection_flow->OnOfferReceived(
SessionDescriptionWrapper(webrtc_frames::DecodeOffer(frame).release())); SessionDescriptionWrapper(webrtc_frames::DecodeOffer(frame).release()));
SendAnswerToPeer(); SendAnswerToPeer(connection_id);
} else if (frame.has_answer()) { } else if (frame.has_answer()) {
connection_flow_->OnAnswerReceived(SessionDescriptionWrapper( DCHECK(role == Role::kOfferer);
webrtc_frames::DecodeAnswer(frame).release())); connection_info->connection_flow->OnAnswerReceived(
SessionDescriptionWrapper(
webrtc_frames::DecodeAnswer(frame).release()));
} else if (frame.has_ice_candidates()) { } else if (frame.has_ice_candidates()) {
if (!connection_flow_->OnRemoteIceCandidatesReceived( if (!connection_info->connection_flow->OnRemoteIceCandidatesReceived(
webrtc_frames::DecodeIceCandidates(frame))) { webrtc_frames::DecodeIceCandidates(frame))) {
LogAndDisconnect("Could not add remote ice candidates."); LogAndDisconnect(role, connection_id,
"Could not add remote ice candidates.");
} }
} }
} }
void WebRtc::SendOfferAndIceCandidatesToPeer() { void WebRtc::SendOfferAndIceCandidatesToPeer(const std::string& service_id) {
if (pending_local_offer_.Empty()) { ConnectionInfo* connection_info =
GetConnectionInfo(Role::kOfferer, service_id);
if (!connection_info) return;
if (connection_info->pending_local_offer.Empty()) {
LogAndDisconnect( LogAndDisconnect(
Role::kOfferer, service_id,
"Unable to send pending offer to remote peer: local offer not set"); "Unable to send pending offer to remote peer: local offer not set");
return; return;
} }
if (!signaling_messenger_->SendMessage(peer_id_.GetId(), if (!connection_info->signaling_messenger->SendMessage(
pending_local_offer_)) { connection_info->peer_id.GetId(),
LogAndDisconnect("Failed to send local offer via signaling messenger"); connection_info->pending_local_offer)) {
LogAndDisconnect(Role::kOfferer, service_id,
"Failed to send local offer via signaling messenger");
return; return;
} }
pending_local_offer_ = ByteArray(); connection_info->pending_local_offer = ByteArray();
if (!pending_local_ice_candidates_.empty()) { if (!connection_info->pending_local_ice_candidates.empty()) {
signaling_messenger_->SendMessage( connection_info->signaling_messenger->SendMessage(
peer_id_.GetId(), connection_info->peer_id.GetId(),
webrtc_frames::EncodeIceCandidates( webrtc_frames::EncodeIceCandidates(
self_id_, std::move(pending_local_ice_candidates_))); connection_info->self_id,
std::move(connection_info->pending_local_ice_candidates)));
} }
} }
void WebRtc::SendAnswerToPeer() { void WebRtc::SendAnswerToPeer(const std::string& peer_id) {
SessionDescriptionWrapper answer = connection_flow_->CreateAnswer(); ConnectionInfo* connection_info = GetConnectionInfo(Role::kAnswerer, peer_id);
if (!connection_info) return;
SessionDescriptionWrapper answer =
connection_info->connection_flow->CreateAnswer();
ByteArray answer_message( ByteArray answer_message(
webrtc_frames::EncodeAnswer(self_id_, answer.GetSdp())); webrtc_frames::EncodeAnswer(connection_info->self_id, answer.GetSdp()));
if (!SetLocalSessionDescription(std::move(answer))) return; if (!SetLocalSessionDescription(std::move(answer), Role::kAnswerer, peer_id))
return;
if (!signaling_messenger_->SendMessage(peer_id_.GetId(), answer_message)) { if (!connection_info->signaling_messenger->SendMessage(
LogAndDisconnect("Failed to send local answer via signaling messenger"); connection_info->peer_id.GetId(), answer_message)) {
LogAndDisconnect(Role::kAnswerer, peer_id,
"Failed to send local answer via signaling messenger");
return; return;
} }
} }
void WebRtc::LogAndDisconnect(const std::string& error_message) { void WebRtc::LogAndDisconnect(const Role& role,
NEARBY_LOG(WARNING, "Disconnecting WebRTC : %s", error_message.c_str()); const std::string& connection_id,
DisconnectLocked(); const std::string& error_message) {
NEARBY_LOG(WARNING,
"Disconnecting WebRTC role: %d, connection id: %s, msg: %s", role,
connection_id.c_str(), error_message.c_str());
DisconnectLocked(role, connection_id);
} }
void WebRtc::LogAndShutdownSignaling(const std::string& error_message) { void WebRtc::LogAndShutdownSignaling(const Role& role,
NEARBY_LOG(WARNING, "Stopping WebRTC signaling : %s", error_message.c_str()); const std::string& connection_id,
ShutdownSignaling(); const std::string& error_message) {
NEARBY_LOG(WARNING, "Stopping WebRTC role: %d, connection id: %s, msg: %s",
role, connection_id.c_str(), error_message.c_str());
ShutdownSignaling(role, connection_id);
} }
void WebRtc::ShutdownSignaling() { void WebRtc::ShutdownSignaling(const Role& role,
role_ = Role::kNone; const std::string& connection_id) {
self_id_ = PeerId(); ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
peer_id_ = PeerId(); if (!connection_info) {
pending_local_offer_ = ByteArray(); return;
pending_local_ice_candidates_.clear();
if (restart_receive_messages_alarm_.IsValid()) {
restart_receive_messages_alarm_.Cancel();
restart_receive_messages_alarm_ = CancelableAlarm();
} }
if (signaling_messenger_) { connection_info->self_id = PeerId();
signaling_messenger_->StopReceivingMessages(); connection_info->peer_id = PeerId();
signaling_messenger_.reset(); connection_info->pending_local_offer = ByteArray();
connection_info->pending_local_ice_candidates.clear();
if (connection_info->restart_receive_messages_alarm.IsValid()) {
connection_info->restart_receive_messages_alarm.Cancel();
connection_info->restart_receive_messages_alarm = CancelableAlarm();
} }
if (!socket_.IsValid()) ShutdownIceCandidateCollection(); if (connection_info->signaling_messenger) {
connection_info->signaling_messenger->StopReceivingMessages();
connection_info->signaling_messenger.reset();
}
if (!connection_info->socket.IsValid())
ShutdownIceCandidateCollection(role, connection_id);
} }
void WebRtc::Disconnect() { void WebRtc::Disconnect(const Role& role, const std::string& connection_id) {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
DisconnectLocked(); DisconnectLocked(role, connection_id);
} }
void WebRtc::DisconnectLocked() { void WebRtc::DisconnectLocked(const Role& role,
ShutdownSignaling(); const std::string& connection_id) {
ShutdownWebRtcSocket(); ShutdownSignaling(role, connection_id);
ShutdownIceCandidateCollection(); ShutdownWebRtcSocket(role, connection_id);
} ShutdownIceCandidateCollection(role, connection_id);
void WebRtc::ShutdownWebRtcSocket() { if (role == Role::kOfferer && accepting_map_.contains(connection_id)) {
if (socket_.IsValid()) { accepting_map_.erase(connection_id);
socket_.Close(); } else if (role == Role::kAnswerer &&
socket_ = WebRtcSocketWrapper(); connecting_map_.contains(connection_id)) {
connecting_map_.erase(connection_id);
} }
} }
void WebRtc::ShutdownIceCandidateCollection() { void WebRtc::ShutdownWebRtcSocket(const Role& role,
if (connection_flow_) { const std::string& connection_id) {
connection_flow_->Close(); ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
connection_flow_.reset(); if (connection_info && connection_info->socket.IsValid()) {
connection_info->socket.Close();
connection_info->socket = WebRtcSocketWrapper();
}
}
void WebRtc::ShutdownIceCandidateCollection(const Role& role,
const std::string& connection_id) {
ConnectionInfo* connection_info = GetConnectionInfo(role, connection_id);
if (connection_info && connection_info->connection_flow) {
connection_info->connection_flow->Close();
connection_info->connection_flow.reset();
} }
} }
@@ -505,25 +639,49 @@ void WebRtc::RestartReceiveMessages(const LocationHint& location_hint,
NEARBY_LOG(INFO, "Restarting listening for receiving signaling messages."); NEARBY_LOG(INFO, "Restarting listening for receiving signaling messages.");
{ {
MutexLock lock(&mutex_); MutexLock lock(&mutex_);
signaling_messenger_->StopReceivingMessages(); ConnectionInfo* connection_info =
GetConnectionInfo(Role::kOfferer, service_id);
if (!connection_info) {
NEARBY_LOG(ERROR,
"Can't find connection info in RestartReceiveMessages for %s",
service_id.c_str());
return;
}
connection_info->signaling_messenger->StopReceivingMessages();
signaling_messenger_ = connection_info->signaling_messenger = medium_.GetSignalingMessenger(
medium_.GetSignalingMessenger(self_id_.GetId(), location_hint); connection_info->self_id.GetId(), location_hint);
auto signaling_message_callback = [this](ByteArray message) { auto signaling_message_callback = std::bind(
OffloadFromSignalingThread([this, message{std::move(message)}]() { [this](ByteArray message, const Role& role,
ProcessSignalingMessage(message); const std::string& connection_id) {
}); OffloadFromSignalingThread([this, message{std::move(message)},
}; role{role},
connection_id{connection_id}]() {
ProcessSignalingMessage(role, connection_id, message);
});
},
std::placeholders::_1, Role::kOfferer, service_id);
if (!signaling_messenger_->IsValid() || if (!connection_info->signaling_messenger->IsValid() ||
!signaling_messenger_->StartReceivingMessages( !connection_info->signaling_messenger->StartReceivingMessages(
signaling_message_callback)) { signaling_message_callback)) {
DisconnectLocked(); DisconnectLocked(Role::kOfferer, service_id);
} }
} }
} }
WebRtc::ConnectionInfo* WebRtc::GetConnectionInfo(
const Role& role, const std::string& connection_id) {
if (role == Role::kOfferer && accepting_map_.contains(connection_id)) {
return &accepting_map_[connection_id];
} else if (role == Role::kAnswerer &&
connecting_map_.contains(connection_id)) {
return &connecting_map_[connection_id];
}
return nullptr;
}
} // namespace mediums } // namespace mediums
} // namespace connections } // namespace connections
} // namespace nearby } // namespace nearby
+70 -31
View File
@@ -37,6 +37,7 @@
#include "platform/public/single_thread_executor.h" #include "platform/public/single_thread_executor.h"
#include "platform/public/webrtc.h" #include "platform/public/webrtc.h"
#include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h" #include "location/nearby/mediums/proto/web_rtc_signaling_frames.pb.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h" #include "absl/container/flat_hash_set.h"
#include "webrtc/api/data_channel_interface.h" #include "webrtc/api/data_channel_interface.h"
#include "webrtc/api/jsep.h" #include "webrtc/api/jsep.h"
@@ -99,65 +100,102 @@ class WebRtc {
kAnswerer = 2, kAnswerer = 2,
}; };
bool InitWebRtcFlow(Role role, const PeerId& self_id, struct ConnectionInfo {
const LocationHint& location_hint) std::unique_ptr<ConnectionFlow> connection_flow;
std::unique_ptr<WebRtcSignalingMessenger> signaling_messenger;
WebRtcSocketWrapper socket;
CancelableAlarm restart_receive_messages_alarm;
PeerId self_id;
PeerId peer_id;
ByteArray pending_local_offer;
std::vector<::location::nearby::mediums::IceCandidate>
pending_local_ice_candidates;
};
bool InitWebRtcFlow(const Role& role, const PeerId& self_id,
const LocationHint& location_hint,
const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
Future<WebRtcSocketWrapper> ListenForWebRtcSocketFuture( Future<WebRtcSocketWrapper> ListenForWebRtcSocketFuture(
const Role& role, const std::string& connection_id,
Future<rtc::scoped_refptr<webrtc::DataChannelInterface>> Future<rtc::scoped_refptr<webrtc::DataChannelInterface>>
data_channel_future, data_channel_future,
AcceptedConnectionCallback callback); AcceptedConnectionCallback callback);
WebRtcSocketWrapper CreateWebRtcSocketWrapper( WebRtcSocketWrapper CreateWebRtcSocketWrapper(
const Role& role, const std::string& connection_id,
rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel); rtc::scoped_refptr<webrtc::DataChannelInterface> data_channel);
LocalIceCandidateListener GetLocalIceCandidateListener(); LocalIceCandidateListener GetLocalIceCandidateListener(
const Role& role, const std::string& connection_id);
void OnLocalIceCandidate( void OnLocalIceCandidate(
const Role& role, const std::string& connection_id,
const webrtc::IceCandidateInterface* local_ice_candidate); const webrtc::IceCandidateInterface* local_ice_candidate);
DataChannelListener GetDataChannelListener(); DataChannelListener GetDataChannelListener(const Role& role,
void OnDataChannelClosed(); const std::string& connection_id);
void OnDataChannelMessageReceived(const ByteArray& message); void OnDataChannelClosed(const Role& role, const std::string& connection_id);
void OnDataChannelBufferedAmountChanged(); void OnDataChannelMessageReceived(const Role& role,
const std::string& connection_id,
const ByteArray& message);
void OnDataChannelBufferedAmountChanged(const Role& role,
const std::string& connection_id);
// Runs on @MainThread and |single_thread_executor_|. // Runs on @MainThread and |single_thread_executor_|.
bool SetLocalSessionDescription(SessionDescriptionWrapper sdp) bool SetLocalSessionDescription(SessionDescriptionWrapper sdp, Role role,
const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|. // Runs on |single_thread_executor_|.
bool IsSignaling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); bool IsSignaling(const Role& role, const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|. // Runs on |single_thread_executor_|.
void ProcessSignalingMessage(const ByteArray& message) void ProcessSignalingMessage(const Role& role,
const std::string& connection_id,
const ByteArray& message)
ABSL_LOCKS_EXCLUDED(mutex_); ABSL_LOCKS_EXCLUDED(mutex_);
// Runs on |single_thread_executor_|. // Runs on |single_thread_executor_|.
void SendOfferAndIceCandidatesToPeer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); void SendOfferAndIceCandidatesToPeer(const std::string& service_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on |single_thread_executor_|. // Runs on |single_thread_executor_|.
void SendAnswerToPeer() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); void SendAnswerToPeer(const std::string& peer_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on @MainThread and |single_thread_executor_|. // Runs on @MainThread and |single_thread_executor_|.
void LogAndDisconnect(const std::string& error_message) void LogAndDisconnect(const Role& role, const std::string& connection_id,
const std::string& error_message)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on @MainThread. // Runs on @MainThread.
void Disconnect() ABSL_LOCKS_EXCLUDED(mutex_); void Disconnect(const Role& role, const std::string& connection_id)
ABSL_LOCKS_EXCLUDED(mutex_);
// Runs on @MainThread and |single_thread_executor_|. // Runs on @MainThread and |single_thread_executor_|.
void DisconnectLocked() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); void DisconnectLocked(const Role& role, const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void LogAndShutdownSignaling(const std::string& error_message) void LogAndShutdownSignaling(const Role& role,
const std::string& connection_id,
const std::string& error_message)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on @MainThread and |single_thread_executor_|. // Runs on @MainThread and |single_thread_executor_|.
void ShutdownSignaling() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); void ShutdownSignaling(const Role& role, const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on @MainThread and |single_thread_executor_|. // Runs on @MainThread and |single_thread_executor_|.
void ShutdownWebRtcSocket() ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_); void ShutdownWebRtcSocket(const Role& role, const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
// Runs on @MainThread and |single_thread_executor_|. // Runs on @MainThread and |single_thread_executor_|.
void ShutdownIceCandidateCollection(); void ShutdownIceCandidateCollection(const Role& role,
const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
void OffloadFromSignalingThread(Runnable runnable); void OffloadFromSignalingThread(Runnable runnable);
@@ -166,26 +204,27 @@ class WebRtc {
const std::string& service_id) const std::string& service_id)
ABSL_LOCKS_EXCLUDED(mutex_); ABSL_LOCKS_EXCLUDED(mutex_);
void PrintStatus(const std::string& func);
ConnectionInfo* GetConnectionInfo(const Role& role,
const std::string& connection_id)
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
Mutex mutex_; Mutex mutex_;
Role role_ ABSL_GUARDED_BY(mutex_) = Role::kNone;
PeerId self_id_ ABSL_GUARDED_BY(mutex_);
PeerId peer_id_ ABSL_GUARDED_BY(mutex_);
ByteArray pending_local_offer_ ABSL_GUARDED_BY(mutex_);
std::vector<::location::nearby::mediums::IceCandidate>
pending_local_ice_candidates_ ABSL_GUARDED_BY(mutex_);
WebRtcMedium medium_; WebRtcMedium medium_;
std::unique_ptr<ConnectionFlow> connection_flow_;
std::unique_ptr<WebRtcSignalingMessenger> signaling_messenger_
ABSL_GUARDED_BY(mutex_);
WebRtcSocketWrapper socket_ ABSL_GUARDED_BY(mutex_);
SingleThreadExecutor single_thread_executor_; SingleThreadExecutor single_thread_executor_;
// Restarts the signaling messenger for receiving messages. // Restarts the signaling messenger for receiving messages.
ScheduledExecutor restart_receive_messages_executor_; ScheduledExecutor restart_receive_messages_executor_;
CancelableAlarm restart_receive_messages_alarm_;
// Use service_id as key for accepting connections.
absl::flat_hash_map<std::string, ConnectionInfo> accepting_map_
ABSL_GUARDED_BY(mutex_);
// Use remote peer_id as key for connecting connections.
absl::flat_hash_map<std::string, ConnectionInfo> connecting_map_
ABSL_GUARDED_BY(mutex_);
}; };
} // namespace mediums } // namespace mediums
+11 -9
View File
@@ -62,7 +62,8 @@ TEST_F(WebRtcTest, StartAcceptingConnectionTwice) {
EXPECT_FALSE(webrtc.StartAcceptingConnections( EXPECT_FALSE(webrtc.StartAcceptingConnections(
service_id, self_id, location_hint, service_id, self_id, location_hint,
{mock_accepted_callback_.AsStdFunction()})); {mock_accepted_callback_.AsStdFunction()}));
EXPECT_TRUE(webrtc.IsAcceptingConnections(std::string{})); EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id));
EXPECT_FALSE(webrtc.IsAcceptingConnections(std::string{}));
} }
// Tests the flow when the device tries to connect but the data channel times // Tests the flow when the device tries to connect but the data channel times
@@ -99,7 +100,7 @@ TEST_F(WebRtcTest, StartAcceptingConnection_ThenConnect) {
{mock_accepted_callback_.AsStdFunction()})); {mock_accepted_callback_.AsStdFunction()}));
WebRtcSocketWrapper wrapper = WebRtcSocketWrapper wrapper =
webrtc.Connect(PeerId("random_peer_id"), location_hint); webrtc.Connect(PeerId("random_peer_id"), location_hint);
EXPECT_TRUE(webrtc.IsAcceptingConnections(std::string{})); EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id));
EXPECT_FALSE(wrapper.IsValid()); EXPECT_FALSE(wrapper.IsValid());
EXPECT_FALSE(webrtc.StartAcceptingConnections( EXPECT_FALSE(webrtc.StartAcceptingConnections(
service_id, self_id, location_hint, service_id, self_id, location_hint,
@@ -122,8 +123,9 @@ TEST_F(WebRtcTest, StartAndStopAcceptingConnections) {
ASSERT_TRUE(webrtc.StartAcceptingConnections( ASSERT_TRUE(webrtc.StartAcceptingConnections(
service_id, self_id, location_hint, service_id, self_id, location_hint,
{mock_accepted_callback_.AsStdFunction()})); {mock_accepted_callback_.AsStdFunction()}));
EXPECT_TRUE(webrtc.IsAcceptingConnections(service_id));
webrtc.StopAcceptingConnections(service_id); webrtc.StopAcceptingConnections(service_id);
EXPECT_FALSE(webrtc.IsAcceptingConnections(std::string{})); EXPECT_FALSE(webrtc.IsAcceptingConnections(service_id));
} }
// Tests the flow when the device tries to connect to two different peers // Tests the flow when the device tries to connect to two different peers
@@ -144,11 +146,8 @@ TEST_F(WebRtcTest, ConnectTwice) {
connected.Set(receiver_socket.IsValid()); connected.Set(receiver_socket.IsValid());
}}); }});
using MockAcceptedCallback =
testing::MockFunction<void(WebRtcSocketWrapper socket)>;
testing::StrictMock<MockAcceptedCallback> mock_accepted_callback_;
device_c.StartAcceptingConnections(service_id, other_id, location_hint, device_c.StartAcceptingConnections(service_id, other_id, location_hint,
{mock_accepted_callback_.AsStdFunction()}); {[](WebRtcSocketWrapper wrapper) {}});
sender_socket = sender.Connect(self_id, location_hint); sender_socket = sender.Connect(self_id, location_hint);
EXPECT_TRUE(sender_socket.IsValid()); EXPECT_TRUE(sender_socket.IsValid());
@@ -157,8 +156,11 @@ TEST_F(WebRtcTest, ConnectTwice) {
ASSERT_TRUE(devices_connected.ok()); ASSERT_TRUE(devices_connected.ok());
EXPECT_TRUE(devices_connected.result()); EXPECT_TRUE(devices_connected.result());
WebRtcSocketWrapper socket = sender.Connect(other_id, location_hint); WebRtcSocketWrapper socket =
EXPECT_FALSE(socket.IsValid()); sender.Connect(other_id, location_hint);
EXPECT_TRUE(socket.IsValid());
socket.Close();
EXPECT_TRUE(receiver_socket.IsValid()); EXPECT_TRUE(receiver_socket.IsValid());
EXPECT_TRUE(sender_socket.IsValid()); EXPECT_TRUE(sender_socket.IsValid());
+12 -1
View File
@@ -16,6 +16,7 @@
#include <algorithm> #include <algorithm>
#include <cinttypes> #include <cinttypes>
#include <limits>
#include <memory> #include <memory>
#include <string> #include <string>
#include <utility> #include <utility>
@@ -89,8 +90,9 @@ bool PayloadManager::SendPayloadLoop(
// This will block if there is no data to transfer. // This will block if there is no data to transfer.
// It will resume when new data arrives, or if Close() is called. // It will resume when new data arrives, or if Close() is called.
int chunk_size = GetOptimalChunkSize(available_endpoint_ids);
ByteArray next_chunk = ByteArray next_chunk =
pending_payload.GetInternalPayload()->DetachNextChunk(); pending_payload.GetInternalPayload()->DetachNextChunk(chunk_size);
if (shutdown_.Get()) return false; if (shutdown_.Get()) return false;
// Save chunk size. We'll need it after we move next_chunk. // Save chunk size. We'll need it after we move next_chunk.
auto next_chunk_size = next_chunk.size(); auto next_chunk_size = next_chunk.size();
@@ -497,6 +499,15 @@ SingleThreadExecutor* PayloadManager::GetOutgoingPayloadExecutor(
} }
} }
int PayloadManager::GetOptimalChunkSize(EndpointIds endpoint_ids) {
int minChunkSize = std::numeric_limits<int>::max();
for (const auto& endpoint_id : endpoint_ids) {
minChunkSize = std::min(
minChunkSize, endpoint_manager_->GetMaxTransmitPacketSize(endpoint_id));
}
return minChunkSize;
}
PayloadTransferFrame::PayloadHeader PayloadManager::CreatePayloadHeader( PayloadTransferFrame::PayloadHeader PayloadManager::CreatePayloadHeader(
const InternalPayload& internal_payload) { const InternalPayload& internal_payload) {
PayloadTransferFrame::PayloadHeader payload_header; PayloadTransferFrame::PayloadHeader payload_header;
+2
View File
@@ -203,6 +203,8 @@ class PayloadManager : public EndpointManager::FrameProcessor {
static PayloadProgressInfo::Status PayloadStatusToTransferUpdateStatus( static PayloadProgressInfo::Status PayloadStatusToTransferUpdateStatus(
proto::connections::PayloadStatus status); proto::connections::PayloadStatus status);
int GetOptimalChunkSize(EndpointIds endpoint_ids);
PayloadTransferFrame::PayloadHeader CreatePayloadHeader( PayloadTransferFrame::PayloadHeader CreatePayloadHeader(
const InternalPayload& payload); const InternalPayload& payload);
PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset, PayloadTransferFrame::PayloadChunk CreatePayloadChunk(std::int64_t offset,
+1
View File
@@ -79,6 +79,7 @@ cc_library(
"platform.h", "platform.h",
], ],
visibility = [ visibility = [
"//googlemac/iPhone/Shared/Nearby/Connections_v2:__subpackages__",
"//platform/base:__pkg__", "//platform/base:__pkg__",
"//platform/impl:__subpackages__", "//platform/impl:__subpackages__",
"//platform/public:__pkg__", "//platform/public:__pkg__",
+4 -4
View File
@@ -61,14 +61,14 @@ void WebRtcMedium::CreatePeerConnection(
webrtc::PeerConnectionInterface::RTCConfiguration rtc_config; webrtc::PeerConnectionInterface::RTCConfiguration rtc_config;
webrtc::PeerConnectionDependencies dependencies(observer); webrtc::PeerConnectionDependencies dependencies(observer);
signaling_thread_ = rtc::Thread::Create(); std::unique_ptr<rtc::Thread> signaling_thread = rtc::Thread::Create();
signaling_thread_->SetName("signaling_thread", nullptr); signaling_thread->SetName("signaling_thread", nullptr);
RTC_CHECK(signaling_thread_->Start()) << "Failed to start thread"; RTC_CHECK(signaling_thread->Start()) << "Failed to start thread";
webrtc::PeerConnectionFactoryDependencies factory_dependencies; webrtc::PeerConnectionFactoryDependencies factory_dependencies;
factory_dependencies.task_queue_factory = factory_dependencies.task_queue_factory =
webrtc::CreateDefaultTaskQueueFactory(); webrtc::CreateDefaultTaskQueueFactory();
factory_dependencies.signaling_thread = signaling_thread_.get(); factory_dependencies.signaling_thread = signaling_thread.release();
callback(webrtc::CreateModularPeerConnectionFactory( callback(webrtc::CreateModularPeerConnectionFactory(
std::move(factory_dependencies)) std::move(factory_dependencies))
-1
View File
@@ -65,7 +65,6 @@ class WebRtcMedium : public api::WebRtcMedium {
const connections::LocationHint& location_hint) override; const connections::LocationHint& location_hint) override;
private: private:
std::unique_ptr<rtc::Thread> signaling_thread_;
}; };
} // namespace g3 } // namespace g3