mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 14:46:12 -04:00
239 lines
9.8 KiB
C++
239 lines
9.8 KiB
C++
// Copyright 2023 Google LLC
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#ifndef CORE_INTERNAL_RECONNECTION_MANAGER_H_
|
|
#define CORE_INTERNAL_RECONNECTION_MANAGER_H_
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
#include <utility>
|
|
|
|
#include "securegcm/ukey2_handshake.h"
|
|
#include "absl/base/thread_annotations.h"
|
|
#include "absl/container/flat_hash_map.h"
|
|
#include "absl/container/flat_hash_set.h"
|
|
#include "absl/functional/any_invocable.h"
|
|
#include "connections/implementation/client_proxy.h"
|
|
#include "connections/implementation/encryption_runner.h"
|
|
#include "connections/implementation/endpoint_channel.h"
|
|
#include "connections/implementation/endpoint_channel_manager.h"
|
|
#include "connections/implementation/mediums/bluetooth_classic.h"
|
|
#include "connections/implementation/mediums/mediums.h"
|
|
#include "connections/implementation/proto/offline_wire_formats.pb.h"
|
|
#include "internal/platform/bluetooth_classic.h"
|
|
#include "internal/platform/byte_array.h"
|
|
#include "internal/platform/cancelable_alarm.h"
|
|
#include "internal/platform/count_down_latch.h"
|
|
#include "internal/platform/mutex.h"
|
|
#include "internal/platform/scheduled_executor.h"
|
|
#include "internal/platform/single_thread_executor.h"
|
|
|
|
namespace nearby {
|
|
namespace connections {
|
|
using AutoReconnectFrame = ::location::nearby::connections::AutoReconnectFrame;
|
|
using OfflineFrame = ::location::nearby::connections::OfflineFrame;
|
|
using Medium = ::location::nearby::proto::connections::Medium;
|
|
using DisconnectionReason =
|
|
::location::nearby::proto::connections::DisconnectionReason;
|
|
|
|
class ReconnectManager {
|
|
public:
|
|
ReconnectManager(Mediums& mediums, EndpointChannelManager& channel_manager);
|
|
~ReconnectManager();
|
|
|
|
struct AutoReconnectCallback {
|
|
absl::AnyInvocable<void(ClientProxy*, const std::string& endpoint_id)>
|
|
on_reconnect_success_cb;
|
|
absl::AnyInvocable<void(ClientProxy*, const std::string& endpoint_id,
|
|
bool send_disconnection_notification,
|
|
DisconnectionReason disconnection_reason)>
|
|
on_reconnect_failure_cb;
|
|
};
|
|
|
|
struct ReconnectMetadata {
|
|
ReconnectMetadata(bool is_incoming, AutoReconnectCallback callback,
|
|
bool send_disconnection_notification,
|
|
DisconnectionReason disconnection_reason,
|
|
const std::string& reconnect_service_id)
|
|
: reconnect_service_id(reconnect_service_id),
|
|
is_incoming(is_incoming),
|
|
send_disconnection_notification(send_disconnection_notification),
|
|
disconnection_reason(disconnection_reason) {
|
|
reconnect_cb = std::move(callback);
|
|
}
|
|
~ReconnectMetadata() noexcept = default;
|
|
ReconnectMetadata(ReconnectMetadata&&) = default;
|
|
ReconnectMetadata& operator=(ReconnectMetadata&&) = default;
|
|
|
|
AutoReconnectCallback reconnect_cb;
|
|
std::string reconnect_service_id;
|
|
bool is_incoming;
|
|
bool send_disconnection_notification;
|
|
DisconnectionReason disconnection_reason =
|
|
DisconnectionReason::UNKNOWN_DISCONNECTION_REASON;
|
|
};
|
|
|
|
// The entry point for AutoReconect, this API will do the auto reconnect for
|
|
// specified "endpoint_id" which connection was lost before.
|
|
bool AutoReconnect(ClientProxy* client, const std::string& endpoint_id,
|
|
AutoReconnectCallback& callback,
|
|
bool send_disconnection_notification,
|
|
DisconnectionReason disconnection_reason);
|
|
|
|
private:
|
|
class MediumConnectionProcessor {
|
|
public:
|
|
virtual ~MediumConnectionProcessor() = default;
|
|
|
|
virtual bool IsMediumRadioOn() const = 0;
|
|
virtual bool IsListeningForIncomingConnections() const = 0;
|
|
virtual bool StartListeningForIncomingConnections() = 0;
|
|
virtual void StopListeningForIncomingConnections() = 0;
|
|
virtual bool ConnectOverMedium() = 0;
|
|
virtual bool SupportEncryptionDisabled() = 0;
|
|
virtual void QuietlyCloseChannelAndSocket() = 0;
|
|
};
|
|
|
|
class BaseMediumImpl : public MediumConnectionProcessor {
|
|
public:
|
|
BaseMediumImpl(ClientProxy* client, const std::string& endpoint_id,
|
|
const std::string& reconnect_service_id, bool is_incoming,
|
|
Medium medium, Mediums* mediums,
|
|
EndpointChannelManager* channel_manager,
|
|
ReconnectManager& reconnect_manager)
|
|
: client_(client),
|
|
endpoint_id_(endpoint_id),
|
|
reconnect_service_id_(reconnect_service_id),
|
|
is_incoming_(is_incoming),
|
|
medium_(medium),
|
|
mediums_(mediums),
|
|
channel_manager_(channel_manager),
|
|
reconnect_manager_(reconnect_manager) {}
|
|
~BaseMediumImpl() override = default;
|
|
|
|
bool Run();
|
|
|
|
protected:
|
|
ClientProxy* client_;
|
|
std::string endpoint_id_;
|
|
std::string reconnect_service_id_;
|
|
bool is_incoming_;
|
|
Medium medium_ = Medium::UNKNOWN_MEDIUM;
|
|
Mediums* mediums_;
|
|
EndpointChannelManager* channel_manager_;
|
|
std::unique_ptr<EndpointChannel> reconnect_channel_;
|
|
ReconnectManager& reconnect_manager_;
|
|
void OnIncomingConnection(const std::string& reconnect_service_id);
|
|
|
|
private:
|
|
bool RehostForIncomingConnections(bool is_last_medium);
|
|
bool ReconnectToRemoteDevice();
|
|
|
|
std::string ReadClientIntroductionFrame(EndpointChannel* endpoint_channel);
|
|
bool ReadClientIntroductionAckFrame(EndpointChannel* endpoint_channel);
|
|
bool ReplaceChannelForEndpoint(
|
|
ClientProxy* client, const std::string& endpoint_id,
|
|
std::unique_ptr<EndpointChannel> new_channel,
|
|
bool support_encryption_disabled,
|
|
absl::AnyInvocable<void(void)> stop_listening_incoming_connection);
|
|
EncryptionRunner::ResultListener GetResultListener();
|
|
void OnEncryptionSuccessRunnable(
|
|
const std::string& endpoint_id,
|
|
std::unique_ptr<securegcm::UKey2Handshake> ukey2,
|
|
const std::string& auth_token, const ByteArray& raw_auth_token);
|
|
void OnEncryptionFailureRunnable(const std::string& endpoint_id,
|
|
EndpointChannel* endpoint_channel);
|
|
void ProcessSuccessfulReconnection(
|
|
const std::string& endpoint_id,
|
|
absl::AnyInvocable<void(void)> stop_listening_incoming_connection);
|
|
void ProcessFailedReconnection(
|
|
const std::string& endpoint_id,
|
|
absl::AnyInvocable<void(void)> stop_listening_incoming_connection);
|
|
void StopListeningIfAllConnected(
|
|
const std::string& reconnect_service_id,
|
|
absl::AnyInvocable<void(void)> stop_listening_incoming_connection,
|
|
bool force_stop);
|
|
bool HasPendingIncomingConnections(const std::string& reconnect_service_id);
|
|
void CancelClearHostTimeoutAlarm(const std::string& service_id);
|
|
void ClearReconnectData(const std::string& service_id, bool is_incoming);
|
|
|
|
mutable Mutex mutex_;
|
|
std::unique_ptr<CountDownLatch> wait_encryption_to_finish_;
|
|
bool replace_channel_succeed_ ABSL_GUARDED_BY(mutex_)= false;
|
|
};
|
|
|
|
class BluetoothImpl : public BaseMediumImpl {
|
|
public:
|
|
BluetoothImpl(ClientProxy* client_proxy, const std::string& endpoint_id,
|
|
const std::string& reconnect_service_id, bool is_incoming,
|
|
Medium medium, Mediums* mediums,
|
|
EndpointChannelManager* channel_manager,
|
|
ReconnectManager& reconnect_manager)
|
|
: BaseMediumImpl(client_proxy, endpoint_id, reconnect_service_id,
|
|
is_incoming, medium, mediums, channel_manager,
|
|
reconnect_manager),
|
|
bluetooth_medium_(mediums_->GetBluetoothClassic()) {}
|
|
|
|
bool IsMediumRadioOn() const override;
|
|
bool IsListeningForIncomingConnections() const override;
|
|
bool StartListeningForIncomingConnections() override;
|
|
void StopListeningForIncomingConnections() override;
|
|
bool ConnectOverMedium() override;
|
|
bool SupportEncryptionDisabled() override;
|
|
void QuietlyCloseChannelAndSocket() override;
|
|
|
|
private:
|
|
void OnIncomingBluetoothConnection(ClientProxy* client,
|
|
const std::string& upgrade_service_id,
|
|
BluetoothSocket socket);
|
|
|
|
BluetoothClassic& bluetooth_medium_;
|
|
BluetoothSocket bluetooth_socket_;
|
|
};
|
|
|
|
bool Start(bool is_incoming, ClientProxy* client_proxy,
|
|
const std::string& endpoint_id,
|
|
const std::string& reconnect_service_id, Medium medium);
|
|
bool RunOnce(bool is_incoming, ClientProxy* client,
|
|
const std::string& endpoint_id,
|
|
const std::string& reconnect_service_id, Medium medium);
|
|
|
|
void ClearReconnectData(ClientProxy* client,
|
|
const std::string& reconnect_service_id,
|
|
bool is_incoming);
|
|
void Shutdown();
|
|
|
|
Mediums* mediums_;
|
|
EndpointChannelManager* channel_manager_;
|
|
EncryptionRunner encryption_runner_;
|
|
|
|
SingleThreadExecutor reconnect_executor_;
|
|
ScheduledExecutor alarm_executor_;
|
|
SingleThreadExecutor incoming_connection_cb_executor_;
|
|
SingleThreadExecutor encryption_cb_executor_;
|
|
|
|
mutable RecursiveMutex mutex_;
|
|
absl::flat_hash_map<std::string, std::unique_ptr<CancelableAlarm>>
|
|
listen_timeout_alarm_by_service_id_ ABSL_GUARDED_BY(mutex_);
|
|
absl::flat_hash_map<std::string, std::unique_ptr<EndpointChannel>>
|
|
new_endpoint_channels_;
|
|
absl::flat_hash_map<std::string, ReconnectMetadata> endpoint_id_metadata_map_;
|
|
absl::flat_hash_set<std::string> resumed_endpoints_;
|
|
};
|
|
|
|
} // namespace connections
|
|
} // namespace nearby
|
|
|
|
#endif // CORE_INTERNAL_RECONNECTION_MANAGER_H_
|