[ntcore] Add ability to announce mDNS for server (#8373)

We can use this as a new way of resolving addresses.
This commit is contained in:
Thad House
2025-12-16 22:26:56 -08:00
committed by GitHub
parent 7cb58962c5
commit e2d492ac3f
27 changed files with 133 additions and 56 deletions

View File

@@ -103,16 +103,20 @@ void InstanceImpl::StopLocal() {
void InstanceImpl::StartServer(std::string_view persistFilename,
std::string_view listenAddress,
std::string_view mdnsService,
unsigned int port) {
std::scoped_lock lock{m_mutex};
if (networkMode != NT_NET_MODE_NONE) {
return;
}
m_networkServer = std::make_shared<NetworkServer>(
persistFilename, listenAddress, port, localStorage, connectionList,
logger, [this] {
persistFilename, listenAddress, mdnsService, port, localStorage,
connectionList, logger, [this](bool announcingmDNS) {
std::scoped_lock lock{m_mutex};
networkMode &= ~NT_NET_MODE_STARTING;
if (announcingmDNS) {
networkMode |= NT_NET_MODE_MDNS_ANNOUNCING;
}
});
networkMode = NT_NET_MODE_SERVER | NT_NET_MODE_STARTING;
listenerStorage.NotifyTimeSync({}, NT_EVENT_TIMESYNC, 0, 0, true);

View File

@@ -44,7 +44,8 @@ class InstanceImpl {
void StartLocal();
void StopLocal();
void StartServer(std::string_view persistFilename,
std::string_view listenAddress, unsigned int port);
std::string_view listenAddress, std::string_view mdnsService,
unsigned int port);
void StopServer();
void StartClient(std::string_view identity);
void StopClient();

View File

@@ -253,17 +253,19 @@ void NetworkServer::ServerConnection4::ProcessWsUpgrade() {
}
NetworkServer::NetworkServer(std::string_view persistentFilename,
std::string_view listenAddress, unsigned int port,
std::string_view listenAddress,
std::string_view mdnsService, unsigned int port,
net::ILocalStorage& localStorage,
IConnectionList& connList,
wpi::util::Logger& logger,
std::function<void()> initDone)
std::function<void(bool)> initDone)
: m_localStorage{localStorage},
m_connList{connList},
m_logger{logger},
m_initDone{std::move(initDone)},
m_persistentFilename{persistentFilename},
m_listenAddress{wpi::util::trim(listenAddress)},
m_mdnsService{wpi::util::trim(mdnsService)},
m_port{port},
m_serverImpl{logger},
m_localQueue{logger},
@@ -462,9 +464,23 @@ void NetworkServer::Init() {
tcp4->Listen();
}
bool announcingmDNS = false;
if (!m_mdnsService.empty()) {
m_mdnsAnnouncer.emplace(m_mdnsService, "_networktables._tcp", m_port);
if (!m_mdnsAnnouncer->HasImplementation()) {
WARN("mDNS service announcer not available; cannot announce '{}'",
m_mdnsService);
m_mdnsAnnouncer.reset();
} else {
m_mdnsAnnouncer->Start();
announcingmDNS = true;
INFO("mDNS announcing as service '{}' on port {}", m_mdnsService, m_port);
}
}
if (m_initDone) {
DEBUG4("NetworkServer initDone()");
m_initDone();
m_initDone(announcingmDNS);
m_initDone = nullptr;
}
}

View File

@@ -7,6 +7,7 @@
#include <atomic>
#include <functional>
#include <memory>
#include <optional>
#include <string>
#include <string_view>
#include <vector>
@@ -15,6 +16,7 @@
#include "net/Message.hpp"
#include "server/ServerImpl.hpp"
#include "wpi/net/EventLoopRunner.hpp"
#include "wpi/net/MulticastServiceAnnouncer.h"
#include "wpi/net/uv/Async.hpp"
#include "wpi/net/uv/Idle.hpp"
#include "wpi/net/uv/Timer.hpp"
@@ -35,9 +37,10 @@ class IConnectionList;
class NetworkServer {
public:
NetworkServer(std::string_view persistentFilename,
std::string_view listenAddress, unsigned int port,
net::ILocalStorage& localStorage, IConnectionList& connList,
wpi::util::Logger& logger, std::function<void()> initDone);
std::string_view listenAddress, std::string_view mdnsService,
unsigned int port, net::ILocalStorage& localStorage,
IConnectionList& connList, wpi::util::Logger& logger,
std::function<void(bool)> initDone);
~NetworkServer();
void FlushLocal();
@@ -57,13 +60,15 @@ class NetworkServer {
net::ILocalStorage& m_localStorage;
IConnectionList& m_connList;
wpi::util::Logger& m_logger;
std::function<void()> m_initDone;
std::function<void(bool)> m_initDone;
std::string m_persistentData;
std::string m_persistentFilename;
std::string m_listenAddress;
std::string m_mdnsService;
unsigned int m_port;
// used only from loop
std::optional<wpi::net::MulticastServiceAnnouncer> m_mdnsAnnouncer;
std::shared_ptr<wpi::net::uv::Timer> m_readLocalTimer;
std::shared_ptr<wpi::net::uv::Timer> m_savePersistentTimer;
std::shared_ptr<wpi::net::uv::Async<>> m_flushLocal;

View File

@@ -1178,12 +1178,12 @@ Java_org_wpilib_networktables_NetworkTablesJNI_stopLocal
/*
* Class: org_wpilib_networktables_NetworkTablesJNI
* Method: startServer
* Signature: (ILjava/lang/String;Ljava/lang/String;I)V
* Signature: (ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;I)V
*/
JNIEXPORT void JNICALL
Java_org_wpilib_networktables_NetworkTablesJNI_startServer
(JNIEnv* env, jclass, jint inst, jstring persistFilename,
jstring listenAddress, jint port)
jstring listenAddress, jstring mdnsService, jint port)
{
if (!persistFilename) {
nullPointerEx.Throw(env, "persistFilename cannot be null");
@@ -1193,8 +1193,13 @@ Java_org_wpilib_networktables_NetworkTablesJNI_startServer
nullPointerEx.Throw(env, "listenAddress cannot be null");
return;
}
if (!mdnsService) {
nullPointerEx.Throw(env, "mdnsService cannot be null");
return;
}
wpi::nt::StartServer(inst, JStringRef{env, persistFilename}.str(),
JStringRef{env, listenAddress}.c_str(), port);
JStringRef{env, listenAddress}.c_str(),
JStringRef{env, mdnsService}.c_str(), port);
}
/*

View File

@@ -532,9 +532,10 @@ void NT_StopLocal(NT_Inst inst) {
void NT_StartServer(NT_Inst inst, const struct WPI_String* persist_filename,
const struct WPI_String* listen_address,
unsigned int port) {
const struct WPI_String* mdns_service, unsigned int port) {
wpi::nt::StartServer(inst, wpi::util::to_string_view(persist_filename),
wpi::util::to_string_view(listen_address), port);
wpi::util::to_string_view(listen_address),
wpi::util::to_string_view(mdns_service), port);
}
void NT_StopServer(NT_Inst inst) {

View File

@@ -633,9 +633,10 @@ void StopLocal(NT_Inst inst) {
}
void StartServer(NT_Inst inst, std::string_view persist_filename,
std::string_view listen_address, unsigned int port) {
std::string_view listen_address, std::string_view mdns_service,
unsigned int port) {
if (auto ii = InstanceImpl::GetTyped(inst, Handle::kInstance)) {
ii->StartServer(persist_filename, listen_address, port);
ii->StartServer(persist_filename, listen_address, mdns_service, port);
}
}

View File

@@ -607,12 +607,17 @@ class NetworkTableInstance final {
* @param listen_address the address to listen on, or an empty string to
* listen on any address. (UTF-8 string, null
* terminated)
* @param mdns_service the mDNS service name to announce, or an empty
* string to not announce via mDNS (UTF-8 string,
* null terminated)
* @param port port to communicate over
*/
void StartServer(std::string_view persist_filename = "networktables.json",
const char* listen_address = "",
std::string_view listen_address = "",
std::string_view mdns_service = "",
unsigned int port = kDefaultPort) {
::wpi::nt::StartServer(m_handle, persist_filename, listen_address, port);
::wpi::nt::StartServer(m_handle, persist_filename, listen_address,
mdns_service, port);
}
/**

View File

@@ -90,6 +90,7 @@ enum NT_NetworkMode {
NT_NET_MODE_CLIENT = 0x04, /* running in client mode */
NT_NET_MODE_STARTING = 0x08, /* flag for starting (either client or server) */
NT_NET_MODE_LOCAL = 0x10, /* running in local-only mode */
NT_NET_MODE_MDNS_ANNOUNCING = 0x20 /* mDNS is enabled and announcing */
};
/** Event notification flags. */
@@ -1116,10 +1117,14 @@ void NT_StopLocal(NT_Inst inst);
* @param listen_address the address to listen on, or an empty string to
* listen on any address. (UTF-8 string, null
* terminated)
* @param mdns_service the mDNS service name to advertise, or an empty
* string to not advertise via mDNS. (UTF-8 string,
* null terminated)
* @param port port to communicate over
*/
void NT_StartServer(NT_Inst inst, const struct WPI_String* persist_filename,
const struct WPI_String* listen_address, unsigned int port);
const struct WPI_String* listen_address,
const struct WPI_String* mdns_service, unsigned int port);
/**
* Stops the server if it is running.

View File

@@ -1057,10 +1057,14 @@ void StopLocal(NT_Inst inst);
* @param listen_address the address to listen on, or an empty string to
* listen on any address. (UTF-8 string, null
* terminated)
* @param mdns_service the mDNS service name to advertise, or an empty
* string to not advertise via mDNS. (UTF-8 string,
* null terminated)
* @param port port to communicate over
*/
void StartServer(NT_Inst inst, std::string_view persist_filename,
std::string_view listen_address, unsigned int port);
std::string_view listen_address, std::string_view mdns_service,
unsigned int port);
/**
* Stops the server if it is running.

View File

@@ -117,11 +117,11 @@ classes:
StopLocal:
StartServer:
cpp_code: |
[](NetworkTableInstance * self, std::string_view persist_filename, const char* listen_address,
unsigned int port) {
[](NetworkTableInstance * self, std::string_view persist_filename, std::string_view listen_address,
std::string_view mdns_service, unsigned int port) {
pyntcore::onInstanceStart(self);
py::gil_scoped_release release;
self->StartServer(persist_filename, listen_address, port);
self->StartServer(persist_filename, listen_address, mdns_service, port);
}
StopServer:
StopClient:
@@ -156,7 +156,7 @@ classes:
operator==:
StartClient:
inline_code: |
.def("configPythonLogging", [](NetworkTableInstance * self,
.def("configPythonLogging", [](NetworkTableInstance * self,
NetworkTableInstance::LogLevel minLevel, NetworkTableInstance::LogLevel maxLevel, py::str logName) {
py::module::import("ntcore._logutil").attr("_config_logging")(self, minLevel, maxLevel, logName);
}, py::kw_only(),