Added custom node id parameter to daemon and WebUI to allow for a user defined node id. See #73

This commit is contained in:
Andrea Bondavalli 2022-05-26 08:33:20 +02:00
parent 1c11e7d212
commit 046babca3d
15 changed files with 62 additions and 19 deletions

View File

@ -185,7 +185,8 @@ Example
"sap_interval": 30,
"mac_addr": "01:00:5e:01:00:01",
"ip_addr": "127.0.0.1",
"node_id": "AES67 daemon ubuntu-d9aca383",
"node_id": "AES67 daemon d9aca383",
"custom_node_id": "",
"ptp_status_script": "./scripts/ptp_status.sh"
}
@ -268,6 +269,11 @@ where:
> JSON string specifying the unique node identifier used to identify mDNS, SAP and SDP services announced by the daemon.
> **_NOTE:_** This parameter is read-only and cannot be set. The server will determine the node id at startup time.
> **custom\_node\_id**
> JSON string specifying a custom node identifier used to identify mDNS, SAP and SDP services announced by the daemon.
> When this parameter is empty the *node_id" is automatically generated by the daemon based on the current IP address.
> **_NOTE:_** When not empty, it is responsibility of the user to specify a unique node id to avoid name clashes on the LAN.
> **ptp\_status\_script**
> JSON string specifying the path to the script executed in background when the PTP slave clock status changes.
> The PTP clock status is passed as first parameter to the script and it can be *unlocked*, *locking* or *locked*.

View File

@ -33,6 +33,7 @@
#include "interface.hpp"
#include "json.hpp"
#include "config.hpp"
#include "utils.hpp"
using namespace boost::asio;
@ -134,7 +135,8 @@ bool Config::save(const Config& config) {
get_sap_mcast_addr() != config.get_sap_mcast_addr() ||
get_rtp_port() != config.get_rtp_port() ||
get_status_file() != config.get_status_file() ||
get_mdns_enabled() != config.get_mdns_enabled();
get_mdns_enabled() != config.get_mdns_enabled() ||
get_custom_node_id() != config.get_custom_node_id();
if (!daemon_restart_)
*this = config;
@ -145,3 +147,11 @@ bool Config::save(const Config& config) {
}
return true;
}
std::string Config::get_node_id() const {
if (custom_node_id_.empty()) {
return get_host_node_id(get_ip_addr());
} else {
return custom_node_id_;
}
}

View File

@ -52,6 +52,8 @@ class Config {
const std::string& get_status_file() const { return status_file_; };
const std::string& get_interface_name() const { return interface_name_; };
const std::string& get_config_filename() const { return config_filename_; };
const std::string& get_custom_node_id() const { return custom_node_id_; };
std::string get_node_id() const;
/* attributes set during init */
const std::array<uint8_t, 6>& get_mac_addr() const { return mac_addr_; };
@ -117,6 +119,9 @@ class Config {
void set_ptp_status_script(const std::string& script) {
ptp_status_script_ = script;
};
void set_custom_node_id(const std::string& node_id) {
custom_node_id_ = node_id;
};
void set_driver_restart(bool restart) { driver_restart_ = restart; }
friend bool operator!=(const Config& lhs, const Config& rhs) {
@ -138,7 +143,8 @@ class Config {
lhs.get_syslog_server() != rhs.get_syslog_server() ||
lhs.get_status_file() != rhs.get_status_file() ||
lhs.get_interface_name() != rhs.get_interface_name() ||
lhs.get_mdns_enabled() != rhs.get_mdns_enabled();
lhs.get_mdns_enabled() != rhs.get_mdns_enabled() ||
lhs.get_custom_node_id() != rhs.get_custom_node_id();
};
friend bool operator==(const Config& lhs, const Config& rhs) {
return !(lhs != rhs);
@ -166,6 +172,8 @@ class Config {
std::string interface_name_{"eth0"};
bool mdns_enabled_{true};
std::string ptp_status_script_;
std::string custom_node_id_;
std::string node_id_;
/* set during init */
std::array<uint8_t, 6> mac_addr_{0, 0, 0, 0, 0, 0};

View File

@ -18,5 +18,6 @@
"status_file": "./status.json",
"interface_name": "lo",
"mdns_enabled": true,
"custom_node_id": "",
"ptp_status_script": "./scripts/ptp_status.sh"
}

View File

@ -99,13 +99,12 @@ std::string config_to_json(const Config& config) {
<< ",\n \"interface_name\": \""
<< escape_json(config.get_interface_name()) << "\""
<< ",\n \"mdns_enabled\": " << std::boolalpha << config.get_mdns_enabled()
<< ",\n \"mac_addr\": \"" << escape_json(config.get_mac_addr_str())
<< "\""
<< ",\n \"ip_addr\": \"" << escape_json(config.get_ip_addr_str()) << "\""
<< ",\n \"node_id\": \"" << escape_json(get_node_id(config.get_ip_addr()))
<< "\""
<< ",\n \"custom_node_id\": \"" << escape_json(config.get_custom_node_id()) << "\""
<< ",\n \"node_id\": \"" << escape_json(config.get_node_id()) << "\""
<< ",\n \"ptp_status_script\": \""
<< escape_json(config.get_ptp_status_script()) << "\""
<< ",\n \"mac_addr\": \"" << escape_json(config.get_mac_addr_str()) << "\""
<< ",\n \"ip_addr\": \"" << escape_json(config.get_ip_addr_str()) << "\""
<< "\n}\n";
return ss.str();
}
@ -325,6 +324,9 @@ Config json_to_config_(std::istream& js, Config& config) {
} else if (key == "ptp_status_script") {
config.set_ptp_status_script(
remove_undesired_chars(val.get_value<std::string>()));
} else if (key == "custom_node_id") {
config.set_custom_node_id(
remove_undesired_chars(val.get_value<std::string>()));
} else if (key == "mac_addr" || key == "ip_addr" || key == "node_id") {
/* ignored */
} else {

View File

@ -58,7 +58,7 @@ class MDNSServer {
std::atomic_bool running_{false};
std::shared_ptr<SessionManager> session_manager_;
std::shared_ptr<Config> config_;
std::string node_id_{get_node_id(config_->get_ip_addr())};
std::string node_id_{config_->get_node_id()};
#ifdef _USE_AVAHI_
using entry_group_bimap_t =

View File

@ -74,7 +74,7 @@ bool RtspSession::announce(uint8_t id,
*/
if (cseq_ < 0 && source_ids_.find(id) != source_ids_.end()) {
std::string path(std::string("/by-name/") +
get_node_id(config_->get_ip_addr()) + " " + name);
config_->get_node_id() + " " + name);
std::stringstream ss;
ss << "ANNOUNCE rtsp://" << address << ":" << std::to_string(port)
<< httplib::detail::encode_url(path) << " RTSP/1.0\r\n"
@ -172,7 +172,7 @@ void RtspSession::build_response(const std::string& url) {
}
auto path = std::get<4>(res);
auto base_path =
std::string("/by-name/") + get_node_id(config_->get_ip_addr()) + " ";
std::string("/by-name/") + config_->get_node_id() + " ";
uint8_t id = SessionManager::stream_id_max + 1;
if (path.rfind(base_path) != std::string::npos) {
/* extract the source name from path and retrive the id */

View File

@ -614,7 +614,7 @@ std::string SessionManager::get_source_sdp_(uint32_t id,
ss << "v=0\n"
<< "o=- " << info.session_id << " " << info.session_version << " IN IP4 "
<< ip::address_v4(info.stream.m_ui32SrcIP).to_string() << "\n"
<< "s=" << get_node_id(config_->get_ip_addr()) << " "
<< "s=" << config_->get_node_id() << " "
<< info.stream.m_cName << "\n"
<< "c=IN IP4 " << ip::address_v4(info.stream.m_ui32DestIP).to_string();
if (IN_MULTICAST(info.stream.m_ui32DestIP)) {

View File

@ -20,6 +20,7 @@
"mdns_enabled": true,
"mac_addr": "00:00:00:00:00:00",
"ip_addr": "127.0.0.1",
"node_id": "AES67 daemon 007f0100",
"custom_node_id": "test node",
"node_id": "test node",
"ptp_status_script": ""
}

View File

@ -393,6 +393,8 @@ BOOST_AUTO_TEST_CASE(get_config) {
auto syslog_server = pt.get<std::string>("syslog_server");
auto status_file = pt.get<std::string>("status_file");
auto ptp_status_script = pt.get<std::string>("ptp_status_script");
auto custom_node_id = pt.get<std::string>("custom_node_id");
auto node_id = pt.get<std::string>("node_id");
auto interface_name = pt.get<std::string>("interface_name");
auto mac_addr = pt.get<std::string>("mac_addr");
auto ip_addr = pt.get<std::string>("ip_addr");
@ -415,6 +417,8 @@ BOOST_AUTO_TEST_CASE(get_config) {
BOOST_CHECK_MESSAGE(mac_addr == "00:00:00:00:00:00", "config as excepcted");
BOOST_CHECK_MESSAGE(ip_addr == "127.0.0.1", "config as excepcted");
BOOST_CHECK_MESSAGE(ptp_status_script == "", "config as excepcted");
BOOST_CHECK_MESSAGE(node_id == "test node", "config as excepcted");
BOOST_CHECK_MESSAGE(custom_node_id == "test node", "config as excepcted");
}
BOOST_AUTO_TEST_CASE(get_ptp_status) {

View File

@ -76,7 +76,7 @@ parse_url(const std::string& _url) {
return {host.length() > 0, protocol, host, port, path};
}
std::string get_node_id(uint32_t ip_addr) {
std::string get_host_node_id(uint32_t ip_addr) {
std::stringstream ss;
ip_addr = htonl(ip_addr);
/* we create an host ID based on the current IP */

View File

@ -34,7 +34,7 @@ std::tuple<bool /* res */,
std::string /* path */>
parse_url(const std::string& _url);
std::string get_node_id(uint32_t ip_addr);
std::string get_host_node_id(uint32_t ip_addr);
std::string sdp_get_subject(const std::string& sdp);

View File

@ -21,5 +21,6 @@
"mac_addr": "00:00:00:00:00:00",
"ip_addr": "127.0.0.1",
"node_id": "AES67 daemon 007f0100",
"custom_node_id": "",
"ptp_status_script": ""
}

View File

@ -53,6 +53,8 @@ class Config extends Component {
syslogServerErr: false,
statusFile: '',
interfaceName: '',
customNodeId: '',
customNodeIdErr: false,
macAddr: '',
ipAddr: '',
errors: 0,
@ -98,6 +100,7 @@ class Config extends Component {
syslogServer: data.syslog_server,
statusFile: data.status_file,
interfaceName: data.interface_name,
customNodeId: data.custom_node_id,
macAddr: data.mac_addr,
ipAddr: data.ip_addr,
nodeId: data.node_id,
@ -115,6 +118,7 @@ class Config extends Component {
!this.state.rtspPortErr &&
!this.state.sapIntervalErr &&
!this.state.syslogServerErr &&
(!this.state.customNodeIdErr || this.state.customNodeId === '') &&
!this.state.isVersionLoading &&
!this.state.isConfigLoading;
}
@ -134,7 +138,8 @@ class Config extends Component {
this.state.maxTicFrameSize,
this.state.sapMcastAddr,
this.state.sapInterval,
this.state.mdnsEnabled)
this.state.mdnsEnabled,
this.state.customNodeId)
.then(response => toast.success('Applying new configuration ...'));
}
@ -186,8 +191,12 @@ class Config extends Component {
{this.state.isConfigLoading ? <Loader/> : <h3>Network Config</h3>}
<table><tbody>
<tr>
<th align="left"> <label>Node ID</label> </th>
<th align="left"> <input value={this.state.nodeId} disabled/> </th>
<th align="left"> <label>Current Node ID</label> </th>
<th align="left"> <input value={this.state.nodeId} size="32" disabled/> </th>
</tr>
<tr>
<th align="left"> <label>Custom Node ID</label> </th>
<th align="left"> <input input type="text" minLength="5" maxLength="48" size="32" pattern="[A-Za-z0-9 _]*" value={this.state.customNodeId} onChange={e => this.setState({customNodeId: e.target.value, customNodeIdErr: !e.currentTarget.checkValidity()})} required/> </th>
</tr>
<tr>
<th align="left"> <label>HTTP port</label> </th>

View File

@ -84,7 +84,7 @@ export default class RestAPI {
});
}
static setConfig(log_severity, syslog_proto, syslog_server, rtp_mcast_base, rtp_port, rtsp_port, playout_delay, tic_frame_size_at_1fs, sample_rate, max_tic_frame_size, sap_mcast_addr, sap_interval, mdns_enabled) {
static setConfig(log_severity, syslog_proto, syslog_server, rtp_mcast_base, rtp_port, rtsp_port, playout_delay, tic_frame_size_at_1fs, sample_rate, max_tic_frame_size, sap_mcast_addr, sap_interval, mdns_enabled, custom_node_id) {
return this.doFetch(config, {
body: JSON.stringify({
log_severity: parseInt(log_severity, 10),
@ -99,6 +99,7 @@ export default class RestAPI {
max_tic_frame_size: parseInt(max_tic_frame_size, 10),
sap_mcast_addr: sap_mcast_addr,
sap_interval: parseInt(sap_interval, 10),
custom_node_id: custom_node_id,
mdns_enabled: mdns_enabled
}),
method: 'POST'