mirror of
https://github.com/wpilibsuite/allwpilib
synced 2026-06-19 00:41:43 +00:00
[wpinet] Handle empty txt block for mdns announcer (#4072)
This commit is contained in:
@@ -26,6 +26,18 @@ public class MulticastServiceAnnouncer implements AutoCloseable {
|
||||
WPINetJNI.createMulticastServiceAnnouncer(serviceName, serviceType, port, keys, values);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a MulticastServiceAnnouncer.
|
||||
*
|
||||
* @param serviceName service name
|
||||
* @param serviceType service type
|
||||
* @param port port
|
||||
*/
|
||||
public MulticastServiceAnnouncer(String serviceName, String serviceType, int port) {
|
||||
m_handle =
|
||||
WPINetJNI.createMulticastServiceAnnouncer(serviceName, serviceType, port, null, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
WPINetJNI.freeMulticastServiceAnnouncer(m_handle);
|
||||
|
||||
@@ -91,17 +91,21 @@ Java_edu_wpi_first_util_WPIUtilJNI_createMulticastServiceAnnouncer
|
||||
JStringRef serviceNameRef{env, serviceName};
|
||||
JStringRef serviceTypeRef{env, serviceType};
|
||||
|
||||
size_t keysLen = env->GetArrayLength(keys);
|
||||
wpi::SmallVector<std::pair<std::string, std::string>, 8> txtVec;
|
||||
txtVec.reserve(keysLen);
|
||||
for (size_t i = 0; i < keysLen; i++) {
|
||||
JLocal<jstring> key{
|
||||
env, static_cast<jstring>(env->GetObjectArrayElement(keys, i))};
|
||||
JLocal<jstring> value{
|
||||
env, static_cast<jstring>(env->GetObjectArrayElement(values, i))};
|
||||
|
||||
txtVec.emplace_back(std::pair<std::string, std::string>{
|
||||
JStringRef{env, key}.str(), JStringRef{env, value}.str()});
|
||||
if (keys != nullptr && values != nullptr) {
|
||||
size_t keysLen = env->GetArrayLength(keys);
|
||||
|
||||
txtVec.reserve(keysLen);
|
||||
for (size_t i = 0; i < keysLen; i++) {
|
||||
JLocal<jstring> key{
|
||||
env, static_cast<jstring>(env->GetObjectArrayElement(keys, i))};
|
||||
JLocal<jstring> value{
|
||||
env, static_cast<jstring>(env->GetObjectArrayElement(values, i))};
|
||||
|
||||
txtVec.emplace_back(std::pair<std::string, std::string>{
|
||||
JStringRef{env, key}.str(), JStringRef{env, value}.str()});
|
||||
}
|
||||
}
|
||||
|
||||
auto announcer = std::make_unique<wpi::MulticastServiceAnnouncer>(
|
||||
|
||||
@@ -22,6 +22,8 @@ class MulticastServiceAnnouncer {
|
||||
MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port,
|
||||
wpi::span<const std::pair<std::string_view, std::string_view>> txt);
|
||||
MulticastServiceAnnouncer(std::string_view serviceName,
|
||||
std::string_view serviceType, int port);
|
||||
~MulticastServiceAnnouncer() noexcept;
|
||||
void Start();
|
||||
void Stop();
|
||||
|
||||
@@ -58,6 +58,7 @@ AvahiFunctionTable::AvahiFunctionTable() {
|
||||
AvahiFunctionLoad(service_resolver_free);
|
||||
AvahiFunctionLoad(entry_group_new);
|
||||
AvahiFunctionLoad(entry_group_free);
|
||||
AvahiFunctionLoad(entry_group_add_service);
|
||||
AvahiFunctionLoad(entry_group_add_service_strlst);
|
||||
AvahiFunctionLoad(entry_group_reset);
|
||||
AvahiFunctionLoad(entry_group_is_empty);
|
||||
|
||||
@@ -263,6 +263,12 @@ class AvahiFunctionTable {
|
||||
(AvahiClient*, AvahiEntryGroupCallback, void*));
|
||||
AvahiFunction(entry_group_free, int, (AvahiEntryGroup*));
|
||||
|
||||
AvahiFunction(entry_group_add_service, int,
|
||||
(AvahiEntryGroup * group, AvahiIfIndex interface,
|
||||
AvahiProtocol protocol, AvahiPublishFlags flags,
|
||||
const char* name, const char* type, const char* domain,
|
||||
const char* host, uint16_t port, ...));
|
||||
|
||||
AvahiFunction(entry_group_add_service_strlst, int,
|
||||
(AvahiEntryGroup * group, AvahiIfIndex interface,
|
||||
AvahiProtocol protocol, AvahiPublishFlags flags,
|
||||
|
||||
@@ -16,7 +16,7 @@ using namespace wpi;
|
||||
struct MulticastServiceAnnouncer::Impl {
|
||||
AvahiFunctionTable& table = AvahiFunctionTable::Get();
|
||||
std::shared_ptr<AvahiThread> thread = AvahiThread::Get();
|
||||
AvahiClient* client;
|
||||
AvahiClient* client = nullptr;
|
||||
AvahiEntryGroup* group = nullptr;
|
||||
std::string serviceName;
|
||||
std::string serviceType;
|
||||
@@ -46,18 +46,22 @@ MulticastServiceAnnouncer::Impl::Impl(std::string_view serviceName,
|
||||
this->serviceType = serviceType;
|
||||
this->port = port;
|
||||
|
||||
std::vector<std::string> txts;
|
||||
for (auto&& i : txt) {
|
||||
txts.push_back(fmt::format("{}={}", i.first, i.second));
|
||||
}
|
||||
if (txt.empty()) {
|
||||
this->stringList = nullptr;
|
||||
} else {
|
||||
std::vector<std::string> txts;
|
||||
for (auto&& i : txt) {
|
||||
txts.push_back(fmt::format("{}={}", i.first, i.second));
|
||||
}
|
||||
|
||||
std::vector<const char*> txtArr;
|
||||
for (auto&& i : txts) {
|
||||
txtArr.push_back(i.c_str());
|
||||
}
|
||||
std::vector<const char*> txtArr;
|
||||
for (auto&& i : txts) {
|
||||
txtArr.push_back(i.c_str());
|
||||
}
|
||||
|
||||
this->stringList =
|
||||
this->table.string_list_new_from_array(txtArr.data(), txtArr.size());
|
||||
this->stringList =
|
||||
this->table.string_list_new_from_array(txtArr.data(), txtArr.size());
|
||||
}
|
||||
}
|
||||
|
||||
static void RegisterService(AvahiClient* client,
|
||||
@@ -85,11 +89,19 @@ static void RegisterService(AvahiClient* client,
|
||||
|
||||
while (true) {
|
||||
if (impl->table.entry_group_is_empty(impl->group)) {
|
||||
auto ret = impl->table.entry_group_add_service_strlst(
|
||||
impl->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
|
||||
AVAHI_PUBLISH_USE_MULTICAST, impl->serviceName.c_str(),
|
||||
impl->serviceType.c_str(), "local", nullptr, impl->port,
|
||||
impl->stringList);
|
||||
int ret = 0;
|
||||
if (impl->stringList == nullptr) {
|
||||
ret = impl->table.entry_group_add_service(
|
||||
impl->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
|
||||
AVAHI_PUBLISH_USE_MULTICAST, impl->serviceName.c_str(),
|
||||
impl->serviceType.c_str(), "local", nullptr, impl->port, nullptr);
|
||||
} else {
|
||||
ret = impl->table.entry_group_add_service_strlst(
|
||||
impl->group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
|
||||
AVAHI_PUBLISH_USE_MULTICAST, impl->serviceName.c_str(),
|
||||
impl->serviceType.c_str(), "local", nullptr, impl->port,
|
||||
impl->stringList);
|
||||
}
|
||||
if (ret == AVAHI_ERR_COLLISION) {
|
||||
// Local collision
|
||||
char* newName =
|
||||
@@ -121,6 +133,12 @@ static void ClientCallback(AvahiClient* client, AvahiClientState state,
|
||||
}
|
||||
}
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port) {
|
||||
wpi::span<const std::pair<std::string_view, std::string_view>> txt;
|
||||
pImpl = std::make_unique<Impl>(serviceName, serviceType, port, txt);
|
||||
}
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port,
|
||||
wpi::span<const std::pair<std::string, std::string>> txt) {
|
||||
|
||||
@@ -22,6 +22,14 @@ struct MulticastServiceAnnouncer::Impl {
|
||||
~Impl() noexcept { TXTRecordDeallocate(&txtRecord); }
|
||||
};
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port) {
|
||||
pImpl = std::make_unique<Impl>();
|
||||
pImpl->serviceName = serviceName;
|
||||
pImpl->serviceType = serviceType;
|
||||
pImpl->port = port;
|
||||
}
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port,
|
||||
wpi::span<const std::pair<std::string, std::string>> txt) {
|
||||
|
||||
@@ -103,6 +103,12 @@ MulticastServiceAnnouncer::Impl::Impl(std::string_view serviceName,
|
||||
std::wstring{wideStorage.data(), wideStorage.size()};
|
||||
}
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port) {
|
||||
wpi::span<const std::pair<std::string_view, std::string_view>> txt;
|
||||
pImpl = std::make_unique<Impl>(serviceName, serviceType, port, txt);
|
||||
}
|
||||
|
||||
MulticastServiceAnnouncer::MulticastServiceAnnouncer(
|
||||
std::string_view serviceName, std::string_view serviceType, int port,
|
||||
wpi::span<const std::pair<std::string, std::string>> txt) {
|
||||
|
||||
47
wpinet/src/test/native/cpp/MulticastTest.cpp
Normal file
47
wpinet/src/test/native/cpp/MulticastTest.cpp
Normal file
@@ -0,0 +1,47 @@
|
||||
// Copyright (c) FIRST and other WPILib contributors.
|
||||
// Open Source Software; you can modify and/or share it under the terms of
|
||||
// the WPILib BSD license file in the root directory of this project.
|
||||
|
||||
#include <wpinet/MulticastServiceAnnouncer.h>
|
||||
#include <wpinet/MulticastServiceResolver.h>
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include <wpi/timestamp.h>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
TEST(MulticastServiceAnnouncerTest, EmptyText) {
|
||||
const std::string_view serviceName = "TestServiceNoText";
|
||||
const std::string_view serviceType = "_wpinotxt";
|
||||
const int port = std::rand();
|
||||
wpi::MulticastServiceAnnouncer announcer(serviceName, serviceType, port);
|
||||
wpi::MulticastServiceResolver resolver(serviceType);
|
||||
|
||||
if (announcer.HasImplementation() && resolver.HasImplementation()) {
|
||||
announcer.Start();
|
||||
resolver.Start();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
|
||||
resolver.Stop();
|
||||
announcer.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
TEST(MulticastServiceAnnouncerTest, SingleText) {
|
||||
const std::string_view serviceName = "TestServiceSingle";
|
||||
const std::string_view serviceType = "_wpitxt";
|
||||
const int port = std::rand();
|
||||
std::array<std::pair<std::string, std::string>, 1> txt = {
|
||||
std::make_pair("hello", "world")};
|
||||
wpi::MulticastServiceAnnouncer announcer(serviceName, serviceType, port, txt);
|
||||
wpi::MulticastServiceResolver resolver(serviceType);
|
||||
|
||||
if (announcer.HasImplementation() && resolver.HasImplementation()) {
|
||||
announcer.Start();
|
||||
resolver.Start();
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::seconds(1));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user