mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Fixed the deadlock in BluetoothServerSocket
PiperOrigin-RevId: 460724338
This commit is contained in:
committed by
Copybara-Service
parent
e4a0f280e2
commit
bff4051015
@@ -147,6 +147,10 @@ bool BluetoothAdapter::SetScanMode(ScanMode scan_mode) {
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#getName()
|
||||
// Returns an empty string on error
|
||||
std::string BluetoothAdapter::GetName() const {
|
||||
if (device_name_.has_value()) {
|
||||
return *device_name_;
|
||||
}
|
||||
|
||||
std::string instance_id(GetGenericBluetoothAdapterInstanceID());
|
||||
|
||||
if (instance_id.empty()) {
|
||||
@@ -217,9 +221,12 @@ bool BluetoothAdapter::SetName(absl::string_view name) {
|
||||
"Android cannot discover Windows bluetooth device "
|
||||
"name that exceeded the 37 bytes limit (11 "
|
||||
"characters in EndpointInfo).";
|
||||
return false;
|
||||
device_name_ = std::string(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
device_name_ = std::nullopt;
|
||||
|
||||
if (registry_bluetooth_adapter_name_ == name) {
|
||||
NEARBY_LOGS(INFO)
|
||||
<< __func__
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include <windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "internal/platform/implementation/bluetooth_adapter.h"
|
||||
@@ -100,11 +101,15 @@ class BluetoothAdapter : public api::BluetoothAdapter {
|
||||
std::string registry_bluetooth_adapter_name_;
|
||||
|
||||
IRadio windows_bluetooth_radio_;
|
||||
char *GetGenericBluetoothAdapterInstanceID(void) const;
|
||||
char *GetGenericBluetoothAdapterInstanceID() const;
|
||||
void find_and_replace(char *source, const char *strFind,
|
||||
const char *strReplace) const;
|
||||
ScanMode scan_mode_ = ScanMode::kNone;
|
||||
ScanModeCallback scan_mode_changed_ = nullptr;
|
||||
|
||||
// Used to fake the device name when the device name is longer than android
|
||||
// limitation.
|
||||
std::optional<std::string> device_name_;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/cancellation_flag.h"
|
||||
#include "internal/platform/cancellation_flag_listener.h"
|
||||
#include "internal/platform/exception.h"
|
||||
@@ -43,11 +44,11 @@ namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
constexpr uint8_t kAndroidDiscoverableBluetoothNameMaxLength = 37; // bytes
|
||||
|
||||
BluetoothClassicMedium::BluetoothClassicMedium(
|
||||
api::BluetoothAdapter& bluetoothAdapter)
|
||||
: bluetooth_adapter_(dynamic_cast<BluetoothAdapter&>(bluetoothAdapter)) {
|
||||
InitializeCriticalSection(&critical_section_);
|
||||
|
||||
InitializeDeviceWatcher();
|
||||
|
||||
bluetooth_adapter_.SetOnScanModeChanged(std::bind(
|
||||
@@ -58,19 +59,60 @@ BluetoothClassicMedium::~BluetoothClassicMedium() {}
|
||||
|
||||
void BluetoothClassicMedium::OnScanModeChanged(
|
||||
BluetoothAdapter::ScanMode scanMode) {
|
||||
scan_mode_ = scanMode;
|
||||
bool radioDiscoverable = bluetooth_adapter_.GetScanMode() ==
|
||||
BluetoothAdapter::ScanMode::kConnectableDiscoverable;
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
if (bluetooth_server_socket_ != nullptr) {
|
||||
bluetooth_server_socket_->SetScanMode(radioDiscoverable);
|
||||
NEARBY_LOGS(INFO) << __func__
|
||||
<< ": OnScanModeChanged is called with scanMode: "
|
||||
<< static_cast<int>(scanMode);
|
||||
|
||||
if (scanMode == scan_mode_) {
|
||||
NEARBY_LOGS(INFO) << __func__ << ": No change of scan mode.";
|
||||
return;
|
||||
}
|
||||
|
||||
scan_mode_ = scanMode;
|
||||
bool radio_discoverable =
|
||||
scan_mode_ == BluetoothAdapter::ScanMode::kConnectableDiscoverable;
|
||||
|
||||
if (bluetooth_adapter_.GetName().size() >
|
||||
kAndroidDiscoverableBluetoothNameMaxLength) {
|
||||
// If the name longer than the android limitation, always set the value to
|
||||
// false.
|
||||
radio_discoverable = false;
|
||||
}
|
||||
|
||||
if (is_radio_discoverable_ == radio_discoverable) {
|
||||
NEARBY_LOGS(INFO) << __func__ << ": No change of radio discovery.";
|
||||
return;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ == nullptr) {
|
||||
NEARBY_LOGS(INFO) << __func__ << ": No advertising.";
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
rfcomm_provider_.StopAdvertising();
|
||||
rfcomm_provider_.StartAdvertising(
|
||||
raw_server_socket_->stream_socket_listener(), radio_discoverable);
|
||||
is_radio_discoverable_ = radio_discoverable;
|
||||
return;
|
||||
} catch (std::exception exception) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": OnScanModeChanged exception: " << exception.what();
|
||||
return;
|
||||
} catch (const winrt::hresult_error& ex) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": OnScanModeChanged exception: " << ex.code() << ": "
|
||||
<< winrt::to_string(ex.message());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::StartDiscovery(
|
||||
BluetoothClassicMedium::DiscoveryCallback discovery_callback) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "StartDiscovery is called.";
|
||||
EnterCriticalSection(&critical_section_);
|
||||
|
||||
bool result = false;
|
||||
discovery_callback_ = discovery_callback;
|
||||
@@ -79,14 +121,12 @@ bool BluetoothClassicMedium::StartDiscovery(
|
||||
result = StartScanning();
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::StopDiscovery() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "StopDiscovery is called.";
|
||||
EnterCriticalSection(&critical_section_);
|
||||
|
||||
bool result = false;
|
||||
|
||||
@@ -94,8 +134,6 @@ bool BluetoothClassicMedium::StopDiscovery() {
|
||||
result = StopScanning();
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -138,6 +176,7 @@ void BluetoothClassicMedium::InitializeDeviceWatcher() {
|
||||
std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
api::BluetoothDevice& remote_device, const std::string& service_uuid,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "ConnectToService is called.";
|
||||
if (service_uuid.empty()) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": service_uuid not specified.";
|
||||
@@ -220,8 +259,6 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
EnterCriticalSection(&critical_section_);
|
||||
|
||||
std::unique_ptr<BluetoothSocket> rfcomm_socket =
|
||||
std::make_unique<BluetoothSocket>();
|
||||
|
||||
@@ -230,7 +267,6 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
<< __func__
|
||||
<< ": Bluetooth Classic socket connection cancelled for device: "
|
||||
<< winrt::to_string(device_id) << ", service: " << service_uuid;
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
return nullptr;
|
||||
}
|
||||
location::nearby::CancellationFlagListener cancellation_flag_listener(
|
||||
@@ -244,7 +280,6 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
rfcomm_socket->Connect(requested_service.ConnectionHostName(),
|
||||
requested_service.ConnectionServiceName());
|
||||
if (!success) {
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
return nullptr;
|
||||
}
|
||||
} catch (std::exception exception) {
|
||||
@@ -252,14 +287,9 @@ std::unique_ptr<api::BluetoothSocket> BluetoothClassicMedium::ConnectToService(
|
||||
// expects nullptr if it fails
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Exception connecting bluetooth async: "
|
||||
<< exception.what();
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return std::move(rfcomm_socket);
|
||||
}
|
||||
|
||||
@@ -345,6 +375,7 @@ bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requestedService) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothAdapter.html#listenUsingInsecureRfcommWithServiceRecord
|
||||
//
|
||||
// service_uuid is the canonical textual representation
|
||||
@@ -357,6 +388,7 @@ bool BluetoothClassicMedium::CheckSdp(RfcommDeviceService requestedService) {
|
||||
std::unique_ptr<api::BluetoothServerSocket>
|
||||
BluetoothClassicMedium::ListenForService(const std::string& service_name,
|
||||
const std::string& service_uuid) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "ListenForService is called with service name: "
|
||||
<< service_name << ".";
|
||||
if (service_uuid.empty()) {
|
||||
@@ -369,26 +401,24 @@ BluetoothClassicMedium::ListenForService(const std::string& service_name,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto bluetooth_server_socket =
|
||||
std::make_unique<location::nearby::windows::BluetoothServerSocket>(
|
||||
service_name, service_uuid);
|
||||
service_name_ = service_name;
|
||||
service_uuid_ = service_uuid;
|
||||
|
||||
if (bluetooth_server_socket == nullptr) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Failed to create the server socket.";
|
||||
return nullptr;
|
||||
}
|
||||
scan_mode_ = bluetooth_adapter_.GetScanMode();
|
||||
|
||||
bool radioDiscoverable = bluetooth_adapter_.GetScanMode() ==
|
||||
BluetoothAdapter::ScanMode::kConnectableDiscoverable;
|
||||
NEARBY_LOGS(INFO) << __func__
|
||||
<< ": scan_mode: " << static_cast<int>(scan_mode_);
|
||||
bool radio_discoverable =
|
||||
scan_mode_ == BluetoothAdapter::ScanMode::kConnectableDiscoverable;
|
||||
|
||||
Exception result = bluetooth_server_socket->StartListening(radioDiscoverable);
|
||||
bool result = StartAdvertising(radio_discoverable);
|
||||
|
||||
if (result.value != Exception::kSuccess) {
|
||||
if (!result) {
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Failed to start listening.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::move(bluetooth_server_socket);
|
||||
return std::move(server_socket_);
|
||||
}
|
||||
|
||||
api::BluetoothDevice* BluetoothClassicMedium::GetRemoteDevice(
|
||||
@@ -432,7 +462,7 @@ bool BluetoothClassicMedium::StopScanning() {
|
||||
|
||||
winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Added(
|
||||
DeviceWatcher sender, DeviceInformation deviceInfo) {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "Device added " << winrt::to_string(deviceInfo.Id());
|
||||
if (IsWatcherStarted()) {
|
||||
// Represents a Bluetooth device.
|
||||
@@ -449,8 +479,6 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Added(
|
||||
// We're already tracking this one NEARBY_LOGS(INFO) <<
|
||||
// "DeviceWatcher_Added entered critical section.";
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
@@ -471,14 +499,12 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Added(
|
||||
}
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
|
||||
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
absl::MutexLock lock(&mutex_);
|
||||
|
||||
NEARBY_LOGS(INFO)
|
||||
<< "Device updated "
|
||||
@@ -487,14 +513,12 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
|
||||
|
||||
if (!IsWatcherStarted()) {
|
||||
// Spurious call, watcher has stopped or wasn't started
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
auto it = discovered_devices_by_id_.find(deviceInfoUpdate.Id());
|
||||
|
||||
if (it == discovered_devices_by_id_.end()) {
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
// Not tracking this device
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
@@ -505,21 +529,17 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Updated(
|
||||
*discovered_devices_by_id_[deviceInfoUpdate.Id()]);
|
||||
}
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Removed(
|
||||
DeviceWatcher sender, DeviceInformationUpdate deviceInfo) {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << "Device removed "
|
||||
<< discovered_devices_by_id_[deviceInfo.Id()]->GetName()
|
||||
<< " (" << winrt::to_string(deviceInfo.Id()) << ")";
|
||||
|
||||
if (!IsWatcherStarted()) {
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
@@ -530,8 +550,6 @@ winrt::fire_and_forget BluetoothClassicMedium::DeviceWatcher_Removed(
|
||||
|
||||
discovered_devices_by_id_.erase(deviceInfo.Id());
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return winrt::fire_and_forget();
|
||||
}
|
||||
|
||||
@@ -556,6 +574,151 @@ bool BluetoothClassicMedium::IsWatcherRunning() {
|
||||
(status == DeviceWatcherStatus::Stopping);
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::StartAdvertising(bool radio_discoverable) {
|
||||
NEARBY_LOGS(INFO) << __func__
|
||||
<< ": StartAdvertising is called with radio_discoverable: "
|
||||
<< radio_discoverable << ".";
|
||||
|
||||
try {
|
||||
if (rfcomm_provider_ != nullptr &&
|
||||
is_radio_discoverable_ == radio_discoverable) {
|
||||
NEARBY_LOGS(WARNING) << __func__
|
||||
<< ": Ignore StartAdvertising due to no change to "
|
||||
"current advertising.";
|
||||
return true;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ != nullptr && !StopAdvertising()) {
|
||||
NEARBY_LOGS(WARNING) << __func__
|
||||
<< ": Failed to StartAdvertising due to cannot stop "
|
||||
"running advertising.";
|
||||
return false;
|
||||
}
|
||||
|
||||
rfcomm_provider_ =
|
||||
RfcommServiceProvider::CreateAsync(
|
||||
RfcommServiceId::FromUuid(winrt::guid(service_uuid_)))
|
||||
.get();
|
||||
|
||||
server_socket_ = std::make_unique<BluetoothServerSocket>(
|
||||
winrt::to_string(rfcomm_provider_.ServiceId().AsString()));
|
||||
|
||||
raw_server_socket_ = server_socket_.get();
|
||||
|
||||
if (!server_socket_->listen()) {
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< __func__
|
||||
<< ": Failed to StartAdvertising due to cannot start socket.";
|
||||
server_socket_->Close();
|
||||
server_socket_ = nullptr;
|
||||
rfcomm_provider_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
server_socket_->SetCloseNotifier([&]() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
StopAdvertising();
|
||||
});
|
||||
|
||||
// Set the SDP attributes and start Bluetooth advertising
|
||||
InitializeServiceSdpAttributes(rfcomm_provider_, service_name_);
|
||||
|
||||
// Start to advertising.
|
||||
rfcomm_provider_.StartAdvertising(server_socket_->stream_socket_listener(),
|
||||
radio_discoverable);
|
||||
is_radio_discoverable_ = radio_discoverable;
|
||||
|
||||
NEARBY_LOGS(INFO) << ": StartListening completed successfully.";
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
// We will log and eat the exception since the caller
|
||||
// expects nullptr if it fails
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Exception setting up for listen: "
|
||||
<< exception.what();
|
||||
|
||||
if (server_socket_ != nullptr) {
|
||||
server_socket_->Close();
|
||||
server_socket_ = nullptr;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ != nullptr) {
|
||||
rfcomm_provider_ = nullptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
} catch (const winrt::hresult_error& ex) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": Exception setting up for listen: " << ex.code()
|
||||
<< ": " << winrt::to_string(ex.message());
|
||||
if (server_socket_ != nullptr) {
|
||||
server_socket_->Close();
|
||||
server_socket_ = nullptr;
|
||||
}
|
||||
|
||||
if (rfcomm_provider_ != nullptr) {
|
||||
rfcomm_provider_ = nullptr;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::StopAdvertising() {
|
||||
NEARBY_LOGS(INFO) << __func__ << ": StopAdvertising is called";
|
||||
|
||||
try {
|
||||
if (rfcomm_provider_ == nullptr) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": Ignore StopAdvertising due to no advertising.";
|
||||
return true;
|
||||
}
|
||||
|
||||
rfcomm_provider_.StopAdvertising();
|
||||
rfcomm_provider_ = nullptr;
|
||||
raw_server_socket_ = nullptr;
|
||||
server_socket_ = nullptr;
|
||||
|
||||
NEARBY_LOGS(INFO) << ": StopAdvertising completed successfully.";
|
||||
return true;
|
||||
} catch (std::exception exception) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": StopAdvertising exception: " << exception.what();
|
||||
return false;
|
||||
} catch (const winrt::hresult_error& ex) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": StopAdvertising exception: " << ex.code() << ": "
|
||||
<< winrt::to_string(ex.message());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothClassicMedium::InitializeServiceSdpAttributes(
|
||||
RfcommServiceProvider rfcomm_provider, std::string service_name) {
|
||||
try {
|
||||
auto sdpWriter = DataWriter();
|
||||
|
||||
// Write the Service Name Attribute.
|
||||
sdpWriter.WriteByte(Constants::SdpServiceNameAttributeType);
|
||||
|
||||
// The length of the UTF-8 encoded Service Name SDP Attribute.
|
||||
sdpWriter.WriteByte(service_name.size());
|
||||
|
||||
// The UTF-8 encoded Service Name value.
|
||||
sdpWriter.UnicodeEncoding(UnicodeEncoding::Utf8);
|
||||
sdpWriter.WriteString(winrt::to_hstring(service_name));
|
||||
|
||||
// Set the SDP Attribute on the RFCOMM Service Provider.
|
||||
rfcomm_provider.SdpRawAttributes().Insert(
|
||||
Constants::SdpServiceNameAttributeId, sdpWriter.DetachBuffer());
|
||||
|
||||
return true;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": Failed to InitializeServiceSdpAttributes.";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
#ifndef PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_MEDIUM_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_BLUETOOTH_CLASSIC_MEDIUM_H_
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/bluetooth_classic.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_adapter.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_classic_device.h"
|
||||
@@ -47,6 +52,14 @@ using winrt::Windows::Devices::Enumeration::DeviceInformationUpdate;
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcher?view=winrt-20348
|
||||
using winrt::Windows::Devices::Enumeration::DeviceWatcher;
|
||||
|
||||
// Writes data to an output stream.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.datawriter?view=winrt-20348
|
||||
using winrt::Windows::Storage::Streams::DataWriter;
|
||||
|
||||
// Specifies the type of character encoding for a stream.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.unicodeencoding?view=winrt-20348
|
||||
using winrt::Windows::Storage::Streams::UnicodeEncoding;
|
||||
|
||||
// Describes the state of a DeviceWatcher object.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.enumeration.devicewatcherstatus?view=winrt-20348
|
||||
using winrt::Windows::Devices::Enumeration::DeviceWatcherStatus;
|
||||
@@ -67,6 +80,10 @@ using winrt::Windows::Devices::Enumeration::DeviceAccessInformation;
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommserviceid?view=winrt-20348
|
||||
using winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId;
|
||||
|
||||
// Represents an instance of a local RFCOMM service.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommserviceprovider?view=winrt-20348
|
||||
using winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceProvider;
|
||||
|
||||
// Reads data from an input stream.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.datareader?view=winrt-20348
|
||||
using winrt::Windows::Storage::Streams::DataReader;
|
||||
@@ -84,7 +101,7 @@ using winrt::Windows::Storage::Streams::DataWriter;
|
||||
// medium.
|
||||
class BluetoothClassicMedium : public api::BluetoothClassicMedium {
|
||||
public:
|
||||
BluetoothClassicMedium(api::BluetoothAdapter& bluetoothAdapter);
|
||||
explicit BluetoothClassicMedium(api::BluetoothAdapter& bluetoothAdapter);
|
||||
|
||||
~BluetoothClassicMedium() override;
|
||||
|
||||
@@ -134,6 +151,10 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
|
||||
private:
|
||||
bool StartScanning();
|
||||
bool StopScanning();
|
||||
bool StartAdvertising(bool radio_discoverable);
|
||||
bool StopAdvertising();
|
||||
bool InitializeServiceSdpAttributes(RfcommServiceProvider rfcomm_provider,
|
||||
std::string service_name);
|
||||
bool IsWatcherStarted();
|
||||
bool IsWatcherRunning();
|
||||
void InitializeDeviceWatcher();
|
||||
@@ -166,7 +187,6 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
|
||||
DeviceWatcher device_watcher_ = nullptr;
|
||||
|
||||
std::unique_ptr<BluetoothSocket> bluetooth_socket_;
|
||||
std::unique_ptr<BluetoothServerSocket> bluetooth_server_socket_;
|
||||
|
||||
std::string service_name_;
|
||||
std::string service_uuid_;
|
||||
@@ -176,14 +196,19 @@ class BluetoothClassicMedium : public api::BluetoothClassicMedium {
|
||||
std::map<winrt::hstring, std::unique_ptr<BluetoothDevice>>
|
||||
discovered_devices_by_id_;
|
||||
|
||||
// CRITICAL_SECTION is a lightweight synchronization mechanism
|
||||
// https://docs.microsoft.com/en-us/windows/win32/sync/critical-section-objects
|
||||
CRITICAL_SECTION critical_section_;
|
||||
|
||||
BluetoothAdapter& bluetooth_adapter_;
|
||||
|
||||
BluetoothAdapter::ScanMode scan_mode_;
|
||||
BluetoothAdapter::ScanMode scan_mode_ = BluetoothAdapter::ScanMode::kUnknown;
|
||||
std::unique_ptr<BluetoothDevice> remote_device_to_connect_;
|
||||
|
||||
// Used for advertising.
|
||||
RfcommServiceProvider rfcomm_provider_ = nullptr;
|
||||
std::unique_ptr<BluetoothServerSocket> server_socket_ = nullptr;
|
||||
BluetoothServerSocket* raw_server_socket_ = nullptr;
|
||||
bool is_radio_discoverable_ = false;
|
||||
|
||||
// Used to enable thread safe for APIs.
|
||||
absl::Mutex mutex_;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
|
||||
@@ -15,31 +15,24 @@
|
||||
#include "internal/platform/implementation/windows/bluetooth_classic_server_socket.h"
|
||||
|
||||
#include <codecvt>
|
||||
#include <functional>
|
||||
#include <locale>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
#include "internal/platform/exception.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_classic_socket.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.Collections.h"
|
||||
#include "internal/platform/implementation/windows/utils.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
BluetoothServerSocket::BluetoothServerSocket(const std::string service_name,
|
||||
const std::string service_uuid)
|
||||
: radio_discoverable_(false),
|
||||
service_name_(service_name),
|
||||
service_uuid_(service_uuid),
|
||||
rfcomm_provider_(nullptr) {
|
||||
InitializeCriticalSection(&critical_section_);
|
||||
}
|
||||
BluetoothServerSocket::BluetoothServerSocket(absl::string_view service_name)
|
||||
: service_name_(service_name) {}
|
||||
|
||||
BluetoothServerSocket::~BluetoothServerSocket() {}
|
||||
BluetoothServerSocket::~BluetoothServerSocket() { Close(); }
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#accept()
|
||||
//
|
||||
// Blocks until either:
|
||||
// - at least one incoming connection request is available, or
|
||||
// - ServerSocket is closed.
|
||||
@@ -47,166 +40,106 @@ BluetoothServerSocket::~BluetoothServerSocket() {}
|
||||
// Returns nullptr on error.
|
||||
// Once error is reported, it is permanent, and ServerSocket has to be closed.
|
||||
std::unique_ptr<api::BluetoothSocket> BluetoothServerSocket::Accept() {
|
||||
while (bluetooth_sockets_.empty() && !closed_) {
|
||||
Sleep(1000);
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Accept is called.";
|
||||
|
||||
while (!closed_ && pending_sockets_.empty()) {
|
||||
cond_.Wait(&mutex_);
|
||||
}
|
||||
if (closed_) return nullptr;
|
||||
|
||||
EnterCriticalSection(&critical_section_);
|
||||
if (!closed_) {
|
||||
std::unique_ptr<BluetoothSocket> bluetoothSocket =
|
||||
std::move(bluetooth_sockets_.front());
|
||||
bluetooth_sockets_.pop();
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
StreamSocket bluetooth_socket = pending_sockets_.front();
|
||||
pending_sockets_.pop_front();
|
||||
|
||||
return std::move(bluetoothSocket);
|
||||
} else {
|
||||
bluetooth_sockets_ = {};
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Accepted a remote connection.";
|
||||
return std::make_unique<BluetoothSocket>(bluetooth_socket);
|
||||
}
|
||||
|
||||
Exception BluetoothServerSocket::StartListening(bool radioDiscoverable) {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
void BluetoothServerSocket::SetCloseNotifier(std::function<void()> notifier) {
|
||||
close_notifier_ = std::move(notifier);
|
||||
}
|
||||
|
||||
radio_discoverable_ = radioDiscoverable;
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception BluetoothServerSocket::Close() {
|
||||
try {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Close is called.";
|
||||
|
||||
// Create the StreamSocketListener
|
||||
if (closed_) {
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
if (stream_socket_listener_ != nullptr) {
|
||||
stream_socket_listener_.ConnectionReceived(listener_event_token_);
|
||||
stream_socket_listener_.Close();
|
||||
stream_socket_listener_ = nullptr;
|
||||
|
||||
for (const auto& pending_socket : pending_sockets_) {
|
||||
pending_socket.Close();
|
||||
}
|
||||
|
||||
pending_sockets_ = {};
|
||||
}
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
|
||||
if (close_notifier_ != nullptr) {
|
||||
close_notifier_();
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Close completed succesfully.";
|
||||
return {Exception::kSuccess};
|
||||
} catch (...) {
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Failed to close server socket.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
bool BluetoothServerSocket::listen() {
|
||||
// Setup stream socket listener.
|
||||
stream_socket_listener_ = StreamSocketListener();
|
||||
|
||||
// Configure control property
|
||||
stream_socket_listener_.Control().QualityOfService(
|
||||
SocketQualityOfService::LowLatency);
|
||||
|
||||
stream_socket_listener_.Control().KeepAlive(true);
|
||||
|
||||
// Note From the perspective of a StreamSocket, a Parallel Patterns Library
|
||||
// (PPL) completion handler is done executing (and the socket is eligible for
|
||||
// disposal) before the continuation body runs. So, to keep your socket from
|
||||
// being disposed if you want to use it inside a continuation, you'll need to
|
||||
// use one of the techniques described in References to StreamSockets in C++
|
||||
// PPL continuations.
|
||||
// Assign ConnectionReceived event to event handler on the server socket
|
||||
stream_socket_listener_.ConnectionReceived(
|
||||
[this](StreamSocketListener streamSocketListener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs args) {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
if (!closed_) {
|
||||
this->bluetooth_sockets_.push(
|
||||
std::make_unique<BluetoothSocket>(args.Socket()));
|
||||
}
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
});
|
||||
// Setup socket event of ConnectionReceived.
|
||||
listener_event_token_ = stream_socket_listener_.ConnectionReceived(
|
||||
{this, &BluetoothServerSocket::Listener_ConnectionReceived});
|
||||
|
||||
try {
|
||||
auto rfcommProviderRef =
|
||||
RfcommServiceProvider::CreateAsync(
|
||||
RfcommServiceId::FromUuid(winrt::guid(service_uuid_)))
|
||||
.get();
|
||||
|
||||
rfcomm_provider_ = rfcommProviderRef;
|
||||
|
||||
stream_socket_listener_
|
||||
.BindServiceNameAsync(
|
||||
winrt::to_hstring(rfcomm_provider_.ServiceId().AsString()),
|
||||
SocketProtectionLevel::PlainSocket)
|
||||
.BindServiceNameAsync(winrt::to_hstring(service_name_),
|
||||
SocketProtectionLevel::PlainSocket)
|
||||
.get();
|
||||
|
||||
// Set the SDP attributes and start Bluetooth advertising
|
||||
InitializeServiceSdpAttributes(rfcomm_provider_, service_name_);
|
||||
} catch (std::exception exception) {
|
||||
// We will log and eat the exception since the caller
|
||||
// expects nullptr if it fails
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Exception setting up for listen: "
|
||||
<< exception.what();
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return {Exception::kFailed};
|
||||
} catch (const winrt::hresult_error& ex) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": Exception setting up for listen: " << ex.code()
|
||||
<< ": " << winrt::to_string(ex.message());
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return {Exception::kFailed};
|
||||
return true;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(WARNING) << "cannot accept connection on preferred port.";
|
||||
}
|
||||
|
||||
StartAdvertising();
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return {Exception::kSuccess};
|
||||
return false;
|
||||
}
|
||||
|
||||
Exception BluetoothServerSocket::StartAdvertising() {
|
||||
try {
|
||||
rfcomm_provider_.StartAdvertising(stream_socket_listener_,
|
||||
radio_discoverable_);
|
||||
} catch (std::exception exception) {
|
||||
// We will log and eat the exception since the caller
|
||||
// expects nullptr if it fails
|
||||
NEARBY_LOGS(ERROR) << __func__ << ": Exception calling StartAdvertising: "
|
||||
<< exception.what();
|
||||
::winrt::fire_and_forget BluetoothServerSocket::Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const& args) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Received connection.";
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return {Exception::kFailed};
|
||||
} catch (const winrt::hresult_error& ex) {
|
||||
NEARBY_LOGS(ERROR) << __func__
|
||||
<< ": Exception calling StartAdvertising: " << ex.code()
|
||||
<< ": " << winrt::to_string(ex.message());
|
||||
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return {Exception::kFailed};
|
||||
}
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
void BluetoothServerSocket::StopAdvertising() {
|
||||
rfcomm_provider_.StopAdvertising();
|
||||
}
|
||||
|
||||
void BluetoothServerSocket::InitializeServiceSdpAttributes(
|
||||
RfcommServiceProvider rfcommProvider, std::string service_name) {
|
||||
auto sdpWriter = DataWriter();
|
||||
|
||||
// Write the Service Name Attribute.
|
||||
sdpWriter.WriteByte(Constants::SdpServiceNameAttributeType);
|
||||
|
||||
// The length of the UTF-8 encoded Service Name SDP Attribute.
|
||||
sdpWriter.WriteByte(service_name.size());
|
||||
|
||||
// The UTF-8 encoded Service Name value.
|
||||
sdpWriter.UnicodeEncoding(UnicodeEncoding::Utf8);
|
||||
sdpWriter.WriteString(winrt::to_hstring(service_name));
|
||||
|
||||
// Set the SDP Attribute on the RFCOMM Service Provider.
|
||||
rfcommProvider.SdpRawAttributes().Insert(Constants::SdpServiceNameAttributeId,
|
||||
sdpWriter.DetachBuffer());
|
||||
}
|
||||
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html#close()
|
||||
//
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception BluetoothServerSocket::Close() {
|
||||
EnterCriticalSection(&critical_section_);
|
||||
if (closed_) {
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
return {Exception::kSuccess};
|
||||
return ::winrt::fire_and_forget{};
|
||||
}
|
||||
|
||||
rfcomm_provider_.StopAdvertising();
|
||||
closed_ = true;
|
||||
bluetooth_sockets_ = {};
|
||||
LeaveCriticalSection(&critical_section_);
|
||||
|
||||
return {Exception::kSuccess};
|
||||
pending_sockets_.push_back(args.Socket());
|
||||
cond_.SignalAll();
|
||||
return ::winrt::fire_and_forget{};
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -17,13 +17,15 @@
|
||||
|
||||
#include <Windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "internal/platform/implementation/bluetooth_classic.h"
|
||||
#include "internal/platform/implementation/windows/bluetooth_classic_socket.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Devices.Bluetooth.Rfcomm.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Foundation.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h"
|
||||
#include "internal/platform/implementation/windows/generated/winrt/base.h"
|
||||
|
||||
namespace location {
|
||||
@@ -40,30 +42,10 @@ using winrt::Windows::Networking::Sockets::StreamSocketListener;
|
||||
using winrt::Windows::Networking::Sockets::
|
||||
StreamSocketListenerConnectionReceivedEventArgs;
|
||||
|
||||
// Represents an asynchronous action.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.foundation.iasyncaction?view=winrt-20348
|
||||
using winrt::Windows::Foundation::IAsyncAction;
|
||||
|
||||
// Specifies the quality of service for a StreamSocket object.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.socketqualityofservice?view=winrt-20348
|
||||
using winrt::Windows::Networking::Sockets::SocketQualityOfService;
|
||||
|
||||
// Represents an instance of a local RFCOMM service.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommserviceprovider?view=winrt-20348
|
||||
using winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceProvider;
|
||||
|
||||
// Represents an RFCOMM service ID.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.devices.bluetooth.rfcomm.rfcommserviceid?view=winrt-20348
|
||||
using winrt::Windows::Devices::Bluetooth::Rfcomm::RfcommServiceId;
|
||||
|
||||
// Writes data to an output stream.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.datawriter?view=winrt-20348
|
||||
using winrt::Windows::Storage::Streams::DataWriter;
|
||||
|
||||
// Specifies the type of character encoding for a stream.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.storage.streams.unicodeencoding?view=winrt-20348
|
||||
using winrt::Windows::Storage::Streams::UnicodeEncoding;
|
||||
|
||||
// Specifies the level of encryption to use on a StreamSocket object.
|
||||
// https://docs.microsoft.com/en-us/uwp/api/windows.networking.sockets.socketprotectionlevel?view=winrt-22000
|
||||
using winrt::Windows::Networking::Sockets::SocketProtectionLevel;
|
||||
@@ -71,8 +53,7 @@ using winrt::Windows::Networking::Sockets::SocketProtectionLevel;
|
||||
// https://developer.android.com/reference/android/bluetooth/BluetoothServerSocket.html.
|
||||
class BluetoothServerSocket : public api::BluetoothServerSocket {
|
||||
public:
|
||||
BluetoothServerSocket(const std::string service_name,
|
||||
const std::string service_uuid);
|
||||
BluetoothServerSocket(absl::string_view service_name);
|
||||
|
||||
~BluetoothServerSocket() override;
|
||||
|
||||
@@ -91,38 +72,41 @@ class BluetoothServerSocket : public api::BluetoothServerSocket {
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
Exception Close() override;
|
||||
|
||||
Exception StartListening(bool radioDiscoverable);
|
||||
// Called by the server side of a connection before passing ownership of
|
||||
// WifiLanServerSocker to user, to track validity of a pointer to this
|
||||
// server socket.
|
||||
void SetCloseNotifier(std::function<void()> notifier);
|
||||
|
||||
void SetScanMode(bool radioDiscoverable) {
|
||||
StopAdvertising();
|
||||
radio_discoverable_ = radioDiscoverable;
|
||||
if (radio_discoverable_) {
|
||||
StartAdvertising();
|
||||
}
|
||||
bool listen();
|
||||
|
||||
const StreamSocketListener& stream_socket_listener() const {
|
||||
return stream_socket_listener_;
|
||||
}
|
||||
|
||||
private:
|
||||
void InitializeServiceSdpAttributes(RfcommServiceProvider rfcommProvider,
|
||||
std::string service_name);
|
||||
// The listener is accepting incoming connections
|
||||
::winrt::fire_and_forget Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const& args);
|
||||
|
||||
Exception StartAdvertising();
|
||||
void StopAdvertising();
|
||||
// Retrieves IP addresses from local machine
|
||||
std::vector<std::string> GetIpAddresses() const;
|
||||
|
||||
// This is used to store sockets in case Accept hasn't been called. Once
|
||||
// Accept has been called the socket is popped from the queue and returned to
|
||||
// the caller
|
||||
std::queue<std::unique_ptr<BluetoothSocket>> bluetooth_sockets_;
|
||||
mutable absl::Mutex mutex_;
|
||||
absl::CondVar cond_;
|
||||
std::deque<StreamSocket> pending_sockets_ ABSL_GUARDED_BY(mutex_);
|
||||
StreamSocketListener stream_socket_listener_{nullptr};
|
||||
winrt::event_token listener_event_token_{};
|
||||
|
||||
StreamSocketListener stream_socket_listener_;
|
||||
winrt::event_token listener_token_;
|
||||
CRITICAL_SECTION critical_section_;
|
||||
// Close notifier
|
||||
std::function<void()> close_notifier_ = nullptr;
|
||||
|
||||
// IP addresses of the computer. mDNS uses them to advertise.
|
||||
std::vector<std::string> ip_addresses_{};
|
||||
|
||||
// Cache socket not be picked by upper layer
|
||||
std::string service_name_;
|
||||
bool closed_ = false;
|
||||
bool radio_discoverable_;
|
||||
|
||||
const std::string service_name_;
|
||||
const std::string service_uuid_;
|
||||
|
||||
RfcommServiceProvider rfcomm_provider_;
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h"
|
||||
#include "internal/platform/implementation/windows/utils.h"
|
||||
#include "internal/platform/implementation/windows/wifi_hotspot.h"
|
||||
#include "internal/platform/logging.h"
|
||||
@@ -19,9 +27,12 @@
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
namespace {
|
||||
constexpr int kMaxRetries = 3;
|
||||
|
||||
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
|
||||
|
||||
constexpr int kMaxRetries = 3;
|
||||
|
||||
} // namespace
|
||||
|
||||
WifiHotspotServerSocket::WifiHotspotServerSocket(int port) : port_(port) {}
|
||||
@@ -53,6 +64,8 @@ int WifiHotspotServerSocket::GetPort() const {
|
||||
|
||||
std::unique_ptr<api::WifiHotspotSocket> WifiHotspotServerSocket::Accept() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Accept is called.";
|
||||
|
||||
while (!closed_ && pending_sockets_.empty()) {
|
||||
cond_.Wait(&mutex_);
|
||||
}
|
||||
@@ -60,6 +73,8 @@ std::unique_ptr<api::WifiHotspotSocket> WifiHotspotServerSocket::Accept() {
|
||||
|
||||
StreamSocket wifi_hotspot_socket = pending_sockets_.front();
|
||||
pending_sockets_.pop_front();
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Accepted a remote connection.";
|
||||
return std::make_unique<WifiHotspotSocket>(wifi_hotspot_socket);
|
||||
}
|
||||
|
||||
@@ -70,6 +85,8 @@ void WifiHotspotServerSocket::SetCloseNotifier(std::function<void()> notifier) {
|
||||
Exception WifiHotspotServerSocket::Close() {
|
||||
try {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Close is called.";
|
||||
|
||||
if (closed_) {
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
@@ -78,28 +95,32 @@ Exception WifiHotspotServerSocket::Close() {
|
||||
stream_socket_listener_.Close();
|
||||
stream_socket_listener_ = nullptr;
|
||||
|
||||
if (!pending_sockets_.empty()) {
|
||||
auto it = pending_sockets_.begin();
|
||||
while (it != pending_sockets_.end()) {
|
||||
it->Close();
|
||||
}
|
||||
for (const auto &pending_socket : pending_sockets_) {
|
||||
pending_socket.Close();
|
||||
}
|
||||
|
||||
cond_.SignalAll();
|
||||
pending_sockets_ = {};
|
||||
}
|
||||
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
if (close_notifier_ != nullptr) {
|
||||
close_notifier_();
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Close completed succesfully.";
|
||||
return {Exception::kSuccess};
|
||||
} catch (...) {
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Failed to close server socket.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiHotspotServerSocket::listen() {
|
||||
// Check IP address
|
||||
// Get current IP addresses of the device.
|
||||
hotspot_ipaddr_ = GetHotspotIpAddresses();
|
||||
|
||||
if (hotspot_ipaddr_.empty()) {
|
||||
@@ -108,10 +129,15 @@ bool WifiHotspotServerSocket::listen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save connection callback
|
||||
// Setup stream socket listener.
|
||||
stream_socket_listener_ = StreamSocketListener();
|
||||
|
||||
// Setup callback
|
||||
stream_socket_listener_.Control().QualityOfService(
|
||||
SocketQualityOfService::LowLatency);
|
||||
|
||||
stream_socket_listener_.Control().KeepAlive(true);
|
||||
|
||||
// Setup socket event of ConnectionReceived.
|
||||
listener_event_token_ = stream_socket_listener_.ConnectionReceived(
|
||||
{this, &WifiHotspotServerSocket::Listener_ConnectionReceived});
|
||||
|
||||
@@ -133,7 +159,7 @@ bool WifiHotspotServerSocket::listen() {
|
||||
|
||||
try {
|
||||
stream_socket_listener_.BindServiceNameAsync({}).get();
|
||||
// need to save the port information
|
||||
// need to save the port information.
|
||||
port_ =
|
||||
std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
|
||||
NEARBY_LOGS(INFO) << "Server Socket port: " << port_;
|
||||
@@ -150,6 +176,7 @@ fire_and_forget WifiHotspotServerSocket::Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const &args) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Received connection.";
|
||||
|
||||
if (closed_) {
|
||||
return fire_and_forget{};
|
||||
@@ -169,7 +196,6 @@ bool HasEnding(std::string const &full_string, std::string const &ending) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> WifiHotspotServerSocket::GetIpAddresses() const {
|
||||
std::vector<std::string> result{};
|
||||
auto host_names = NetworkInformation::GetHostNames();
|
||||
|
||||
@@ -12,6 +12,14 @@
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include <functional>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "internal/platform/implementation/windows/generated/winrt/Windows.Networking.Sockets.h"
|
||||
#include "internal/platform/implementation/windows/utils.h"
|
||||
#include "internal/platform/implementation/windows/wifi_lan.h"
|
||||
#include "internal/platform/logging.h"
|
||||
@@ -19,12 +27,17 @@
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
namespace {
|
||||
|
||||
using ::winrt::Windows::Networking::Sockets::SocketQualityOfService;
|
||||
|
||||
}
|
||||
|
||||
WifiLanServerSocket::WifiLanServerSocket(int port) : port_(port) {}
|
||||
|
||||
WifiLanServerSocket::~WifiLanServerSocket() { Close(); }
|
||||
|
||||
// Returns ip address.
|
||||
// Returns the first IP address.
|
||||
std::string WifiLanServerSocket::GetIPAddress() const {
|
||||
if (stream_socket_listener_ == nullptr) {
|
||||
return {};
|
||||
@@ -40,7 +53,7 @@ std::string WifiLanServerSocket::GetIPAddress() const {
|
||||
return ip_addresses_.front();
|
||||
}
|
||||
|
||||
// Returns port.
|
||||
// Returns socket port.
|
||||
int WifiLanServerSocket::GetPort() const {
|
||||
if (stream_socket_listener_ == nullptr) {
|
||||
return 0;
|
||||
@@ -57,6 +70,8 @@ int WifiLanServerSocket::GetPort() const {
|
||||
// Once error is reported, it is permanent, and ServerSocket has to be closed.
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Accept is called.";
|
||||
|
||||
while (!closed_ && pending_sockets_.empty()) {
|
||||
cond_.Wait(&mutex_);
|
||||
}
|
||||
@@ -64,6 +79,8 @@ std::unique_ptr<api::WifiLanSocket> WifiLanServerSocket::Accept() {
|
||||
|
||||
StreamSocket wifi_lan_socket = pending_sockets_.front();
|
||||
pending_sockets_.pop_front();
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Accepted a remote connection.";
|
||||
return std::make_unique<WifiLanSocket>(wifi_lan_socket);
|
||||
}
|
||||
|
||||
@@ -75,6 +92,8 @@ void WifiLanServerSocket::SetCloseNotifier(std::function<void()> notifier) {
|
||||
Exception WifiLanServerSocket::Close() {
|
||||
try {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Close is called.";
|
||||
|
||||
if (closed_) {
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
@@ -83,27 +102,33 @@ Exception WifiLanServerSocket::Close() {
|
||||
stream_socket_listener_.Close();
|
||||
stream_socket_listener_ = nullptr;
|
||||
|
||||
if (!pending_sockets_.empty()) {
|
||||
auto it = pending_sockets_.begin();
|
||||
while (it != pending_sockets_.end()) {
|
||||
it->Close();
|
||||
}
|
||||
for (const auto& pending_socket : pending_sockets_) {
|
||||
pending_socket.Close();
|
||||
}
|
||||
|
||||
cond_.SignalAll();
|
||||
pending_sockets_ = {};
|
||||
}
|
||||
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
|
||||
if (close_notifier_ != nullptr) {
|
||||
close_notifier_();
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Close completed succesfully.";
|
||||
return {Exception::kSuccess};
|
||||
} catch (...) {
|
||||
closed_ = true;
|
||||
cond_.SignalAll();
|
||||
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Failed to close server socket.";
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiLanServerSocket::listen() {
|
||||
// Check IP address
|
||||
// Get current IP addresses of the device.
|
||||
ip_addresses_ = GetIpAddresses();
|
||||
|
||||
if (ip_addresses_.empty()) {
|
||||
@@ -112,10 +137,15 @@ bool WifiLanServerSocket::listen() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Save connection callback
|
||||
// Setup stream socket listener.
|
||||
stream_socket_listener_ = StreamSocketListener();
|
||||
|
||||
// Setup callback
|
||||
stream_socket_listener_.Control().QualityOfService(
|
||||
SocketQualityOfService::LowLatency);
|
||||
|
||||
stream_socket_listener_.Control().KeepAlive(true);
|
||||
|
||||
// Setup socket event of ConnectionReceived.
|
||||
listener_event_token_ = stream_socket_listener_.ConnectionReceived(
|
||||
{this, &WifiLanServerSocket::Listener_ConnectionReceived});
|
||||
|
||||
@@ -135,7 +165,8 @@ bool WifiLanServerSocket::listen() {
|
||||
|
||||
try {
|
||||
stream_socket_listener_.BindServiceNameAsync({}).get();
|
||||
// need to save the port information
|
||||
|
||||
// Need to save the port information.
|
||||
port_ =
|
||||
std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
|
||||
return true;
|
||||
@@ -151,6 +182,7 @@ fire_and_forget WifiLanServerSocket::Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const& args) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
NEARBY_LOGS(INFO) << __func__ << ": Received connection.";
|
||||
|
||||
if (closed_) {
|
||||
return fire_and_forget{};
|
||||
@@ -161,7 +193,7 @@ fire_and_forget WifiLanServerSocket::Listener_ConnectionReceived(
|
||||
return fire_and_forget{};
|
||||
}
|
||||
|
||||
// Retrieves IP addresses from local machine
|
||||
// Retrieves IP addresses from local machine.
|
||||
std::vector<std::string> WifiLanServerSocket::GetIpAddresses() const {
|
||||
std::vector<std::string> result{};
|
||||
auto host_names = NetworkInformation::GetHostNames();
|
||||
@@ -170,7 +202,7 @@ std::vector<std::string> WifiLanServerSocket::GetIpAddresses() const {
|
||||
host_name.IPInformation().NetworkAdapter() != nullptr &&
|
||||
host_name.Type() == HostNameType::Ipv4) {
|
||||
std::string ipv4_s = winrt::to_string(host_name.ToString());
|
||||
// Converts ip address from x.x.x.x to 4 bytes format
|
||||
// Converts ip address from x.x.x.x to 4 bytes format.
|
||||
in_addr address;
|
||||
address.S_un.S_addr = inet_addr(ipv4_s.c_str());
|
||||
char ipv4_b[5];
|
||||
|
||||
Reference in New Issue
Block a user