mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-14 22:56:12 -04:00
Register MDNS service using Win32 API
PiperOrigin-RevId: 714283635
This commit is contained in:
committed by
Copybara-Service
parent
694a722d2c
commit
877a2d3e5b
@@ -105,6 +105,7 @@ cc_library(
|
||||
"wifi_hotspot_native.h",
|
||||
"wifi_intel.h",
|
||||
"wifi_lan.h",
|
||||
"wifi_lan_mdns.h",
|
||||
],
|
||||
copts = ["-DNO_INTEL_PIE"],
|
||||
visibility = ["//visibility:private"],
|
||||
@@ -204,6 +205,7 @@ cc_library(
|
||||
"wifi_hotspot_server_socket.cc",
|
||||
"wifi_hotspot_socket.cc",
|
||||
"wifi_intel.cc",
|
||||
"wifi_lan_mdns.cc",
|
||||
"wifi_lan_medium.cc",
|
||||
"wifi_lan_server_socket.cc",
|
||||
"wifi_lan_socket.cc",
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
// Copyright 2025 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 "internal/platform/implementation/windows/wifi_lan_mdns.h"
|
||||
|
||||
// clang-format off
|
||||
#include <windows.h>
|
||||
#include <windns.h>
|
||||
// clang-format on
|
||||
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/synchronization/notification.h"
|
||||
#include "absl/time/time.h"
|
||||
#include "internal/platform/implementation/windows/string_utils.h"
|
||||
#include "internal/platform/logging.h"
|
||||
|
||||
namespace nearby::windows {
|
||||
namespace {
|
||||
// mDNS information for advertising and discovery
|
||||
const char kMdnsHostName[] = "%s.local";
|
||||
const char kMdnsInstanceNameFormat[] = "%s.%slocal";
|
||||
|
||||
// Timeout for starting mDNS service
|
||||
constexpr absl::Duration kDnsServiceTimeout = absl::Seconds(3);
|
||||
} // namespace
|
||||
|
||||
WifiLanMdns::~WifiLanMdns() {
|
||||
if (is_service_started_) {
|
||||
StopMdnsService();
|
||||
}
|
||||
}
|
||||
|
||||
bool WifiLanMdns::StartMdnsService(
|
||||
const std::string& service_name, const std::string& service_type, int port,
|
||||
absl::flat_hash_map<std::string, std::string> text_records) {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
LOG(INFO) << "StartMdnsService: " << service_name << " " << service_type
|
||||
<< " " << port;
|
||||
if (is_service_started_) {
|
||||
LOG(WARNING) << "The mDNS service is already started.";
|
||||
return false;
|
||||
}
|
||||
|
||||
memset(&dns_service_instance_, 0, sizeof(dns_service_instance_));
|
||||
memset(&dns_service_register_request_, 0,
|
||||
sizeof(dns_service_register_request_));
|
||||
|
||||
// Composite the service request.
|
||||
std::string instance_name =
|
||||
absl::StrFormat(kMdnsInstanceNameFormat, service_name, service_type);
|
||||
dns_service_instance_name_ = std::make_unique<std::wstring>(
|
||||
string_utils::StringToWideString(instance_name));
|
||||
|
||||
std::optional<std::string> computer_name = GetComputerName();
|
||||
if (!computer_name.has_value()) {
|
||||
LOG(ERROR) << "Failed to get computer name.";
|
||||
return false;
|
||||
}
|
||||
|
||||
std::string host_name = absl::StrFormat(kMdnsHostName, *computer_name);
|
||||
host_name_ = std::make_unique<std::wstring>(
|
||||
string_utils::StringToWideString(host_name));
|
||||
|
||||
dns_service_instance_.pszInstanceName =
|
||||
(LPWSTR)dns_service_instance_name_->c_str();
|
||||
dns_service_instance_.pszHostName = (LPWSTR)host_name_->c_str();
|
||||
dns_service_instance_.wPort = port;
|
||||
|
||||
// Allocate memory for filling text records, it should be freed in
|
||||
// stopping mDNS service.
|
||||
if (!text_records.empty()) {
|
||||
dns_service_instance_.dwPropertyCount = text_records.size();
|
||||
|
||||
for (const auto& [key, value] : text_records) {
|
||||
text_keys_.push_back(string_utils::StringToWideString(key));
|
||||
text_values_.push_back(string_utils::StringToWideString(value));
|
||||
}
|
||||
|
||||
keys_ = new PWSTR[text_records.size()];
|
||||
values_ = new PWSTR[text_records.size()];
|
||||
|
||||
for (int i = 0; i < text_records.size(); ++i) {
|
||||
keys_[i] = text_keys_[i].data();
|
||||
values_[i] = text_values_[i].data();
|
||||
}
|
||||
|
||||
dns_service_instance_.keys = keys_;
|
||||
dns_service_instance_.values = values_;
|
||||
}
|
||||
|
||||
// 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 = nullptr;
|
||||
dns_service_register_request_.pServiceInstance = &dns_service_instance_;
|
||||
dns_service_register_request_.pQueryContext = this; // callback use it
|
||||
dns_service_register_request_.pRegisterCompletionCallback =
|
||||
WifiLanMdns::DnsServiceRegisterComplete;
|
||||
|
||||
dns_service_notification_ = std::make_unique<absl::Notification>();
|
||||
|
||||
DWORD status = DnsServiceRegister(&dns_service_register_request_, nullptr);
|
||||
|
||||
if (status != DNS_REQUEST_PENDING) {
|
||||
NEARBY_LOGS(ERROR) << "Failed to start mDNS advertising for service type ="
|
||||
<< service_type;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dns_service_notification_->WaitForNotificationWithTimeout(
|
||||
kDnsServiceTimeout)) {
|
||||
LOG(ERROR) << "Failed to start mDNS advertising for service type ="
|
||||
<< service_type;
|
||||
return false;
|
||||
}
|
||||
|
||||
dns_service_notification_ = nullptr;
|
||||
is_service_started_ = true;
|
||||
|
||||
LOG(INFO) << "Succeeded to start mDNS advertising for service type "
|
||||
<< service_type;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool WifiLanMdns::StopMdnsService() {
|
||||
absl::MutexLock lock(&mutex_);
|
||||
LOG(INFO) << "StopMdnsService is called";
|
||||
if (!is_service_started_) {
|
||||
LOG(WARNING) << "The mDNS service is not started.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dns_service_notification_ = std::make_unique<absl::Notification>();
|
||||
|
||||
DWORD status = DnsServiceDeRegister(&dns_service_register_request_, nullptr);
|
||||
|
||||
if (status != DNS_REQUEST_PENDING) {
|
||||
NEARBY_LOGS(ERROR) << "Failed to stop mDNS advertising.";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!dns_service_notification_->WaitForNotificationWithTimeout(
|
||||
kDnsServiceTimeout)) {
|
||||
LOG(ERROR) << "Failed to start mDNS advertising.";
|
||||
return false;
|
||||
}
|
||||
|
||||
dns_service_notification_ = nullptr;
|
||||
if (dns_service_instance_.keys != nullptr) {
|
||||
delete[] dns_service_instance_.keys;
|
||||
delete[] dns_service_instance_.values;
|
||||
dns_service_instance_.keys = nullptr;
|
||||
dns_service_instance_.values = nullptr;
|
||||
}
|
||||
|
||||
is_service_started_ = false;
|
||||
LOG(INFO) << "Succeeded to stop mDNS advertising.";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void WifiLanMdns::NotifyStatusUpdated(DWORD status) {
|
||||
VLOG(1) << "NotifyStatusUpdated: " << status;
|
||||
if (dns_service_notification_ != nullptr) {
|
||||
dns_service_notification_->Notify();
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<std::string> WifiLanMdns::GetComputerName() {
|
||||
char computer_name[MAX_COMPUTERNAME_LENGTH + 1];
|
||||
DWORD size = sizeof(computer_name);
|
||||
|
||||
// Get the computer name.
|
||||
if (::GetComputerNameA(computer_name, &size)) {
|
||||
return std::string(computer_name, size);
|
||||
} else {
|
||||
return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
void WifiLanMdns::DnsServiceRegisterComplete(DWORD Status, PVOID pQueryContext,
|
||||
PDNS_SERVICE_INSTANCE pInstance) {
|
||||
LOG(INFO) << "DnsServiceRegisterComplete: " << Status;
|
||||
WifiLanMdns* mdns = static_cast<WifiLanMdns*>(pQueryContext);
|
||||
mdns->NotifyStatusUpdated(Status);
|
||||
}
|
||||
|
||||
} // namespace nearby::windows
|
||||
@@ -0,0 +1,70 @@
|
||||
// Copyright 2025 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 THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_WIFI_LAN_MDNS_H_
|
||||
#define THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_WIFI_LAN_MDNS_H_
|
||||
|
||||
// clang-format off
|
||||
#include <windows.h>
|
||||
#include <windns.h>
|
||||
// clang-format on
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "absl/base/thread_annotations.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "absl/synchronization/mutex.h"
|
||||
#include "absl/synchronization/notification.h"
|
||||
|
||||
namespace nearby::windows {
|
||||
|
||||
class WifiLanMdns {
|
||||
public:
|
||||
WifiLanMdns() = default;
|
||||
~WifiLanMdns();
|
||||
|
||||
bool StartMdnsService(
|
||||
const std::string& service_name, const std::string& service_type,
|
||||
int port, absl::flat_hash_map<std::string, std::string> text_records);
|
||||
|
||||
bool StopMdnsService();
|
||||
|
||||
void NotifyStatusUpdated(DWORD status);
|
||||
|
||||
private:
|
||||
static void DnsServiceRegisterComplete(DWORD Status, PVOID pQueryContext,
|
||||
PDNS_SERVICE_INSTANCE pInstance);
|
||||
std::optional<std::string> GetComputerName();
|
||||
|
||||
absl::Mutex mutex_;
|
||||
std::unique_ptr<absl::Notification> dns_service_notification_ = nullptr;
|
||||
bool is_service_started_ ABSL_GUARDED_BY(mutex_) = false;
|
||||
std::unique_ptr<std::wstring> dns_service_instance_name_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
std::unique_ptr<std::wstring> host_name_ ABSL_GUARDED_BY(mutex_);
|
||||
DNS_SERVICE_INSTANCE
|
||||
dns_service_instance_ ABSL_GUARDED_BY(mutex_);
|
||||
DNS_SERVICE_REGISTER_REQUEST dns_service_register_request_
|
||||
ABSL_GUARDED_BY(mutex_);
|
||||
std::vector<std::wstring> text_keys_ ABSL_GUARDED_BY(mutex_);
|
||||
std::vector<std::wstring> text_values_ ABSL_GUARDED_BY(mutex_);
|
||||
PWSTR* keys_ ABSL_GUARDED_BY(mutex_) = nullptr;
|
||||
PWSTR* values_ ABSL_GUARDED_BY(mutex_) = nullptr;
|
||||
};
|
||||
|
||||
} // namespace nearby::windows
|
||||
|
||||
#endif // THIRD_PARTY_NEARBY_INTERNAL_PLATFORM_IMPLEMENTATION_WINDOWS_WIFI_LAN_MDNS_H_
|
||||
Reference in New Issue
Block a user