diff --git a/daemon/README.md b/daemon/README.md index 4415aaf..02998cb 100644 --- a/daemon/README.md +++ b/daemon/README.md @@ -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*. diff --git a/daemon/config.cpp b/daemon/config.cpp index c364a93..b32199a 100644 --- a/daemon/config.cpp +++ b/daemon/config.cpp @@ -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_; + } +} diff --git a/daemon/config.hpp b/daemon/config.hpp index 6502071..003ee69 100644 --- a/daemon/config.hpp +++ b/daemon/config.hpp @@ -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& 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 mac_addr_{0, 0, 0, 0, 0, 0}; diff --git a/daemon/daemon.conf b/daemon/daemon.conf index 7a02015..b049a64 100644 --- a/daemon/daemon.conf +++ b/daemon/daemon.conf @@ -18,5 +18,6 @@ "status_file": "./status.json", "interface_name": "lo", "mdns_enabled": true, + "custom_node_id": "", "ptp_status_script": "./scripts/ptp_status.sh" } diff --git a/daemon/json.cpp b/daemon/json.cpp index 68a16c7..a42bb74 100644 --- a/daemon/json.cpp +++ b/daemon/json.cpp @@ -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())); + } else if (key == "custom_node_id") { + config.set_custom_node_id( + remove_undesired_chars(val.get_value())); } else if (key == "mac_addr" || key == "ip_addr" || key == "node_id") { /* ignored */ } else { diff --git a/daemon/mdns_server.hpp b/daemon/mdns_server.hpp index 0800d31..178b3ce 100644 --- a/daemon/mdns_server.hpp +++ b/daemon/mdns_server.hpp @@ -58,7 +58,7 @@ class MDNSServer { std::atomic_bool running_{false}; std::shared_ptr session_manager_; std::shared_ptr 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 = diff --git a/daemon/rtsp_server.cpp b/daemon/rtsp_server.cpp index c695245..55b482e 100644 --- a/daemon/rtsp_server.cpp +++ b/daemon/rtsp_server.cpp @@ -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 */ diff --git a/daemon/session_manager.cpp b/daemon/session_manager.cpp index f6a5a91..ffa5dbc 100644 --- a/daemon/session_manager.cpp +++ b/daemon/session_manager.cpp @@ -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)) { diff --git a/daemon/tests/daemon.conf b/daemon/tests/daemon.conf index f4d2d72..853fd97 100644 --- a/daemon/tests/daemon.conf +++ b/daemon/tests/daemon.conf @@ -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": "" } diff --git a/daemon/tests/daemon_test.cpp b/daemon/tests/daemon_test.cpp index d633c13..3e8cabe 100644 --- a/daemon/tests/daemon_test.cpp +++ b/daemon/tests/daemon_test.cpp @@ -393,6 +393,8 @@ BOOST_AUTO_TEST_CASE(get_config) { auto syslog_server = pt.get("syslog_server"); auto status_file = pt.get("status_file"); auto ptp_status_script = pt.get("ptp_status_script"); + auto custom_node_id = pt.get("custom_node_id"); + auto node_id = pt.get("node_id"); auto interface_name = pt.get("interface_name"); auto mac_addr = pt.get("mac_addr"); auto ip_addr = pt.get("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) { diff --git a/daemon/utils.cpp b/daemon/utils.cpp index 5271ee7..1f3c753 100644 --- a/daemon/utils.cpp +++ b/daemon/utils.cpp @@ -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 */ diff --git a/daemon/utils.hpp b/daemon/utils.hpp index 100ccf6..343f75d 100644 --- a/daemon/utils.hpp +++ b/daemon/utils.hpp @@ -34,7 +34,7 @@ std::tuple 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); diff --git a/test/daemon.conf b/test/daemon.conf index 3d3131f..279bae0 100644 --- a/test/daemon.conf +++ b/test/daemon.conf @@ -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": "" } diff --git a/webui/src/Config.jsx b/webui/src/Config.jsx index 2019c9e..ecc6513 100644 --- a/webui/src/Config.jsx +++ b/webui/src/Config.jsx @@ -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 ? :

Network Config

} - - + + + + + + diff --git a/webui/src/Services.js b/webui/src/Services.js index 733801c..35ffab6 100644 --- a/webui/src/Services.js +++ b/webui/src/Services.js @@ -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'
this.setState({customNodeId: e.target.value, customNodeIdErr: !e.currentTarget.checkValidity()})} required/>