mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-16 15:36:12 -04:00
Windows doesn't support BWU from WIFI_LAN to WIFI_HOTSPOT. Because when the discoverer side try to switch from current AP to the Hotspot, it loss physical connection. When here's no physical connection, BWU protocol frame exchange won't be finished successfully, then BWU will fail eventually. In the current code implementation, if Windows Nearby act as Advertiser, it will not do BWU from WLAN to Hotspot. This CL adds similar logic when Windows Nearby act as discoverer. PiperOrigin-RevId: 453248717
177 lines
7.3 KiB
C++
177 lines
7.3 KiB
C++
// Copyright 2020 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_ENDPOINT_CHANNEL_MANAGER_H_
|
|
#define CORE_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_
|
|
|
|
#include <memory>
|
|
#include <string>
|
|
|
|
#include "securegcm/d2d_connection_context_v1.h"
|
|
#include "absl/container/flat_hash_map.h"
|
|
#include "connections/implementation/client_proxy.h"
|
|
#include "connections/implementation/endpoint_channel.h"
|
|
#include "internal/platform/logging.h"
|
|
#include "internal/platform/mutex.h"
|
|
|
|
namespace location {
|
|
namespace nearby {
|
|
namespace connections {
|
|
|
|
// NOTE(std::string):
|
|
// All the strings in internal class public interfaces should be exchanged as
|
|
// const std::string& if they are immutable, and as std::string if they are
|
|
// mutable.
|
|
// This is to keep all the internal classes compatible with each other,
|
|
// and minimize resources spent on the type conversion.
|
|
// Project-wide, strings are either passed around as reference (which has
|
|
// zero maintenance costs, and sizeof(void*) memory usage => passed around in a
|
|
// CPU register), and whenever lifetime etension is required, it must be copied
|
|
// to std::string instance (which will again propagate as a const reference
|
|
// within it's lifetime domain).
|
|
|
|
// Manages the communication channels to all the remote endpoints with which we
|
|
// are interacting.
|
|
class EndpointChannelManager final {
|
|
public:
|
|
using EncryptionContext = EndpointChannel::EncryptionContext;
|
|
|
|
~EndpointChannelManager();
|
|
|
|
// Registers the initial EndpointChannel to be associated with an endpoint;
|
|
// if there already exists a previously-associated EndpointChannel, that will
|
|
// be closed before continuing the registration.
|
|
void RegisterChannelForEndpoint(ClientProxy* client,
|
|
const std::string& endpoint_id,
|
|
std::unique_ptr<EndpointChannel> channel)
|
|
ABSL_LOCKS_EXCLUDED(mutex_);
|
|
|
|
// Replaces the EndpointChannel to be associated with an endpoint from here on
|
|
// in, transferring the encryption context from the previous EndpointChannel
|
|
// to the newly-provided EndpointChannel.
|
|
void ReplaceChannelForEndpoint(ClientProxy* client,
|
|
const std::string& endpoint_id,
|
|
std::unique_ptr<EndpointChannel> channel)
|
|
ABSL_LOCKS_EXCLUDED(mutex_);
|
|
|
|
bool EncryptChannelForEndpoint(const std::string& endpoint_id,
|
|
std::unique_ptr<EncryptionContext> context)
|
|
ABSL_LOCKS_EXCLUDED(mutex_);
|
|
|
|
// NOTE(shared_ptr<> usage):
|
|
//
|
|
// EndpointChannelManager is holding an EndpointChannel instance;
|
|
// GetChannelForEndpoint() is passing ownership over to a worker thread.
|
|
// It is not a pointer passing but an ownership passing, to guarantee that
|
|
// channel instance will not disappear underneath the feet of a worker thread
|
|
// inside EndpointManager [ EndpointManager::EndpointChannelLoopRunnable() ].
|
|
// If it is just a pointer, Channel will get destroyed while in use by a
|
|
// worker thread. shared_ptr is a simple and reliable tool to avoid that.
|
|
//
|
|
// The reason why it can not be std::unique_ptr<> is: there are other code
|
|
// paths that expect to be able to read the pointer value multiple times, from
|
|
// multiple places (each of them needs "ownership" for the duration of their
|
|
// use). EndpointManager::SendTransferFrameBytes() is another such place.
|
|
// If EndpointChannelManager replaces the current channel, and any (or both)
|
|
// EndpointManager methods that use a channel are running, it is better to
|
|
// have a shared ownership.
|
|
std::shared_ptr<EndpointChannel> GetChannelForEndpoint(
|
|
const std::string& endpoint_id) ABSL_LOCKS_EXCLUDED(mutex_);
|
|
|
|
// Returns true if 'endpoint_id' actually had a registered EndpointChannel.
|
|
// IOW, a return of false signifies a no-op.
|
|
bool UnregisterChannelForEndpoint(const std::string& endpoint_id)
|
|
ABSL_LOCKS_EXCLUDED(mutex_);
|
|
|
|
int GetConnectedEndpointsCount() const ABSL_LOCKS_EXCLUDED(mutex_);
|
|
|
|
// Check if any endpoint uses WLAN Medium
|
|
bool isWifiLanConnected() const ABSL_LOCKS_EXCLUDED(mutex_);
|
|
|
|
private:
|
|
// Tracks channel state for all endpoints. This includes what EndpointChannel
|
|
// the endpoint is currently using and whether or not the EndpointChannel has
|
|
// been encrypted yet.
|
|
class ChannelState {
|
|
public:
|
|
struct EndpointData {
|
|
EndpointData() = default;
|
|
EndpointData(EndpointData&&) = default;
|
|
EndpointData& operator=(EndpointData&&) = default;
|
|
~EndpointData() {
|
|
if (channel != nullptr) {
|
|
channel->Close(disconnect_reason);
|
|
}
|
|
}
|
|
|
|
// True if we have a 'context' for the endpoint.
|
|
bool IsEncrypted() const { return context != nullptr; }
|
|
|
|
std::shared_ptr<EndpointChannel> channel;
|
|
std::shared_ptr<EncryptionContext> context;
|
|
proto::connections::DisconnectionReason disconnect_reason =
|
|
proto::connections::DisconnectionReason::UNKNOWN_DISCONNECTION_REASON;
|
|
};
|
|
|
|
ChannelState() = default;
|
|
~ChannelState() { DestroyAll(); }
|
|
ChannelState(ChannelState&&) = default;
|
|
ChannelState& operator=(ChannelState&&) = default;
|
|
|
|
// Provides a way to destroy contents of a container, while holding a lock.
|
|
void DestroyAll() { endpoints_.clear(); }
|
|
// Return pointer to endpoint data, or nullptr, it not found.
|
|
EndpointData* LookupEndpointData(const std::string& endpoint_id);
|
|
|
|
// Stores a new EndpointChannel for the endpoint.
|
|
// Prevoius one is destroyed, if it existed.
|
|
void UpdateChannelForEndpoint(const std::string& endpoint_id,
|
|
std::unique_ptr<EndpointChannel> channel);
|
|
|
|
// Stores a new EncryptionContext for the endpoint.
|
|
// Prevoius one is destroyed, if it existed.
|
|
void UpdateEncryptionContextForEndpoint(
|
|
const std::string& endpoint_id,
|
|
std::unique_ptr<EncryptionContext> context);
|
|
|
|
// Removes all knowledge of this endpoint, cleaning up as necessary.
|
|
// Returns false if the endpoint was not found.
|
|
bool RemoveEndpoint(const std::string& endpoint_id,
|
|
proto::connections::DisconnectionReason reason);
|
|
|
|
bool EncryptChannel(EndpointData* endpoint);
|
|
int GetConnectedEndpointsCount() const { return endpoints_.size(); }
|
|
bool isWifiLanConnected() const;
|
|
|
|
private:
|
|
// Endpoint ID -> EndpointData. Contains everything we know about the
|
|
// endpoint.
|
|
absl::flat_hash_map<std::string, EndpointData> endpoints_;
|
|
};
|
|
|
|
void SetActiveEndpointChannel(ClientProxy* client,
|
|
const std::string& endpoint_id,
|
|
std::unique_ptr<EndpointChannel> channel)
|
|
ABSL_EXCLUSIVE_LOCKS_REQUIRED(mutex_);
|
|
|
|
mutable Mutex mutex_;
|
|
ChannelState channel_state_ ABSL_GUARDED_BY(mutex_);
|
|
};
|
|
|
|
} // namespace connections
|
|
} // namespace nearby
|
|
} // namespace location
|
|
|
|
#endif // CORE_INTERNAL_ENDPOINT_CHANNEL_MANAGER_H_
|