mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Add WiFi LAN medium on Windows
PiperOrigin-RevId: 399587411
This commit is contained in:
committed by
Copybara-Service
parent
deb5776362
commit
1f0ec837b6
@@ -107,6 +107,9 @@ cc_library(
|
||||
"system_clock.cc",
|
||||
"thread_pool.cc",
|
||||
"utils.cc",
|
||||
"wifi_lan_medium.cc",
|
||||
"wifi_lan_nsd.cc",
|
||||
"wifi_lan_socket.cc",
|
||||
],
|
||||
hdrs = [
|
||||
"bluetooth_classic.h",
|
||||
@@ -121,9 +124,12 @@ cc_library(
|
||||
"scheduled_executor.h",
|
||||
"submittable_executor.h",
|
||||
"thread_pool.h",
|
||||
"wifi_lan.h",
|
||||
],
|
||||
compatible_with = ["//buildenv/target:non_prod"],
|
||||
copts = ["-Ithird_party/nearby_connections/cpp/platform/impl/windows/generated"],
|
||||
copts = [
|
||||
"-Ithird_party/nearby_connections/cpp/platform/impl/windows/generated",
|
||||
],
|
||||
visibility = [
|
||||
"//third_party/nearby_connections/windows:__subpackages__",
|
||||
],
|
||||
|
||||
@@ -32,6 +32,7 @@ cc_library(
|
||||
"winspool.lib",
|
||||
"comsuppwd.lib",
|
||||
"setupapi.lib",
|
||||
"dnsapi.lib",
|
||||
],
|
||||
textual_hdrs = glob(["**/*.h"]),
|
||||
visibility = [
|
||||
|
||||
@@ -1,36 +1,127 @@
|
||||
// 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.
|
||||
|
||||
#include "platform/impl/windows/utils.h"
|
||||
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
std::string uint64_to_mac_address_string(uint64_t bluetoothAddress) {
|
||||
std::string buffer = absl::StrFormat(
|
||||
"%2llx:%2llx:%2llx:%2llx:%2llx:%2llx", bluetoothAddress >> 40,
|
||||
(bluetoothAddress >> 32) & 0xff, (bluetoothAddress >> 24) & 0xff,
|
||||
(bluetoothAddress >> 16) & 0xff, (bluetoothAddress >> 8) & 0xff,
|
||||
bluetoothAddress & 0xff);
|
||||
|
||||
return absl::AsciiStrToUpper(buffer);
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
// 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.
|
||||
|
||||
#include "platform/impl/windows/utils.h"
|
||||
|
||||
// Windows headers
|
||||
#include <strsafe.h>
|
||||
|
||||
// Standard C/C++ headers
|
||||
#include <codecvt>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
|
||||
// Third party headers
|
||||
#include "absl/strings/ascii.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
// Nearby connections headers
|
||||
#include "platform/api/crypto.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
std::string uint64_to_mac_address_string(uint64_t bluetoothAddress) {
|
||||
std::string buffer = absl::StrFormat(
|
||||
"%2llx:%2llx:%2llx:%2llx:%2llx:%2llx", bluetoothAddress >> 40,
|
||||
(bluetoothAddress >> 32) & 0xff, (bluetoothAddress >> 24) & 0xff,
|
||||
(bluetoothAddress >> 16) & 0xff, (bluetoothAddress >> 8) & 0xff,
|
||||
bluetoothAddress & 0xff);
|
||||
|
||||
return absl::AsciiStrToUpper(buffer);
|
||||
}
|
||||
|
||||
std::wstring string_to_wstring(std::string str) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
return converter.from_bytes(str);
|
||||
}
|
||||
|
||||
std::string wstring_to_string(std::wstring wstr) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
|
||||
return converter.to_bytes(wstr);
|
||||
}
|
||||
|
||||
ByteArray Sha256(absl::string_view input, size_t size) {
|
||||
ByteArray hash = location::nearby::Crypto::Sha256(input);
|
||||
return ByteArray{hash.data(), size};
|
||||
}
|
||||
|
||||
uint16 InspectableReader::ReadUint16(IInspectable inspectable) {
|
||||
auto property_value =
|
||||
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
||||
if (property_value == nullptr) {
|
||||
throw std::invalid_argument("no property value interface.");
|
||||
}
|
||||
if (property_value.Type() !=
|
||||
winrt::Windows::Foundation::PropertyType::UInt16) {
|
||||
throw std::invalid_argument("not uin16 data type.");
|
||||
}
|
||||
|
||||
return property_value.GetUInt16();
|
||||
}
|
||||
|
||||
uint32 InspectableReader::ReadUint32(IInspectable inspectable) {
|
||||
auto property_value =
|
||||
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
||||
if (property_value == nullptr) {
|
||||
throw std::invalid_argument("no property value interface.");
|
||||
}
|
||||
if (property_value.Type() !=
|
||||
winrt::Windows::Foundation::PropertyType::UInt32) {
|
||||
throw std::invalid_argument("not uin32 data type.");
|
||||
}
|
||||
|
||||
return property_value.GetUInt32();
|
||||
}
|
||||
|
||||
std::string InspectableReader::ReadString(IInspectable inspectable) {
|
||||
auto property_value =
|
||||
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
||||
if (property_value == nullptr) {
|
||||
throw std::invalid_argument("no property value interface.");
|
||||
}
|
||||
if (property_value.Type() !=
|
||||
winrt::Windows::Foundation::PropertyType::String) {
|
||||
throw std::invalid_argument("not string data type.");
|
||||
}
|
||||
|
||||
return wstring_to_string(property_value.GetString().c_str());
|
||||
}
|
||||
|
||||
std::vector<std::string> InspectableReader::ReadStringArray(
|
||||
IInspectable inspectable) {
|
||||
std::vector<std::string> result;
|
||||
auto property_value =
|
||||
inspectable.try_as<winrt::Windows::Foundation::IPropertyValue>();
|
||||
if (property_value == nullptr) {
|
||||
throw std::invalid_argument("no property value interface.");
|
||||
}
|
||||
if (property_value.Type() !=
|
||||
winrt::Windows::Foundation::PropertyType::StringArray) {
|
||||
throw std::invalid_argument("not string array data type.");
|
||||
}
|
||||
|
||||
winrt::com_array<winrt::hstring> strings;
|
||||
property_value.GetStringArray(strings);
|
||||
|
||||
for (winrt::hstring str : strings) {
|
||||
result.push_back(winrt::to_string(str));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
@@ -1,45 +1,65 @@
|
||||
// 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 PLATFORM_IMPL_WINDOWS_UTILS_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_UTILS_H_
|
||||
|
||||
#include <windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
std::string uint64_to_mac_address_string(uint64_t bluetoothAddress);
|
||||
|
||||
namespace Constants {
|
||||
// The Id of the Service Name SDP attribute
|
||||
const uint16_t SdpServiceNameAttributeId = 0x100;
|
||||
|
||||
// The SDP Type of the Service Name SDP attribute.
|
||||
// The first byte in the SDP Attribute encodes the SDP Attribute Type as
|
||||
// follows:
|
||||
// - the Attribute Type size in the least significant 3 bits,
|
||||
// - the SDP Attribute Type value in the most significant 5 bits.
|
||||
const char SdpServiceNameAttributeType = (4 << 3) | 5;
|
||||
} // namespace Constants
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_WINDOWS_UTILS_H_
|
||||
// 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 PLATFORM_IMPL_WINDOWS_UTILS_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_UTILS_H_
|
||||
|
||||
#include <Windows.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/string_view.h"
|
||||
#include "platform/base/byte_array.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Foundation.h"
|
||||
#include "platform/impl/windows/generated/winrt/base.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
using winrt::Windows::Foundation::IInspectable;
|
||||
|
||||
std::string uint64_to_mac_address_string(uint64_t bluetoothAddress);
|
||||
|
||||
// Helpers to windows platform
|
||||
std::wstring string_to_wstring(std::string str);
|
||||
std::string wstring_to_string(std::wstring wstr);
|
||||
ByteArray Sha256(absl::string_view input, size_t size);
|
||||
|
||||
namespace Constants {
|
||||
// The Id of the Service Name SDP attribute
|
||||
const uint16_t SdpServiceNameAttributeId = 0x100;
|
||||
|
||||
// The SDP Type of the Service Name SDP attribute.
|
||||
// The first byte in the SDP Attribute encodes the SDP Attribute Type as
|
||||
// follows:
|
||||
// - the Attribute Type size in the least significant 3 bits,
|
||||
// - the SDP Attribute Type value in the most significant 5 bits.
|
||||
const char SdpServiceNameAttributeType = (4 << 3) | 5;
|
||||
} // namespace Constants
|
||||
|
||||
class InspectableReader {
|
||||
public:
|
||||
static uint16 ReadUint16(IInspectable inspectable);
|
||||
static uint32 ReadUint32(IInspectable inspectable);
|
||||
static std::string ReadString(IInspectable inspectable);
|
||||
static std::vector<std::string> ReadStringArray(IInspectable inspectable);
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
|
||||
#endif // PLATFORM_IMPL_WINDOWS_UTILS_H_
|
||||
|
||||
@@ -15,33 +15,100 @@
|
||||
#ifndef PLATFORM_IMPL_WINDOWS_WIFI_LAN_H_
|
||||
#define PLATFORM_IMPL_WINDOWS_WIFI_LAN_H_
|
||||
|
||||
// Windows headers
|
||||
#include <windows.h> // NOLINT
|
||||
#include <win32/windns.h> // NOLINT
|
||||
|
||||
// Standard C/C++ headers
|
||||
#include <exception>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
// Nearby connections headers
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/container/flat_hash_set.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "platform/api/wifi_lan.h"
|
||||
#include "platform/base/exception.h"
|
||||
#include "platform/base/input_stream.h"
|
||||
#include "platform/base/output_stream.h"
|
||||
#include "platform/public/count_down_latch.h"
|
||||
#include "platform/public/mutex.h"
|
||||
|
||||
// WinRT headers
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Devices.Enumeration.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Foundation.Collections.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Foundation.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Networking.Connectivity.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Networking.ServiceDiscovery.Dnssd.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Networking.Sockets.h"
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Storage.Streams.h"
|
||||
#include "platform/impl/windows/generated/winrt/base.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
// Opaque wrapper over a WifiLan service which contains |NsdServiceInfo|.
|
||||
using winrt::fire_and_forget;
|
||||
using winrt::Windows::Devices::Enumeration::DeviceInformation;
|
||||
using winrt::Windows::Devices::Enumeration::DeviceInformationKind;
|
||||
using winrt::Windows::Devices::Enumeration::DeviceInformationUpdate;
|
||||
using winrt::Windows::Devices::Enumeration::DeviceWatcher;
|
||||
using winrt::Windows::Foundation::IInspectable;
|
||||
using winrt::Windows::Foundation::Collections::IMapView;
|
||||
using winrt::Windows::Networking::HostName;
|
||||
using winrt::Windows::Networking::Connectivity::NetworkInformation;
|
||||
using winrt::Windows::Networking::ServiceDiscovery::Dnssd::
|
||||
DnssdRegistrationResult;
|
||||
using winrt::Windows::Networking::ServiceDiscovery::Dnssd::
|
||||
DnssdRegistrationStatus;
|
||||
using winrt::Windows::Networking::ServiceDiscovery::Dnssd::DnssdServiceInstance;
|
||||
using winrt::Windows::Networking::Sockets::StreamSocket;
|
||||
using winrt::Windows::Networking::Sockets::StreamSocketListener;
|
||||
using winrt::Windows::Networking::Sockets::
|
||||
StreamSocketListenerConnectionReceivedEventArgs;
|
||||
using winrt::Windows::Networking::Sockets::StreamSocketListenerInformation;
|
||||
using winrt::Windows::Storage::Streams::Buffer;
|
||||
using winrt::Windows::Storage::Streams::DataReader;
|
||||
using winrt::Windows::Storage::Streams::IBuffer;
|
||||
using winrt::Windows::Storage::Streams::IInputStream;
|
||||
using winrt::Windows::Storage::Streams::InputStreamOptions;
|
||||
using winrt::Windows::Storage::Streams::IOutputStream;
|
||||
|
||||
class WifiLanMedium;
|
||||
|
||||
// WifiLanService includes NSD service information and
|
||||
// related medium information.
|
||||
class WifiLanService : public api::WifiLanService {
|
||||
public:
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
WifiLanService() = default;
|
||||
explicit WifiLanService(NsdServiceInfo nsd_service_info)
|
||||
: nsd_service_info_(std::move(nsd_service_info)) {}
|
||||
~WifiLanService() override = default;
|
||||
|
||||
// Returns the |NsdServiceInfo| which contains the packed string of
|
||||
// |WifiLanServiceInfo| and the endpoint info with named key in a TXTRecord
|
||||
// map.
|
||||
// The details refer to
|
||||
// https://developer.android.com/reference/android/net/nsd/NsdServiceInfo.html.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
NsdServiceInfo GetServiceInfo() const override { return NsdServiceInfo{}; }
|
||||
NsdServiceInfo GetServiceInfo() const override { return nsd_service_info_; }
|
||||
|
||||
void SetServiceInfo(NsdServiceInfo nsd_service_info) {
|
||||
nsd_service_info_ = std::move(nsd_service_info);
|
||||
}
|
||||
|
||||
WifiLanMedium* GetMedium() { return medium_; }
|
||||
|
||||
void SetMedium(WifiLanMedium* medium) { medium_ = medium; }
|
||||
|
||||
private:
|
||||
NsdServiceInfo nsd_service_info_;
|
||||
WifiLanMedium* medium_ = nullptr;
|
||||
};
|
||||
|
||||
// WifiLanSocket wraps the socket functions to read and write stream.
|
||||
// In WiFi LAN, A WifiLanSocket will be passed to StartAcceptingConnections's
|
||||
// call back when StreamSocketListener got connect. When call API to connect to
|
||||
// remote WiFi LAN service, also will return a WifiLanSocket to caller.
|
||||
class WifiLanSocket : public api::WifiLanSocket {
|
||||
public:
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
WifiLanSocket(StreamSocket socket);
|
||||
~WifiLanSocket() override;
|
||||
|
||||
// Returns the InputStream of the WifiLanSocket.
|
||||
@@ -49,108 +116,296 @@ class WifiLanSocket : public api::WifiLanSocket {
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the WifiLanSocket object is destroyed.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
InputStream& GetInputStream() override { return fake_input_stream_; }
|
||||
InputStream& GetInputStream() override;
|
||||
|
||||
// Returns the OutputStream of the WifiLanSocket.
|
||||
// On error, returned stream will report Exception::kIo on any operation.
|
||||
//
|
||||
// The returned object is not owned by the caller, and can be invalidated once
|
||||
// the WifiLanSocket object is destroyed.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
OutputStream& GetOutputStream() override { return fake_output_stream_; }
|
||||
OutputStream& GetOutputStream() override;
|
||||
|
||||
// Returns Exception::kIo on error, Exception::kSuccess otherwise.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
Exception Close() override { return Exception{}; }
|
||||
Exception Close() override;
|
||||
|
||||
// Returns valid WifiLanService pointer if there is a connection, and
|
||||
// nullptr otherwise.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
WifiLanService* GetRemoteWifiLanService() override { return nullptr; }
|
||||
api::WifiLanService* GetRemoteWifiLanService() override;
|
||||
|
||||
// When connect to remove WiFi LAN servie, need to save remove WiFi LAN
|
||||
// information, so that can return it based on ip address and port query
|
||||
void SetRemoteWifiLanService(api::WifiLanService* wifi_lan_service);
|
||||
|
||||
// Sets service id binding to the socket
|
||||
void SetServiceId(std::string service_id);
|
||||
|
||||
// Sets medium information
|
||||
void SetMedium(WifiLanMedium* medium);
|
||||
|
||||
// Returns the socket IP address
|
||||
std::string GetLocalAddress();
|
||||
|
||||
// Returns the socket port, range is between 49152 and 65535
|
||||
int GetLocalPort();
|
||||
|
||||
private:
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
class FakeInputStream : public InputStream {
|
||||
~FakeInputStream() override = default;
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override {
|
||||
return ExceptionOr<ByteArray>(Exception::kFailed);
|
||||
}
|
||||
Exception Close() override { return {.value = Exception::kFailed}; }
|
||||
};
|
||||
class FakeOutputStream : public OutputStream {
|
||||
~FakeOutputStream() override = default;
|
||||
// A simple wrapper to handle input stream of socket
|
||||
class SocketInputStream : public InputStream {
|
||||
public:
|
||||
SocketInputStream(IInputStream input_stream);
|
||||
~SocketInputStream() = default;
|
||||
|
||||
Exception Write(const ByteArray& data) override {
|
||||
return {.value = Exception::kFailed};
|
||||
}
|
||||
Exception Flush() override { return {.value = Exception::kFailed}; }
|
||||
Exception Close() override { return {.value = Exception::kFailed}; }
|
||||
ExceptionOr<ByteArray> Read(std::int64_t size) override;
|
||||
ExceptionOr<size_t> Skip(size_t offset) override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
IInputStream input_stream_{nullptr};
|
||||
};
|
||||
FakeInputStream fake_input_stream_;
|
||||
FakeOutputStream fake_output_stream_;
|
||||
|
||||
// A simple wrapper to handle output stream of socket
|
||||
class SocketOutputStream : public OutputStream {
|
||||
public:
|
||||
SocketOutputStream(IOutputStream output_stream);
|
||||
~SocketOutputStream() = default;
|
||||
|
||||
Exception Write(const ByteArray& data) override;
|
||||
Exception Flush() override;
|
||||
Exception Close() override;
|
||||
|
||||
private:
|
||||
IOutputStream output_stream_;
|
||||
};
|
||||
|
||||
// Internal properties
|
||||
StreamSocket stream_soket_{nullptr};
|
||||
std::unique_ptr<SocketInputStream> input_stream_{nullptr};
|
||||
std::unique_ptr<SocketOutputStream> output_stream_{nullptr};
|
||||
|
||||
api::WifiLanService* remote_wifi_lan_service_ = nullptr;
|
||||
WifiLanMedium* medium_ = nullptr;
|
||||
std::string service_id_;
|
||||
};
|
||||
|
||||
// WifiLanNsd implements the NSD functions for a specific service ID.
|
||||
// WifiLan Medium separates NSD functions using WifiLanNsd. WifiLanNsd
|
||||
// maintians the states of mDNS service.
|
||||
class WifiLanNsd {
|
||||
public:
|
||||
explicit WifiLanNsd(WifiLanMedium* medium, const std::string service_id);
|
||||
WifiLanNsd(WifiLanNsd&&) = default;
|
||||
WifiLanNsd& operator=(WifiLanNsd&&) = default;
|
||||
~WifiLanNsd() = default;
|
||||
|
||||
// Implements medium functions based on service id
|
||||
bool StartAcceptingConnections(
|
||||
api::WifiLanMedium::AcceptedConnectionCallback callback);
|
||||
bool StopAcceptingConnections();
|
||||
bool StartAdvertising(const NsdServiceInfo& nsd_service_info);
|
||||
bool StopAdvertising();
|
||||
bool StartDiscovery(api::WifiLanMedium::DiscoveredServiceCallback callback);
|
||||
bool StopDiscovery();
|
||||
|
||||
// In the class, not using ENUM to describe the mDNS states, because a little
|
||||
// complicate to combine all states based on accepting, advertising and
|
||||
// discovery.
|
||||
bool IsIdle() { return nsd_status_ == 0; }
|
||||
|
||||
bool IsAccepting() { return (nsd_status_ & NSD_STATUS_ACCEPTING) != 0; }
|
||||
|
||||
bool IsAdvertising() { return (nsd_status_ & NSD_STATUS_ADVERTISING) != 0; }
|
||||
|
||||
bool IsDiscovering() { return (nsd_status_ & NSD_STATUS_DISCOVERING) != 0; }
|
||||
|
||||
// A pair of IP Address and Port. A remote device can use this information
|
||||
// to connect to us. This is non-null while IsAccepting is true.
|
||||
std::pair<std::string, int> GetServiceAddress();
|
||||
|
||||
// DnsServiceDeRegister is a async process, after operation finish, callback
|
||||
// will call this method to notify the waiting method StopAdvertising to
|
||||
// continue.
|
||||
void NotifyDnsServiceUnregistered(DWORD status);
|
||||
|
||||
private:
|
||||
// Nsd status
|
||||
static const int NSD_STATUS_IDLE = 0;
|
||||
static const int NSD_STATUS_ACCEPTING = (1 << 0);
|
||||
static const int NSD_STATUS_ADVERTISING = (1 << 1);
|
||||
static const int NSD_STATUS_DISCOVERING = (1 << 2);
|
||||
|
||||
//
|
||||
// Constants
|
||||
//
|
||||
|
||||
// Socket listening ports
|
||||
static const uint16 PORT_MIN = 49152;
|
||||
static const uint16 PORT_MAX = 65535;
|
||||
static const uint16 PORT_RANGE = PORT_MAX - PORT_MIN;
|
||||
|
||||
// mDNS text attributes
|
||||
static constexpr std::string_view KEY_ENDPOINT_INFO = "n";
|
||||
|
||||
// mDNS information for advertising and discovery
|
||||
static constexpr std::wstring_view MDNS_HOST_NAME = L"Windows.local";
|
||||
static constexpr std::string_view MDNS_INSTANCE_NAME_FORMAT =
|
||||
"%s.%s._tcp.local";
|
||||
static constexpr std::string_view MDNS_DEVICE_SELECTOR_FORMAT =
|
||||
"System.Devices.AepService.ProtocolId:=\"{4526e8c1-8aac-4153-9b16-"
|
||||
"55e86ada0e54}\" "
|
||||
"AND System.Devices.Dnssd.ServiceName:=\"%s._tcp\" AND "
|
||||
"System.Devices.Dnssd.Domain:=\"local\"";
|
||||
static const int SERVICE_ID_HASH_LENGTH = 6;
|
||||
static constexpr std::string_view SERVICE_ID_FORMAT =
|
||||
"_%02X%02X%02X%02X%02X%02X";
|
||||
|
||||
//
|
||||
// Private methods
|
||||
//
|
||||
|
||||
// Generates prefered listening port. If cannot bind to this port,
|
||||
// NSD will assign a random port for the service.
|
||||
// TODO: Windows firewall may break the solution, need to futher solution to
|
||||
// resolve the potential issue
|
||||
uint16 GenerateSocketPort(const std::string& service_id);
|
||||
|
||||
// From mDNS device information, to build NsdServiceInfo.
|
||||
// the properties are from DeviceInformation and DeviceInformationUpdate.
|
||||
// The API gets IP addresses, service name and text attributes of mDNS
|
||||
// from these properties,
|
||||
NsdServiceInfo GetNsdServiceInformation(
|
||||
IMapView<winrt::hstring, IInspectable> properties);
|
||||
|
||||
// mDNS callbacks for advertising and discovery
|
||||
fire_and_forget Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const& args);
|
||||
fire_and_forget Watcher_DeviceAdded(DeviceWatcher sender,
|
||||
DeviceInformation deviceInfo);
|
||||
fire_and_forget Watcher_DeviceUpdated(
|
||||
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate);
|
||||
fire_and_forget Watcher_DeviceRemoved(
|
||||
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate);
|
||||
static void Advertising_StopCompleted(DWORD Status, PVOID pQueryContext,
|
||||
PDNS_SERVICE_INSTANCE pInstance);
|
||||
|
||||
// Retrieves IP addresses from local machine
|
||||
std::vector<std::string> GetIpAddresses();
|
||||
|
||||
std::string GetServiceIdHash();
|
||||
|
||||
// Manages remote connections
|
||||
WifiLanService* GetRemoteWifiLanService(
|
||||
std::string endpoint, std::unique_ptr<WifiLanService> wifi_lan_service);
|
||||
void RemoveRemoteWifiLanService(std::string endpoint);
|
||||
|
||||
// Basic information of Nsd
|
||||
location::nearby::Mutex mutex_{};
|
||||
std::string service_id_{};
|
||||
// TODO(200421848): NsdServiceInfo should support service type
|
||||
std::string service_type_{};
|
||||
WifiLanMedium* medium_ = nullptr;
|
||||
WifiLanService wifi_lan_service_{};
|
||||
absl::flat_hash_map<std::string, std::unique_ptr<WifiLanService>>
|
||||
remote_wifi_lan_services_{};
|
||||
|
||||
// NSD Status
|
||||
int nsd_status_ = NSD_STATUS_IDLE;
|
||||
|
||||
//
|
||||
// Dns-sd related properties
|
||||
//
|
||||
|
||||
// Advertising properties
|
||||
winrt::event_token listener_event_token_{};
|
||||
StreamSocketListener stream_socket_listener_{nullptr};
|
||||
DnssdServiceInstance dnssd_service_instance_{nullptr};
|
||||
DnssdRegistrationResult dnssd_regirstraion_result_{nullptr};
|
||||
|
||||
// Stop advertising properties
|
||||
DNS_SERVICE_INSTANCE dns_service_instance_{nullptr};
|
||||
DNS_SERVICE_REGISTER_REQUEST dns_service_register_request_;
|
||||
std::unique_ptr<std::wstring> dns_service_instance_name_{nullptr};
|
||||
std::unique_ptr<CountDownLatch> dns_service_stop_latch_;
|
||||
DWORD dns_service_stop_status_;
|
||||
|
||||
// Discovery properties
|
||||
DeviceWatcher device_watcher_{nullptr};
|
||||
winrt::event_token device_watcher_added_event_token;
|
||||
winrt::event_token device_watcher_updated_event_token;
|
||||
winrt::event_token device_watcher_removed_event_token;
|
||||
|
||||
// callbacks for advertising and discovery
|
||||
api::WifiLanMedium::AcceptedConnectionCallback accepted_connection_callback_;
|
||||
api::WifiLanMedium::DiscoveredServiceCallback discovered_service_callback_;
|
||||
|
||||
// IP addresses of the computer. mDNS uses them to advertise.
|
||||
std::vector<std::string> ip_addresses_{};
|
||||
};
|
||||
|
||||
// Container of operations that can be performed over the WifiLan medium.
|
||||
class WifiLanMedium : public api::WifiLanMedium {
|
||||
public:
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
~WifiLanMedium() override = default;
|
||||
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
// Starts to advertising
|
||||
bool StartAdvertising(const std::string& service_id,
|
||||
const NsdServiceInfo& nsd_service_info) override {
|
||||
return false;
|
||||
}
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
bool StopAdvertising(const std::string& service_id) override { return false; }
|
||||
const NsdServiceInfo& nsd_service_info) override;
|
||||
|
||||
// Returns true once the WifiLan discovery has been initiated.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
// Stops to advertising
|
||||
bool StopAdvertising(const std::string& service_id) override;
|
||||
|
||||
// Starts to discovery
|
||||
bool StartDiscovery(const std::string& service_id,
|
||||
DiscoveredServiceCallback callback) override {
|
||||
return false;
|
||||
}
|
||||
DiscoveredServiceCallback callback) override;
|
||||
|
||||
// Returns true once WifiLan discovery for service_id is well and truly
|
||||
// stopped; after this returns, there must be no more invocations of the
|
||||
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
bool StopDiscovery(const std::string& service_id) override { return false; }
|
||||
bool StopDiscovery(const std::string& service_id) override;
|
||||
|
||||
// Returns true once WifiLan socket connection requests to service_id can be
|
||||
// accepted.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
bool StartAcceptingConnections(const std::string& service_id,
|
||||
AcceptedConnectionCallback callback) override {
|
||||
return false;
|
||||
}
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
bool StopAcceptingConnections(const std::string& service_id) override {
|
||||
return false;
|
||||
}
|
||||
AcceptedConnectionCallback callback) override;
|
||||
|
||||
// Stops to accept connections
|
||||
bool StopAcceptingConnections(const std::string& service_id) override;
|
||||
|
||||
// Connects to a WifiLan service.
|
||||
// On success, returns a new WifiLanSocket.
|
||||
// On error, returns nullptr.
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
std::unique_ptr<api::WifiLanSocket> Connect(
|
||||
api::WifiLanService& wifi_lan_service, const std::string& service_id,
|
||||
CancellationFlag* cancellation_flag) override {
|
||||
return nullptr;
|
||||
}
|
||||
CancellationFlag* cancellation_flag) override;
|
||||
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
WifiLanService* GetRemoteService(const std::string& ip_address,
|
||||
int port) override {
|
||||
return nullptr;
|
||||
}
|
||||
// Returns WiFi LAN service from local ip address and port information
|
||||
api::WifiLanService* GetRemoteService(const std::string& ip_address,
|
||||
int port) override;
|
||||
|
||||
// TODO(b/184975123): replace with real implementation.
|
||||
// returns advertising service address
|
||||
std::pair<std::string, int> GetServiceAddress(
|
||||
const std::string& service_id) override {
|
||||
return std::pair<std::string, int>{"Un-implemented", 0};
|
||||
}
|
||||
const std::string& service_id) override;
|
||||
|
||||
// for internal to clean closed connection.
|
||||
void CloseConnection(WifiLanSocket& socket);
|
||||
|
||||
private:
|
||||
// Accesses NSD by service id
|
||||
WifiLanNsd* GetNsd(std::string service_id, bool create = false);
|
||||
bool RemoveNsd(std::string service_id);
|
||||
|
||||
// Gets error message from exception pointer
|
||||
std::string GetErrorMessage(std::exception_ptr eptr);
|
||||
|
||||
// Protects the access to NSD and connections
|
||||
location::nearby::Mutex mutex_{};
|
||||
|
||||
// Tracks of active advertising or discovery
|
||||
absl::flat_hash_map<std::string, std::unique_ptr<WifiLanNsd>>
|
||||
service_to_nsd_map_ ABSL_GUARDED_BY(mutex_);
|
||||
|
||||
// Tracks of active connetions
|
||||
absl::flat_hash_set<WifiLanSocket*> wifi_lan_sockets_ ABSL_GUARDED_BY(mutex_);
|
||||
};
|
||||
|
||||
} // namespace windows
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#include "platform/impl/windows/wifi_lan.h"
|
||||
|
||||
// Windows headers
|
||||
#include <windows.h>
|
||||
|
||||
// Standard C/C++ headers
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <string>
|
||||
|
||||
// ABSL headers
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
// Nearby connections headers
|
||||
#include "platform/base/cancellation_flag_listener.h"
|
||||
#include "platform/impl/windows/utils.h"
|
||||
#include "platform/public/logging.h"
|
||||
#include "platform/public/mutex_lock.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
bool WifiLanMedium::StartAcceptingConnections(
|
||||
const std::string& service_id, AcceptedConnectionCallback callback) {
|
||||
try {
|
||||
WifiLanNsd* nsd = GetNsd(service_id, true);
|
||||
return nsd->StartAcceptingConnections(callback);
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to start accepting connections due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAcceptingConnections(const std::string& service_id) {
|
||||
try {
|
||||
WifiLanNsd* nsd = GetNsd(service_id);
|
||||
if (nsd == nullptr) {
|
||||
NEARBY_LOGS(WARNING) << "no running accepting connections.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nsd->StopAcceptingConnections()) {
|
||||
if (nsd->IsIdle()) {
|
||||
this->RemoveNsd(service_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(ERROR) << "failed to stop accepting connections.";
|
||||
return false;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to stop accepting connections due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StartAdvertising(const std::string& service_id,
|
||||
const NsdServiceInfo& nsd_service_info) {
|
||||
try {
|
||||
WifiLanNsd* nsd = GetNsd(service_id);
|
||||
if (nsd == nullptr) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "cannot start advertising without accepting connections.";
|
||||
return false;
|
||||
}
|
||||
return nsd->StartAdvertising(nsd_service_info);
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to start advertising due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiLanMedium::StopAdvertising(const std::string& service_id) {
|
||||
try {
|
||||
WifiLanNsd* nsd = GetNsd(service_id);
|
||||
if (nsd == nullptr) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "cannot stop advertising without accepting connections.";
|
||||
return false;
|
||||
}
|
||||
if (nsd->StopAdvertising()) {
|
||||
if (nsd->IsIdle()) {
|
||||
this->RemoveNsd(service_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(ERROR) << "failed to stop advertising.";
|
||||
return false;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to stop advertising due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true once the WifiLan discovery has been initiated.
|
||||
bool WifiLanMedium::StartDiscovery(const std::string& service_id,
|
||||
DiscoveredServiceCallback callback) {
|
||||
try {
|
||||
WifiLanNsd* nsd = GetNsd(service_id, true);
|
||||
return nsd->StartDiscovery(callback);
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to start discovery due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true once WifiLan discovery for service_id is well and truly
|
||||
// stopped; after this returns, there must be no more invocations of the
|
||||
// DiscoveredServiceCallback passed in to StartDiscovery() for service_id.
|
||||
bool WifiLanMedium::StopDiscovery(const std::string& service_id) {
|
||||
try {
|
||||
WifiLanNsd* nsd = GetNsd(service_id);
|
||||
if (nsd == nullptr) {
|
||||
NEARBY_LOGS(WARNING) << "no running discovery to stop.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nsd->StopDiscovery()) {
|
||||
if (nsd->IsIdle()) {
|
||||
this->RemoveNsd(service_id);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(WARNING) << "failed to stop discovery.";
|
||||
|
||||
return false;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to stop discovery due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Connects to a WifiLan service.
|
||||
// On success, returns a new WifiLanSocket.
|
||||
// On error, returns nullptr.
|
||||
std::unique_ptr<api::WifiLanSocket> WifiLanMedium::Connect(
|
||||
api::WifiLanService& wifi_lan_service, const std::string& service_id,
|
||||
CancellationFlag* cancellation_flag) {
|
||||
try {
|
||||
auto address = wifi_lan_service.GetServiceInfo().GetServiceAddress();
|
||||
if (address.first.empty() || address.second == 0) {
|
||||
NEARBY_LOGS(ERROR) << "no valid service address and port to connect.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
HostName host_name{string_to_wstring(address.first)};
|
||||
winrt::hstring service_name{winrt::to_hstring(address.second)};
|
||||
|
||||
StreamSocket socket{};
|
||||
|
||||
// setup cancel listener
|
||||
if (cancellation_flag != nullptr) {
|
||||
if (cancellation_flag->Cancelled()) {
|
||||
NEARBY_LOGS(INFO) << "connect has been cancelled: "
|
||||
"service_id="
|
||||
<< service_id;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
location::nearby::CancellationFlagListener cancellationFlagListener(
|
||||
cancellation_flag, [socket]() { socket.CancelIOAsync().get(); });
|
||||
}
|
||||
|
||||
// connection to the service
|
||||
try {
|
||||
socket.ConnectAsync(host_name, service_name).get();
|
||||
// connected need to keep connection
|
||||
std::unique_ptr<WifiLanSocket> wifi_lan_socket =
|
||||
std::make_unique<WifiLanSocket>(std::move(socket));
|
||||
wifi_lan_socket->SetServiceId(service_id);
|
||||
wifi_lan_socket->SetMedium(this);
|
||||
wifi_lan_socket->SetRemoteWifiLanService(&wifi_lan_service);
|
||||
{
|
||||
MutexLock lock(&mutex_);
|
||||
wifi_lan_sockets_.insert(wifi_lan_socket.get());
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << "connected to remote Wifi LAN service";
|
||||
return wifi_lan_socket;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to connect remote service.";
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to connect due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
api::WifiLanService* WifiLanMedium::GetRemoteService(
|
||||
const std::string& ip_address, int port) {
|
||||
try {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
for (WifiLanSocket* socket : wifi_lan_sockets_) {
|
||||
if (socket->GetLocalAddress() == ip_address &&
|
||||
socket->GetLocalPort() == port) {
|
||||
return socket->GetRemoteWifiLanService();
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to get remove service due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
std::pair<std::string, int> WifiLanMedium::GetServiceAddress(
|
||||
const std::string& service_id) {
|
||||
try {
|
||||
WifiLanNsd* nsd = GetNsd(service_id, true);
|
||||
if (nsd == nullptr) {
|
||||
// no nsd service
|
||||
NEARBY_LOGS(WARNING) << "no service for service id " << service_id;
|
||||
return std::pair<std::string, int>{"", 0};
|
||||
}
|
||||
|
||||
return nsd->GetServiceAddress();
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to get service address due to "
|
||||
<< GetErrorMessage(std::current_exception());
|
||||
return {"", 0};
|
||||
}
|
||||
}
|
||||
|
||||
void WifiLanMedium::CloseConnection(WifiLanSocket& socket) {
|
||||
MutexLock lock(&mutex_);
|
||||
if (wifi_lan_sockets_.contains(&socket)) {
|
||||
wifi_lan_sockets_.erase(&socket);
|
||||
}
|
||||
}
|
||||
|
||||
WifiLanNsd* WifiLanMedium::GetNsd(std::string service_id, bool create) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (!service_to_nsd_map_.contains(service_id)) {
|
||||
if (create) {
|
||||
// if no the service id, create a new one
|
||||
std::unique_ptr<WifiLanNsd> nsd =
|
||||
std::make_unique<WifiLanNsd>(this, service_id);
|
||||
service_to_nsd_map_[service_id] = std::move(nsd);
|
||||
}
|
||||
}
|
||||
|
||||
return service_to_nsd_map_[service_id].get();
|
||||
}
|
||||
|
||||
bool WifiLanMedium::RemoveNsd(std::string service_id) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
if (!service_to_nsd_map_.contains(service_id)) {
|
||||
return true;
|
||||
}
|
||||
auto nsd = service_to_nsd_map_.find(service_id);
|
||||
if (nsd == service_to_nsd_map_.end() || nsd->second == nullptr ||
|
||||
!nsd->second->IsIdle()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
service_to_nsd_map_.erase(nsd);
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string WifiLanMedium::GetErrorMessage(std::exception_ptr eptr) {
|
||||
try {
|
||||
if (eptr) {
|
||||
std::rethrow_exception(eptr);
|
||||
} else {
|
||||
return "";
|
||||
}
|
||||
} catch (const std::exception& e) {
|
||||
return e.what();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,506 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
// Absl headers
|
||||
#include "absl/strings/str_format.h"
|
||||
|
||||
// Nearby connections headers
|
||||
#include "platform/impl/windows/utils.h"
|
||||
#include "platform/impl/windows/wifi_lan.h"
|
||||
#include "platform/public/logging.h"
|
||||
#include "platform/public/mutex_lock.h"
|
||||
|
||||
// WinRT headers
|
||||
#include "platform/impl/windows/generated/winrt/Windows.Foundation.Collections.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
WifiLanNsd::WifiLanNsd(WifiLanMedium* medium, const std::string service_id) {
|
||||
medium_ = medium;
|
||||
service_id_ = service_id;
|
||||
service_type_ = GetServiceIdHash();
|
||||
}
|
||||
|
||||
bool WifiLanNsd::StartAcceptingConnections(
|
||||
api::WifiLanMedium::AcceptedConnectionCallback callback) {
|
||||
// TODO: check windows version to decide whether support mDNS service
|
||||
|
||||
// Check IP address
|
||||
ip_addresses_ = GetIpAddresses();
|
||||
|
||||
if (ip_addresses_.empty()) {
|
||||
NEARBY_LOGS(WARNING) << "failed to start accepting connection without IP "
|
||||
"addreses configured on computer.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// check current status
|
||||
if (IsAccepting()) {
|
||||
NEARBY_LOGS(WARNING) << "accepting connections already started. service id="
|
||||
<< service_id_;
|
||||
return false;
|
||||
}
|
||||
|
||||
int port = GenerateSocketPort(service_id_);
|
||||
|
||||
// Save connection callback
|
||||
accepted_connection_callback_ = std::move(callback);
|
||||
stream_socket_listener_ = StreamSocketListener();
|
||||
|
||||
// Setup callback
|
||||
listener_event_token_ = stream_socket_listener_.ConnectionReceived(
|
||||
{this, &WifiLanNsd::Listener_ConnectionReceived});
|
||||
|
||||
try {
|
||||
stream_socket_listener_.BindServiceNameAsync(winrt::to_hstring(port)).get();
|
||||
nsd_status_ |= NSD_STATUS_ACCEPTING;
|
||||
return true;
|
||||
} catch (...) {
|
||||
// Cannot bind to the preferred port, will let system to assign port.
|
||||
NEARBY_LOGS(WARNING) << "cannot accept connection on preferred port.";
|
||||
}
|
||||
|
||||
try {
|
||||
stream_socket_listener_.BindServiceNameAsync({}).get();
|
||||
// need to save the port information
|
||||
port = std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
|
||||
nsd_status_ |= NSD_STATUS_ACCEPTING;
|
||||
return true;
|
||||
} catch (...) {
|
||||
// Cannot bind to the preferred port, will let system to assign port.
|
||||
NEARBY_LOGS(ERROR) << "cannot bind to any port.";
|
||||
}
|
||||
|
||||
// clean up
|
||||
stream_socket_listener_.ConnectionReceived(listener_event_token_);
|
||||
stream_socket_listener_ = nullptr;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool WifiLanNsd::StopAcceptingConnections() {
|
||||
if (!IsAccepting()) {
|
||||
NEARBY_LOGS(WARNING) << "no accepting connections to stop.";
|
||||
return false;
|
||||
}
|
||||
|
||||
stream_socket_listener_.ConnectionReceived(listener_event_token_);
|
||||
stream_socket_listener_ = nullptr;
|
||||
nsd_status_ &= (~NSD_STATUS_ACCEPTING);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanNsd::StartAdvertising(const NsdServiceInfo& nsd_service_info) {
|
||||
if (!IsAccepting()) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "cannot start advertising without accepting connetions.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (IsAdvertising()) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "cannot start advertising again when it is running.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nsd_service_info.GetTxtRecord(KEY_ENDPOINT_INFO.data()).empty()) {
|
||||
NEARBY_LOGS(ERROR) << "cannot start advertising without endpoint info.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (nsd_service_info.GetServiceInfoName().empty()) {
|
||||
NEARBY_LOGS(ERROR) << "cannot start advertising without service name.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Setup WiFi LAN service information
|
||||
int port =
|
||||
std::stoi(stream_socket_listener_.Information().LocalPort().c_str());
|
||||
NsdServiceInfo new_nsd_servcie_info = nsd_service_info;
|
||||
// TODO: need feature enhancement to support multiple network interfaces
|
||||
new_nsd_servcie_info.SetServiceAddress(ip_addresses_[0], port);
|
||||
wifi_lan_service_ = WifiLanService(new_nsd_servcie_info);
|
||||
wifi_lan_service_.SetMedium(medium_);
|
||||
|
||||
std::string instance_name = absl::StrFormat(
|
||||
MDNS_INSTANCE_NAME_FORMAT.data(),
|
||||
wifi_lan_service_.GetServiceInfo().GetServiceInfoName(), service_type_);
|
||||
|
||||
NEARBY_LOGS(INFO) << "mDNS instance name is " << instance_name;
|
||||
|
||||
dnssd_service_instance_ = DnssdServiceInstance{
|
||||
string_to_wstring(instance_name),
|
||||
nullptr, // let windows use default computer's local name
|
||||
(uint16)port};
|
||||
|
||||
// Add TextRecords from NsdServiceInfo
|
||||
auto text_attributes = dnssd_service_instance_.TextAttributes();
|
||||
// TODO(b/200298824): NsdServiceInfo should have function to return all text
|
||||
// records will be more generic
|
||||
text_attributes.Insert(string_to_wstring(KEY_ENDPOINT_INFO.data()),
|
||||
string_to_wstring(nsd_service_info.GetTxtRecord(
|
||||
KEY_ENDPOINT_INFO.data())));
|
||||
|
||||
dnssd_regirstraion_result_ =
|
||||
dnssd_service_instance_
|
||||
.RegisterStreamSocketListenerAsync(stream_socket_listener_)
|
||||
.get();
|
||||
|
||||
if (dnssd_regirstraion_result_.HasInstanceNameChanged()) {
|
||||
NEARBY_LOGS(WARNING) << "advertising instance name was changed due to have "
|
||||
"same name instance was running.";
|
||||
// stop the service and return false
|
||||
StopAdvertising();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dnssd_regirstraion_result_.Status() == DnssdRegistrationStatus::Success) {
|
||||
NEARBY_LOGS(INFO) << "started to advertising.";
|
||||
nsd_status_ |= NSD_STATUS_ADVERTISING;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Clean up
|
||||
NEARBY_LOGS(ERROR)
|
||||
<< "failed to start advertising due to registration failure.";
|
||||
dnssd_service_instance_ = nullptr;
|
||||
dnssd_regirstraion_result_ = nullptr;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Win32 call only can use globel function or static method in class
|
||||
void WifiLanNsd::Advertising_StopCompleted(DWORD Status, PVOID pQueryContext,
|
||||
PDNS_SERVICE_INSTANCE pInstance) {
|
||||
NEARBY_LOGS(INFO) << "unregister with status=" << Status;
|
||||
try {
|
||||
WifiLanNsd* nsd = static_cast<WifiLanNsd*>(pQueryContext);
|
||||
nsd->NotifyDnsServiceUnregistered(Status);
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "failed to notify the stop of DNS service instance."
|
||||
<< Status;
|
||||
}
|
||||
}
|
||||
|
||||
void WifiLanNsd::NotifyDnsServiceUnregistered(DWORD status) {
|
||||
if (dns_service_stop_latch_.get() != nullptr) {
|
||||
dns_service_stop_status_ = status;
|
||||
dns_service_stop_latch_.get()->CountDown();
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiLanNsd::StopAdvertising() {
|
||||
// Need to use Win32 API to deregister the Dnssd instance
|
||||
if (!IsAdvertising()) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "Cannot stop advertising because no advertising is running.";
|
||||
return false;
|
||||
}
|
||||
|
||||
// Init DNS service instance
|
||||
std::string instance_name = absl::StrFormat(
|
||||
MDNS_INSTANCE_NAME_FORMAT.data(),
|
||||
wifi_lan_service_.GetServiceInfo().GetServiceInfoName(), service_type_);
|
||||
int port = wifi_lan_service_.GetServiceInfo().GetServiceAddress().second;
|
||||
dns_service_instance_name_ =
|
||||
std::make_unique<std::wstring>(string_to_wstring(instance_name));
|
||||
|
||||
dns_service_instance_.pszInstanceName =
|
||||
(LPWSTR)dns_service_instance_name_->c_str();
|
||||
dns_service_instance_.pszHostName = (LPWSTR)MDNS_HOST_NAME.data();
|
||||
dns_service_instance_.wPort = port;
|
||||
|
||||
// Init DNS service register request
|
||||
dns_service_register_request_.Version = DNS_QUERY_REQUEST_VERSION1;
|
||||
dns_service_register_request_.InterfaceIndex =
|
||||
0; // all interfaces will be considered
|
||||
dns_service_register_request_.unicastEnabled = false;
|
||||
dns_service_register_request_.hCredentials = NULL;
|
||||
dns_service_register_request_.pServiceInstance = &dns_service_instance_;
|
||||
dns_service_register_request_.pQueryContext = this; // callback use it
|
||||
dns_service_register_request_.pRegisterCompletionCallback =
|
||||
WifiLanNsd::Advertising_StopCompleted;
|
||||
|
||||
dns_service_stop_latch_ = std::make_unique<CountDownLatch>(1);
|
||||
DWORD status = DnsServiceDeRegister(&dns_service_register_request_, nullptr);
|
||||
|
||||
if (status != DNS_REQUEST_PENDING) {
|
||||
NEARBY_LOGS(ERROR) << "failed to stop mDNS advertising for service id ="
|
||||
<< service_id_;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Wait for stop finish
|
||||
dns_service_stop_latch_.get()->Await();
|
||||
dns_service_stop_latch_ = nullptr;
|
||||
if (dns_service_stop_status_ != 0) {
|
||||
NEARBY_LOGS(INFO) << "failed to stop mDNS advertising for service id ="
|
||||
<< service_id_;
|
||||
return false;
|
||||
}
|
||||
|
||||
NEARBY_LOGS(INFO) << "succeeded to stop mDNS advertising for service id ="
|
||||
<< service_id_;
|
||||
nsd_status_ &= (~NSD_STATUS_ADVERTISING);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanNsd::StartDiscovery(
|
||||
api::WifiLanMedium::DiscoveredServiceCallback callback) {
|
||||
if (IsDiscovering()) {
|
||||
NEARBY_LOGS(WARNING) << "discovery already running for service id ="
|
||||
<< service_id_;
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string selector =
|
||||
absl::StrFormat(MDNS_DEVICE_SELECTOR_FORMAT.data(), service_type_);
|
||||
|
||||
std::vector<winrt::hstring> requestedProperties{
|
||||
L"System.Devices.IpAddress",
|
||||
L"System.Devices.Dnssd.HostName",
|
||||
L"System.Devices.Dnssd.InstanceName",
|
||||
L"System.Devices.Dnssd.PortNumber",
|
||||
L"System.Devices.Dnssd.ServiceName",
|
||||
L"System.Devices.Dnssd.TextAttributes"};
|
||||
|
||||
device_watcher_ = DeviceInformation::CreateWatcher(
|
||||
string_to_wstring(selector), requestedProperties,
|
||||
DeviceInformationKind::AssociationEndpointService);
|
||||
|
||||
device_watcher_added_event_token =
|
||||
device_watcher_.Added({this, &WifiLanNsd::Watcher_DeviceAdded});
|
||||
device_watcher_updated_event_token =
|
||||
device_watcher_.Updated({this, &WifiLanNsd::Watcher_DeviceUpdated});
|
||||
device_watcher_removed_event_token =
|
||||
device_watcher_.Removed({this, &WifiLanNsd::Watcher_DeviceRemoved});
|
||||
|
||||
device_watcher_.Start();
|
||||
discovered_service_callback_ = std::move(callback);
|
||||
nsd_status_ |= NSD_STATUS_DISCOVERING;
|
||||
|
||||
NEARBY_LOGS(INFO) << "started to discovery.";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanNsd::StopDiscovery() {
|
||||
if (!IsDiscovering()) {
|
||||
NEARBY_LOGS(WARNING) << "no discovering service to stop.";
|
||||
return false;
|
||||
}
|
||||
// TODO: handle exception
|
||||
device_watcher_.Stop();
|
||||
device_watcher_.Added(device_watcher_added_event_token);
|
||||
device_watcher_.Updated(device_watcher_updated_event_token);
|
||||
device_watcher_.Removed(device_watcher_removed_event_token);
|
||||
nsd_status_ &= (~NSD_STATUS_DISCOVERING);
|
||||
device_watcher_ = nullptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
std::pair<std::string, int> WifiLanNsd::GetServiceAddress() {
|
||||
if (!IsAdvertising()) {
|
||||
// no advertising is running
|
||||
NEARBY_LOGS(WARNING) << "no advertising for service id " << service_id_;
|
||||
return std::pair<std::string, int>{"", 0};
|
||||
}
|
||||
|
||||
return wifi_lan_service_.GetServiceInfo().GetServiceAddress();
|
||||
}
|
||||
|
||||
std::vector<std::string> WifiLanNsd::GetIpAddresses() {
|
||||
std::vector<std::string> result{};
|
||||
auto host_names = NetworkInformation::GetHostNames();
|
||||
for (auto host_name : host_names) {
|
||||
if (host_name.IPInformation() != nullptr &&
|
||||
host_name.IPInformation().NetworkAdapter() != nullptr) {
|
||||
result.push_back(wstring_to_string(host_name.ToString().c_str()));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
fire_and_forget WifiLanNsd::Listener_ConnectionReceived(
|
||||
StreamSocketListener listener,
|
||||
StreamSocketListenerConnectionReceivedEventArgs const& args) {
|
||||
NEARBY_LOGS(INFO) << "got connection message for service " << service_id_;
|
||||
StreamSocket stream_socket = args.Socket();
|
||||
|
||||
// Send to callback
|
||||
WifiLanSocket socket{stream_socket};
|
||||
socket.SetMedium(medium_);
|
||||
socket.SetServiceId(service_id_);
|
||||
accepted_connection_callback_.accepted_cb(socket, service_id_);
|
||||
return fire_and_forget{};
|
||||
}
|
||||
|
||||
NsdServiceInfo WifiLanNsd::GetNsdServiceInformation(
|
||||
IMapView<winrt::hstring, IInspectable> properties) {
|
||||
NsdServiceInfo nsd_service_info{};
|
||||
|
||||
// Service name information
|
||||
IInspectable inspectable =
|
||||
properties.TryLookup(L"System.Devices.Dnssd.InstanceName");
|
||||
if (inspectable == nullptr) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "no service name information in device information.";
|
||||
return nsd_service_info;
|
||||
}
|
||||
nsd_service_info.SetServiceInfoName(
|
||||
InspectableReader::ReadString(inspectable));
|
||||
|
||||
// IP Address information
|
||||
inspectable = properties.TryLookup(L"System.Devices.IPAddress");
|
||||
if (inspectable == nullptr) {
|
||||
NEARBY_LOGS(WARNING) << "no IP address information in device information.";
|
||||
return nsd_service_info;
|
||||
}
|
||||
|
||||
auto ipaddresses = InspectableReader::ReadStringArray(inspectable);
|
||||
if (ipaddresses.size() == 0) {
|
||||
NEARBY_LOGS(WARNING) << "no IP address information in device information.";
|
||||
return nsd_service_info;
|
||||
}
|
||||
|
||||
std::string ip_address = ipaddresses[0];
|
||||
|
||||
// read IP port
|
||||
inspectable = properties.TryLookup(L"System.Devices.Dnssd.PortNumber");
|
||||
if (inspectable == nullptr) {
|
||||
NEARBY_LOGS(WARNING) << "no IP port information in device information.";
|
||||
return nsd_service_info;
|
||||
}
|
||||
|
||||
int port = InspectableReader::ReadUint16(inspectable);
|
||||
nsd_service_info.SetServiceAddress(ip_address, port);
|
||||
|
||||
// read text record
|
||||
inspectable = properties.TryLookup(L"System.Devices.Dnssd.TextAttributes");
|
||||
if (inspectable == nullptr) {
|
||||
NEARBY_LOGS(WARNING)
|
||||
<< "no text attributes information in device information.";
|
||||
return nsd_service_info;
|
||||
}
|
||||
|
||||
auto text_attributes = InspectableReader::ReadStringArray(inspectable);
|
||||
for (auto text_attribute : text_attributes) {
|
||||
// text attribute in format key=value
|
||||
int pos = text_attribute.find("=");
|
||||
if (pos <= 0 || pos == text_attribute.size() - 1) {
|
||||
NEARBY_LOGS(WARNING) << "found invalid text attribute " << text_attribute;
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string key = text_attribute.substr(0, pos);
|
||||
std::string value = text_attribute.substr(pos + 1);
|
||||
nsd_service_info.SetTxtRecord(key, value);
|
||||
}
|
||||
|
||||
return nsd_service_info;
|
||||
}
|
||||
|
||||
fire_and_forget WifiLanNsd::Watcher_DeviceAdded(DeviceWatcher sender,
|
||||
DeviceInformation deviceInfo) {
|
||||
NEARBY_LOGS(INFO) << "device added for service " << service_id_;
|
||||
|
||||
// need to read IP address and port informaiton from deviceInfo
|
||||
NsdServiceInfo nsd_service_info =
|
||||
GetNsdServiceInformation(deviceInfo.Properties());
|
||||
|
||||
std::string endpoint =
|
||||
nsd_service_info.GetTxtRecord(KEY_ENDPOINT_INFO.data());
|
||||
if (endpoint.empty()) {
|
||||
return fire_and_forget{};
|
||||
}
|
||||
|
||||
std::unique_ptr<WifiLanService> wifi_lan_service =
|
||||
std::make_unique<WifiLanService>(nsd_service_info);
|
||||
WifiLanService* pwifi_lan_service =
|
||||
GetRemoteWifiLanService(endpoint, std::move(wifi_lan_service));
|
||||
discovered_service_callback_.service_discovered_cb(*pwifi_lan_service,
|
||||
service_id_);
|
||||
return fire_and_forget();
|
||||
}
|
||||
fire_and_forget WifiLanNsd::Watcher_DeviceUpdated(
|
||||
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
|
||||
// TODO(b/200421481): discovery servcie callback needs to support device
|
||||
// update.
|
||||
NEARBY_LOGS(INFO) << "device updated for service " << service_id_;
|
||||
|
||||
return fire_and_forget();
|
||||
}
|
||||
fire_and_forget WifiLanNsd::Watcher_DeviceRemoved(
|
||||
DeviceWatcher sender, DeviceInformationUpdate deviceInfoUpdate) {
|
||||
NEARBY_LOGS(INFO) << "device removed for service " << service_id_;
|
||||
// need to read IP address and port informaiton from deviceInfo
|
||||
NsdServiceInfo nsd_service_info =
|
||||
GetNsdServiceInformation(deviceInfoUpdate.Properties());
|
||||
|
||||
std::string endpoint =
|
||||
nsd_service_info.GetTxtRecord(KEY_ENDPOINT_INFO.data());
|
||||
if (endpoint.empty()) {
|
||||
return fire_and_forget{};
|
||||
}
|
||||
std::unique_ptr<WifiLanService> wifi_lan_service =
|
||||
std::make_unique<WifiLanService>(nsd_service_info);
|
||||
WifiLanService* pwifi_lan_service =
|
||||
GetRemoteWifiLanService(endpoint, std::move(wifi_lan_service));
|
||||
discovered_service_callback_.service_lost_cb(*pwifi_lan_service, service_id_);
|
||||
RemoveRemoteWifiLanService(endpoint);
|
||||
return fire_and_forget();
|
||||
}
|
||||
|
||||
uint16 WifiLanNsd::GenerateSocketPort(const std::string& service_id) {
|
||||
ByteArray service_id_sha = Sha256(service_id, 4);
|
||||
char* hash = service_id_sha.data();
|
||||
int b1 = hash[0] & 0xff;
|
||||
int b2 = hash[1] & 0xff;
|
||||
int b3 = hash[2] & 0xff;
|
||||
int b4 = hash[3] & 0xff;
|
||||
int hashValue = (b1 << 24) | (b2 << 16) | (b3 << 8) | b4;
|
||||
return PORT_MIN + (hashValue % PORT_RANGE);
|
||||
}
|
||||
|
||||
WifiLanService* WifiLanNsd::GetRemoteWifiLanService(
|
||||
std::string endpoint, std::unique_ptr<WifiLanService> wifi_lan_service) {
|
||||
MutexLock lock(&mutex_);
|
||||
|
||||
remote_wifi_lan_services_[endpoint] = std::move(wifi_lan_service);
|
||||
return remote_wifi_lan_services_[endpoint].get();
|
||||
}
|
||||
|
||||
void WifiLanNsd::RemoveRemoteWifiLanService(std::string endpoint) {
|
||||
MutexLock lock(&mutex_);
|
||||
if (remote_wifi_lan_services_.contains(endpoint)) {
|
||||
remote_wifi_lan_services_.erase(endpoint);
|
||||
}
|
||||
}
|
||||
|
||||
std::string WifiLanNsd::GetServiceIdHash() {
|
||||
// Get hashed service id
|
||||
ByteArray service_id_sha = Sha256(service_id_, SERVICE_ID_HASH_LENGTH);
|
||||
char* sha_data = service_id_sha.data();
|
||||
std::string service_id_hash = absl::StrFormat(
|
||||
SERVICE_ID_FORMAT.data(), sha_data[0] & 0xFF, sha_data[1] & 0xFF,
|
||||
sha_data[2] & 0xFF, sha_data[3] & 0xFF, sha_data[4] & 0xFF,
|
||||
sha_data[5] & 0xFF);
|
||||
|
||||
return service_id_hash;
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
@@ -0,0 +1,171 @@
|
||||
// Copyright 2021 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.
|
||||
|
||||
#include "platform/impl/windows/wifi_lan.h"
|
||||
#include "platform/public/logging.h"
|
||||
|
||||
namespace location {
|
||||
namespace nearby {
|
||||
namespace windows {
|
||||
|
||||
WifiLanSocket::WifiLanSocket(StreamSocket socket) {
|
||||
stream_soket_ = socket;
|
||||
input_stream_ = std::make_unique<SocketInputStream>(socket.InputStream());
|
||||
output_stream_ = std::make_unique<SocketOutputStream>(socket.OutputStream());
|
||||
}
|
||||
|
||||
WifiLanSocket::~WifiLanSocket() {
|
||||
if (stream_soket_ != nullptr) {
|
||||
try {
|
||||
Close();
|
||||
} catch (...) {
|
||||
NEARBY_LOGS(ERROR) << "Failed to destructor class WifiLanSocket.";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
InputStream& WifiLanSocket::GetInputStream() { return *input_stream_.get(); }
|
||||
|
||||
OutputStream& WifiLanSocket::GetOutputStream() { return *output_stream_.get(); }
|
||||
|
||||
Exception WifiLanSocket::Close() {
|
||||
try {
|
||||
if (stream_soket_ != nullptr) {
|
||||
stream_soket_.Close();
|
||||
stream_soket_ = nullptr;
|
||||
input_stream_ = nullptr;
|
||||
output_stream_ = nullptr;
|
||||
medium_->CloseConnection(*this);
|
||||
}
|
||||
return {Exception::kSuccess};
|
||||
} catch (...) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
api::WifiLanService* WifiLanSocket::GetRemoteWifiLanService() {
|
||||
return remote_wifi_lan_service_;
|
||||
}
|
||||
|
||||
void WifiLanSocket::SetRemoteWifiLanService(
|
||||
api::WifiLanService* wifi_lan_service) {
|
||||
remote_wifi_lan_service_ = wifi_lan_service;
|
||||
}
|
||||
|
||||
void WifiLanSocket::SetServiceId(std::string service_id) {
|
||||
service_id_ = service_id;
|
||||
}
|
||||
|
||||
void WifiLanSocket::SetMedium(WifiLanMedium* medium) { medium_ = medium; }
|
||||
|
||||
std::string WifiLanSocket::GetLocalAddress() {
|
||||
if (stream_soket_ == nullptr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
return winrt::to_string(
|
||||
stream_soket_.Information().LocalAddress().ToString());
|
||||
}
|
||||
|
||||
int WifiLanSocket::GetLocalPort() {
|
||||
if (stream_soket_ == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return std::stoi(stream_soket_.Information().LocalPort().c_str());
|
||||
}
|
||||
|
||||
// SocketInputStream
|
||||
WifiLanSocket::SocketInputStream::SocketInputStream(IInputStream input_stream) {
|
||||
input_stream_ = input_stream;
|
||||
}
|
||||
|
||||
ExceptionOr<ByteArray> WifiLanSocket::SocketInputStream::Read(
|
||||
std::int64_t size) {
|
||||
try {
|
||||
Buffer buffer = Buffer(size);
|
||||
|
||||
auto ibuffer =
|
||||
input_stream_.ReadAsync(buffer, size, InputStreamOptions::None).get();
|
||||
ByteArray data((char*)ibuffer.data(), ibuffer.Length());
|
||||
return ExceptionOr(data);
|
||||
} catch (...) {
|
||||
return Exception{Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
ExceptionOr<size_t> WifiLanSocket::SocketInputStream::Skip(size_t offset) {
|
||||
try {
|
||||
Buffer buffer = Buffer(offset);
|
||||
|
||||
auto ibuffer =
|
||||
input_stream_.ReadAsync(buffer, offset, InputStreamOptions::None).get();
|
||||
return ExceptionOr((size_t)ibuffer.Length());
|
||||
} catch (...) {
|
||||
return Exception{Exception::kIo};
|
||||
}
|
||||
}
|
||||
|
||||
Exception WifiLanSocket::SocketInputStream::Close() {
|
||||
try {
|
||||
input_stream_.Close();
|
||||
} catch (std::exception exception) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
// SocketOutputStream
|
||||
WifiLanSocket::SocketOutputStream::SocketOutputStream(
|
||||
IOutputStream output_stream) {
|
||||
output_stream_ = output_stream;
|
||||
}
|
||||
|
||||
Exception WifiLanSocket::SocketOutputStream::Write(const ByteArray& data) {
|
||||
Buffer buffer = Buffer(data.size());
|
||||
std::memcpy(buffer.data(), data.data(), data.size());
|
||||
|
||||
try {
|
||||
output_stream_.WriteAsync(buffer);
|
||||
} catch (std::exception exception) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception WifiLanSocket::SocketOutputStream::Flush() {
|
||||
try {
|
||||
output_stream_.FlushAsync().get();
|
||||
} catch (std::exception exception) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
Exception WifiLanSocket::SocketOutputStream::Close() {
|
||||
try {
|
||||
output_stream_.Close();
|
||||
} catch (std::exception exception) {
|
||||
return {Exception::kIo};
|
||||
}
|
||||
|
||||
return {Exception::kSuccess};
|
||||
}
|
||||
|
||||
} // namespace windows
|
||||
} // namespace nearby
|
||||
} // namespace location
|
||||
Reference in New Issue
Block a user