From 4765392c690a3a5248e261b56a3a1fe33db1f3fe Mon Sep 17 00:00:00 2001 From: Andrianov Roman Date: Wed, 3 Apr 2024 14:57:33 +0200 Subject: [PATCH] qos_provider support (#1955) * qos_provider support added * qos_provider tests * qos_provider documentation * qos_provider build flag * system definition parsing support Signed-off-by: Splinter1984 * fix #1955 remarks * CI analyzer comliant fixes Signed-off-by: Splinter1984 --------- Signed-off-by: Splinter1984 --- README.md | 1 + docs/manual/about_dds/eclipse_cyclone_dds.rst | 65 +- docs/manual/about_dds/qos_provider.rst | 402 +++ docs/manual/api/qosprovider.rst | 6 + docs/manual/ddsc.rst | 1 + docs/manual/external-links.part.rst | 64 +- src/CMakeLists.txt | 1 + src/core/CMakeLists.txt | 13 + src/core/ddsc/CMakeLists.txt | 13 + src/core/ddsc/include/dds/dds.h | 1 + .../dds/ddsc/dds_public_qos_provider.h | 121 + src/core/ddsc/src/dds__qos_provider.h | 47 + src/core/ddsc/src/dds__sysdef_model.h | 706 ++++ src/core/ddsc/src/dds__sysdef_parser.h | 145 + src/core/ddsc/src/dds__sysdef_validation.h | 26 + src/core/ddsc/src/dds_qos_provider.c | 292 ++ src/core/ddsc/src/dds_sysdef_parser.c | 3065 +++++++++++++++++ src/core/ddsc/src/dds_sysdef_validation.c | 141 + src/core/ddsc/tests/CMakeLists.txt | 5 + src/core/ddsc/tests/qos_provider.c | 1205 +++++++ src/core/xtests/symbol_export/symbol_export.c | 11 + src/ddsrt/CMakeLists.txt | 2 +- src/ddsrt/include/dds/ddsrt/log.h | 4 + src/ddsrt/include/dds/features.h.in | 4 + 24 files changed, 6278 insertions(+), 63 deletions(-) create mode 100644 docs/manual/about_dds/qos_provider.rst create mode 100644 docs/manual/api/qosprovider.rst create mode 100644 src/core/ddsc/include/dds/ddsc/dds_public_qos_provider.h create mode 100644 src/core/ddsc/src/dds__qos_provider.h create mode 100644 src/core/ddsc/src/dds__sysdef_model.h create mode 100644 src/core/ddsc/src/dds__sysdef_parser.h create mode 100644 src/core/ddsc/src/dds__sysdef_validation.h create mode 100644 src/core/ddsc/src/dds_qos_provider.c create mode 100644 src/core/ddsc/src/dds_sysdef_parser.c create mode 100644 src/core/ddsc/src/dds_sysdef_validation.c create mode 100644 src/core/ddsc/tests/qos_provider.c diff --git a/README.md b/README.md index 808566ded4..2345238261 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ There are some configuration options specified using CMake defines in addition t * `-DENABLE_SOURCE_SPECIFIC_MULTICAST=NO`: to disable support for source-specific multicast (disabling this and `-DENABLE_IPV6=NO` may be needed for QNX builds) * `-DENABLE_IPV6=NO`: to disable ipv6 support (disabling this and `-DENABLE_SOURCE_SPECIFIC_MULTICAST=NO` may be needed for QNX builds) * `-DBUILD_IDLC_XTESTS=NO`: Include a set of tests for the IDL compiler that use the C back-end to compile an idl file at (test) runtime, and use the C compiler to build a test application for the generated types, that is executed to do the actual testing (not supported on Windows) +* `-DENABLE_QOS_PROVIDER=NO`: to disable support for qos provider ### For application developers diff --git a/docs/manual/about_dds/eclipse_cyclone_dds.rst b/docs/manual/about_dds/eclipse_cyclone_dds.rst index 280ecdb46f..66448cc1e7 100644 --- a/docs/manual/about_dds/eclipse_cyclone_dds.rst +++ b/docs/manual/about_dds/eclipse_cyclone_dds.rst @@ -22,6 +22,7 @@ datareaders datawriters qos + qos_provider listener waitset status @@ -30,13 +31,13 @@ ddsi_concepts contributing -|var-project| is a performant and robust OMG-compliant **Data Distribution Service** -(DDS) implementation (see |url::dds_spec|). |var-project-short| is developed -completely in the open as an Eclipse IoT project (see |url::cyclone_dds-link|) with a -growing list of |url::cyclone_adopters|. It is a tier-1 middleware for the Robot +|var-project| is a performant and robust OMG-compliant **Data Distribution Service** +(DDS) implementation (see |url::dds_spec|). |var-project-short| is developed +completely in the open as an Eclipse IoT project (see |url::cyclone_dds-link|) with a +growing list of |url::cyclone_adopters|. It is a tier-1 middleware for the Robot Operating System |url::ros2|. -The core of |var-project-short| is implemented in C and provides C-APIs to applications. +The core of |var-project-short| is implemented in C and provides C-APIs to applications. Through its C++ package, the |url::omg.org| 2003 language binding is also supported. .. index:: About DDS @@ -44,14 +45,14 @@ Through its C++ package, the |url::omg.org| 2003 language binding is also suppor About DDS ========= -DDS is the best-kept secret in distributed systems, one that has been around for much +DDS is the best-kept secret in distributed systems, one that has been around for much longer than most publish-subscribe messaging systems and still outclasses so many of them. -DDS is used in a wide variety of systems, including air-traffic control, jet engine -testing, railway control, medical systems, naval command-and-control, smart greenhouses -and much more. In short, it is well-established in aerospace and defense but no longer +DDS is used in a wide variety of systems, including air-traffic control, jet engine +testing, railway control, medical systems, naval command-and-control, smart greenhouses +and much more. In short, it is well-established in aerospace and defense but no longer limited to that. And yet it is easy to use! -Types are usually defined in IDL and preprocessed with the IDL compiler included in Cyclone, +Types are usually defined in IDL and preprocessed with the IDL compiler included in Cyclone, but our |url::python-link2| allows you to define data types on the fly: .. code-block:: python @@ -96,30 +97,30 @@ but our |url::python-link2| allows you to define data types on the fly: print("Read ", sample) sleep(rng.exponential()) -Today DDS is also popular in robotics and autonomous vehicles because those really -depend on high-throughput, low-latency control systems without introducing a single -point of failure by having a message broker in the middle. Indeed, it is by far the -most used and the default middleware choice in ROS 2. It is used to transfer commands, +Today DDS is also popular in robotics and autonomous vehicles because those really +depend on high-throughput, low-latency control systems without introducing a single +point of failure by having a message broker in the middle. Indeed, it is by far the +most used and the default middleware choice in ROS 2. It is used to transfer commands, sensor data and even video and point clouds between components. -The OMG DDS specifications cover everything one needs to build systems using -publish-subscribe messaging. They define a structural type system that allows -automatic endianness conversion and type checking between readers and writers. This -type system also supports type evolution. The interoperable networking protocol and -standard C++ API make it easy to build systems that integrate multiple DDS -implementations. Zero-configuration discovery is also included in the standard and +The OMG DDS specifications cover everything one needs to build systems using +publish-subscribe messaging. They define a structural type system that allows +automatic endianness conversion and type checking between readers and writers. This +type system also supports type evolution. The interoperable networking protocol and +standard C++ API make it easy to build systems that integrate multiple DDS +implementations. Zero-configuration discovery is also included in the standard and supported by all implementations. -DDS actually brings more: publish-subscribe messaging is a nice abstraction over -"ordinary" networking, but plain publish-subscribe doesn't affect how one *thinks* -about systems. A very powerful architecture that truly changes the perspective on -distributed systems is that of the "shared data space", in itself an old idea, and -really just a distributed database. Most shared data space designs have failed -miserably in real-time control systems because they provided strong consistency -guarantees and sacrificed too much performance and flexibility. The *eventually -consistent* shared data space of DDS has been very successful in helping with building -systems that need to satisfy many "ilities": dependability, maintainability, -extensibility, upgradeability, ... Truth be told, that's why it was invented, and +DDS actually brings more: publish-subscribe messaging is a nice abstraction over +"ordinary" networking, but plain publish-subscribe doesn't affect how one *thinks* +about systems. A very powerful architecture that truly changes the perspective on +distributed systems is that of the "shared data space", in itself an old idea, and +really just a distributed database. Most shared data space designs have failed +miserably in real-time control systems because they provided strong consistency +guarantees and sacrificed too much performance and flexibility. The *eventually +consistent* shared data space of DDS has been very successful in helping with building +systems that need to satisfy many "ilities": dependability, maintainability, +extensibility, upgradeability, ... Truth be told, that's why it was invented, and publish-subscribe messaging was simply an implementation technique. |var-project| aims at full coverage of the specs and today already covers most of this. @@ -136,8 +137,8 @@ With references to the individual OMG specifications, the following is available - |url::dds_xtypes| - the structural type system (some [caveats](docs/dev/xtypes_relnotes.md) here) - |url::dds2.5| - the interoperable network protocol -The network stack in |var-project| has been around for over a decade in one form or -another and has proven itself in many systems, including large, high-availability +The network stack in |var-project| has been around for over a decade in one form or +another and has proven itself in many systems, including large, high-availability ones and systems where inter-operation with other implementations was needed. .. include:: disclaimer.part.rst \ No newline at end of file diff --git a/docs/manual/about_dds/qos_provider.rst b/docs/manual/about_dds/qos_provider.rst new file mode 100644 index 0000000000..4de6874a00 --- /dev/null +++ b/docs/manual/about_dds/qos_provider.rst @@ -0,0 +1,402 @@ +.. + Copyright(c) 2024 ZettaScale Technology and others + + This program and the accompanying materials are made available under the + terms of the Eclipse Public License v. 2.0 which is available at + http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + v. 1.0 which is available at + http://www.eclipse.org/org/documents/edl-v10.php. + + SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + +.. include:: ../external-links.part.rst +.. index:: ! QoS Provider + +.. _qos_provider: + +QoS Provider +############ + +This page provides information on using the QoS provider API of |var-project|. The QoS provider API allows users to specify the QoS settings of their DDS entities outside of application code in XML. This can be seen as a useful feature where code recompilation is restricted during the later stages of application development / during application support. The following sections explain the API and explain how to build QoS Profiles in XML. + +XML file syntax +=============== + +The syntax for the XML configuration file is defined in |url::omg_xml_1.0|. + +Entity QoS +---------- + +To configure the QoS for a DDS Entity using XML, the following tags have to be used: + +- `` +- `` +- `` +- `` +- `` +- `` + +Each XML tag with or without an associated name can be uniquely identified by its fully qualified name in C++ style. +In case of unnamed XML tag, only one tag of this kind is allowed in scope of parent ``. + +QoS Policies +------------ + +The fields in a Qos policy are described in XML using a 1-to-1 mapping with the equivalent IDL representation in the DDS specification. For example, the Reliability Qos policy is represented with the following structures: + +.. code-block:: C + + struct Duration_t { + long sec; + unsigned long nanosec; + }; + struct ReliabilityQosPolicy { + ReliabilityQosPolicyKind kind; + Duration_t max_blocking_time; + }; + +The equivalent representation in XML is as follows: + +.. code-block:: xml + + + + + + + + + +Sequences +--------- + +In general, the sequences contained in the QoS policies are described with the following XML format: + +.. code-block:: xml + + + ... + ... + ... + + +Each element of the sequence is enclosed in an tag, as shown in the following example: + +.. code-block:: xml + + + + + my name + my value + + + my name2 + my value2 + + + + + +Enumerations +------------ + +Enumeration values are represented using their IDL string representation. For example: + +.. code-block:: xml + + + KEEP_ALL_HISTORY_QOS + + + +Time values (Durations) +----------------------- + +Following values can be used for fields that require seconds or nanoseconds: + +- DURATION_INFINITE_SEC +- DURATION_INFINITE_NSEC + +The following example shows the use of time values: + +.. code-block:: xml + + + + DURATION_INFINITE_SEC + DURATION_INFINITE_NSEC + + + +QoS Profiles +------------ + +A QoS profile groups a set of related QoS, usually one per entity. For example: + +.. code-block:: xml + + + + + KEEP_LAST_HISTORY_QOS + 5 + + + + + KEEP_LAST_HISTORY_QOS + 1 + + + + +XML Example +----------- + +Consider the following XML file that describes two QoS profiles: + +- FooQosProfile + - DataReaderQos - KEEP_LAST (5) + - DataWriterQos - KEEP_LAST (1) + - TopicQos - KEEP_ALL +- BarQosProfile + - DataWriterQos - KEEP_ALL + - TopicQos - KEEP_LAST (5) + + +.. code-block:: xml + + + + + + + KEEP_LAST_HISTORY_QOS + 5 + + + + + KEEP_LAST_HISTORY_QOS + 1 + + + + + KEEP_ALL_HISTORY_QOS + + + + + + + KEEP_ALL_HISTORY_QOS + + + + + KEEP_LAST_HISTORY_QOS + 10 + + + + + + + +Code Example +============ + +The following C application is an example to illustrate how the QoS settings from the above XML could be accessed. + +.. tabs:: + + .. group-tab:: C + + .. code-block:: C + + #include "dds/dds.h" + #include "dds/ddsc/dds_qos_provider.h" + #include "datatypes.h" + + int main (int argc, char **argv) + { + (void) argc; + (void) argv; + + // provider will contains: + // myqoslib::foo_profile READER (KEEP_LAST 5) + // myqoslib::foo_profile WRITER (KEEP_LAST 1) + // myqoslib::foo_profile::my_topic TOPIC (KEEP_ALL) + // myqoslib::bar_profile WRITER (KEEP_ALL) + // myqoslib::bar_profile::my_topic TOPIC (KEEP_LAST 10) + dds_qos_provider_t *provider; + dds_return_t ret = dds_create_qos_provider ("/path/to/qos_definitions.xml", &provider); + assert (ret == DDS_RETCODE_OK); + + const dds_qos_t *tp_qos, *wr_qos; + // qos can be accessed by ::::[entity_name] if exist. + ret = dds_qos_provider_get_qos (provider, DDS_TOPIC_QOS, "myqoslib::bar_profile::my_topic", &tp_qos); + assert (ret == DDS_RETCODE_OK); + // or if entity_qos is unnamed only by ::. + ret = dds_qos_provider_get_qos (provider, DDS_WRITER_QOS, "myqoslib::bar_profile", &wr_qos); + assert (ret == DDS_RETCODE_OK); + + dds_entity_t pp = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + dds_entity_t tp = dds_create_topic (pp, &mydatatype_desc, "topic_A", tp_qos, NULL); + dds_entity_t wr = dds_create_writer (pp, tp, wr_qos, NULL); + dds_delete (pp); + dds_delete_qos_provider (provider); + + return 0; + } + + .. group-tab:: C++ + + .. code-block:: C++ + + #include "dds/dds.hpp" + #include "DataType.hpp" + + using namespace org::eclipse::cyclonedds; + + int main() + { + // provider will contains: + // myqoslib::foo_profile READER (KEEP_LAST 5) + // myqoslib::foo_profile WRITER (KEEP_LAST 1) + // myqoslib::foo_profile::my_topic TOPIC (KEEP_ALL) + // myqoslib::bar_profile WRITER (KEEP_ALL) + // myqoslib::bar_profile::my_topic TOPIC (KEEP_LAST 10) + dds::core::QosProvider provider("/path/to/qos_definitions.xml"); + auto topic_qos = provider.topic_qos("myqoslib::bar_profile::my_topic"); + auto writer_qos = provider.datawriter_qos("myqoslib::bar_profile"); + + dds::domain::DomainParticipant participant(domain::default_id()); + dds::topic::Topic topic(participant, "topic_A", topic_qos); + dds::pub::Publisher publisher(participant); + dds::pub::DataWriter writer(publisher, topic, writer_qos); + (void)writer; + return 0; + } + +Also C API allows you to specify which library, profile QoS Provider should contains. +Let's extend XML file example above, and omit QoS settings details for simplicity. + +.. code-block:: xml + + + + + + + + + + + + + + + + + + + + + + + + + + +Let's create QoS Provider that contains versions of both profiles from different libraries. + +.. tabs:: + + .. group-tab:: C + + .. code-block:: C + + #include "dds/dds.h" + #include "dds/ddsc/dds_qos_provider.h" + #include "datatypes.h" + + int main (int argc, char **argv) + { + (void) argc; + (void) argv; + + // foo_provider will contains: + // qos1_lib::foo_profile READER + // qos1_lib::foo_profile WRITER + // qos1_lib::foo_profile TOPIC + // qos2_lib::foo_profile READER + // qos2_lib::foo_profile WRITER + // qos2_lib::foo_profile TOPIC + dds_qos_provider_t *foo_provider; + char *foo_scope = "*::foo_profile"; + dds_return_t ret = dds_create_qos_provider_scope ("/path/to/qos_definitions.xml", &foo_provider, foo_scope); + assert (ret == DDS_RETCODE_OK); + + // bar_provider will contains: + // qos1_lib::bar_profile WRITER + // qos1_lib::bar_profile TOPIC + // qos2_lib::bar_profile WRITER + // qos2_lib::bar_profile TOPIC + dds_qos_provider_t *bar_provider; + char *bar_scope = "*::bar_profile"; + dds_return_t ret = dds_create_qos_provider_scope ("/path/to/qos_definitions.xml", &bar_provider, bar_scope); + assert (ret == DDS_RETCODE_OK); + ... + dds_delete_qos_provider (foo_provider); + dds_delete_qos_provider (bar_provider); + + return 0; + } + + .. group-tab:: C++ + + .. code-block:: C++ + + #include "dds/dds.hpp" + #include "DataType.hpp" + + using namespace org::eclipse::cyclonedds; + + int main() + { + // foo_provider will contains: + // qos1_lib::foo_profile READER + // qos1_lib::foo_profile WRITER + // qos1_lib::foo_profile TOPIC + // qos2_lib::foo_profile READER + // qos2_lib::foo_profile WRITER + // qos2_lib::foo_profile TOPIC + std::string foo_scope = "*::foo_profile"; + dds::core::QosProvider foo_provider("/path/to/qos_definitions.xml", foo_scope); + + // bar_provider will contains: + // qos1_lib::bar_profile WRITER + // qos1_lib::bar_profile TOPIC + // qos2_lib::bar_profile WRITER + // qos2_lib::bar_profile TOPIC + std::string bar_scope = "*::bar_profile"; + dds::core::QosProvider bar_provider("/path/to/qos_definitions.xml", bar_scope); + ... + return 0; + } + +Known limitations +================= + +- Inheritance of QoS policies and QoS profiles in XML using the "base_name" attribute is not supported +- The "topic_filter" attribute for writer, reader and topic QoSes to associate a set of topics to a specific QoS when that QoS is part of a DDS profile, is not supported yet. +- The "entity_factory" attribute for participant, writer and reader QoSes, is not supported yet. +- The <(user|topic|group)_data> base64 syntax is not supported yet. +- The C++ API QosProvider may throw an UnsupportedError when trying to access a policy that is not supported yet. diff --git a/docs/manual/api/qosprovider.rst b/docs/manual/api/qosprovider.rst new file mode 100644 index 0000000000..e8475f2554 --- /dev/null +++ b/docs/manual/api/qosprovider.rst @@ -0,0 +1,6 @@ +QosProvider +=========== + +.. doxygengroup:: qos_provider + :project: ddsc_api_docs + :members: diff --git a/docs/manual/ddsc.rst b/docs/manual/ddsc.rst index d0b2e0d31a..30ca91b846 100644 --- a/docs/manual/ddsc.rst +++ b/docs/manual/ddsc.rst @@ -22,6 +22,7 @@ C API reference api/basics api/entity api/qos + api/qosprovider api/domain api/topic api/data diff --git a/docs/manual/external-links.part.rst b/docs/manual/external-links.part.rst index ec60eb7bab..c52e892a9d 100644 --- a/docs/manual/external-links.part.rst +++ b/docs/manual/external-links.part.rst @@ -29,47 +29,47 @@ DDSI-RTPS 2.5 .. |url::omg.org| raw:: html - + DDS ISO/IEC C++ PSM API .. |url::dds_xtypes| raw:: html - + DDS XTypes .. |url::ros2| raw:: html - + ROS 2 .. |url::omg.security| raw:: html - + DDS security .. |url::logoimage| raw:: html - + .. |url::python-link| raw:: html - + Eclipse Cyclone DDS: Python API documentation .. |url::python-link2| raw:: html - + Python binding .. |url::cyclone_dds-link| raw:: html - + Eclipse Cyclone DDS .. |url::cyclone_adopters| raw:: html - + adopters .. |url::cyclone_git_logo| raw:: html - + logo .. |url::cpp-link| raw:: html - + Eclipse Cyclone DDS: C++ API documentation .. |url::git_link| raw:: html @@ -105,80 +105,80 @@ Scoop .. |url::c-api-liveliness| raw:: html - + dds_liveliness_kind .. |url::rfc5751_link| raw:: html - + IETF RFC 5751 .. |url::rfc5751_2-4-2_link| raw:: html - + IETF RFC 5751 section 2.4.2 .. |url::rfc5751_3-4-3_link| raw:: html - + IETF RFC 5751 section 3.4.3 .. |url::DDS_plugins| raw:: html - + DDS Plugins .. |url::DDS_plugins_access-control| raw:: html - + access control plugin .. |url::DDS_plugins_authentication| raw:: html - + authentication plugin .. |url::DDS_plugins_cryptographic| raw:: html - + cryptographic plugin .. |url::iceoryx_issues| raw:: html - + iceoryx issues .. |url::adlink-ROS| raw:: html - + ADLINK Advanced Robotics Platform Group .. |url::Apex.AI| raw:: html - + Apex.AI .. |url::iceoryx_introspection| raw:: html - + iceoryx introspection .. |url::scripts| raw:: html - + Scripts .. |url::environment_details| raw:: html - + Environment details .. |url::throughput| raw:: html - + Throughput .. |url::latency| raw:: html - + Latency .. |url::helloworld_cpp_github| raw:: html - + GitHub cyclonedds-cxx/examples/helloworld/ .. |url::helloworld_c_github| raw:: html - + GitHub cyclonedds/examples/helloworld/ .. |url::ddsperf_github| raw:: html - + GitHub ddsperf .. |url::cpp_api_link| raw:: html @@ -196,3 +196,7 @@ .. |url::runtype_link| raw:: html runtype + +.. |url::omg_xml_1.0| raw:: html + + DDS Consolidated XML Syntax diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index da328a2ea2..9240255504 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,7 @@ option(ENABLE_IPV6 "Enable ipv6 support" ON) option(ENABLE_TYPELIB "Enable Type Library support" ON) option(ENABLE_TYPE_DISCOVERY "Enable Type Discovery support" ON) option(ENABLE_TOPIC_DISCOVERY "Enable Topic Discovery support" ON) +option(ENABLE_QOS_PROVIDER "Enable Qos Provider support" ON) if(ENABLE_TYPE_DISCOVERY) if(NOT ENABLE_TYPELIB) message(FATAL_ERROR "ENABLE_TYPE_DISCOVERY requires ENABLE_TYPELIB to be enabled") diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 2c5761e36b..a37f837212 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -133,6 +133,19 @@ set_property( TARGET ddsc APPEND PROPERTY EXPORT_PROPERTIES "TOPIC_DISCOVERY_IS_AVAILABLE") +# define target property to indicate if Cyclone DDS is compiled with qos provider +define_property(TARGET + PROPERTY QOS_PROVIDER_IS_AVAILABLE + BRIEF_DOCS "Indicator whether qos provider is available with current Cyclone DDS build configuration." + FULL_DOCS "Indicator whether qos provider is available with current Cyclone DDS build configuration." + ) +set_property( + TARGET ddsc + APPEND PROPERTY QOS_PROVIDER_IS_AVAILABLE "${ENABLE_QOS_PROVIDER}") +set_property( + TARGET ddsc + APPEND PROPERTY EXPORT_PROPERTIES "QOS_PROVIDER_IS_AVAILABLE") + # Create a pseudo-target that other targets (i.e. examples, tests) can depend # on and can also be provided as import-target by a package-file when building # those targets outside the regular Cyclone build-tree (i.e. the installed tree) diff --git a/src/core/ddsc/CMakeLists.txt b/src/core/ddsc/CMakeLists.txt index dd21a6772d..9ac86c23e3 100644 --- a/src/core/ddsc/CMakeLists.txt +++ b/src/core/ddsc/CMakeLists.txt @@ -51,6 +51,12 @@ prepend(srcs_ddsc "${CMAKE_CURRENT_LIST_DIR}/src/" if(ENABLE_TYPELIB) list(APPEND srcs_ddsc "${CMAKE_CURRENT_LIST_DIR}/src/dds_dynamic_type.c") endif() +if(ENABLE_QOS_PROVIDER) + list(APPEND srcs_ddsc + "${CMAKE_CURRENT_LIST_DIR}/src/dds_sysdef_parser.c" + "${CMAKE_CURRENT_LIST_DIR}/src/dds_sysdef_validation.c" + "${CMAKE_CURRENT_LIST_DIR}/src/dds_qos_provider.c") +endif() prepend(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src/" dds__builtin.h @@ -81,6 +87,10 @@ prepend(hdrs_private_ddsc "${CMAKE_CURRENT_LIST_DIR}/src/" dds__loaned_sample.h dds__heap_loan.h dds__psmx.h + dds__sysdef_model.h + dds__sysdef_parser.h + dds__sysdef_validation.h + dds__qos_provider.h ) prepend(hdrs_public_ddsc "$$/dds/" @@ -104,6 +114,9 @@ prepend(hdrs_public_ddsc "$$< if(ENABLE_TYPELIB) list(APPEND hdrs_public_ddsc "$$/dds/ddsc/dds_public_dynamic_type.h") endif() +if(ENABLE_QOS_PROVIDER) + list(APPEND hdrs_public_ddsc "$$/dds/ddsc/dds_public_qos_provider.h") +endif() generate_export_header( ddsc BASE_NAME DDS EXPORT_FILE_NAME include/dds/export.h) diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h index 60b73aa017..b196553aae 100644 --- a/src/core/ddsc/include/dds/dds.h +++ b/src/core/ddsc/include/dds/dds.h @@ -47,6 +47,7 @@ #include "dds/ddsc/dds_public_listener.h" #include "dds/ddsc/dds_public_dynamic_type.h" #include "dds/ddsc/dds_public_loan_api.h" +#include "dds/ddsc/dds_public_qos_provider.h" #if defined (__cplusplus) extern "C" { diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_qos_provider.h b/src/core/ddsc/include/dds/ddsc/dds_public_qos_provider.h new file mode 100644 index 0000000000..6e84126b51 --- /dev/null +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qos_provider.h @@ -0,0 +1,121 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +#ifndef DDS_QOS_PROVIDER_H +#define DDS_QOS_PROVIDER_H + +#include "dds/export.h" +#include "dds/ddsrt/retcode.h" +#include "dds/ddsc/dds_public_qosdefs.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#ifdef DDS_HAS_QOS_PROVIDER + +/** + * @defgroup qos_provider (QosProvider) + * @ingroup dds + * The Qos Provider API. + */ + +/** + * @brief All kind of entities for which qos can be stored in Profile. + * @ingroup qos_provider + * @component qos_provider_api + */ +enum dds_qos_kind +{ + DDS_PARTICIPANT_QOS, + DDS_PUBLISHER_QOS, + DDS_SUBSCRIBER_QOS, + DDS_TOPIC_QOS, + DDS_READER_QOS, + DDS_WRITER_QOS +}; +typedef enum dds_qos_kind dds_qos_kind_t; + +/** + * @brief Sample structure of the Qos Provider. + * @ingroup qos_provider + * @component qos_provider_api + */ +struct dds_qos_provider; +typedef struct dds_qos_provider dds_qos_provider_t; + +/** + * @brief Initialize Qos Provider. + * @ingroup qos_provider + * @component qos_provider_api + * + * Create dds_qos_provider with provided system definition file path. + * + * @param[in] path - String that contains system definition inself or path to system defenition file. + * @param[in,out] provider - Pointer to the Qos Provider structure. + * + * @return a DDS return code + */ +DDS_EXPORT dds_return_t +dds_create_qos_provider (const char *path, dds_qos_provider_t **provider); + +/** + * @brief Initialize Qos Provider with certain scope. + * @ingroup qos_provider + * @component qos_provider_api + * + * Create dds_qos_provider with provided system definition file path and scope. + * + * @param[in] path - String that contains system definition inself or path to system defenition file. + * @param[in,out] provider - Pointer to the Qos Provider structure. + * @param[in] key - String that contains pattern of interested qos from `path` in format '::::'. + * + * @return a DDS return code + */ +DDS_EXPORT dds_return_t +dds_create_qos_provider_scope (const char *path, dds_qos_provider_t **provider, + const char *key); + +/** + * @brief Get Qos from Qos Provider. + * @ingroup qos_provider + * @component qos_provider_api + * + * Provide access to dds_qos_t from dds_qos_provider by full key and type of qos entity. + * + * @param[in] provider - Pointer to the Qos Provider structure. + * @param[in] type - Type of entity which Qos to get. + * @param[in] key - Full qualify name of Qos to get in format '::::'. + * @param[in,out] qos - Pointer to the Qos structure. + * + * @return a DDS return code + */ +DDS_EXPORT dds_return_t +dds_qos_provider_get_qos (const dds_qos_provider_t *provider, dds_qos_kind_t type, + const char *key, const dds_qos_t **qos); + +/** + * @brief Finalize Qos Provider. + * @ingroup qos_provider + * @component qos_provider_api + * + * Release resources allocated by dds_qos_provider. + * + * @param[in] provider - Pointer to the Qos Provider structure. + */ +DDS_EXPORT void +dds_delete_qos_provider (dds_qos_provider_t *provider); + +#endif /* DDS_HAS_QOS_PROVIDER */ + +#if defined (__cplusplus) +} +#endif + +#endif // DDS_QOS_PROVIDER_H diff --git a/src/core/ddsc/src/dds__qos_provider.h b/src/core/ddsc/src/dds__qos_provider.h new file mode 100644 index 0000000000..ce60e4cef2 --- /dev/null +++ b/src/core/ddsc/src/dds__qos_provider.h @@ -0,0 +1,47 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +#ifndef DDS__QOS_PROVIDER_H +#define DDS__QOS_PROVIDER_H + +#include "dds/dds.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#define PROVIDER_ITEM_SEP "::" +#define PROVIDER_ITEM_SCOPE_NONE "*" +#define QOSPROV_ERROR(...) DDS_LOG(DDS_LC_QOSPROV | DDS_LC_ERROR, __VA_ARGS__) +#define QOSPROV_WARN(...) DDS_LOG(DDS_LC_QOSPROV | DDS_LC_WARNING, __VA_ARGS__) +#define QOSPROV_TRACE(...) DDS_LOG(DDS_LC_QOSPROV | DDS_LC_TRACE, __VA_ARGS__) + +/** + * @brief Sample structure of the Qos stored in Provider. + * @ingroup qos_provider + * @component qos_provider_api + */ +typedef struct dds_qos_item +{ + char *full_name; + dds_qos_t *qos; + enum dds_qos_kind kind; +} dds_qos_item_t; + +struct dds_qos_provider +{ + char* file_path; + struct ddsrt_hh *keyed_qos; +}; + +#if defined (__cplusplus) +} +#endif + +#endif // DDS__QOS_PROVIDER_H diff --git a/src/core/ddsc/src/dds__sysdef_model.h b/src/core/ddsc/src/dds__sysdef_model.h new file mode 100644 index 0000000000..8c673dfb0e --- /dev/null +++ b/src/core/ddsc/src/dds__sysdef_model.h @@ -0,0 +1,706 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +#ifndef DDS__SYSDEF_MODEL_H +#define DDS__SYSDEF_MODEL_H + +#include "dds/dds.h" +#include "dds/ddsi/ddsi_xqos.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#define TYPE_HASH_LENGTH 14 + +struct dds_sysdef_type_metadata { + unsigned char *type_hash; + size_t type_info_cdr_sz; + unsigned char *type_info_cdr; + size_t type_map_cdr_sz; + unsigned char *type_map_cdr; +}; + +struct dds_sysdef_type_metadata_admin { + struct ddsrt_hh *m; +}; + +struct xml_element; +struct dds_sysdef_type; +struct dds_sysdef_type_lib; +struct dds_sysdef_qos; +struct dds_sysdef_qos_profile; +struct dds_sysdef_qos_lib; +struct dds_sysdef_domain; +struct dds_sysdef_domain_lib; +struct dds_sysdef_participant; +struct dds_sysdef_participant_lib; +struct dds_sysdef_publisher; +struct dds_sysdef_subscriber; +struct dds_sysdef_application; +struct dds_sysdef_application_lib; +struct dds_sysdef_node_lib; +struct parse_sysdef_state; + +enum element_kind +{ + ELEMENT_KIND_UNDEFINED, + ELEMENT_KIND_DDS, + + ELEMENT_KIND_TYPE_LIB, + ELEMENT_KIND_TYPE, + + ELEMENT_KIND_QOS_LIB, + ELEMENT_KIND_QOS_PROFILE, + ELEMENT_KIND_QOS_PARTICIPANT, + ELEMENT_KIND_QOS_PUBLISHER, + ELEMENT_KIND_QOS_SUBSCRIBER, + ELEMENT_KIND_QOS_TOPIC, + ELEMENT_KIND_QOS_WRITER, + ELEMENT_KIND_QOS_READER, + + ELEMENT_KIND_QOS_DURATION_SEC, + ELEMENT_KIND_QOS_DURATION_NSEC, + + ELEMENT_KIND_QOS_POLICY_DEADLINE, + ELEMENT_KIND_QOS_POLICY_DEADLINE_PERIOD, + ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER, + ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER_KIND, + ELEMENT_KIND_QOS_POLICY_DURABILITY, + ELEMENT_KIND_QOS_POLICY_DURABILITY_KIND, + ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, + ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_SERVICE_CLEANUP_DELAY, + ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_HISTORY_KIND, + ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_HISTORY_DEPTH, + ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_SAMPLES, + ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_INSTANCES, + ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_SAMPLES_PER_INSTANCE, + ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY, + ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY_AUTOENABLE_CREATED_ENTITIES, + ELEMENT_KIND_QOS_POLICY_GROUPDATA, + ELEMENT_KIND_QOS_POLICY_GROUPDATA_VALUE, + ELEMENT_KIND_QOS_POLICY_HISTORY, + ELEMENT_KIND_QOS_POLICY_HISTORY_KIND, + ELEMENT_KIND_QOS_POLICY_HISTORY_DEPTH, + ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET, + ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET_DURATION, + ELEMENT_KIND_QOS_POLICY_LIFESPAN, + ELEMENT_KIND_QOS_POLICY_LIFESPAN_DURATION, + ELEMENT_KIND_QOS_POLICY_LIVELINESS, + ELEMENT_KIND_QOS_POLICY_LIVELINESS_KIND, + ELEMENT_KIND_QOS_POLICY_LIVELINESS_LEASE_DURATION, + ELEMENT_KIND_QOS_POLICY_OWNERSHIP, + ELEMENT_KIND_QOS_POLICY_OWNERSHIP_KIND, + ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH, + ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH_VALUE, + ELEMENT_KIND_QOS_POLICY_PARTITION, + ELEMENT_KIND_QOS_POLICY_PARTITION_NAME, + ELEMENT_KIND_QOS_POLICY_PARTITION_NAME_ELEMENT, + ELEMENT_KIND_QOS_POLICY_PRESENTATION, + ELEMENT_KIND_QOS_POLICY_PRESENTATION_ACCESS_SCOPE, + ELEMENT_KIND_QOS_POLICY_PRESENTATION_COHERENT_ACCESS, + ELEMENT_KIND_QOS_POLICY_PRESENTATION_ORDERED_ACCESS, + ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE, + ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE_AUTOPURGE_NOWRITER_SAMPLES_DELAY, + ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE_AUTOPURGE_DISPOSED_SAMPLES_DELAY, + ELEMENT_KIND_QOS_POLICY_RELIABILITY, + ELEMENT_KIND_QOS_POLICY_RELIABILITY_KIND, + ELEMENT_KIND_QOS_POLICY_RELIABILITY_MAX_BLOCKING_DELAY, + ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, + ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_INITIAL_INSTANCES, + ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_INITIAL_SAMPLES, + ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_SAMPLES, + ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_INSTANCES, + ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_SAMPLES_PER_INSTANCE, + ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER, + ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER_MINIMUM_SEPARATION, + ELEMENT_KIND_QOS_POLICY_TOPICDATA, + ELEMENT_KIND_QOS_POLICY_TOPICDATA_VALUE, + ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY, + ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY_VALUE, + ELEMENT_KIND_QOS_POLICY_USERDATA, + ELEMENT_KIND_QOS_POLICY_USERDATA_VALUE, + ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE, + ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE_AUTODISPOSE_UNREGISTERED_INSTANCES, + + ELEMENT_KIND_DOMAIN_LIB, + ELEMENT_KIND_DOMAIN, + ELEMENT_KIND_REGISTER_TYPE, + ELEMENT_KIND_TOPIC, + + ELEMENT_KIND_PARTICIPANT_LIB, + ELEMENT_KIND_PARTICIPANT, + ELEMENT_KIND_PUBLISHER, + ELEMENT_KIND_SUBSCRIBER, + ELEMENT_KIND_WRITER, + ELEMENT_KIND_READER, + + ELEMENT_KIND_APPLICATION_LIB, + ELEMENT_KIND_APPLICATION, + + ELEMENT_KIND_NODE_LIB, + ELEMENT_KIND_NODE, + ELEMENT_KIND_NODE_HOSTNAME, + ELEMENT_KIND_NODE_IPV4_ADDRESS, + ELEMENT_KIND_NODE_IPV6_ADDRESS, + ELEMENT_KIND_NODE_MAC_ADDRESS, + + ELEMENT_KIND_DEPLOYMENT_LIB, + ELEMENT_KIND_DEPLOYMENT, + ELEMENT_KIND_DEPLOYMENT_NODE_REF, + ELEMENT_KIND_DEPLOYMENT_APPLICATION_LIST, + ELEMENT_KIND_DEPLOYMENT_APPLICATION_REF, + ELEMENT_KIND_DEPLOYMENT_CONF, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_SOURCE_IP_ADDRESS, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DESTINATION_IP_ADDRESS, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DSCP, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_PROTOCOL, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_SOURCE_PORT, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DESTINATION_PORT, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_SOURCE_IP_ADDRESS, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DESTINATION_IP_ADDRESS, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DSCP, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_PROTOCOL, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_SOURCE_PORT, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DESTINATION_PORT, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_PERIODICITY, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_SAMPLES_PER_PERIOD, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_MAX_BYTES_PER_SAMPLE, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TRANSMISSION_SELECTION, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_EARLIEST_TRANSMIT_OFFSET, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_LATEST_TRANSMIT_OFFSET, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_JITTER, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS_NUM_SEAMLESS_TREES, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS_MAX_LATENCY, + + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS_NUM_SEAMLESS_TREES, + ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS_MAX_LATENCY +}; + +enum element_data_type { + ELEMENT_DATA_TYPE_GENERIC, + ELEMENT_DATA_TYPE_DURATION +}; + +typedef int (* init_fn) (struct parse_sysdef_state * const pstate, struct xml_element *element); +typedef void (* fini_fn) (struct xml_element *element); + +struct xml_element +{ + struct xml_element *parent; + enum element_kind kind; + enum element_data_type data_type; + bool retain; + bool handle_close; + struct xml_element *next; + fini_fn fini; +}; + +/* Type library */ +struct dds_sysdef_type { + struct xml_element xmlnode; + char *name; + unsigned char *identifier; + struct dds_sysdef_type_lib *parent; +}; + +struct dds_sysdef_type_lib { + struct xml_element xmlnode; + struct dds_sysdef_type *types; +}; + +/* QoS library */ +enum dds_sysdef_qos_kind { + DDS_SYSDEF_TOPIC_QOS, + DDS_SYSDEF_READER_QOS, + DDS_SYSDEF_WRITER_QOS, + DDS_SYSDEF_SUBSCRIBER_QOS, + DDS_SYSDEF_PUBLISHER_QOS, + DDS_SYSDEF_PARTICIPANT_QOS +}; + +#define QOS_POLICY_SYSDEF_STRUCT(p,t) \ + struct dds_sysdef_ ## p { \ + struct xml_element xmlnode; \ + t values; \ + uint32_t populated; \ + }; + +#define QOS_POLICY_DEADLINE_PARAM_PERIOD (1 << 0u) +#define QOS_POLICY_DEADLINE_PARAMS (QOS_POLICY_DEADLINE_PARAM_PERIOD) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_DEADLINE, dds_deadline_qospolicy_t) + +#define QOS_POLICY_DESTINATIONORDER_PARAM_KIND (1 << 0u) +#define QOS_POLICY_DESTINATIONORDER_PARAMS (QOS_POLICY_DESTINATIONORDER_PARAM_KIND) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_DESTINATIONORDER, dds_destination_order_qospolicy_t) + +#define QOS_POLICY_DURABILITY_PARAM_KIND (1 << 0u) +#define QOS_POLICY_DURABILITY_PARAMS (QOS_POLICY_DURABILITY_PARAM_KIND) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_DURABILITY, dds_durability_qospolicy_t) + +#define QOS_POLICY_DURABILITYSERVICE_PARAM_SERVICE_CLEANUP_DELAY (1 << 0u) +#define QOS_POLICY_DURABILITYSERVICE_PARAM_HISTORY_KIND (1 << 1u) +#define QOS_POLICY_DURABILITYSERVICE_PARAM_HISTORY_DEPTH (1 << 2u) +#define QOS_POLICY_DURABILITYSERVICE_PARAM_RESOURCE_LIMIT_MAX_SAMPLES (1 << 3u) +#define QOS_POLICY_DURABILITYSERVICE_PARAM_RESOURCE_LIMIT_MAX_INSTANCES (1 << 4u) +#define QOS_POLICY_DURABILITYSERVICE_PARAM_RESOURCE_LIMIT_MAX_SAMPLES_PER_INSTANCE (1 << 5u) +#define QOS_POLICY_DURABILITYSERVICE_PARAMS (\ + QOS_POLICY_DURABILITYSERVICE_PARAM_SERVICE_CLEANUP_DELAY \ + | QOS_POLICY_DURABILITYSERVICE_PARAM_HISTORY_KIND \ + | QOS_POLICY_DURABILITYSERVICE_PARAM_HISTORY_DEPTH \ + | QOS_POLICY_DURABILITYSERVICE_PARAM_RESOURCE_LIMIT_MAX_SAMPLES \ + | QOS_POLICY_DURABILITYSERVICE_PARAM_RESOURCE_LIMIT_MAX_INSTANCES \ + | QOS_POLICY_DURABILITYSERVICE_PARAM_RESOURCE_LIMIT_MAX_SAMPLES_PER_INSTANCE) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_DURABILITYSERVICE, dds_durability_service_qospolicy_t) + +#define QOS_POLICY_ENTITYFACTORY_PARAM_AUTOENABLE_CREATED_ENTITIES (1 << 0u) +#define QOS_POLICY_ENTITYFACTORY_PARAMS (QOS_POLICY_ENTITYFACTORY_PARAM_AUTOENABLE_CREATED_ENTITIES) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_ENTITYFACTORY, dds_entity_factory_qospolicy_t) + +#define QOS_POLICY_HISTORY_PARAM_KIND (1 << 0u) +#define QOS_POLICY_HISTORY_PARAM_DEPTH (1 << 1u) +#define QOS_POLICY_HISTORY_PARAMS (QOS_POLICY_HISTORY_PARAM_KIND | QOS_POLICY_HISTORY_PARAM_DEPTH) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_HISTORY, dds_history_qospolicy_t) + +#define QOS_POLICY_LATENCYBUDGET_PARAM_DURATION (1 << 0u) +#define QOS_POLICY_LATENCYBUDGET_PARAMS (QOS_POLICY_LATENCYBUDGET_PARAM_DURATION) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_LATENCYBUDGET, dds_latency_budget_qospolicy_t) + +#define QOS_POLICY_LIFESPAN_PARAM_DURATION (1 << 0u) +#define QOS_POLICY_LIFESPAN_PARAMS (QOS_POLICY_LIFESPAN_PARAM_DURATION) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_LIFESPAN, dds_lifespan_qospolicy_t) + +#define QOS_POLICY_LIVELINESS_PARAM_KIND (1 << 0u) +#define QOS_POLICY_LIVELINESS_PARAM_LEASE_DURATION (1 << 1u) +#define QOS_POLICY_LIVELINESS_PARAMS (QOS_POLICY_LIVELINESS_PARAM_KIND | QOS_POLICY_LIVELINESS_PARAM_LEASE_DURATION) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_LIVELINESS, dds_liveliness_qospolicy_t) + +#define QOS_POLICY_OWNERSHIP_PARAM_KIND (1 << 0u) +#define QOS_POLICY_OWNERSHIP_PARAMS (QOS_POLICY_OWNERSHIP_PARAM_KIND) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_OWNERSHIP, dds_ownership_qospolicy_t) + +#define QOS_POLICY_OWNERSHIPSTRENGTH_PARAM_VALUE (1 << 0u) +#define QOS_POLICY_OWNERSHIPSTRENGTH_PARAMS (QOS_POLICY_OWNERSHIPSTRENGTH_PARAM_VALUE) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_OWNERSHIPSTRENGTH, dds_ownership_strength_qospolicy_t) + +#define QOS_POLICY_PARTITION_PARAM_NAME (1 << 0u) +#define QOS_POLICY_PARTITION_PARAMS (QOS_POLICY_PARTITION_PARAM_NAME) +struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT { + struct xml_element xmlnode; + char *element; +}; + +struct dds_sysdef_QOS_POLICY_PARTITION_NAME { + struct xml_element xmlnode; + struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *elements; +}; + +struct dds_sysdef_QOS_POLICY_PARTITION { + struct xml_element xmlnode; + struct dds_sysdef_QOS_POLICY_PARTITION_NAME *name; + uint32_t populated; +}; + +#define QOS_POLICY_PRESENTATION_PARAM_ACCESS_SCOPE (1 << 0u) +#define QOS_POLICY_PRESENTATION_PARAM_COHERENT_ACCESS (1 << 1u) +#define QOS_POLICY_PRESENTATION_PARAM_ORDERED_ACCESS (1 << 2u) +#define QOS_POLICY_PRESENTATION_PARAMS (QOS_POLICY_PRESENTATION_PARAM_ACCESS_SCOPE | QOS_POLICY_PRESENTATION_PARAM_COHERENT_ACCESS | QOS_POLICY_PRESENTATION_PARAM_ORDERED_ACCESS) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_PRESENTATION, dds_presentation_qospolicy_t) + +#define QOS_POLICY_READERDATALIFECYCLE_PARAM_AUTOPURGE_NOWRITER_SAMPLES_DELAY (1 << 0u) +#define QOS_POLICY_READERDATALIFECYCLE_PARAM_AUTOPURGE_DISPOSED_SAMPLES_DELAY (1 << 1u) +#define QOS_POLICY_READERDATALIFECYCLE_PARAMS (QOS_POLICY_READERDATALIFECYCLE_PARAM_AUTOPURGE_NOWRITER_SAMPLES_DELAY | QOS_POLICY_READERDATALIFECYCLE_PARAM_AUTOPURGE_DISPOSED_SAMPLES_DELAY) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_READERDATALIFECYCLE, dds_reader_data_lifecycle_qospolicy_t) + +#define QOS_POLICY_RELIABILITY_PARAM_KIND (1 << 0u) +#define QOS_POLICY_RELIABILITY_PARAM_MAX_BLOCKING_DELAY (1 << 1u) +#define QOS_POLICY_RELIABILITY_PARAMS (QOS_POLICY_RELIABILITY_PARAM_KIND | QOS_POLICY_RELIABILITY_PARAM_MAX_BLOCKING_DELAY) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_RELIABILITY, dds_reliability_qospolicy_t) + +#define QOS_POLICY_RESOURCELIMITS_PARAM_MAX_SAMPLES (1 << 0u) +#define QOS_POLICY_RESOURCELIMITS_PARAM_MAX_INSTANCES (1 << 1u) +#define QOS_POLICY_RESOURCELIMITS_PARAM_MAX_SAMPLES_PER_INSTANCE (1 << 2u) +#define QOS_POLICY_RESOURCELIMITS_PARAMS (QOS_POLICY_RESOURCELIMITS_PARAM_MAX_SAMPLES | QOS_POLICY_RESOURCELIMITS_PARAM_MAX_INSTANCES | QOS_POLICY_RESOURCELIMITS_PARAM_MAX_SAMPLES_PER_INSTANCE) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_RESOURCELIMITS, dds_resource_limits_qospolicy_t) + +#define QOS_POLICY_TIMEBASEDFILTER_PARAM_MINIMUM_SEPARATION (1 << 0u) +#define QOS_POLICY_TIMEBASEDFILTER_PARAMS (QOS_POLICY_TIMEBASEDFILTER_PARAM_MINIMUM_SEPARATION) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_TIMEBASEDFILTER, dds_time_based_filter_qospolicy_t) + +#define QOS_POLICY_TRANSPORTPRIORITY_PARAM_VALUE (1 << 0u) +#define QOS_POLICY_TRANSPORTPRIORITY_PARAMS (QOS_POLICY_TRANSPORTPRIORITY_PARAM_VALUE) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_TRANSPORTPRIORITY, dds_transport_priority_qospolicy_t) + +#define QOS_POLICY_WRITERDATALIFECYCLE_PARAM_AUTODISPOSE_UNREGISTERED_INSTANCES (1 << 0u) +#define QOS_POLICY_WRITERDATALIFECYCLE_PARAMS (QOS_POLICY_WRITERDATALIFECYCLE_PARAM_AUTODISPOSE_UNREGISTERED_INSTANCES) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_WRITERDATALIFECYCLE, dds_writer_data_lifecycle_qospolicy_t) + +#define QOS_POLICY_GROUPDATA_PARAM_VALUE (1 << 0u) +#define QOS_POLICY_GROUPDATA_PARAMS (QOS_POLICY_GROUPDATA_PARAM_VALUE) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_GROUPDATA, dds_groupdata_qospolicy_t) + +#define QOS_POLICY_TOPICDATA_PARAM_VALUE (1 << 0u) +#define QOS_POLICY_TOPICDATA_PARAMS (QOS_POLICY_TOPICDATA_PARAM_VALUE) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_TOPICDATA, dds_topicdata_qospolicy_t) + +#define QOS_POLICY_USERDATA_PARAM_VALUE (1 << 0u) +#define QOS_POLICY_USERDATA_PARAMS (QOS_POLICY_USERDATA_PARAM_VALUE) +QOS_POLICY_SYSDEF_STRUCT (QOS_POLICY_USERDATA, dds_userdata_qospolicy_t) + +struct dds_sysdef_qos_generic_property { + struct xml_element xmlnode; +}; + +#define QOS_LENGTH_UNLIMITED "LENGTH_UNLIMITED" +#define QOS_DURATION_INFINITY "DURATION_INFINITY" +#define QOS_DURATION_INFINITY_SEC "DURATION_INFINITE_SEC" +#define QOS_DURATION_INFINITY_NSEC "DURATION_INFINITE_NSEC" + +#define QOS_DURATION_PARAM_SEC (1 << 0u) +#define QOS_DURATION_PARAM_NSEC (1 << 1u) +struct dds_sysdef_qos_duration_property { + struct xml_element xmlnode; + dds_duration_t sec; + dds_duration_t nsec; + uint32_t populated; +}; + +struct dds_sysdef_qos { + struct xml_element xmlnode; + enum dds_sysdef_qos_kind kind; + dds_qos_t *qos; + char *name; + struct dds_sysdef_qos_profile *base_profile; +}; + +struct dds_sysdef_qos_profile { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_qos *qos; + struct dds_sysdef_qos_profile *base_profile; +}; + +struct dds_sysdef_qos_lib { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_qos_profile *qos_profiles; +}; + +/* Domain library */ +struct dds_sysdef_topic { + struct xml_element xmlnode; + char *name; + // TODO: registered_name? + struct dds_sysdef_qos *qos; + struct dds_sysdef_register_type *register_type_ref; +}; + +enum dds_sysdef_register_type_parent_kind { + DDS_SYSDEF_TYPEREG_PARENT_KIND_DOMAIN, + DDS_SYSDEF_TYPEREG_PARENT_KIND_PARTICIPANT +}; + +struct dds_sysdef_register_type { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_type *type_ref; + enum dds_sysdef_register_type_parent_kind parent_kind; +}; + +#define SYSDEF_DOMAIN_DOMAIN_ID_PARAM_VALUE (1 << 0u) +#define SYSDEF_DOMAIN_PARTICIPANT_INDEX_PARAM_VALUE (1 << 1u) +#define SYSDEF_DOMAIN_PARAMS (SYSDEF_DOMAIN_DOMAIN_ID_PARAM_VALUE) +struct dds_sysdef_domain { + struct xml_element xmlnode; + uint32_t domain_id; + char *name; + int32_t participant_index; + struct dds_sysdef_register_type *register_types; + struct dds_sysdef_topic *topics; + uint32_t populated; +}; + +struct dds_sysdef_domain_lib { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_domain *domains; +}; + +/* Participant library */ +struct dds_sysdef_endpoint { + struct xml_element xmlnode; + char *name; + uint32_t entity_key; +}; + +#define SYSDEF_WRITER_ENTITY_KEY_PARAM_VALUE (1 << 0u) +#define SYSDEF_WRITER_PARAMS (SYSDEF_WRITER_ENTITY_KEY_PARAM_VALUE) +struct dds_sysdef_writer { + struct xml_element xmlnode; + char *name; + uint32_t entity_key; + struct dds_sysdef_topic *topic; + struct dds_sysdef_qos *qos; + uint32_t populated; +}; +DDSRT_STATIC_ASSERT (offsetof (struct dds_sysdef_writer, xmlnode) == offsetof (struct dds_sysdef_endpoint, xmlnode)); +DDSRT_STATIC_ASSERT (offsetof (struct dds_sysdef_writer, name) == offsetof (struct dds_sysdef_endpoint, name)); +DDSRT_STATIC_ASSERT (offsetof (struct dds_sysdef_writer, entity_key) == offsetof (struct dds_sysdef_endpoint, entity_key)); + +#define SYSDEF_READER_ENTITY_KEY_PARAM_VALUE (1 << 0u) +#define SYSDEF_READER_PARAMS (SYSDEF_READER_ENTITY_KEY_PARAM_VALUE) +struct dds_sysdef_reader { + struct xml_element xmlnode; + char *name; + uint32_t entity_key; + struct dds_sysdef_topic *topic; + struct dds_sysdef_qos *qos; + uint32_t populated; +}; +DDSRT_STATIC_ASSERT (offsetof (struct dds_sysdef_reader, xmlnode) == offsetof (struct dds_sysdef_endpoint, xmlnode)); +DDSRT_STATIC_ASSERT (offsetof (struct dds_sysdef_reader, name) == offsetof (struct dds_sysdef_endpoint, name)); +DDSRT_STATIC_ASSERT (offsetof (struct dds_sysdef_reader, entity_key) == offsetof (struct dds_sysdef_endpoint, entity_key)); + +struct dds_sysdef_publisher { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_qos *qos; + struct dds_sysdef_writer *writers; +}; + +struct dds_sysdef_subscriber { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_qos *qos; + struct dds_sysdef_reader *readers; +}; + +enum dds_sysdef_participant_parent_kind { + DDS_SYSDEF_PARTICIPANT_PARENT_KIND_APPLICATION, + DDS_SYSDEF_PARTICIPANT_PARENT_KIND_PARTICIPANTLIB +}; + +struct dds_sysdef_participant_guid_prefix { + uint32_t p; +}; + +struct dds_sysdef_participant { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_qos *qos; + struct dds_sysdef_domain *domain_ref; + struct dds_sysdef_participant *base; + struct dds_sysdef_participant_guid_prefix *guid_prefix; + + struct dds_sysdef_register_type *register_types; + struct dds_sysdef_topic *topics; + struct dds_sysdef_publisher *publishers; + struct dds_sysdef_subscriber *subscribers; + + enum dds_sysdef_participant_parent_kind parent_kind; + uint32_t populated; +}; + +struct dds_sysdef_participant_lib { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_participant *participants; +}; + +/* Application library */ +struct dds_sysdef_application { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_participant *participants; +}; + +struct dds_sysdef_application_lib { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_application *applications; +}; + +/* Node library */ +struct dds_sysdef_mac_addr { + uint8_t addr[6]; +}; +struct dds_sysdef_ip_addr { + struct sockaddr_storage addr; +}; +struct dds_sysdef_node { + struct xml_element xmlnode; + char *name; + char *hostname; + struct dds_sysdef_ip_addr *ipv4_addr; + struct dds_sysdef_ip_addr *ipv6_addr; + struct dds_sysdef_mac_addr *mac_addr; +}; + +struct dds_sysdef_node_lib { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_node *nodes; +}; + +/* Deployment library */ +#define SYSDEF_TSN_TIME_AWARE_EARLIEST_TRANSMIT_OFFSET_PARAM_VALUE (1 << 0u) +#define SYSDEF_TSN_TIME_AWARE_LATEST_TRANSMIT_OFFSET_PARAM_VALUE (1 << 1u) +#define SYSDEF_TSN_TIME_JITTER_PARAM_VALUE (1 << 2u) +struct dds_sysdef_tsn_time_aware { + struct xml_element xmlnode; + uint32_t earliest_transmit_offset; + uint32_t latest_transmit_offset; + uint32_t jitter; + uint32_t populated; +}; + +enum dds_sysdef_tsn_traffic_transmission_selection { + DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_STRICT_PRIORITY, + DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_CREDIT_BASED_SHAPER, + DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_ENHANCED_TRANSMISSION_SELECTION, + DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_ATS_TRANSMISSION_SELECTION +}; + +#define SYSDEF_TSN_TRAFFIC_SPEC_SAMPLES_PER_PERIOD_PARAM_VALUE (1 << 0u) +#define SYSDEF_TSN_TRAFFIC_SPEC_MAX_BYTES_PER_SAMPLE_PARAM_VALUE (1 << 1u) +#define SYSDEF_TSN_TRAFFIC_SPEC_TRANSMISSION_SELECTION_PARAM_VALUE (1 << 2u) +struct dds_sysdef_tsn_traffic_specification { + struct xml_element xmlnode; + dds_duration_t periodicity; + uint16_t samples_per_period; + uint16_t max_bytes_per_sample; + enum dds_sysdef_tsn_traffic_transmission_selection transmission_selection; + struct dds_sysdef_tsn_time_aware *time_aware; + uint32_t populated; +}; + +#define SYSDEF_TSN_NETWORK_REQ_NUM_SEAMLESS_TREES_PARAM_VALUE (1 << 0u) +#define SYSDEF_TSN_NETWORK_REQ_MAX_LATENCY_PARAM_VALUE (1 << 1u) +struct dds_sysdef_tsn_network_requirements { + struct xml_element xmlnode; + uint8_t num_seamless_trees; + uint32_t max_latency; + uint32_t populated; +}; + +struct dds_sysdef_tsn_ieee802_mac_addresses { + struct xml_element xmlnode; + char *destination_mac_address; + char *source_mac_address; +}; + +struct dds_sysdef_tsn_ieee802_vlan_tag { + struct xml_element xmlnode; + uint8_t priority_code_point; + uint16_t vlan_id; + uint32_t populated; +}; + +#define SYSDEF_TSN_IP_TUPLE_DSCP_PARAM_VALUE (1 << 0u) +#define SYSDEF_TSN_IP_TUPLE_PROTOCOL_PARAM_VALUE (1 << 1u) +#define SYSDEF_TSN_IP_TUPLE_SOURCE_PORT_PARAM_VALUE (1 << 2u) +#define SYSDEF_TSN_IP_TUPLE_DESTINATION_PORT_PARAM_VALUE (1 << 3u) +struct dds_sysdef_tsn_ip_tuple { + struct xml_element xmlnode; + char *source_ip_address; + char *destination_ip_address; + uint8_t dscp; + uint16_t protocol; + uint16_t source_port; + uint16_t destination_port; + uint32_t populated; +}; + +struct dds_sysdef_tsn_data_frame_specification { + struct xml_element xmlnode; + struct dds_sysdef_tsn_ieee802_mac_addresses *mac_addresses; + struct dds_sysdef_tsn_ieee802_vlan_tag *vlan_tag; + struct dds_sysdef_tsn_ip_tuple *ipv4_tuple; + struct dds_sysdef_tsn_ip_tuple *ipv6_tuple; +}; + +struct dds_sysdef_tsn_talker_configuration { + struct xml_element xmlnode; + char *name; + char *stream_name; + struct dds_sysdef_writer *writer; + struct dds_sysdef_tsn_traffic_specification *traffic_specification; + struct dds_sysdef_tsn_network_requirements *network_requirements; + struct dds_sysdef_tsn_data_frame_specification *data_frame_specification; +}; + +struct dds_sysdef_tsn_listener_configuration { + struct xml_element xmlnode; + char *name; + char *stream_name; + struct dds_sysdef_reader *reader; + struct dds_sysdef_tsn_network_requirements *network_requirements; +}; + +struct dds_sysdef_tsn_configuration { + struct xml_element xmlnode; + struct dds_sysdef_tsn_talker_configuration *tsn_talker_configurations; + struct dds_sysdef_tsn_listener_configuration *tsn_listener_configurations; +}; + +struct dds_sysdef_configuration { + struct xml_element xmlnode; + struct dds_sysdef_tsn_configuration *tsn_configuration; +}; + +struct dds_sysdef_application_ref { + struct xml_element xmlnode; + struct dds_sysdef_application *application; +}; + +struct dds_sysdef_application_list { + struct xml_element xmlnode; + struct dds_sysdef_application_ref *application_refs; +}; + +struct dds_sysdef_deployment { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_node *node; + struct dds_sysdef_application_list *application_list; + struct dds_sysdef_configuration *configuration; +}; + +struct dds_sysdef_deployment_lib { + struct xml_element xmlnode; + char *name; + struct dds_sysdef_deployment *deployments; +}; + +struct dds_sysdef_system { + struct xml_element xmlnode; + struct dds_sysdef_type_lib *type_libs; + struct dds_sysdef_qos_lib *qos_libs; + struct dds_sysdef_domain_lib *domain_libs; + struct dds_sysdef_participant_lib *participant_libs; + struct dds_sysdef_application_lib *application_libs; + struct dds_sysdef_node_lib *node_libs; + struct dds_sysdef_deployment_lib *deployment_libs; +}; + +#if defined (__cplusplus) +} +#endif + +#endif // DDS__SYSDEF_MODEL_H diff --git a/src/core/ddsc/src/dds__sysdef_parser.h b/src/core/ddsc/src/dds__sysdef_parser.h new file mode 100644 index 0000000000..f999767e85 --- /dev/null +++ b/src/core/ddsc/src/dds__sysdef_parser.h @@ -0,0 +1,145 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +#ifndef DDS_SYSDEF_PARSER_H +#define DDS_SYSDEF_PARSER_H + +#include "dds/dds.h" +#include "dds/ddsrt/log.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +#define SYSDEF_SCOPE_TYPE_LIB (1u << 0u) +#define SYSDEF_SCOPE_QOS_LIB (1u << 1u) +#define SYSDEF_SCOPE_DOMAIN_LIB (1u << 2u) +#define SYSDEF_SCOPE_PARTICIPANT_LIB (1u << 3u) +#define SYSDEF_SCOPE_APPLICATION_LIB (1u << 4u) +#define SYSDEF_SCOPE_NODE_LIB (1u << 5u) +#define SYSDEF_SCOPE_DEPLOYMENT_LIB (1u << 6u) + +#define SYSDEF_SCOPE_ALL_LIB ( \ + SYSDEF_SCOPE_TYPE_LIB |\ + SYSDEF_SCOPE_QOS_LIB |\ + SYSDEF_SCOPE_DOMAIN_LIB |\ + SYSDEF_SCOPE_PARTICIPANT_LIB |\ + SYSDEF_SCOPE_APPLICATION_LIB |\ + SYSDEF_SCOPE_NODE_LIB |\ + SYSDEF_SCOPE_DEPLOYMENT_LIB \ +) + +#define SYSDEF_RET_OK 0 +#define SYSDEF_RET_FAILURE 1 + +#define SD_PARSE_RESULT_OK 0 +#define SD_PARSE_RESULT_ERR -1 +#define SD_PARSE_RESULT_SYNTAX_ERR -2 +#define SD_PARSE_RESULT_OUT_OF_RESOURCES -3 +#define SD_PARSE_RESULT_NOT_SUPPORTED -4 +#define SD_PARSE_RESULT_INVALID_REF -5 +#define SD_PARSE_RESULT_DUPLICATE -6 + +/** + * @defgroup sysdef_parser (SysdefParser) + */ + +#define SYSDEF_TRACE(...) DDS_LOG(DDS_LC_SYSDEF | DDS_LC_TRACE, __VA_ARGS__) +#define SYSDEF_ERROR(...) DDS_LOG(DDS_LC_SYSDEF | DDS_LC_ERROR, __VA_ARGS__) + +/** + * @brief Sample structure of System definition. + * @ingroup sysdef_parser + * @componen sysdef_parser_api + */ +struct dds_sysdef_system; +/** + * @brief Sample structure of System definition for data types. + * @ingroup sysdef_parser + * @componen sysdef_parser_api + */ +struct dds_sysdef_type_metadata_admin; + +/** + * @defgroup sysdef_parser (SysdefParser) + */ + +/** +* @brief Initialize System definition from file. +* @ingroup dds_sysdef +* @component dds_sysdef_api +* +* Create dds_sysdef_system with provided system definition. +* +* @param[in] fp - Pointer to system definition file. +* @param[in,out] sysdef - Pointer dds_sysdef_system structure. +* @param[in] lib_scope - Library initialization mask. +* +* @return a DDS return code +*/ +dds_return_t dds_sysdef_init_sysdef (FILE *fp, struct dds_sysdef_system **sysdef, uint32_t lib_scope); + +/** +* @brief Initialize System definition from `xml` string. +* @ingroup dds_sysdef +* @component dds_sysdef_api +* +* Create dds_sysdef_system with provided system definition. +* +* @param[in] raw - System definition string. +* @param[in,out] sysdef - Pointer dds_sysdef_system structure. +* @param[in] lib_scope - Library initialization mask. +* +* @return a DDS return code +*/ +dds_return_t dds_sysdef_init_sysdef_str (const char *raw, struct dds_sysdef_system **sysdef, uint32_t lib_scope); + +/** +* @brief Finalize System definition. +* @ingroup dds_sysdef +* @component dds_sysdef_api +* +* Release resources allocated by dds_sysdef_system. +* +* @param[in] sysdef - Pointer to dds_sysdef_system structure. +* +*/ +void dds_sysdef_fini_sysdef (struct dds_sysdef_system *sysdef); + +/** +* @brief Initialize System definition for data types. +* @ingroup dds_sysdef +* @component dds_sysdef_api +* +* Create dds_sysdef_type_metadata_admin with provided system definition. +* +* @param[in] fp - Pointer to system definition file. +* @param[in,out] type_meta_data - Pointer dds_sysdef_type_metadata_admin structure. +* +* @return a DDS return code +*/ +dds_return_t dds_sysdef_init_data_types (FILE *fp, struct dds_sysdef_type_metadata_admin **type_meta_data); + +/** +* @brief Finalize System definition for data types. +* @ingroup dds_sysdef +* @component dds_sysdef_api +* +* Release resources allocated by dds_sysdef_system. +* +* @param[in,out] type_meta_data - Pointer dds_sysdef_type_metadata_admin structure. +* +*/ +void dds_sysdef_fini_data_types (struct dds_sysdef_type_metadata_admin *type_meta_data); + +#if defined (__cplusplus) +} +#endif + +#endif // DDS_SYSDEF_PARSER_H diff --git a/src/core/ddsc/src/dds__sysdef_validation.h b/src/core/ddsc/src/dds__sysdef_validation.h new file mode 100644 index 0000000000..341b19b537 --- /dev/null +++ b/src/core/ddsc/src/dds__sysdef_validation.h @@ -0,0 +1,26 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +#ifndef DDS__SYSDEF_VALIDATION_H +#define DDS__SYSDEF_VALIDATION_H + +#if defined (__cplusplus) +extern "C" { +#endif + +#include "dds/dds.h" +#include "dds__sysdef_model.h" + +dds_return_t dds_validate_qos_lib ( + const struct dds_sysdef_system *sysdef, uint64_t qos_mask); + +#if defined (__cplusplus) +} +#endif +#endif // DDS__SYSDEF_VALIDATION_H diff --git a/src/core/ddsc/src/dds_qos_provider.c b/src/core/ddsc/src/dds_qos_provider.c new file mode 100644 index 0000000000..6f638b4d1c --- /dev/null +++ b/src/core/ddsc/src/dds_qos_provider.c @@ -0,0 +1,292 @@ + +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +#include "string.h" + +#include "dds/ddsrt/io.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/mh3.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/hopscotch.h" + +#include "dds__sysdef_model.h" +#include "dds__sysdef_parser.h" +#include "dds__sysdef_validation.h" +#include "dds__qos_provider.h" +#include "dds__qos.h" + +static dds_return_t read_sysdef (const char *path, struct dds_sysdef_system **sysdef) +{ + dds_return_t ret = DDS_RETCODE_BAD_PARAMETER; + if (path == NULL) + return ret; + if (path[0] == '<') + { + ret = dds_sysdef_init_sysdef_str(path, sysdef, SYSDEF_SCOPE_QOS_LIB); + } else { + FILE *fp; + DDSRT_WARNING_MSVC_OFF(4996) + if ((fp = fopen (path, "r")) == NULL) + { + SYSDEF_ERROR ("Error reading system definition: can't read from path '%s'\n", path); + ret = DDS_RETCODE_BAD_PARAMETER; + } else { + ret = dds_sysdef_init_sysdef (fp, sysdef, SYSDEF_SCOPE_QOS_LIB); + (void)fclose(fp); + DDSRT_WARNING_MSVC_ON(4996) + } + } + + return ret; +} + +static uint32_t qos_item_hash_fn(const void *a) +{ + dds_qos_item_t *item = (dds_qos_item_t *)a; + uint32_t x = ddsrt_mh3(&item->kind, sizeof(item->kind), 0); + x = ddsrt_mh3(item->full_name, strlen(item->full_name), x); + return x; +} + +static bool qos_item_equals_fn(const void *a, const void *b) +{ + dds_qos_item_t *aa = (dds_qos_item_t *)a; + dds_qos_item_t *bb = (dds_qos_item_t *)b; + + return aa->kind == bb->kind && strcmp(aa->full_name, bb->full_name) == 0; +} + +static void cleanup_qos_items (void *vnode, void *varg) +{ + (void) varg; + dds_qos_item_t *d = (dds_qos_item_t *) vnode; + ddsrt_free (d->full_name); + dds_delete_qos(d->qos); + ddsrt_free(d); +} + +#define PROVIDER_ALLOWED_QOS_MASK \ + (DDS_TOPIC_QOS_MASK | DDS_READER_QOS_MASK | DDS_WRITER_QOS_MASK | \ + DDS_SUBSCRIBER_QOS_MASK | DDS_PUBLISHER_QOS_MASK | DDS_PARTICIPANT_QOS_MASK) ^ \ + (DDSI_QP_ENTITY_NAME | DDSI_QP_ADLINK_ENTITY_FACTORY | \ + DDSI_QP_CYCLONE_IGNORELOCAL | DDSI_QP_PSMX) +static dds_return_t read_validate_sysdef(const char *path, struct dds_sysdef_system **sysdef) +{ + dds_return_t ret = DDS_RETCODE_OK; + struct dds_sysdef_system *def; + if ((ret = read_sysdef (path, &def)) != DDS_RETCODE_OK) + { + QOSPROV_ERROR("Failed during read sysdef: %s\n", path); + goto err_read; + } + if ((ret = dds_validate_qos_lib (def, PROVIDER_ALLOWED_QOS_MASK)) != DDS_RETCODE_OK) + { + QOSPROV_ERROR("Failed during validate sysdef: %s\n", path); + goto err_validate; + } + *sysdef = def; + + return ret; +err_validate: + dds_sysdef_fini_sysdef(def); +err_read: + return ret; +} +#undef PROVIDER_ALLOWED_QOS_MASK + +static dds_return_t init_qos_provider (const struct dds_sysdef_system *sysdef, const char *path, dds_qos_provider_t **provider, char *lib_scope, char *prof_scope, char *ent_scope) +{ + dds_return_t ret = DDS_RETCODE_OK; + dds_qos_provider_t *qos_provider = (dds_qos_provider_t *)ddsrt_malloc(sizeof(*qos_provider)); + struct ddsrt_hh *keyed_qos = ddsrt_hh_new(1, qos_item_hash_fn, qos_item_equals_fn); + for (const struct dds_sysdef_qos_lib *lib = sysdef->qos_libs; lib != NULL; lib = (const struct dds_sysdef_qos_lib *)lib->xmlnode.next) + { + char *lib_name = lib->name; + if (lib_scope != NULL && strcmp(lib_scope, PROVIDER_ITEM_SCOPE_NONE) != 0 && strcmp(lib_name, lib_scope) != 0) + continue; + for (const struct dds_sysdef_qos_profile *prof = lib->qos_profiles; prof != NULL; prof = (const struct dds_sysdef_qos_profile *)prof->xmlnode.next) + { + char *prof_name = prof->name; + if (prof_scope != NULL && strcmp(prof_scope, PROVIDER_ITEM_SCOPE_NONE) != 0 && strcmp(prof_name, prof_scope) != 0) + continue; + char *prefix; + (void) ddsrt_asprintf(&prefix, "%s"PROVIDER_ITEM_SEP"%s", lib_name, prof_name); + for (const struct dds_sysdef_qos *qos = prof->qos; qos != NULL; qos = (const struct dds_sysdef_qos *)qos->xmlnode.next) + { + if (ent_scope != NULL && strcmp(ent_scope, PROVIDER_ITEM_SCOPE_NONE) != 0 && (qos->name == NULL || strcmp(qos->name, ent_scope) != 0)) + continue; + dds_qos_item_t *item = ddsrt_malloc(sizeof(*item)); + dds_qos_kind_t kind; + switch(qos->kind) + { + case DDS_SYSDEF_TOPIC_QOS: + kind = DDS_TOPIC_QOS; + break; + case DDS_SYSDEF_READER_QOS: + kind = DDS_READER_QOS; + break; + case DDS_SYSDEF_WRITER_QOS: + kind = DDS_WRITER_QOS; + break; + case DDS_SYSDEF_SUBSCRIBER_QOS: + kind = DDS_SUBSCRIBER_QOS; + break; + case DDS_SYSDEF_PUBLISHER_QOS: + kind = DDS_PUBLISHER_QOS; + break; + case DDS_SYSDEF_PARTICIPANT_QOS: + kind = DDS_PARTICIPANT_QOS; + break; + default: + ddsrt_free(prefix); + ddsrt_free(item); + goto err_prov; + } + item->kind = kind; + item->qos = dds_create_qos(); + dds_merge_qos(item->qos, qos->qos); + if (qos->name != NULL) + (void) ddsrt_asprintf(&item->full_name, "%s"PROVIDER_ITEM_SEP"%s", prefix, qos->name); + else + item->full_name = ddsrt_strdup(prefix); + if (!ddsrt_hh_add(keyed_qos, item)) + { + QOSPROV_ERROR("Qos duplicate name: %s kind: %d file: %s.\n", + item->full_name, item->kind, path); + ret = DDS_RETCODE_BAD_PARAMETER; + ddsrt_free(prefix); + cleanup_qos_items(item, NULL); + goto err_prov; + } + } + ddsrt_free(prefix); + } + } + qos_provider->file_path = ddsrt_strdup(path); + qos_provider->keyed_qos = keyed_qos; + *provider = qos_provider; + + return ret; +err_prov: + ddsrt_hh_enum(keyed_qos, cleanup_qos_items, NULL); + ddsrt_hh_free(keyed_qos); + ddsrt_free(qos_provider); + return ret; +} + +dds_return_t dds_create_qos_provider (const char *path, dds_qos_provider_t **provider) +{ + dds_return_t ret = DDS_RETCODE_OK; + if ((ret = dds_create_qos_provider_scope (path, provider, PROVIDER_ITEM_SCOPE_NONE)) != DDS_RETCODE_OK) + goto err; + +err: + return ret; +} + +dds_return_t dds_qos_provider_get_qos (const dds_qos_provider_t *provider, dds_qos_kind_t type, const char *key, const dds_qos_t **qos) +{ + dds_return_t ret = DDS_RETCODE_OK; + if (provider == NULL || provider->keyed_qos == NULL) + { + QOSPROV_WARN("Failed to access provider qos\n"); + ret = DDS_RETCODE_BAD_PARAMETER; + goto err; + } + QOSPROV_TRACE("request qos for entity type: %d, scope: %s", type, key); + dds_qos_item_t it = {.full_name = ddsrt_strdup(key), .kind = type}; + dds_qos_item_t *item; + if ((item = ddsrt_hh_lookup(provider->keyed_qos, &it)) == NULL) + { + QOSPROV_WARN("Failed to get qos with name: %s, kind: %d ref file: %s\n", + it.full_name, it.kind, provider->file_path); + ret = DDS_RETCODE_BAD_PARAMETER; + goto err2; + } + *qos = item->qos; + +err2: + ddsrt_free(it.full_name); +err: + return ret; +} + +static void fill_token(char **start, char **end, char **token) +{ + char *bg = *start; + char *ed = *end; + if ((bg != NULL) && (ed = strstr(bg, PROVIDER_ITEM_SEP)) != NULL) + *token = ((ed-bg) > 0)? ddsrt_strndup(bg, (size_t)(ed-bg)): ddsrt_strdup(PROVIDER_ITEM_SCOPE_NONE); + else + *token = (bg != NULL && *bg != '\0')? ddsrt_strdup(bg): ddsrt_strdup(PROVIDER_ITEM_SCOPE_NONE); + *start = (ed != NULL)? ed + strlen(PROVIDER_ITEM_SEP): NULL; + *end = ed; +} + +static void fill_tokens_str(const char *start, char **lib, char **pro, char **ent) +{ + char *current = ddsrt_strdup(start); + char *next = current; + char *ending = next; + fill_token(&next, &ending, lib); + fill_token(&next, &ending, pro); + fill_token(&next, &ending, ent); + ddsrt_free(current); +} + +static void empty_tokens_str(char *lib, char *pro, char *ent) +{ + ddsrt_free(lib); + ddsrt_free(pro); + ddsrt_free(ent); +} + +static dds_return_t resolve_token(const char *key, char **lib, char **prof, char **ent) +{ + dds_return_t ret = DDS_RETCODE_OK; + if (key == NULL) + { + ret = DDS_RETCODE_ERROR; + goto err; + } + fill_tokens_str(key, lib, prof, ent); +err: + return ret; +} + +dds_return_t dds_create_qos_provider_scope (const char *path, dds_qos_provider_t **provider, const char *key) +{ + dds_return_t ret = DDS_RETCODE_OK; + struct dds_sysdef_system *sysdef; + if ((ret = read_validate_sysdef(path, &sysdef)) != DDS_RETCODE_OK) + return ret; + char *lib_name = NULL, *prof_name = NULL, *ent_name = NULL; + (void)resolve_token(key, &lib_name, &prof_name, &ent_name); + if ((ret = init_qos_provider(sysdef, path, provider, lib_name, prof_name, ent_name)) != DDS_RETCODE_OK) + { + QOSPROV_ERROR("Failed to create qos provider file: %s, scope: %s", path, key); + goto err; + } +err: + empty_tokens_str(lib_name, prof_name, ent_name); + dds_sysdef_fini_sysdef(sysdef); + return ret; +} + +void dds_delete_qos_provider (dds_qos_provider_t *provider) +{ + if (provider) + { + ddsrt_hh_enum(provider->keyed_qos, cleanup_qos_items, NULL); + ddsrt_hh_free(provider->keyed_qos); + ddsrt_free(provider->file_path); + ddsrt_free(provider); + } +} diff --git a/src/core/ddsc/src/dds_sysdef_parser.c b/src/core/ddsc/src/dds_sysdef_parser.c new file mode 100644 index 0000000000..63c5150d87 --- /dev/null +++ b/src/core/ddsc/src/dds_sysdef_parser.c @@ -0,0 +1,3065 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + +#include +#include + +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/strtol.h" +#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsrt/xmlparser.h" +#include "dds/ddsrt/sockets.h" +#include "dds/ddsi/ddsi_unused.h" +#include "dds/ddsi/ddsi_domaingv.h" + +#include "dds__sysdef_model.h" +#include "dds__sysdef_parser.h" + +#define _STR(s) #s +#define STR(s) _STR(s) + +#define PP ELEMENT_KIND_QOS_PARTICIPANT +#define SUB ELEMENT_KIND_QOS_SUBSCRIBER +#define PUB ELEMENT_KIND_QOS_PUBLISHER +#define TP ELEMENT_KIND_QOS_TOPIC +#define WR ELEMENT_KIND_QOS_WRITER +#define RD ELEMENT_KIND_QOS_READER +#define QOS_POLICY_MAPPING(p,...) \ + static const enum element_kind qos_policy_mapping_ ## p[] = { __VA_ARGS__ }; + + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_DEADLINE, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_DURABILITY, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY, SUB, PUB, PP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_GROUPDATA, SUB, PUB) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_HISTORY, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_LIFESPAN, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_LIVELINESS, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_OWNERSHIP, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH, WR) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_PARTITION, SUB, PUB) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_PRESENTATION, SUB, PUB) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE, RD) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_RELIABILITY, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, RD, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER, RD) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_TOPICDATA, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY, WR, TP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_USERDATA, RD, WR, PP) + QOS_POLICY_MAPPING (ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE, WR) + +#undef PP +#undef SUB +#undef PUB +#undef TP +#undef WR +#undef RD + +#define MAX_ERRMSG_SZ 300 + +#define NO_INIT NULL +#define NO_FINI NULL + +#define PARSER_ERROR(pstate,line,...) \ + do { \ + (void) snprintf ((pstate)->err_msg, MAX_ERRMSG_SZ, __VA_ARGS__); \ + (pstate)->err_line = (line); \ + (pstate)->has_err = true; \ + } while (0) + +#define CHECK_PARENT_NULL(pstate, current) \ + do { if ((current) == NULL) { \ + PARSER_ERROR (pstate, line, "Current element NULL for element '%s'", name); \ + return SD_PARSE_RESULT_SYNTAX_ERR; \ + } } while (0) + +#define CHECK_PARENT_KIND(pstate, parent_kind, current) \ + do { if ((current)->kind != parent_kind) { \ + PARSER_ERROR (pstate, line, "Invalid parent kind (%d) for element '%s'", (current)->kind, name); \ + return SD_PARSE_RESULT_SYNTAX_ERR; \ + } } while (0) + +#define _CREATE_NODE(pstate, element_type, element_kind, element_data_type, parent_kind, current, element_init, element_fini) \ + { \ + CHECK_PARENT_KIND (pstate, (parent_kind), current); \ + if (((current) = new_node (pstate, element_kind, element_data_type, current, sizeof (struct element_type), element_init, element_fini)) == NULL) \ + return SD_PARSE_RESULT_ERR; \ + } + +#define CREATE_NODE_LIST(pstate, element_type, element_kind, element_init, element_fini, element_name, parent_type, parent_kind, current) \ + do { \ + struct parent_type *parent = (struct parent_type *) current; \ + _CREATE_NODE(pstate, element_type, element_kind, ELEMENT_DATA_TYPE_GENERIC, parent_kind, current, element_init, element_fini); \ + if (parent->element_name == NULL) { \ + parent->element_name = (struct element_type *) current; \ + } else { \ + struct xml_element *tail = (struct xml_element *) parent->element_name; \ + while (tail->next != NULL) { \ + tail = tail->next; \ + } \ + tail->next = current; \ + } \ + goto status_ok; \ + } while (0) + +#define CREATE_NODE_SINGLE(pstate, element_type, element_kind, element_init, element_fini, element_name, parent_type, parent_kind, current) \ + do { \ + struct parent_type *parent = (struct parent_type *) current; \ + if (parent->element_name != NULL) { \ + PARSER_ERROR (pstate, line, "Duplicate element '%s'", name); \ + return SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + _CREATE_NODE(pstate, element_type, element_kind, ELEMENT_DATA_TYPE_GENERIC, parent_kind, current, element_init, element_fini); \ + parent->element_name = (struct element_type *) current; \ + goto status_ok; \ + } while (0) + +#define CREATE_NODE_CUSTOM(pstate, element_type, element_kind, element_init, element_fini, parent_kind, current) \ + do { \ + _CREATE_NODE(pstate, element_type, element_kind, ELEMENT_DATA_TYPE_GENERIC, parent_kind, current, element_init, element_fini); \ + current->retain = false; \ + goto status_ok; \ + } while (0) + +#define CREATE_NODE_DURATION(pstate, element_type, element_kind, element_init, element_fini, parent_kind, current) \ + do { \ + _CREATE_NODE(pstate, element_type, element_kind, ELEMENT_DATA_TYPE_DURATION, parent_kind, current, element_init, element_fini); \ + current->retain = false; \ + current->handle_close = true; \ + goto status_ok; \ + } while (0) + +#define CREATE_NODE_DURATION_SEC(pstate, current) \ + do { \ + _CREATE_NODE(pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_DURATION_SEC, ELEMENT_DATA_TYPE_GENERIC, current->kind, current, NO_INIT, NO_FINI); \ + current->retain = false; \ + goto status_ok; \ + } while (0) + +#define CREATE_NODE_DURATION_NSEC(pstate, current) \ + do { \ + _CREATE_NODE(pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_DURATION_NSEC, ELEMENT_DATA_TYPE_GENERIC, current->kind, current, NO_INIT, NO_FINI); \ + current->retain = false; \ + goto status_ok; \ + } while (0) + +#define CREATE_NODE_QOS(pstate, element_type, element_kind, element_init, element_fini, current) \ + do { \ + bool allowed = false; \ + for (uint32_t n = 0; !allowed && n < sizeof (qos_policy_mapping_ ## element_kind) / sizeof (qos_policy_mapping_ ## element_kind[0]); n++) { \ + allowed = (current)->kind == qos_policy_mapping_ ## element_kind[n]; \ + } \ + if (!allowed) { \ + PARSER_ERROR (pstate, line, "Invalid parent kind (%d) for element '%s'", (current)->kind, name); \ + return SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + if (((current) = new_node (pstate, element_kind, ELEMENT_DATA_TYPE_GENERIC, current, sizeof (struct element_type), element_init, element_fini)) == NULL) \ + return SD_PARSE_RESULT_ERR;\ + current->retain = false; \ + current->handle_close = true; \ + goto status_ok; \ + } while (0) + +struct parse_sysdef_state { + struct dds_sysdef_system *sysdef; + struct xml_element *current; + uint32_t scope; + bool has_err; + int err_line; + char err_msg[MAX_ERRMSG_SZ]; +}; + +static bool str_to_int32 (const char *str, int32_t *value) +{ + char *endptr; + long long l; + if (ddsrt_strtoll (str, &endptr, 0, &l) != DDS_RETCODE_OK || l < INT32_MIN || l > INT32_MAX) { + return false; + } + *value = (int32_t) l; + return (*endptr == '\0'); +} + +static bool str_to_uint8 (const char *str, uint8_t *value) +{ + char *endptr; + long long l; + if (ddsrt_strtoll (str, &endptr, 0, &l) != DDS_RETCODE_OK || l < 0 || l > UINT8_MAX) { + return false; + } + *value = (uint8_t) l; + return (*endptr == '\0'); +} + +static bool str_to_uint16 (const char *str, uint16_t *value) +{ + char *endptr; + long long l; + if (ddsrt_strtoll (str, &endptr, 0, &l) != DDS_RETCODE_OK || l < 0 || l > UINT16_MAX) { + return false; + } + *value = (uint16_t) l; + return (*endptr == '\0'); +} + +static bool str_to_uint32 (const char *str, uint32_t *value) +{ + char *endptr; + long long l; + if (ddsrt_strtoll (str, &endptr, 0, &l) != DDS_RETCODE_OK || l < 0 || l > UINT32_MAX) { + return false; + } + *value = (uint32_t) l; + return (*endptr == '\0'); +} + +static bool str_to_int64 (const char *str, int64_t *value) +{ + char *endptr; + long long l; + if (ddsrt_strtoll (str, &endptr, 0, &l) != DDS_RETCODE_OK || l < INT64_MIN || l > INT64_MAX) { + return false; + } + *value = (int64_t) l; + return (*endptr == '\0'); +} + +static bool str_to_bool (const char *str, bool *value) +{ + if (strcmp (str, "true") == 0 || strcmp (str, "1") == 0) + *value = true; + else if (strcmp (str, "false") == 0 || strcmp (str, "0") == 0) + *value = false; + else + return false; + + return true; +} + +static struct xml_element *new_node (struct parse_sysdef_state * const pstate, enum element_kind kind, enum element_data_type data_type, struct xml_element *parent, size_t size, init_fn init, fini_fn fini) +{ + struct xml_element *e = ddsrt_malloc (size); + if (e == NULL) { + PARSER_ERROR (pstate, 0, "Out of memory"); + return NULL; + } + memset (e, 0, size); + e->parent = parent; + e->kind = kind; + e->data_type = data_type; + e->retain = true; + e->handle_close = false; + e->next = NULL; + e->fini = fini; + if (init) { + if (init (pstate, e) != 0) { + return NULL; + } + } + return e; +} + +static void free_node (void *node) +{ + struct xml_element *element = (struct xml_element *) node; + while (element != NULL) + { + struct xml_element *tmp = element; + element = tmp->next; + if (tmp->fini) + tmp->fini (tmp); + ddsrt_free (tmp); + } +} + +static void fini_type (struct xml_element *node) +{ + struct dds_sysdef_type *type = (struct dds_sysdef_type *) node; + ddsrt_free (type->name); + ddsrt_free (type->identifier); +} + +static void fini_type_lib (struct xml_element *node) +{ + struct dds_sysdef_type_lib *type_lib = (struct dds_sysdef_type_lib *) node; + free_node (type_lib->types); +} + +static void fini_qos_groupdata (struct xml_element *node) +{ + struct dds_sysdef_QOS_POLICY_GROUPDATA *qp = (struct dds_sysdef_QOS_POLICY_GROUPDATA *) node; + assert (qp != NULL); + ddsrt_free (qp->values.value); +} + +static void fini_qos_topicdata (struct xml_element *node) +{ + struct dds_sysdef_QOS_POLICY_TOPICDATA *qp = (struct dds_sysdef_QOS_POLICY_TOPICDATA *) node; + assert (qp != NULL); + ddsrt_free (qp->values.value); +} + +static void fini_qos_userdata (struct xml_element *node) +{ + struct dds_sysdef_QOS_POLICY_USERDATA *qp = (struct dds_sysdef_QOS_POLICY_USERDATA *) node; + assert (qp != NULL); + ddsrt_free (qp->values.value); +} + +static void fini_qos_partition (struct xml_element *node) +{ + struct dds_sysdef_QOS_POLICY_PARTITION *qp = (struct dds_sysdef_QOS_POLICY_PARTITION *) node; + assert (qp != NULL); + free_node (qp->name); +} + +static void fini_qos_partition_name (struct xml_element *node) +{ + struct dds_sysdef_QOS_POLICY_PARTITION_NAME *p = (struct dds_sysdef_QOS_POLICY_PARTITION_NAME *) node; + assert (p != NULL); + free_node (p->elements); +} + +static void fini_qos_partition_name_element (struct xml_element *node) +{ + struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *p = (struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *) node; + assert (p != NULL); + ddsrt_free (p->element); +} + +static void fini_qos (struct xml_element *node) +{ + struct dds_sysdef_qos *qos = (struct dds_sysdef_qos *) node; + assert (qos != NULL); + dds_delete_qos (qos->qos); + ddsrt_free (qos->name); +} + +static void fini_qos_profile (struct xml_element *node) +{ + struct dds_sysdef_qos_profile *qos_profile = (struct dds_sysdef_qos_profile *) node; + free_node (qos_profile->qos); + ddsrt_free (qos_profile->name); +} + +static void fini_qos_lib (struct xml_element *node) +{ + struct dds_sysdef_qos_lib *qos_lib = (struct dds_sysdef_qos_lib *) node; + free_node (qos_lib->qos_profiles); + ddsrt_free (qos_lib->name); +} + +static void fini_register_type (struct xml_element *node) +{ + struct dds_sysdef_register_type *reg_type = (struct dds_sysdef_register_type *) node; + ddsrt_free (reg_type->name); +} + +static void fini_topic (struct xml_element *node) +{ + struct dds_sysdef_topic *topic = (struct dds_sysdef_topic *) node; + free_node (topic->qos); + ddsrt_free (topic->name); +} + +static void fini_domain (struct xml_element *node) +{ + struct dds_sysdef_domain *domain = (struct dds_sysdef_domain *) node; + free_node (domain->register_types); + free_node (domain->topics); + ddsrt_free (domain->name); +} + +static void fini_domain_lib (struct xml_element *node) +{ + struct dds_sysdef_domain_lib *domain_lib = (struct dds_sysdef_domain_lib *) node; + free_node (domain_lib->domains); + ddsrt_free (domain_lib->name); +} + +static void fini_publisher (struct xml_element *node) +{ + struct dds_sysdef_publisher *publisher = (struct dds_sysdef_publisher *) node; + free_node (publisher->writers); + free_node (publisher->qos); + ddsrt_free (publisher->name); +} + +static void fini_writer (struct xml_element *node) +{ + struct dds_sysdef_writer *writer = (struct dds_sysdef_writer *) node; + free_node (writer->qos); + ddsrt_free (writer->name); +} + +static void fini_subscriber (struct xml_element *node) +{ + struct dds_sysdef_subscriber *subscriber = (struct dds_sysdef_subscriber *) node; + free_node (subscriber->readers); + free_node (subscriber->qos); + ddsrt_free (subscriber->name); +} + +static void fini_reader (struct xml_element *node) +{ + struct dds_sysdef_reader *reader = (struct dds_sysdef_reader *) node; + free_node (reader->qos); + ddsrt_free (reader->name); +} + +static void fini_participant (struct xml_element *node) +{ + struct dds_sysdef_participant *participant = (struct dds_sysdef_participant *) node; + free_node (participant->publishers); + free_node (participant->subscribers); + free_node (participant->topics); + free_node (participant->qos); + free_node (participant->register_types); + ddsrt_free (participant->name); + ddsrt_free (participant->guid_prefix); +} + +static void fini_participant_lib (struct xml_element *node) +{ + struct dds_sysdef_participant_lib *participant_lib = (struct dds_sysdef_participant_lib *) node; + free_node (participant_lib->participants); + ddsrt_free (participant_lib->name); +} + +static void fini_application (struct xml_element *node) +{ + struct dds_sysdef_application *application = (struct dds_sysdef_application *) node; + free_node (application->participants); + ddsrt_free (application->name); +} + +static void fini_application_lib (struct xml_element *node) +{ + struct dds_sysdef_application_lib *application_lib = (struct dds_sysdef_application_lib *) node; + free_node (application_lib->applications); + ddsrt_free (application_lib->name); +} + +static void fini_node (struct xml_element *node) +{ + struct dds_sysdef_node *n = (struct dds_sysdef_node *) node; + ddsrt_free (n->name); + ddsrt_free (n->hostname); + ddsrt_free (n->ipv4_addr); + ddsrt_free (n->ipv6_addr); + ddsrt_free (n->mac_addr); +} + +static void fini_node_lib (struct xml_element *node) +{ + struct dds_sysdef_node_lib *node_lib = (struct dds_sysdef_node_lib *) node; + free_node (node_lib->nodes); + ddsrt_free (node_lib->name); +} + +static void fini_conf (struct xml_element *node) +{ + struct dds_sysdef_configuration *conf = (struct dds_sysdef_configuration *) node; + free_node (conf->tsn_configuration); +} + +static void fini_conf_tsn (struct xml_element *node) +{ + struct dds_sysdef_tsn_configuration *conf = (struct dds_sysdef_tsn_configuration *) node; + free_node (conf->tsn_talker_configurations); + free_node (conf->tsn_listener_configurations); +} + +static void fini_conf_tsn_talker (struct xml_element *node) +{ + struct dds_sysdef_tsn_talker_configuration *conf = (struct dds_sysdef_tsn_talker_configuration *) node; + free_node (conf->data_frame_specification); + free_node (conf->network_requirements); + free_node (conf->traffic_specification); + ddsrt_free (conf->stream_name); + ddsrt_free (conf->name); +} + +static void fini_conf_tsn_traffic_specification (struct xml_element *node) +{ + struct dds_sysdef_tsn_traffic_specification *conf = (struct dds_sysdef_tsn_traffic_specification *) node; + free_node (conf->time_aware); +} + +static void fini_conf_tsn_ip_tuple (struct xml_element *node) +{ + struct dds_sysdef_tsn_ip_tuple *conf = (struct dds_sysdef_tsn_ip_tuple *) node; + ddsrt_free (conf->destination_ip_address); + ddsrt_free (conf->source_ip_address); +} + +static void fini_conf_tsn_data_frame_specification (struct xml_element *node) +{ + struct dds_sysdef_tsn_data_frame_specification *conf = (struct dds_sysdef_tsn_data_frame_specification *) node; + free_node (conf->ipv4_tuple); + free_node (conf->ipv6_tuple); + free_node (conf->mac_addresses); + free_node (conf->vlan_tag); +} + +static void fini_conf_tsn_listener (struct xml_element *node) +{ + struct dds_sysdef_tsn_listener_configuration *conf = (struct dds_sysdef_tsn_listener_configuration *) node; + free_node (conf->network_requirements); + ddsrt_free (conf->stream_name); + ddsrt_free (conf->name); +} + +static void fini_application_list (struct xml_element *node) +{ + struct dds_sysdef_application_list *application_list = (struct dds_sysdef_application_list *) node; + free_node (application_list->application_refs); +} + +static void fini_deployment (struct xml_element *node) +{ + struct dds_sysdef_deployment *deployment = (struct dds_sysdef_deployment *) node; + free_node (deployment->application_list); + free_node (deployment->configuration); + ddsrt_free (deployment->name); +} + +static void fini_deployment_lib (struct xml_element *node) +{ + struct dds_sysdef_deployment_lib *deployment_lib = (struct dds_sysdef_deployment_lib *) node; + free_node (deployment_lib->deployments); + ddsrt_free (deployment_lib->name); +} + +static void fini_sysdef (struct xml_element *node) +{ + struct dds_sysdef_system *sysdef = (struct dds_sysdef_system *) node; + free_node (sysdef->type_libs); + free_node (sysdef->qos_libs); + free_node (sysdef->domain_libs); + free_node (sysdef->participant_libs); + free_node (sysdef->application_libs); + free_node (sysdef->node_libs); + free_node (sysdef->deployment_libs); +} + +static int init_qos (UNUSED_ARG (struct parse_sysdef_state * const pstate), struct xml_element *node) +{ + struct dds_sysdef_qos *sdqos = (struct dds_sysdef_qos *) node; + sdqos->qos = dds_create_qos (); + enum dds_sysdef_qos_kind qos_kind; + switch (node->kind) { + case ELEMENT_KIND_QOS_PARTICIPANT: + qos_kind = DDS_SYSDEF_PARTICIPANT_QOS; + break; + case ELEMENT_KIND_QOS_TOPIC: + qos_kind = DDS_SYSDEF_TOPIC_QOS; + break; + case ELEMENT_KIND_QOS_PUBLISHER: + qos_kind = DDS_SYSDEF_PUBLISHER_QOS; + break; + case ELEMENT_KIND_QOS_SUBSCRIBER: + qos_kind = DDS_SYSDEF_SUBSCRIBER_QOS; + break; + case ELEMENT_KIND_QOS_READER: + qos_kind = DDS_SYSDEF_READER_QOS; + break; + case ELEMENT_KIND_QOS_WRITER: + qos_kind = DDS_SYSDEF_WRITER_QOS; + break; + default: + return SD_PARSE_RESULT_SYNTAX_ERR; + } + sdqos->kind = qos_kind; + return 0; +} + +#define PROC_ATTR_STRING(type,attr_name,param_field,validator_fn) \ + do { \ + if (ddsrt_strcasecmp (name, attr_name) == 0) \ + { \ + if (!validator_fn (value)) { \ + PARSER_ERROR (pstate, line, "Invalid identifier '%s'", value); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } else { \ + struct type *t = (struct type *) pstate->current; \ + if (t->param_field == NULL) { \ + assert (!attr_processed); \ + t->param_field = ddsrt_strdup (value); \ + attr_processed = true; \ + } else { \ + PARSER_ERROR (pstate, line, "Duplicate attribute '%s'", attr_name); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + } \ + } \ + } while (0) + +#define PROC_ATTR_NAME(type) PROC_ATTR_STRING(type, "name", name, dds_sysdef_is_valid_identifier_syntax) + +#define _PROC_ATTR_INTEGER(type, attr_type, attr_name, param_field, param_populated_bit) \ + do { \ + if (ddsrt_strcasecmp (name, attr_name) == 0) \ + { \ + assert (!attr_processed); \ + struct type *t = (struct type *) pstate->current; \ + if (t->populated & param_populated_bit) { \ + PARSER_ERROR (pstate, line, "Duplicate attribute '%s'", STR(param_field)); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } else { \ + attr_type ## _t v; \ + if (str_to_ ## attr_type (value, &v)) { \ + t->param_field = v; \ + t->populated |= param_populated_bit; \ + attr_processed = true; \ + } else { \ + PARSER_ERROR (pstate, line, "Invalid value for attribute '%s'", attr_name); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + } \ + } \ + } while (0) + +#define PROC_ATTR_UINT32(type, attr_name, param_field, param_populated_bit) \ + _PROC_ATTR_INTEGER(type,uint32,attr_name,param_field,param_populated_bit) + +#define PROC_ATTR_INT32(type, attr_name, param_field, param_populated_bit) \ + _PROC_ATTR_INTEGER(type,int32,attr_name,param_field,param_populated_bit) + +#define _PROC_ATTR_FN(type, attr_name, current, param_field, fn) \ + do { \ + if (ddsrt_strcasecmp (name, attr_name) == 0) \ + { \ + assert (!attr_processed); \ + struct type *t = (struct type *) current; \ + int fn_ret; \ + if ((fn_ret = fn (pstate, value, &t->param_field)) == SD_PARSE_RESULT_OK) { \ + attr_processed = true; \ + } else { \ + if (fn_ret == SD_PARSE_RESULT_DUPLICATE) \ + PARSER_ERROR (pstate, line, "Duplicate attribute '%s'", attr_name); \ + else \ + PARSER_ERROR (pstate, line, "Invalid value for attribute '%s'", attr_name); \ + ret = fn_ret; \ + } \ + } \ + } while (0) + +#define PROC_ATTR_FN(type, attr_name, param_field, fn) \ + _PROC_ATTR_FN(type, attr_name, pstate->current, param_field, fn) + +#define PROC_ATTR_FN_PARENT(type, attr_name, param_field, fn) \ + _PROC_ATTR_FN(type, attr_name, pstate->current->parent, param_field, fn) + +static int proc_attr_resolve_type_ref (struct parse_sysdef_state * const pstate, const char *type_ref, struct dds_sysdef_type **type) +{ + if (*type != NULL) { + return SD_PARSE_RESULT_DUPLICATE; + } + for (struct dds_sysdef_type_lib *tlib = pstate->sysdef->type_libs; *type == NULL && tlib != NULL; tlib = (struct dds_sysdef_type_lib *) tlib->xmlnode.next) + { + for (struct dds_sysdef_type *t = tlib->types; *type == NULL && t != NULL; t = (struct dds_sysdef_type *) t->xmlnode.next) + { + if (strcmp (t->name, type_ref) == 0) { + *type = t; + } + } + } + return *type != NULL ? SD_PARSE_RESULT_OK : SD_PARSE_RESULT_INVALID_REF; +} + +static struct dds_sysdef_register_type *find_reg_type_impl (const char *register_type_ref, struct dds_sysdef_register_type *register_types) +{ + struct dds_sysdef_register_type *register_type = NULL; + for (struct dds_sysdef_register_type *t = register_types; register_type == NULL && t != NULL; t = (struct dds_sysdef_register_type *) t->xmlnode.next) + { + if (strcmp (t->name, register_type_ref) == 0) + register_type = t; + } + return register_type; +} + +static int proc_attr_resolve_register_type_ref (struct parse_sysdef_state * const pstate, const char *register_type_ref, struct dds_sysdef_register_type **register_type) +{ + assert (pstate->current->parent->kind == ELEMENT_KIND_DOMAIN || pstate->current->parent->kind == ELEMENT_KIND_PARTICIPANT); + if (*register_type != NULL) { + return SD_PARSE_RESULT_DUPLICATE; + } + struct dds_sysdef_domain *domain = NULL; + if (pstate->current->parent->kind == ELEMENT_KIND_PARTICIPANT) + { + for (struct dds_sysdef_participant *participant = (struct dds_sysdef_participant *) pstate->current->parent; *register_type == NULL && participant != NULL; participant = participant->base) + { + if ((*register_type = find_reg_type_impl (register_type_ref, participant->register_types)) == NULL) + { + // Not found in this participant, get the domain to search in + if (participant->domain_ref == NULL) + ; + else if (domain == NULL) + domain = participant->domain_ref; + else + { + // Domain ref for a participant should be equal to the domain ref of its base-participants + if (domain != participant->domain_ref) + return SD_PARSE_RESULT_ERR; + } + } + } + if (domain == NULL && *register_type == NULL) + return SD_PARSE_RESULT_ERR; + } + else + { + domain = (struct dds_sysdef_domain *) pstate->current->parent; + } + + if (*register_type == NULL) + *register_type = find_reg_type_impl (register_type_ref, domain->register_types); + + return *register_type != NULL ? SD_PARSE_RESULT_OK : SD_PARSE_RESULT_INVALID_REF; +} + +static int proc_attr_resolve_topic_ref (struct parse_sysdef_state * const pstate, const char *topic_ref, struct dds_sysdef_topic **topic) +{ + if (*topic != NULL) { + return SD_PARSE_RESULT_DUPLICATE; + } + assert ((pstate->current->kind == ELEMENT_KIND_READER && pstate->current->parent->kind == ELEMENT_KIND_SUBSCRIBER) || + (pstate->current->kind == ELEMENT_KIND_WRITER && pstate->current->parent->kind == ELEMENT_KIND_PUBLISHER)); + assert (pstate->current->parent->parent->kind == ELEMENT_KIND_PARTICIPANT); + struct dds_sysdef_domain *domain = NULL; + for (struct dds_sysdef_participant *participant = (struct dds_sysdef_participant *) pstate->current->parent->parent; *topic == NULL && participant != NULL; participant = participant->base) + { + struct dds_sysdef_topic *topics[2] = { participant->topics }; + if (participant->domain_ref == NULL) + ; + else if (domain == NULL) + { + domain = participant->domain_ref; + topics[1] = domain->topics; + } + else + { + /* Domain ref for a participant should be equal to the domain ref of its base-participants, + this is checked in the validation step after parsing */ + } + for (uint32_t n = 0; n < sizeof (topics) / sizeof (topics[0]); n++) + { + for (struct dds_sysdef_topic *t = topics[n]; *topic == NULL && t != NULL; t = (struct dds_sysdef_topic *) t->xmlnode.next) + { + if (strcmp (t->name, topic_ref) == 0) { + *topic = t; + } + } + } + } + + return *topic != NULL ? SD_PARSE_RESULT_OK : SD_PARSE_RESULT_INVALID_REF; +} + + +static int split_ref (const char *ref, char **lib, char **local_name) +{ + int ret = SD_PARSE_RESULT_OK; + const char *sep = "::"; + const char *spos = strstr (ref, sep); + if (spos != NULL) + { + ptrdiff_t lib_len = spos - ref; + *lib = ddsrt_strndup (ref, (size_t) lib_len); + *local_name = ddsrt_strdup (spos + strlen (sep)); + } + else + { + ret = SD_PARSE_RESULT_INVALID_REF; + } + return ret; +} + +#define _RESOLVE_LIB(lib_type, lib_name, dst) \ + do { for (struct dds_sysdef_## lib_type ## _lib *l = pstate->sysdef->lib_type ## _libs ; dst == NULL && l != NULL; l = (struct dds_sysdef_ ## lib_type ## _lib *) l->xmlnode.next) \ + { \ + if (strcmp (l->name, lib_name) == 0) { \ + dst = l; \ + } \ + } } while (0) + +#define _RESOLVE_ENTITY(lib, entity_type, ent_var, ent_name, dst) \ + do { for (struct dds_sysdef_ ## entity_type *e = lib->ent_var; dst == NULL && e != NULL; e = (struct dds_sysdef_## entity_type *) e->xmlnode.next) \ + { \ + if (strcmp (e->name, ent_name) == 0) { \ + dst = e; \ + } \ + } } while (0) + +#define RESOLVE_REF_FNDEF(type, lib_type, type_var) \ + static int proc_attr_resolve_ ## type ## _ref (struct parse_sysdef_state * const pstate, const char *type_ref, struct dds_sysdef_ ## type **type) \ + { \ + char *lib_name, *local_name; \ + if (*type != NULL) { \ + return SD_PARSE_RESULT_DUPLICATE; \ + } \ + if (split_ref (type_ref, &lib_name, &local_name) != SD_PARSE_RESULT_OK) \ + return SD_PARSE_RESULT_ERR; \ + struct dds_sysdef_ ## lib_type ## _lib *lib = NULL; \ + _RESOLVE_LIB(lib_type, lib_name, lib); \ + if (lib != NULL) \ + _RESOLVE_ENTITY(lib, type, type_var, local_name, *type); \ + ddsrt_free (lib_name); \ + ddsrt_free (local_name); \ + return *type != NULL ? SD_PARSE_RESULT_OK : SD_PARSE_RESULT_INVALID_REF; \ + } + +RESOLVE_REF_FNDEF(qos_profile, qos, qos_profiles) +RESOLVE_REF_FNDEF(domain, domain, domains) +RESOLVE_REF_FNDEF(participant, participant, participants) +RESOLVE_REF_FNDEF(node, node, nodes) +RESOLVE_REF_FNDEF(application, application, applications) + +enum resolve_endpoint_kind { + RESOLVE_ENDPOINT_READER, + RESOLVE_ENDPOINT_WRITER +}; + +static int proc_attr_resolve_endpoint_ref (struct parse_sysdef_state * const pstate, const char *type_ref, enum resolve_endpoint_kind kind, struct xml_element **endpoint) +{ + char *appl_lib_name, *tail; + if (*endpoint != NULL) { + return SD_PARSE_RESULT_ERR; + } + if (split_ref (type_ref, &appl_lib_name, &tail) != SD_PARSE_RESULT_OK) + return SD_PARSE_RESULT_ERR; + struct dds_sysdef_application_lib *appl_lib = NULL; + _RESOLVE_LIB(application, appl_lib_name, appl_lib); + if (appl_lib != NULL) + { + char *appl_name, *tail1; + if (split_ref (tail, &appl_name, &tail1) != SD_PARSE_RESULT_OK) + return SD_PARSE_RESULT_ERR; + + struct dds_sysdef_application *appl = NULL; + _RESOLVE_ENTITY(appl_lib, application, applications, appl_name, appl); + if (appl != NULL) + { + char *pp_name, *tail2; + if (split_ref (tail1, &pp_name, &tail2) != SD_PARSE_RESULT_OK) + return SD_PARSE_RESULT_ERR; + + struct dds_sysdef_participant *pp = NULL; + _RESOLVE_ENTITY(appl, participant, participants, pp_name, pp); + if (pp != NULL) + { + char *pubsub_name, *endpoint_name; + if (split_ref (tail2, &pubsub_name, &endpoint_name) != SD_PARSE_RESULT_OK) + return SD_PARSE_RESULT_ERR; + + if (kind == RESOLVE_ENDPOINT_WRITER) + { + struct dds_sysdef_publisher *pub = NULL; + _RESOLVE_ENTITY(pp, publisher, publishers, pubsub_name, pub); + if (pub != NULL) + { + struct dds_sysdef_writer **writer = (struct dds_sysdef_writer **) endpoint; + _RESOLVE_ENTITY(pub, writer, writers, endpoint_name, *writer); + } + } + else + { + struct dds_sysdef_subscriber *sub = NULL; + _RESOLVE_ENTITY(pp, subscriber, subscribers, pubsub_name, sub); + if (sub != NULL) + { + struct dds_sysdef_reader **reader = (struct dds_sysdef_reader **) endpoint; + _RESOLVE_ENTITY(sub, reader, readers, endpoint_name, *reader); + } + } + ddsrt_free (endpoint_name); + ddsrt_free (pubsub_name); + } + ddsrt_free (pp_name); + ddsrt_free (tail2); + } + ddsrt_free (appl_name); + ddsrt_free (tail1); + } + ddsrt_free (appl_lib_name); + ddsrt_free (tail); + + return *endpoint != NULL ? SD_PARSE_RESULT_OK : SD_PARSE_RESULT_INVALID_REF; +} + +static int proc_attr_resolve_datawriter_ref (struct parse_sysdef_state * const pstate, const char *type_ref, struct dds_sysdef_writer **writer) +{ + return proc_attr_resolve_endpoint_ref (pstate, type_ref, RESOLVE_ENDPOINT_WRITER, (struct xml_element **) writer); +} + +static int proc_attr_resolve_datareader_ref (struct parse_sysdef_state * const pstate, const char *type_ref, struct dds_sysdef_reader **reader) +{ + return proc_attr_resolve_endpoint_ref (pstate, type_ref, RESOLVE_ENDPOINT_READER, (struct xml_element **) reader); +} + +static int dds_sysdef_parse_hex (const char* hex, unsigned char* bytes) +{ + size_t hex_len = strlen (hex); + if (hex_len % 2 != 0) + return SD_PARSE_RESULT_ERR; + + for (size_t i = 0; i < hex_len; i += 2) + { + int a = ddsrt_todigit (hex[i]), b = ddsrt_todigit (hex[i + 1]); + if (a == -1 || a > 15 || b == -1 || b > 15) + return SD_PARSE_RESULT_ERR; + bytes[i / 2] = (unsigned char) (((uint8_t) a << 4) + b); + } + return SD_PARSE_RESULT_OK; +} + +static int proc_attr_type_identifier (struct parse_sysdef_state * const pstate, const char *value, unsigned char **identifier) +{ + (void) pstate; + if (*identifier != NULL) + return SD_PARSE_RESULT_DUPLICATE; + if (strlen (value) != 2 * TYPE_HASH_LENGTH) + return SD_PARSE_RESULT_ERR; + *identifier = ddsrt_malloc (TYPE_HASH_LENGTH); + if (dds_sysdef_parse_hex (value, *identifier) != SD_PARSE_RESULT_OK) + return SD_PARSE_RESULT_ERR; + return SD_PARSE_RESULT_OK; +} + +static int proc_attr_guid_prefix (struct parse_sysdef_state * const pstate, const char *value, struct dds_sysdef_participant_guid_prefix **prefix) +{ + (void) pstate; + if (strlen (value) != 2 * sizeof (struct dds_sysdef_participant_guid_prefix)) + return SD_PARSE_RESULT_ERR; + + if (*prefix != NULL) + return SD_PARSE_RESULT_DUPLICATE; + + *prefix = ddsrt_malloc (sizeof (**prefix)); + union { struct dds_sysdef_participant_guid_prefix p; unsigned char d[sizeof (struct dds_sysdef_participant_guid_prefix)]; } u = {.p = {0}}; + if (dds_sysdef_parse_hex (value, u.d) != SD_PARSE_RESULT_OK) + return SD_PARSE_RESULT_ERR; + + (*prefix)->p = ddsrt_fromBE4u (u.p.p); + return SD_PARSE_RESULT_OK; +} + +static bool is_alpha (char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); +} + +static bool is_alphanum (char c) +{ + return is_alpha (c) || (c >= '0' && c <= '9'); +} + +static bool is_valid_identifier_char (char c) +{ + return is_alphanum (c) || c == '_'; +} + +static bool dds_sysdef_is_valid_identifier_syntax (const char *name) +{ + if (strlen (name) == 0) + return false; + if (!is_alpha (name[0])) + return false; + for (size_t i = 1; i < strlen (name); i++) + { + if (!is_valid_identifier_char (name[i])) + return false; + } + return true; +} + +static int proc_attr (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *name, const char *value, int line) +{ + /* All attributes are processed immediately after opening the element */ + struct parse_sysdef_state * const pstate = varg; + bool attr_processed = false; + + if (ddsrt_strcasecmp(name, "xmlns") == 0 || ddsrt_strcasecmp(name, "xmlns:xsi") == 0 ||ddsrt_strcasecmp(name, "xsi:schemaLocation") == 0) + return 0; + + int ret = SD_PARSE_RESULT_OK; + if (pstate->current == NULL) { + PARSER_ERROR (pstate, line, "Current element NULL in proc_attr"); + ret = SD_PARSE_RESULT_ERR; + } + else + { + switch (pstate->current->kind) + { + // Type library + case ELEMENT_KIND_TYPE: + PROC_ATTR_NAME(dds_sysdef_type); + PROC_ATTR_FN(dds_sysdef_type, "identifier", identifier, proc_attr_type_identifier); + break; + + // QoS library + case ELEMENT_KIND_QOS_LIB: + PROC_ATTR_NAME(dds_sysdef_qos_lib); + break; + case ELEMENT_KIND_QOS_PROFILE: + PROC_ATTR_NAME(dds_sysdef_qos_profile); + PROC_ATTR_FN(dds_sysdef_qos_profile, "base_name", base_profile, proc_attr_resolve_qos_profile_ref); + break; + case ELEMENT_KIND_QOS_PARTICIPANT: + case ELEMENT_KIND_QOS_TOPIC: + case ELEMENT_KIND_QOS_PUBLISHER: + case ELEMENT_KIND_QOS_SUBSCRIBER: + case ELEMENT_KIND_QOS_WRITER: + case ELEMENT_KIND_QOS_READER: + PROC_ATTR_NAME(dds_sysdef_qos); + PROC_ATTR_FN(dds_sysdef_qos, "base_name", base_profile, proc_attr_resolve_qos_profile_ref); + break; + + // Domain library + case ELEMENT_KIND_DOMAIN_LIB: + PROC_ATTR_NAME(dds_sysdef_domain_lib); + break; + case ELEMENT_KIND_DOMAIN: + PROC_ATTR_NAME(dds_sysdef_domain); + PROC_ATTR_UINT32(dds_sysdef_domain, "domain_id", domain_id, SYSDEF_DOMAIN_DOMAIN_ID_PARAM_VALUE); + PROC_ATTR_INT32(dds_sysdef_domain, "participant_index", participant_index, SYSDEF_DOMAIN_PARTICIPANT_INDEX_PARAM_VALUE); + break; + case ELEMENT_KIND_PARTICIPANT: + PROC_ATTR_NAME(dds_sysdef_participant); + PROC_ATTR_FN(dds_sysdef_participant, "domain_ref", domain_ref, proc_attr_resolve_domain_ref); + PROC_ATTR_FN(dds_sysdef_participant, "base_name", base, proc_attr_resolve_participant_ref); + PROC_ATTR_FN(dds_sysdef_participant, "guid_prefix", guid_prefix, proc_attr_guid_prefix); + break; + case ELEMENT_KIND_REGISTER_TYPE: + PROC_ATTR_NAME(dds_sysdef_register_type); + PROC_ATTR_FN(dds_sysdef_register_type, "type_ref", type_ref, proc_attr_resolve_type_ref); + break; + case ELEMENT_KIND_PARTICIPANT_LIB: + PROC_ATTR_NAME(dds_sysdef_participant); + break; + case ELEMENT_KIND_TOPIC: + PROC_ATTR_NAME(dds_sysdef_topic); + PROC_ATTR_FN(dds_sysdef_topic, "register_type_ref", register_type_ref, proc_attr_resolve_register_type_ref); + break; + case ELEMENT_KIND_PUBLISHER: + PROC_ATTR_NAME(dds_sysdef_publisher); + break; + case ELEMENT_KIND_SUBSCRIBER: + PROC_ATTR_NAME(dds_sysdef_subscriber); + break; + case ELEMENT_KIND_WRITER: + PROC_ATTR_NAME(dds_sysdef_writer); + PROC_ATTR_FN(dds_sysdef_writer, "topic_ref", topic, proc_attr_resolve_topic_ref); + PROC_ATTR_UINT32(dds_sysdef_writer, "entity_key", entity_key, SYSDEF_WRITER_ENTITY_KEY_PARAM_VALUE); + break; + case ELEMENT_KIND_READER: + PROC_ATTR_NAME(dds_sysdef_reader); + PROC_ATTR_FN(dds_sysdef_reader, "topic_ref", topic, proc_attr_resolve_topic_ref); + PROC_ATTR_UINT32(dds_sysdef_reader, "entity_key", entity_key, SYSDEF_READER_ENTITY_KEY_PARAM_VALUE); + break; + + // Application library + case ELEMENT_KIND_APPLICATION_LIB: + PROC_ATTR_NAME(dds_sysdef_application_lib); + break; + case ELEMENT_KIND_APPLICATION: + PROC_ATTR_NAME(dds_sysdef_application); + break; + + // Node library + case ELEMENT_KIND_NODE_LIB: + PROC_ATTR_NAME(dds_sysdef_node_lib); + break; + case ELEMENT_KIND_NODE: + PROC_ATTR_NAME(dds_sysdef_node); + break; + + // Deployment library + case ELEMENT_KIND_DEPLOYMENT_LIB: + PROC_ATTR_NAME(dds_sysdef_deployment_lib); + break; + case ELEMENT_KIND_DEPLOYMENT: + PROC_ATTR_NAME(dds_sysdef_deployment); + break; + case ELEMENT_KIND_DEPLOYMENT_NODE_REF: + PROC_ATTR_FN_PARENT(dds_sysdef_deployment, "node_ref", node, proc_attr_resolve_node_ref); + break; + case ELEMENT_KIND_DEPLOYMENT_APPLICATION_REF: + PROC_ATTR_FN(dds_sysdef_application_ref, "application_ref", application, proc_attr_resolve_application_ref); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER: + PROC_ATTR_NAME(dds_sysdef_tsn_talker_configuration); + PROC_ATTR_STRING(dds_sysdef_tsn_talker_configuration, "stream_name", stream_name, dds_sysdef_is_valid_identifier_syntax); + PROC_ATTR_FN(dds_sysdef_tsn_talker_configuration, "datawriter_ref", writer, proc_attr_resolve_datawriter_ref); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER: + PROC_ATTR_NAME(dds_sysdef_tsn_listener_configuration); + PROC_ATTR_STRING(dds_sysdef_tsn_listener_configuration, "stream_name", stream_name, dds_sysdef_is_valid_identifier_syntax); + PROC_ATTR_FN(dds_sysdef_tsn_listener_configuration, "datareader_ref", reader, proc_attr_resolve_datareader_ref); + break; + + default: + break; + } + + if (!attr_processed && ret == SD_PARSE_RESULT_OK) + { + PARSER_ERROR (pstate, line, "Unknown attribute '%s'", name); + ret = SD_PARSE_RESULT_ERR; + } + } + return ret; +} + +#define ELEM_CLOSE_QOS_POLICY(policy, policy_desc) \ + do { \ + struct dds_sysdef_QOS_POLICY_ ## policy *qp = (struct dds_sysdef_QOS_POLICY_ ## policy *) pstate->current; \ + struct dds_sysdef_qos *sdqos = (struct dds_sysdef_qos *) pstate->current->parent; \ + if (qp->populated != QOS_POLICY_ ## policy ## _PARAMS) \ + { \ + PARSER_ERROR (pstate, line, "Not all params set for " policy_desc " QoS policy"); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + else if (qget_ ## policy (sdqos->qos)) \ + { \ + PARSER_ERROR (pstate, line, policy_desc " QoS policy already set"); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + else \ + { \ + qset_ ## policy (sdqos->qos, qp ); \ + } \ + } while (0) + +#define ELEM_CLOSE_QOS_DURATION_PROPERTY(policy, param, element_name) \ + do { \ + assert (pstate->current->data_type == ELEMENT_DATA_TYPE_DURATION); \ + struct dds_sysdef_qos_duration_property *d = (struct dds_sysdef_qos_duration_property *) pstate->current; \ + struct dds_sysdef_QOS_POLICY_ ## policy *qp = (struct dds_sysdef_QOS_POLICY_ ## policy *) pstate->current->parent; \ + if (d->populated == 0) \ + { \ + PARSER_ERROR (pstate, line, "Duration not set"); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + else \ + { \ + qp->values.element_name = DDS_SECS(d->sec) + d->nsec; \ + qp->populated |= QOS_POLICY_ ## policy ## _PARAM_ ## param; \ + } \ + } while (0) + +static bool qget_DEADLINE (dds_qos_t *qos) +{ + return dds_qget_deadline (qos, NULL); +} + +static void qset_DEADLINE (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_DEADLINE *qp) +{ + dds_qset_deadline (qos, qp->values.deadline); +} + +static bool qget_DESTINATIONORDER (dds_qos_t *qos) +{ + return dds_qget_destination_order (qos, NULL); +} + +static void qset_DESTINATIONORDER (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_DESTINATIONORDER *qp) +{ + dds_qset_destination_order (qos, qp->values.kind); +} + +static bool qget_DURABILITY (dds_qos_t *qos) +{ + return dds_qget_durability (qos, NULL); +} + +static void qset_DURABILITY (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_DURABILITY *qp) +{ + dds_qset_durability (qos, qp->values.kind); +} + +static bool qget_DURABILITYSERVICE (dds_qos_t *qos) +{ + return dds_qget_durability_service (qos, NULL, NULL, NULL, NULL, NULL, NULL); +} + +static void qset_DURABILITYSERVICE (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_DURABILITYSERVICE *qp) +{ + dds_qset_durability_service (qos, qp->values.service_cleanup_delay, qp->values.history.kind, qp->values.history.depth, qp->values.resource_limits.max_samples, qp->values.resource_limits.max_instances, qp->values.resource_limits.max_samples_per_instance); +} + +static bool qget_GROUPDATA (dds_qos_t *qos) +{ + return dds_qget_groupdata (qos, NULL, NULL); +} + +static void qset_GROUPDATA (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_GROUPDATA *qp) +{ + dds_qset_groupdata (qos, qp->values.value, qp->values.length); +} + +static bool qget_TOPICDATA (dds_qos_t *qos) +{ + return dds_qget_topicdata (qos, NULL, NULL); +} + +static void qset_TOPICDATA (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_TOPICDATA *qp) +{ + dds_qset_topicdata (qos, qp->values.value, qp->values.length); +} + +static bool qget_USERDATA (dds_qos_t *qos) +{ + return dds_qget_userdata (qos, NULL, NULL); +} + +static void qset_USERDATA (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_USERDATA *qp) +{ + dds_qset_userdata (qos, qp->values.value, qp->values.length); +} + +static bool qget_HISTORY (dds_qos_t *qos) +{ + return dds_qget_history (qos, NULL, NULL); +} + +static void qset_HISTORY (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_HISTORY *qp) +{ + dds_qset_history (qos, qp->values.kind, qp->values.depth); +} + +static bool qget_LATENCYBUDGET (dds_qos_t *qos) +{ + return dds_qget_latency_budget (qos, NULL); +} + +static void qset_LATENCYBUDGET (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_LATENCYBUDGET *qp) +{ + dds_qset_latency_budget (qos, qp->values.duration); +} + +static bool qget_LIFESPAN (dds_qos_t *qos) +{ + return dds_qget_lifespan (qos, NULL); +} + +static void qset_LIFESPAN (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_LIFESPAN *qp) +{ + dds_qset_lifespan (qos, qp->values.duration); +} + +static bool qget_LIVELINESS (dds_qos_t *qos) +{ + return dds_qget_liveliness (qos, NULL, NULL); +} + +static void qset_LIVELINESS (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_LIVELINESS *qp) +{ + dds_qset_liveliness (qos, qp->values.kind, qp->values.lease_duration); +} + +static bool qget_OWNERSHIP (dds_qos_t *qos) +{ + return dds_qget_ownership (qos, NULL); +} + +static void qset_OWNERSHIP (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_OWNERSHIP *qp) +{ + dds_qset_ownership (qos, qp->values.kind); +} + +static bool qget_OWNERSHIPSTRENGTH (dds_qos_t *qos) +{ + return dds_qget_ownership_strength (qos, NULL); +} + +static void qset_OWNERSHIPSTRENGTH (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_OWNERSHIPSTRENGTH *qp) +{ + dds_qset_ownership_strength (qos, qp->values.value); +} + +static bool qget_PARTITION (dds_qos_t *qos) +{ + return dds_qget_partition (qos, NULL, NULL); +} + +static void qset_PARTITION (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_PARTITION *qp) +{ + uint32_t c = 0; + for (struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *v = qp->name->elements; v != NULL; v = (struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *) v->xmlnode.next) + c++; + + const char **partitions = ddsrt_malloc (c * sizeof (*partitions)); + uint32_t i = 0; + for (struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *v = qp->name->elements; v != NULL; v = (struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *) v->xmlnode.next) + partitions[i++] = v->element; + dds_qset_partition (qos, c, partitions); +#if _MSC_VER +__pragma(warning(push)) +__pragma(warning(disable: 4090)) +#endif + ddsrt_free (partitions); +#if _MSC_VER +__pragma(warning(pop)) +#endif +} + +static bool qget_PRESENTATION (dds_qos_t *qos) +{ + return dds_qget_presentation (qos, NULL, NULL, NULL); +} + +static void qset_PRESENTATION (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_PRESENTATION *qp) +{ + dds_qset_presentation (qos, qp->values.access_scope, qp->values.coherent_access, qp->values.ordered_access); +} + +static bool qget_READERDATALIFECYCLE (dds_qos_t *qos) +{ + return dds_qget_reader_data_lifecycle (qos, NULL, NULL); +} + +static void qset_READERDATALIFECYCLE (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_READERDATALIFECYCLE *qp) +{ + dds_qset_reader_data_lifecycle (qos, qp->values.autopurge_nowriter_samples_delay, qp->values.autopurge_disposed_samples_delay); +} + +static bool qget_RELIABILITY (dds_qos_t *qos) +{ + return dds_qget_reliability (qos, NULL, NULL); +} + +static void qset_RELIABILITY (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_RELIABILITY *qp) +{ + dds_qset_reliability (qos, qp->values.kind, qp->values.max_blocking_time); +} + +static bool qget_RESOURCELIMITS (dds_qos_t *qos) +{ + return dds_qget_resource_limits (qos, NULL, NULL, NULL); +} + +static void qset_RESOURCELIMITS (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_RESOURCELIMITS *qp) +{ + dds_qset_resource_limits (qos, qp->values.max_samples, qp->values.max_instances, qp->values.max_samples_per_instance); +} + +static bool qget_TIMEBASEDFILTER (dds_qos_t *qos) +{ + return dds_qget_time_based_filter (qos, NULL); +} + +static void qset_TIMEBASEDFILTER (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_TIMEBASEDFILTER *qp) +{ + dds_qset_time_based_filter (qos, qp->values.minimum_separation); +} + +static bool qget_TRANSPORTPRIORITY (dds_qos_t *qos) +{ + return dds_qget_transport_priority (qos, NULL); +} + +static void qset_TRANSPORTPRIORITY (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_TRANSPORTPRIORITY *qp) +{ + dds_qset_transport_priority (qos, qp->values.value); +} + +static bool qget_WRITERDATALIFECYCLE (dds_qos_t *qos) +{ + return dds_qget_writer_data_lifecycle (qos, NULL); +} + +static void qset_WRITERDATALIFECYCLE (dds_qos_t *qos, struct dds_sysdef_QOS_POLICY_WRITERDATALIFECYCLE *qp) +{ + dds_qset_writer_data_lifecycle (qos, qp->values.autodispose_unregistered_instances); +} + +#define _ELEM_CLOSE_REQUIRE_ATTR(type,attr_name,current,element_name) \ + do { \ + struct type *t = (struct type *) current; \ + if (t->element_name == NULL) \ + { \ + PARSER_ERROR (pstate, line, "Attribute '%s' not set", STR(attr_name)); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + } while (0) + +#define ELEM_CLOSE_REQUIRE_ATTR(type,attr_name,param_field) \ + _ELEM_CLOSE_REQUIRE_ATTR(type, attr_name, pstate->current, param_field) + +#define ELEM_CLOSE_REQUIRE_ATTR_PARENT(type,attr_name,param_field) \ + _ELEM_CLOSE_REQUIRE_ATTR(type, attr_name, pstate->current->parent, param_field) + +#define ELEM_CLOSE_REQUIRE_ATTR_POPULATED(type,type_name,exp_populated) \ + do { \ + if (~(((struct type *) pstate->current)->populated) & exp_populated) \ + { \ + PARSER_ERROR (pstate, line, "Not all params set for %s", type_name); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + } while (0) + + +static int proc_elem_close (void *varg, UNUSED_ARG (uintptr_t eleminfo), UNUSED_ARG (int line)) +{ + struct parse_sysdef_state * const pstate = varg; + int ret = SD_PARSE_RESULT_OK; + if (pstate->current == NULL) { + PARSER_ERROR (pstate, line, "Current element NULL in close element"); + ret = SD_PARSE_RESULT_ERR; + } + else + { + switch (pstate->current->kind) + { + case ELEMENT_KIND_QOS_POLICY_DEADLINE: + ELEM_CLOSE_QOS_POLICY(DEADLINE, "Deadline"); + break; + case ELEMENT_KIND_QOS_POLICY_DEADLINE_PERIOD: + ELEM_CLOSE_QOS_DURATION_PROPERTY(DEADLINE, PERIOD, deadline); + break; + case ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER: + ELEM_CLOSE_QOS_POLICY(DESTINATIONORDER, "Destination Order"); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITY: + ELEM_CLOSE_QOS_POLICY(DURABILITY, "Durability"); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE: + ELEM_CLOSE_QOS_POLICY(DURABILITYSERVICE, "Durability Service"); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_SERVICE_CLEANUP_DELAY: + ELEM_CLOSE_QOS_DURATION_PROPERTY(DURABILITYSERVICE, SERVICE_CLEANUP_DELAY, service_cleanup_delay); + break; + case ELEMENT_KIND_QOS_POLICY_GROUPDATA: + ELEM_CLOSE_QOS_POLICY(GROUPDATA, "Group Data"); + break; + case ELEMENT_KIND_QOS_POLICY_HISTORY: + ELEM_CLOSE_QOS_POLICY(HISTORY, "History"); + break; + case ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET: + ELEM_CLOSE_QOS_POLICY(LATENCYBUDGET, "Latency Budget"); + break; + case ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET_DURATION: + ELEM_CLOSE_QOS_DURATION_PROPERTY(LATENCYBUDGET, DURATION, duration); + break; + case ELEMENT_KIND_QOS_POLICY_LIFESPAN: + ELEM_CLOSE_QOS_POLICY(LIFESPAN, "Lifespan"); + break; + case ELEMENT_KIND_QOS_POLICY_LIFESPAN_DURATION: + ELEM_CLOSE_QOS_DURATION_PROPERTY(LIFESPAN, DURATION, duration); + break; + case ELEMENT_KIND_QOS_POLICY_LIVELINESS: + ELEM_CLOSE_QOS_POLICY(LIVELINESS, "Liveliness"); + break; + case ELEMENT_KIND_QOS_POLICY_LIVELINESS_LEASE_DURATION: + ELEM_CLOSE_QOS_DURATION_PROPERTY(LIVELINESS, LEASE_DURATION, lease_duration); + break; + case ELEMENT_KIND_QOS_POLICY_OWNERSHIP: + ELEM_CLOSE_QOS_POLICY(OWNERSHIP, "Ownership"); + break; + case ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH: + ELEM_CLOSE_QOS_POLICY(OWNERSHIPSTRENGTH, "Ownership Strength"); + break; + case ELEMENT_KIND_QOS_POLICY_PARTITION: + ELEM_CLOSE_QOS_POLICY(PARTITION, "Partition"); + break; + case ELEMENT_KIND_QOS_POLICY_PRESENTATION: + ELEM_CLOSE_QOS_POLICY(PRESENTATION, "Presentation"); + break; + case ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE_AUTOPURGE_NOWRITER_SAMPLES_DELAY: + ELEM_CLOSE_QOS_DURATION_PROPERTY(READERDATALIFECYCLE, AUTOPURGE_NOWRITER_SAMPLES_DELAY, autopurge_nowriter_samples_delay); + break; + case ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE_AUTOPURGE_DISPOSED_SAMPLES_DELAY: + ELEM_CLOSE_QOS_DURATION_PROPERTY(READERDATALIFECYCLE, AUTOPURGE_DISPOSED_SAMPLES_DELAY, autopurge_disposed_samples_delay); + break; + case ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE: + ELEM_CLOSE_QOS_POLICY(READERDATALIFECYCLE, "Reader Data Life-cycle"); + break; + case ELEMENT_KIND_QOS_POLICY_RELIABILITY: + ELEM_CLOSE_QOS_POLICY(RELIABILITY, "Reliability"); + break; + case ELEMENT_KIND_QOS_POLICY_RELIABILITY_MAX_BLOCKING_DELAY: + ELEM_CLOSE_QOS_DURATION_PROPERTY(RELIABILITY, MAX_BLOCKING_DELAY, max_blocking_time); + break; + case ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS: + ELEM_CLOSE_QOS_POLICY(RESOURCELIMITS, "Resource Limits"); + break; + case ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER_MINIMUM_SEPARATION: + ELEM_CLOSE_QOS_DURATION_PROPERTY(TIMEBASEDFILTER, MINIMUM_SEPARATION, minimum_separation); + break; + case ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER: + ELEM_CLOSE_QOS_POLICY(TIMEBASEDFILTER, "Time-based Filter"); + break; + case ELEMENT_KIND_QOS_POLICY_TOPICDATA: + ELEM_CLOSE_QOS_POLICY(TOPICDATA, "Topic Data"); + break; + case ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY: + ELEM_CLOSE_QOS_POLICY(TRANSPORTPRIORITY, "Transport Priority"); + break; + case ELEMENT_KIND_QOS_POLICY_USERDATA: + ELEM_CLOSE_QOS_POLICY(USERDATA, "User data"); + break; + case ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE: + ELEM_CLOSE_QOS_POLICY(WRITERDATALIFECYCLE, "Writer Data Life-cycle"); + break; + case ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY: + //ELEM_CLOSE_QOS_POLICY(ENTITYFACTORY, "Entity factory"); + PARSER_ERROR (pstate, line, "Unsupported QoS policy"); + ret = SD_PARSE_RESULT_NOT_SUPPORTED; + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_PERIODICITY: { + struct dds_sysdef_tsn_traffic_specification *t = (struct dds_sysdef_tsn_traffic_specification *) pstate->current->parent; + struct dds_sysdef_qos_duration_property *d = (struct dds_sysdef_qos_duration_property *) pstate->current; + t->periodicity = DDS_SECS (d->sec) + d->nsec; + break; + } + case ELEMENT_KIND_TYPE: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_type, "name", name); + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_type, "identifier", identifier); + break; + case ELEMENT_KIND_QOS_LIB: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_qos_lib, "name", name); + break; + case ELEMENT_KIND_QOS_PROFILE: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_qos_profile, "name", name); + break; + case ELEMENT_KIND_DOMAIN_LIB: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_domain_lib, "name", name); + break; + case ELEMENT_KIND_DOMAIN: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_domain, "name", name); + ELEM_CLOSE_REQUIRE_ATTR_POPULATED (dds_sysdef_domain, "domain", SYSDEF_DOMAIN_PARAMS); + break; + case ELEMENT_KIND_PARTICIPANT: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_participant, "name", name); + break; + case ELEMENT_KIND_REGISTER_TYPE: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_register_type, "name", name); + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_register_type, "type_ref", type_ref); + break; + case ELEMENT_KIND_PARTICIPANT_LIB: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_participant, "name", name); + break; + case ELEMENT_KIND_TOPIC: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_topic, "name", name); + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_topic, "register_type_ref", register_type_ref); + break; + case ELEMENT_KIND_PUBLISHER: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_publisher, "name", name); + break; + case ELEMENT_KIND_SUBSCRIBER: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_subscriber, "name", name); + break; + case ELEMENT_KIND_WRITER: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_writer, "name", name); + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_writer, "topic_ref", topic); + ELEM_CLOSE_REQUIRE_ATTR_POPULATED (dds_sysdef_writer, "writer", SYSDEF_WRITER_PARAMS); + break; + case ELEMENT_KIND_READER: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_reader, "name", name); + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_reader, "topic_ref", topic); + ELEM_CLOSE_REQUIRE_ATTR_POPULATED (dds_sysdef_reader, "reader", SYSDEF_READER_PARAMS); + break; + case ELEMENT_KIND_APPLICATION_LIB: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_application_lib, "name", name); + break; + case ELEMENT_KIND_APPLICATION: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_application, "name", name); + break; + case ELEMENT_KIND_DEPLOYMENT_NODE_REF: + ELEM_CLOSE_REQUIRE_ATTR_PARENT (dds_sysdef_deployment, "node_ref", node); + break; + case ELEMENT_KIND_DEPLOYMENT_APPLICATION_REF: + ELEM_CLOSE_REQUIRE_ATTR (dds_sysdef_application_ref, "application_ref", application); + break; + default: + if (pstate->current->handle_close) + { + PARSER_ERROR (pstate, line, "Close element not handled"); + ret = SD_PARSE_RESULT_ERR; + } + break; + } + } + + struct xml_element *parent = pstate->current->parent; + if (!pstate->current->retain) { + free_node (pstate->current); + } + pstate->current = parent; + return ret; +} + +#define QOS_PARAM_SET_NUMERIC_UNLIMITED(policy, param, param_field, type) \ + static int set_ ## policy ## _ ## param (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_ ## policy *qp, const char *value, int line) \ + { \ + int ret = SD_PARSE_RESULT_OK; \ + type ## _t s; \ + if (!strcmp(value, QOS_LENGTH_UNLIMITED)){ \ + qp->values.param_field = -1; \ + } else if (str_to_ ## type (value, &s)) { \ + qp->values.param_field = s; \ + } else { \ + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + return ret; \ + } + +#define QOS_PARAM_SET_NUMERIC(policy, param, param_field, type) \ + static int set_ ## policy ## _ ## param (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_ ## policy *qp, const char *value, int line) \ + { \ + int ret = SD_PARSE_RESULT_OK; \ + type ## _t s; \ + if (str_to_ ## type (value, &s)) { \ + qp->values.param_field = s; \ + } else { \ + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + return ret; \ + } + +#define QOS_PARAM_SET_BOOLEAN(policy, param, param_field) \ + static int set_ ## policy ## _ ## param (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_ ## policy *qp, const char *value, int line) \ + { \ + int ret = SD_PARSE_RESULT_OK; \ + bool s; \ + if (str_to_bool (value, &s)) { \ + qp->values.param_field = s; \ + } else { \ + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + return ret; \ + } + +#define QOS_PARAM_SET_STRING(policy, param, param_field) \ + static int set_ ## policy ## _ ## param (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_ ## policy *qp, const char *value, int line) \ + { \ + qp->values.param_field = ddsrt_strdup (value); \ + return SD_PARSE_RESULT_OK; \ + } + +#define QOS_PARAM_SET_BASE64(policy, param, param_data_field, param_length_field) \ + static int set_ ## policy ## _ ## param (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_ ## policy *qp, const char *value, int line) \ + { \ + (void) pstate; (void) line; \ + /* FIXME: base 64 decode */ \ + qp->values.param_data_field = ddsrt_memdup (value, strlen (value)); \ + qp->values.param_length_field = (uint32_t) strlen (value); \ + return SD_PARSE_RESULT_OK; \ + } + +static int set_DESTINATIONORDER_KIND (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_DESTINATIONORDER *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS") == 0) { + qp->values.kind = DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP; + } else if (strcmp (value, "BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS") == 0) { + qp->values.kind = DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +static int set_DURABILITY_KIND (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_DURABILITY *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "VOLATILE_DURABILITY_QOS") == 0) { + qp->values.kind = DDS_DURABILITY_VOLATILE; + } else if (strcmp (value, "TRANSIENT_LOCAL_DURABILITY_QOS") == 0) { + qp->values.kind = DDS_DURABILITY_TRANSIENT_LOCAL; + } else if (strcmp (value, "TRANSIENT_DURABILITY_QOS") == 0) { + qp->values.kind = DDS_DURABILITY_TRANSIENT; + } else if (strcmp (value, "PERSISTENT_DURABILITY_QOS") == 0) { + PARSER_ERROR (pstate, line, "Unsupported value '%s'", value); + ret = SD_PARSE_RESULT_NOT_SUPPORTED; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +static int set_DURABILITYSERVICE_HISTORY_KIND (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_DURABILITYSERVICE *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "KEEP_LAST_HISTORY_QOS") == 0) { + qp->values.history.kind = DDS_HISTORY_KEEP_LAST; + } else if (strcmp (value, "KEEP_ALL_HISTORY_QOS") == 0) { + qp->values.history.kind = DDS_HISTORY_KEEP_ALL; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +static int set_HISTORY_KIND (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_HISTORY *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "KEEP_LAST_HISTORY_QOS") == 0) { + qp->values.kind = DDS_HISTORY_KEEP_LAST; + } else if (strcmp (value, "KEEP_ALL_HISTORY_QOS") == 0) { + qp->values.kind = DDS_HISTORY_KEEP_ALL; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +static int set_LIVELINESS_KIND (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_LIVELINESS *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "AUTOMATIC_LIVELINESS_QOS") == 0) { + qp->values.kind = DDS_LIVELINESS_AUTOMATIC; + } else if (strcmp (value, "MANUAL_BY_PARTICIPANT_LIVELINESS_QOS") == 0) { + qp->values.kind = DDS_LIVELINESS_MANUAL_BY_PARTICIPANT; + } else if (strcmp (value, "MANUAL_BY_TOPIC_LIVELINESS_QOS") == 0) { + qp->values.kind = DDS_LIVELINESS_MANUAL_BY_TOPIC; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +static int set_OWNERSHIP_KIND (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_OWNERSHIP *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "SHARED_OWNERSHIP_QOS") == 0) { + qp->values.kind = DDS_OWNERSHIP_SHARED; + } else if (strcmp (value, "EXCLUSIVE_OWNERSHIP_QOS") == 0) { + qp->values.kind = DDS_OWNERSHIP_EXCLUSIVE; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +static int set_PRESENTATION_ACCESS_SCOPE (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_PRESENTATION *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "INSTANCE_PRESENTATION_QOS") == 0) { + qp->values.access_scope = DDS_PRESENTATION_INSTANCE; + } else if (strcmp (value, "TOPIC_PRESENTATION_QOS") == 0) { + qp->values.access_scope = DDS_PRESENTATION_TOPIC; + } else if (strcmp (value, "GROUP_PRESENTATION_QOS") == 0) { + qp->values.access_scope = DDS_PRESENTATION_GROUP; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +static int set_RELIABILITY_KIND (struct parse_sysdef_state * const pstate, struct dds_sysdef_QOS_POLICY_RELIABILITY *qp, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "BEST_EFFORT_RELIABILITY_QOS") == 0) { + qp->values.kind = DDS_RELIABILITY_BEST_EFFORT; + } else if (strcmp (value, "RELIABLE_RELIABILITY_QOS") == 0) { + qp->values.kind = DDS_RELIABILITY_RELIABLE; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +QOS_PARAM_SET_NUMERIC(DURABILITYSERVICE, HISTORY_DEPTH, history.depth, int32) +QOS_PARAM_SET_NUMERIC_UNLIMITED(DURABILITYSERVICE, RESOURCE_LIMIT_MAX_SAMPLES, resource_limits.max_samples, int32) +QOS_PARAM_SET_NUMERIC_UNLIMITED(DURABILITYSERVICE, RESOURCE_LIMIT_MAX_INSTANCES, resource_limits.max_instances, int32) +QOS_PARAM_SET_NUMERIC_UNLIMITED(DURABILITYSERVICE, RESOURCE_LIMIT_MAX_SAMPLES_PER_INSTANCE, resource_limits.max_samples_per_instance, int32) +QOS_PARAM_SET_BOOLEAN(ENTITYFACTORY, AUTOENABLE_CREATED_ENTITIES, autoenable_created_entities) +QOS_PARAM_SET_NUMERIC(HISTORY, DEPTH, depth, int32) +QOS_PARAM_SET_NUMERIC(OWNERSHIPSTRENGTH, VALUE, value, int32) +QOS_PARAM_SET_BOOLEAN(PRESENTATION, COHERENT_ACCESS, coherent_access) +QOS_PARAM_SET_BOOLEAN(PRESENTATION, ORDERED_ACCESS, ordered_access) +QOS_PARAM_SET_NUMERIC_UNLIMITED(RESOURCELIMITS, MAX_SAMPLES, max_samples, int32) +QOS_PARAM_SET_NUMERIC_UNLIMITED(RESOURCELIMITS, MAX_INSTANCES, max_instances, int32) +QOS_PARAM_SET_NUMERIC_UNLIMITED(RESOURCELIMITS, MAX_SAMPLES_PER_INSTANCE, max_samples_per_instance, int32) +QOS_PARAM_SET_NUMERIC(TRANSPORTPRIORITY, VALUE, value, int32) +QOS_PARAM_SET_BOOLEAN(WRITERDATALIFECYCLE, AUTODISPOSE_UNREGISTERED_INSTANCES, autodispose_unregistered_instances) +QOS_PARAM_SET_BASE64(GROUPDATA, VALUE, value, length) +QOS_PARAM_SET_BASE64(TOPICDATA, VALUE, value, length) +QOS_PARAM_SET_BASE64(USERDATA, VALUE, value, length) + +static int parse_tsn_traffic_transmission_selection (struct parse_sysdef_state * const pstate, enum dds_sysdef_tsn_traffic_transmission_selection *s, const char *value, int line) +{ + int ret = SD_PARSE_RESULT_OK; + if (strcmp (value, "STRICT_PRIORITY") == 0) { + *s = DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_STRICT_PRIORITY; + } else if (strcmp (value, "CREDIT_BASED_SHAPER") == 0) { + *s = DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_CREDIT_BASED_SHAPER; + } else if (strcmp (value, "ENHANCED_TRANSMISSION_SELECTION") == 0) { + *s = DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_ENHANCED_TRANSMISSION_SELECTION; + } else if (strcmp (value, "ATS_TRANSMISSION_SELECTION") == 0) { + *s = DDS_SYSDEF_TSN_TRAFFIC_TRANSMISSION_ATS_TRANSMISSION_SELECTION; + } else { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + return ret; +} + +#define QOS_PARAM_DATA(policy,param) \ + do { \ + struct dds_sysdef_QOS_POLICY_ ## policy *qp = (struct dds_sysdef_QOS_POLICY_ ## policy *) pstate->current->parent; \ + assert (qp->xmlnode.kind == ELEMENT_KIND_QOS_POLICY_ ## policy); \ + if (qp->populated & QOS_POLICY_ ## policy ## _PARAM_ ## param) { \ + PARSER_ERROR (pstate, line, "Parameter '%s' already set", STR(param)); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } else { \ + ret = set_## policy ## _ ## param (pstate, qp, value, line); \ + qp->populated |= QOS_POLICY_ ## policy ## _PARAM_ ## param; \ + } \ + } while (0) + +#define PARENT_PARAM_DATA_STRING(parent_kind, parent_type, param_field) \ + do { \ + assert (pstate->current->parent->kind == parent_kind); \ + struct parent_type *parent = (struct parent_type *) pstate->current->parent; \ + if (parent->param_field != NULL) { \ + PARSER_ERROR (pstate, line, "Parameter '%s' already set", STR(param_field)); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } else { \ + parent->param_field = ddsrt_strdup (value); \ + } \ + } while (0) + +#define PARENT_PARAM_DATA_NUMERIC(parent_kind, parent_type, type, param_field, param_populated_bit) \ + do { \ + assert (pstate->current->parent->kind == parent_kind); \ + struct parent_type *parent = (struct parent_type *) pstate->current->parent; \ + if (parent->populated & param_populated_bit) { \ + PARSER_ERROR (pstate, line, "Parameter '%s' already set", STR(param_field)); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } else { \ + type ## _t s; \ + if (str_to_ ## type (value, &s)) { \ + parent->param_field = s; \ + parent->populated |= param_populated_bit; \ + } else { \ + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); \ + ret = SD_PARSE_RESULT_SYNTAX_ERR; \ + } \ + } \ + } while (0) + + + +static int parse_mac_addr (const char *value, struct dds_sysdef_mac_addr **mac_addr) +{ + DDSRT_STATIC_ASSERT (sizeof ((*mac_addr)->addr) == 6); + if (strlen (value) != 17 || value[2] != ':' || value[5] != ':' || value[8] != ':' || value[11] != ':' || value[14] != ':') + return SD_PARSE_RESULT_ERR; + + *mac_addr = ddsrt_malloc (sizeof (**mac_addr)); + char v[13] = {'\0'}; + for (uint32_t i = 0; i < 6; i++) + memcpy (v + 2 * i, value + 3 * i, 2); + v[12] = '\0'; + + if (dds_sysdef_parse_hex (v, (*mac_addr)->addr) != SD_PARSE_RESULT_OK) + return SD_PARSE_RESULT_ERR; + return SD_PARSE_RESULT_OK; +} + +static int parse_ipv4_addr (const char *value, struct dds_sysdef_ip_addr **ipv4_addr) +{ + *ipv4_addr = ddsrt_malloc (sizeof (**ipv4_addr)); + if (ddsrt_sockaddrfromstr (AF_INET, value, (struct sockaddr *) &(*ipv4_addr)->addr) != 0) + return SD_PARSE_RESULT_ERR; + return SD_PARSE_RESULT_OK; +} + +static int parse_ipv6_addr (const char *value, struct dds_sysdef_ip_addr **ipv6_addr) +{ + *ipv6_addr = ddsrt_malloc (sizeof (**ipv6_addr)); + if (ddsrt_sockaddrfromstr (AF_INET6, value, (struct sockaddr *) &(*ipv6_addr)->addr) != 0) + return SD_PARSE_RESULT_ERR; + return SD_PARSE_RESULT_OK; +} + +static int proc_elem_data (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *value, int line) +{ + struct parse_sysdef_state * const pstate = varg; + int ret = SD_PARSE_RESULT_OK; + if (pstate == NULL) { + return SD_PARSE_RESULT_ERR; + } + + if (!pstate->current) { + PARSER_ERROR (pstate, line, "Current element NULL in processing element data"); + return SD_PARSE_RESULT_ERR; + } + + switch (pstate->current->kind) + { + case ELEMENT_KIND_QOS_DURATION_SEC: + case ELEMENT_KIND_QOS_DURATION_NSEC: { + assert (pstate->current->parent->data_type == ELEMENT_DATA_TYPE_DURATION); + struct dds_sysdef_qos_duration_property *qp = (struct dds_sysdef_qos_duration_property *) pstate->current->parent; + int64_t v; + bool res = true; + if ((pstate->current->kind == ELEMENT_KIND_QOS_DURATION_SEC && (!strcmp(value, QOS_DURATION_INFINITY) || !strcmp(value, QOS_DURATION_INFINITY_SEC))) || + (pstate->current->kind == ELEMENT_KIND_QOS_DURATION_NSEC && (!strcmp(value, QOS_DURATION_INFINITY) || !strcmp(value, QOS_DURATION_INFINITY_NSEC)))) + v = DDS_INFINITY; + else + res = str_to_int64(value, &v); + + if (res) + { + if (qp->populated & (pstate->current->kind == ELEMENT_KIND_QOS_DURATION_SEC ? QOS_DURATION_PARAM_SEC : QOS_DURATION_PARAM_NSEC)) + { + PARSER_ERROR (pstate, line, "Already set"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else + { + if (pstate->current->kind == ELEMENT_KIND_QOS_DURATION_SEC && (v != DDS_INFINITY)) { + qp->sec = v; + } else { + qp->nsec = v; + } + qp->populated |= (pstate->current->kind == ELEMENT_KIND_QOS_DURATION_SEC ? QOS_DURATION_PARAM_SEC : QOS_DURATION_PARAM_NSEC); + } + } + else + { + PARSER_ERROR (pstate, line, "Invalid value '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + break; + } + case ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER_KIND: + QOS_PARAM_DATA (DESTINATIONORDER, KIND); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITY_KIND: + QOS_PARAM_DATA (DURABILITY, KIND); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_HISTORY_KIND: + QOS_PARAM_DATA (DURABILITYSERVICE, HISTORY_KIND); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_HISTORY_DEPTH: + QOS_PARAM_DATA (DURABILITYSERVICE, HISTORY_DEPTH); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_SAMPLES: + QOS_PARAM_DATA (DURABILITYSERVICE, RESOURCE_LIMIT_MAX_SAMPLES); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_INSTANCES: + QOS_PARAM_DATA (DURABILITYSERVICE, RESOURCE_LIMIT_MAX_INSTANCES); + break; + case ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_SAMPLES_PER_INSTANCE: + QOS_PARAM_DATA (DURABILITYSERVICE, RESOURCE_LIMIT_MAX_SAMPLES_PER_INSTANCE); + break; + case ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY_AUTOENABLE_CREATED_ENTITIES: + QOS_PARAM_DATA (ENTITYFACTORY, AUTOENABLE_CREATED_ENTITIES); + break; + case ELEMENT_KIND_QOS_POLICY_GROUPDATA_VALUE: + QOS_PARAM_DATA (GROUPDATA, VALUE); + break; + case ELEMENT_KIND_QOS_POLICY_HISTORY_KIND: + QOS_PARAM_DATA (HISTORY, KIND); + break; + case ELEMENT_KIND_QOS_POLICY_HISTORY_DEPTH: + QOS_PARAM_DATA (HISTORY, DEPTH); + break; + case ELEMENT_KIND_QOS_POLICY_LIVELINESS_KIND: + QOS_PARAM_DATA (LIVELINESS, KIND); + break; + case ELEMENT_KIND_QOS_POLICY_OWNERSHIP_KIND: + QOS_PARAM_DATA (OWNERSHIP, KIND); + break; + case ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH_VALUE: + QOS_PARAM_DATA (OWNERSHIPSTRENGTH, VALUE); + break; + case ELEMENT_KIND_QOS_POLICY_PARTITION_NAME_ELEMENT: { + struct dds_sysdef_QOS_POLICY_PARTITION *qp = (struct dds_sysdef_QOS_POLICY_PARTITION *) pstate->current->parent->parent; + struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *p = (struct dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT *) pstate->current; + if (dds_sysdef_is_valid_identifier_syntax (value)) + { + p->element = ddsrt_strdup (value); + qp->populated = true; + } + else + { + // free_node (qp); + // pstate->current = NULL; + PARSER_ERROR (pstate, line, "Invalid partition name '%s'", value); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + break; + } + case ELEMENT_KIND_QOS_POLICY_RELIABILITY_KIND: + QOS_PARAM_DATA (RELIABILITY, KIND); + break; + case ELEMENT_KIND_QOS_POLICY_PRESENTATION_ACCESS_SCOPE: + QOS_PARAM_DATA (PRESENTATION, ACCESS_SCOPE); + break; + case ELEMENT_KIND_QOS_POLICY_PRESENTATION_COHERENT_ACCESS: + QOS_PARAM_DATA (PRESENTATION, COHERENT_ACCESS); + break; + case ELEMENT_KIND_QOS_POLICY_PRESENTATION_ORDERED_ACCESS: + QOS_PARAM_DATA (PRESENTATION, ORDERED_ACCESS); + break; + // case ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_INITIAL_INSTANCES: + // QOS_PARAM_DATA (RESOURCELIMITS, INITIAL_INSTANCES); + // break; + // case ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_INITIAL_SAMPLES: + // QOS_PARAM_DATA (RESOURCELIMITS, INITIAL_SAMPLES); + // break; + case ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_SAMPLES: + QOS_PARAM_DATA (RESOURCELIMITS, MAX_SAMPLES); + break; + case ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_INSTANCES: + QOS_PARAM_DATA (RESOURCELIMITS, MAX_INSTANCES); + break; + case ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_SAMPLES_PER_INSTANCE: + QOS_PARAM_DATA (RESOURCELIMITS, MAX_SAMPLES_PER_INSTANCE); + break; + case ELEMENT_KIND_QOS_POLICY_TOPICDATA_VALUE: + QOS_PARAM_DATA (TOPICDATA, VALUE); + break; + case ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY_VALUE: + QOS_PARAM_DATA (TRANSPORTPRIORITY, VALUE); + break; + case ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE_AUTODISPOSE_UNREGISTERED_INSTANCES: + QOS_PARAM_DATA (WRITERDATALIFECYCLE, AUTODISPOSE_UNREGISTERED_INSTANCES); + break; + case ELEMENT_KIND_QOS_POLICY_USERDATA_VALUE: + QOS_PARAM_DATA (USERDATA, VALUE); + break; + case ELEMENT_KIND_NODE_HOSTNAME: + PARENT_PARAM_DATA_STRING(ELEMENT_KIND_NODE, dds_sysdef_node, hostname); + break; + case ELEMENT_KIND_NODE_IPV4_ADDRESS: { + assert (pstate->current->parent->kind == ELEMENT_KIND_NODE); + struct dds_sysdef_node *node = (struct dds_sysdef_node *) pstate->current->parent; + if (node->ipv4_addr != NULL) + { + PARSER_ERROR (pstate, line, "Parameter 'ipv4_addr' already set"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else if (parse_ipv4_addr (value, &node->ipv4_addr) != SD_PARSE_RESULT_OK) + { + PARSER_ERROR (pstate, line, "Invalid value for parameter 'ipv4_addr'"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + break; + } + case ELEMENT_KIND_NODE_IPV6_ADDRESS: { + assert (pstate->current->parent->kind == ELEMENT_KIND_NODE); + struct dds_sysdef_node *node = (struct dds_sysdef_node *) pstate->current->parent; + if (node->ipv6_addr != NULL) + { + PARSER_ERROR (pstate, line, "Parameter 'ipv6_addr' already set"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else if (parse_ipv6_addr (value, &node->ipv6_addr) != SD_PARSE_RESULT_OK) + { + PARSER_ERROR (pstate, line, "Invalid value for parameter 'ipv6_addr'"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + break; + } + case ELEMENT_KIND_NODE_MAC_ADDRESS: { + assert (pstate->current->parent->kind == ELEMENT_KIND_NODE); + struct dds_sysdef_node *node = (struct dds_sysdef_node *) pstate->current->parent; + if (node->mac_addr != NULL) + { + PARSER_ERROR (pstate, line, "Parameter 'mac_addr' already set"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else if (parse_mac_addr (value, &node->mac_addr) != SD_PARSE_RESULT_OK) + { + PARSER_ERROR (pstate, line, "Invalid value for parameter 'mac_addr'"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + break; + } + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_SOURCE_IP_ADDRESS: + PARENT_PARAM_DATA_STRING(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, dds_sysdef_tsn_ip_tuple, source_ip_address); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DESTINATION_IP_ADDRESS: + PARENT_PARAM_DATA_STRING(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, dds_sysdef_tsn_ip_tuple, destination_ip_address); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DSCP: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, dds_sysdef_tsn_ip_tuple, uint8, dscp, SYSDEF_TSN_IP_TUPLE_DSCP_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_PROTOCOL: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, dds_sysdef_tsn_ip_tuple, uint16, protocol, SYSDEF_TSN_IP_TUPLE_PROTOCOL_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_SOURCE_PORT: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, dds_sysdef_tsn_ip_tuple, uint16, source_port, SYSDEF_TSN_IP_TUPLE_SOURCE_PORT_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DESTINATION_PORT: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, dds_sysdef_tsn_ip_tuple, uint16, destination_port, SYSDEF_TSN_IP_TUPLE_DESTINATION_PORT_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_SOURCE_IP_ADDRESS: + PARENT_PARAM_DATA_STRING(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, dds_sysdef_tsn_ip_tuple, source_ip_address); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DESTINATION_IP_ADDRESS: + PARENT_PARAM_DATA_STRING(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, dds_sysdef_tsn_ip_tuple, destination_ip_address); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DSCP: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, dds_sysdef_tsn_ip_tuple, uint8, dscp, SYSDEF_TSN_IP_TUPLE_DSCP_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_PROTOCOL: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, dds_sysdef_tsn_ip_tuple, uint16, protocol, SYSDEF_TSN_IP_TUPLE_PROTOCOL_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_SOURCE_PORT: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, dds_sysdef_tsn_ip_tuple, uint16, source_port, SYSDEF_TSN_IP_TUPLE_SOURCE_PORT_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DESTINATION_PORT: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, dds_sysdef_tsn_ip_tuple, uint16, destination_port, SYSDEF_TSN_IP_TUPLE_DESTINATION_PORT_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_SAMPLES_PER_PERIOD: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, dds_sysdef_tsn_traffic_specification, uint16, samples_per_period, SYSDEF_TSN_TRAFFIC_SPEC_SAMPLES_PER_PERIOD_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_MAX_BYTES_PER_SAMPLE: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, dds_sysdef_tsn_traffic_specification, uint16, max_bytes_per_sample, SYSDEF_TSN_TRAFFIC_SPEC_MAX_BYTES_PER_SAMPLE_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TRANSMISSION_SELECTION: { + assert (pstate->current->parent->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC); + struct dds_sysdef_tsn_traffic_specification *parent = (struct dds_sysdef_tsn_traffic_specification *) pstate->current->parent; + if (parent->populated & SYSDEF_TSN_TRAFFIC_SPEC_TRANSMISSION_SELECTION_PARAM_VALUE) + { + PARSER_ERROR (pstate, line, "Parameter 'transmission_selection' already set"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else + { + enum dds_sysdef_tsn_traffic_transmission_selection s; + if ((ret = parse_tsn_traffic_transmission_selection (pstate, &s, value, line)) == SD_PARSE_RESULT_OK) { + parent->transmission_selection = s; + parent->populated |= SYSDEF_TSN_TRAFFIC_SPEC_TRANSMISSION_SELECTION_PARAM_VALUE; + } + } + break; + } + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_EARLIEST_TRANSMIT_OFFSET: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, dds_sysdef_tsn_time_aware, uint32, earliest_transmit_offset, SYSDEF_TSN_TIME_AWARE_EARLIEST_TRANSMIT_OFFSET_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_LATEST_TRANSMIT_OFFSET: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, dds_sysdef_tsn_time_aware, uint32, latest_transmit_offset, SYSDEF_TSN_TIME_AWARE_LATEST_TRANSMIT_OFFSET_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_JITTER: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, dds_sysdef_tsn_time_aware, uint32, jitter, SYSDEF_TSN_TIME_JITTER_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS_NUM_SEAMLESS_TREES: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS, dds_sysdef_tsn_network_requirements, uint8, num_seamless_trees, SYSDEF_TSN_NETWORK_REQ_NUM_SEAMLESS_TREES_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS_MAX_LATENCY: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS, dds_sysdef_tsn_network_requirements, uint32, max_latency, SYSDEF_TSN_NETWORK_REQ_MAX_LATENCY_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS_NUM_SEAMLESS_TREES: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS, dds_sysdef_tsn_network_requirements, uint8, num_seamless_trees, SYSDEF_TSN_NETWORK_REQ_NUM_SEAMLESS_TREES_PARAM_VALUE); + break; + case ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS_MAX_LATENCY: + PARENT_PARAM_DATA_NUMERIC(ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS, dds_sysdef_tsn_network_requirements, uint32, max_latency, SYSDEF_TSN_NETWORK_REQ_MAX_LATENCY_PARAM_VALUE); + break; + default: + PARSER_ERROR (pstate, line, "Element data not allowed"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + break; + } + + if (ret != SD_PARSE_RESULT_OK) + { + struct xml_element *n = pstate->current, *tmp; + while (n != NULL) + { + tmp = n->parent; + if (!n->retain) + free_node (n); + n = tmp; + } + } + + return ret; +} + +#define PARSER_ERROR_INVALID_PARENT_KIND() \ + do { \ + PARSER_ERROR (pstate, line, "Invalid parent kind (%d) for element '%s'", pstate->current->kind, name); \ + return SD_PARSE_RESULT_SYNTAX_ERR; \ + } while (0) + +static int proc_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED_ARG (uintptr_t *eleminfo), const char *name, int line) +{ + if (varg == NULL) + return SD_PARSE_RESULT_ERR; + + struct parse_sysdef_state * const pstate = varg; + int ret = SD_PARSE_RESULT_OK; + + if (ddsrt_strcasecmp (name, "dds") == 0) + { + if (pstate->current != NULL || pstate->sysdef != NULL) { + PARSER_ERROR (pstate, line, "Nested element '%s' not supported", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else if ((pstate->current = new_node (pstate, ELEMENT_KIND_DDS, ELEMENT_DATA_TYPE_GENERIC, NULL, sizeof(struct dds_sysdef_system), NO_INIT, fini_sysdef)) == NULL) + { + PARSER_ERROR (pstate, line, "Error creating root node"); + ret = SD_PARSE_RESULT_ERR; + } + else + { + pstate->sysdef = (struct dds_sysdef_system *) pstate->current; + goto status_ok; + } + } + else + { + CHECK_PARENT_NULL (pstate, pstate->current); + if (pstate->scope & SYSDEF_SCOPE_TYPE_LIB) + { + // Type library + if (ddsrt_strcasecmp (name, "types") == 0) + CREATE_NODE_SINGLE (pstate, dds_sysdef_type_lib, ELEMENT_KIND_TYPE_LIB, NO_INIT, fini_type_lib, type_libs, dds_sysdef_system, ELEMENT_KIND_DDS, pstate->current); + else if (ddsrt_strcasecmp (name, "struct") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_type, ELEMENT_KIND_TYPE, NO_INIT, fini_type, types, dds_sysdef_type_lib, ELEMENT_KIND_TYPE_LIB, pstate->current); + } + + if (pstate->scope & SYSDEF_SCOPE_QOS_LIB) + { + // QoS library + if (ddsrt_strcasecmp (name, "qos_library") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_qos_lib, ELEMENT_KIND_QOS_LIB, NO_INIT, fini_qos_lib, qos_libs, dds_sysdef_system, ELEMENT_KIND_DDS, pstate->current); + else if (ddsrt_strcasecmp (name, "qos_profile") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_qos_profile, ELEMENT_KIND_QOS_PROFILE, NO_INIT, fini_qos_profile, qos_profiles, dds_sysdef_qos_lib, ELEMENT_KIND_QOS_LIB, pstate->current); + + else if (ddsrt_strcasecmp (name, "domain_participant_qos") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_PROFILE) + CREATE_NODE_LIST (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_PARTICIPANT, init_qos, fini_qos, qos, dds_sysdef_qos_profile, ELEMENT_KIND_QOS_PROFILE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_PARTICIPANT) + CREATE_NODE_SINGLE (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_PARTICIPANT, init_qos, fini_qos, qos, dds_sysdef_participant, ELEMENT_KIND_PARTICIPANT, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "publisher_qos") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_PROFILE) + CREATE_NODE_LIST (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_PUBLISHER, init_qos, fini_qos, qos, dds_sysdef_qos_profile, ELEMENT_KIND_QOS_PROFILE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_PUBLISHER) + CREATE_NODE_SINGLE (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_PUBLISHER, init_qos, fini_qos, qos, dds_sysdef_publisher, ELEMENT_KIND_PUBLISHER, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "subscriber_qos") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_PROFILE) + CREATE_NODE_LIST (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_SUBSCRIBER, init_qos, fini_qos, qos, dds_sysdef_qos_profile, ELEMENT_KIND_QOS_PROFILE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_SUBSCRIBER) + CREATE_NODE_SINGLE (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_SUBSCRIBER, init_qos, fini_qos, qos, dds_sysdef_subscriber, ELEMENT_KIND_SUBSCRIBER, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "topic_qos") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_PROFILE) + CREATE_NODE_LIST (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_TOPIC, init_qos, fini_qos, qos, dds_sysdef_qos_profile, ELEMENT_KIND_QOS_PROFILE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_TOPIC) + CREATE_NODE_SINGLE (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_TOPIC, init_qos, fini_qos, qos, dds_sysdef_topic, ELEMENT_KIND_TOPIC, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "datawriter_qos") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_PROFILE) + CREATE_NODE_LIST (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_WRITER, init_qos, fini_qos, qos, dds_sysdef_qos_profile, ELEMENT_KIND_QOS_PROFILE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_WRITER) + CREATE_NODE_SINGLE (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_WRITER, init_qos, fini_qos, qos, dds_sysdef_writer, ELEMENT_KIND_WRITER, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "datareader_qos") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_PROFILE) + CREATE_NODE_LIST (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_READER, init_qos, fini_qos, qos, dds_sysdef_qos_profile, ELEMENT_KIND_QOS_PROFILE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_READER) + CREATE_NODE_SINGLE (pstate, dds_sysdef_qos, ELEMENT_KIND_QOS_READER, init_qos, fini_qos, qos, dds_sysdef_reader, ELEMENT_KIND_READER, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + + // QoS policies + else if (ddsrt_strcasecmp (name, "deadline") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_DEADLINE, ELEMENT_KIND_QOS_POLICY_DEADLINE, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "destination_order") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_DESTINATIONORDER, ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "durability") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_DURABILITY, ELEMENT_KIND_QOS_POLICY_DURABILITY, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "durability_service") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_DURABILITYSERVICE, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "entity_factory") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_ENTITYFACTORY, ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "group_data") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_GROUPDATA, ELEMENT_KIND_QOS_POLICY_GROUPDATA, NO_INIT, fini_qos_groupdata, pstate->current); + else if (ddsrt_strcasecmp (name, "history") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_HISTORY, ELEMENT_KIND_QOS_POLICY_HISTORY, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "latency_budget") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_LATENCYBUDGET, ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "lifespan") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_LIFESPAN, ELEMENT_KIND_QOS_POLICY_LIFESPAN, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "liveliness") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_LIVELINESS, ELEMENT_KIND_QOS_POLICY_LIVELINESS, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "ownership") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_OWNERSHIP, ELEMENT_KIND_QOS_POLICY_OWNERSHIP, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "ownership_strength") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_OWNERSHIPSTRENGTH, ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "partition") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_PARTITION, ELEMENT_KIND_QOS_POLICY_PARTITION, NO_INIT, fini_qos_partition, pstate->current); + else if (ddsrt_strcasecmp (name, "presentation") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_PRESENTATION, ELEMENT_KIND_QOS_POLICY_PRESENTATION, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "reader_data_lifecycle") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_READERDATALIFECYCLE, ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "reliability") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_RELIABILITY, ELEMENT_KIND_QOS_POLICY_RELIABILITY, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "resource_limits") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_RESOURCELIMITS, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "time_based_filter") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_TIMEBASEDFILTER, ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "topic_data") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_TOPICDATA, ELEMENT_KIND_QOS_POLICY_TOPICDATA, NO_INIT, fini_qos_topicdata, pstate->current); + else if (ddsrt_strcasecmp (name, "transport_priority") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_TRANSPORTPRIORITY, ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY, NO_INIT, NO_FINI, pstate->current); + else if (ddsrt_strcasecmp (name, "user_data") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_USERDATA, ELEMENT_KIND_QOS_POLICY_USERDATA, NO_INIT, fini_qos_userdata, pstate->current); + else if (ddsrt_strcasecmp (name, "writer_data_lifecycle") == 0) + CREATE_NODE_QOS (pstate, dds_sysdef_QOS_POLICY_WRITERDATALIFECYCLE, ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE, NO_INIT, NO_FINI, pstate->current); + + // QoS policy parameters + else if (ddsrt_strcasecmp (name, "period") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_DEADLINE_PERIOD, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DEADLINE, pstate->current); + else if (ddsrt_strcasecmp (name, "duration") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET_DURATION, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_LATENCYBUDGET, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_LIFESPAN) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_LIFESPAN_DURATION, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_LIFESPAN, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "service_cleanup_delay") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_SERVICE_CLEANUP_DELAY, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, pstate->current); + else if (ddsrt_strcasecmp (name, "history_kind") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_HISTORY_KIND, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, pstate->current); + else if (ddsrt_strcasecmp (name, "history_depth") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_HISTORY_DEPTH, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, pstate->current); + else if (ddsrt_strcasecmp (name, "depth") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_HISTORY_DEPTH, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_HISTORY, pstate->current); + else if (ddsrt_strcasecmp (name, "max_samples") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_SAMPLES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_SAMPLES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "max_instances") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_INSTANCES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_INSTANCES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "max_samples_per_instance") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE_RESOURCE_LIMIT_MAX_SAMPLES_PER_INSTANCE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DURABILITYSERVICE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_MAX_SAMPLES_PER_INSTANCE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "max_blocking_time") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_RELIABILITY_MAX_BLOCKING_DELAY, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_RELIABILITY, pstate->current); + else if (ddsrt_strcasecmp (name, "lease_duration") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_LIVELINESS_LEASE_DURATION, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_LIVELINESS, pstate->current); + else if (ddsrt_strcasecmp (name, "access_scope") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_PRESENTATION_ACCESS_SCOPE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_PRESENTATION, pstate->current); + else if (ddsrt_strcasecmp (name, "coherent_access") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_PRESENTATION_COHERENT_ACCESS, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_PRESENTATION, pstate->current); + else if (ddsrt_strcasecmp (name, "ordered_access") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_PRESENTATION_ORDERED_ACCESS, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_PRESENTATION, pstate->current); + else if (ddsrt_strcasecmp (name, "autopurge_nowriter_samples_delay") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE_AUTOPURGE_NOWRITER_SAMPLES_DELAY, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE, pstate->current); + else if (ddsrt_strcasecmp (name, "autopurge_disposed_samples_delay") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE_AUTOPURGE_DISPOSED_SAMPLES_DELAY, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_READERDATALIFECYCLE, pstate->current); + // else if (ddsrt_strcasecmp (name, "initial_instances") == 0) + // CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_INITIAL_INSTANCES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, pstate->current); + // else if (ddsrt_strcasecmp (name, "initial_samples") == 0) + // CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS_INITIAL_SAMPLES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_RESOURCELIMITS, pstate->current); + else if (ddsrt_strcasecmp (name, "ordered_access") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_PRESENTATION_ORDERED_ACCESS, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_PRESENTATION, pstate->current); + else if (ddsrt_strcasecmp (name, "minimum_separation") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER_MINIMUM_SEPARATION, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_TIMEBASEDFILTER, pstate->current); + else if (ddsrt_strcasecmp (name, "autodispose_unregistered_instances") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE_AUTODISPOSE_UNREGISTERED_INSTANCES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_WRITERDATALIFECYCLE, pstate->current); + else if (ddsrt_strcasecmp (name, "autoenable_created_entities") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY_AUTOENABLE_CREATED_ENTITIES, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_ENTITYFACTORY, pstate->current); + else if (ddsrt_strcasecmp (name, "kind") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER_KIND, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DESTINATIONORDER, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_DURABILITY) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_DURABILITY_KIND, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_DURABILITY, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_HISTORY) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_HISTORY_KIND, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_HISTORY, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_LIVELINESS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_LIVELINESS_KIND, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_LIVELINESS, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_OWNERSHIP) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_OWNERSHIP_KIND, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_OWNERSHIP, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_RELIABILITY) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_RELIABILITY_KIND, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_RELIABILITY, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "value") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_GROUPDATA) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_GROUPDATA_VALUE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_GROUPDATA, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_TOPICDATA) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_TOPICDATA_VALUE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_TOPICDATA, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_USERDATA) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_USERDATA_VALUE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_USERDATA, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH_VALUE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_OWNERSHIPSTRENGTH, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY_VALUE, NO_INIT, NO_FINI, ELEMENT_KIND_QOS_POLICY_TRANSPORTPRIORITY, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "name") == 0) + CREATE_NODE_SINGLE (pstate, dds_sysdef_QOS_POLICY_PARTITION_NAME, ELEMENT_KIND_QOS_POLICY_PARTITION_NAME, NO_INIT, fini_qos_partition_name, name, dds_sysdef_QOS_POLICY_PARTITION, ELEMENT_KIND_QOS_POLICY_PARTITION, pstate->current); + else if (ddsrt_strcasecmp (name, "element") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_QOS_POLICY_PARTITION_NAME_ELEMENT, ELEMENT_KIND_QOS_POLICY_PARTITION_NAME_ELEMENT, NO_INIT, fini_qos_partition_name_element, elements, dds_sysdef_QOS_POLICY_PARTITION_NAME, ELEMENT_KIND_QOS_POLICY_PARTITION_NAME, pstate->current); + else if (ddsrt_strcasecmp (name, "sec") == 0) + { + if (pstate->current->data_type == ELEMENT_DATA_TYPE_DURATION) + CREATE_NODE_DURATION_SEC (pstate, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "nanosec") == 0) + { + if (pstate->current->data_type == ELEMENT_DATA_TYPE_DURATION) + CREATE_NODE_DURATION_NSEC (pstate, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + } + + if (pstate->scope & SYSDEF_SCOPE_DOMAIN_LIB) + { + // Domain library + if (ddsrt_strcasecmp (name, "domain_library") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_domain_lib, ELEMENT_KIND_DOMAIN_LIB, NO_INIT, fini_domain_lib, domain_libs, dds_sysdef_system, ELEMENT_KIND_DDS, pstate->current); + else if (ddsrt_strcasecmp (name, "domain") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_domain, ELEMENT_KIND_DOMAIN, NO_INIT, fini_domain, domains, dds_sysdef_domain_lib, ELEMENT_KIND_DOMAIN_LIB, pstate->current); + else if (ddsrt_strcasecmp (name, "register_type") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DOMAIN) + CREATE_NODE_LIST (pstate, dds_sysdef_register_type, ELEMENT_KIND_REGISTER_TYPE, NO_INIT, fini_register_type, register_types, dds_sysdef_domain, ELEMENT_KIND_DOMAIN, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_PARTICIPANT) + CREATE_NODE_LIST (pstate, dds_sysdef_register_type, ELEMENT_KIND_REGISTER_TYPE, NO_INIT, fini_register_type, register_types, dds_sysdef_participant, ELEMENT_KIND_PARTICIPANT, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "topic") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DOMAIN) + CREATE_NODE_LIST (pstate, dds_sysdef_topic, ELEMENT_KIND_TOPIC, NO_INIT, fini_topic, topics, dds_sysdef_domain, ELEMENT_KIND_DOMAIN, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_PARTICIPANT) + CREATE_NODE_LIST (pstate, dds_sysdef_topic, ELEMENT_KIND_TOPIC, NO_INIT, fini_topic, topics, dds_sysdef_participant, ELEMENT_KIND_PARTICIPANT, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + } + + if (pstate->scope & SYSDEF_SCOPE_PARTICIPANT_LIB) + { + // Domain participant library + if (ddsrt_strcasecmp (name, "domain_participant_library") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_participant_lib, ELEMENT_KIND_PARTICIPANT_LIB, NO_INIT, fini_participant_lib, participant_libs, dds_sysdef_system, ELEMENT_KIND_DDS, pstate->current); + else if (ddsrt_strcasecmp (name, "domain_participant") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_PARTICIPANT_LIB) + CREATE_NODE_LIST (pstate, dds_sysdef_participant, ELEMENT_KIND_PARTICIPANT, NO_INIT, fini_participant, participants, dds_sysdef_participant_lib, ELEMENT_KIND_PARTICIPANT_LIB, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_APPLICATION) + CREATE_NODE_LIST (pstate, dds_sysdef_participant, ELEMENT_KIND_PARTICIPANT, NO_INIT, fini_participant, participants, dds_sysdef_application, ELEMENT_KIND_APPLICATION, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "publisher") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_publisher, ELEMENT_KIND_PUBLISHER, NO_INIT, fini_publisher, publishers, dds_sysdef_participant, ELEMENT_KIND_PARTICIPANT, pstate->current); + else if (ddsrt_strcasecmp (name, "data_writer") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_writer, ELEMENT_KIND_WRITER, NO_INIT, fini_writer, writers, dds_sysdef_publisher, ELEMENT_KIND_PUBLISHER, pstate->current); + else if (ddsrt_strcasecmp (name, "subscriber") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_subscriber, ELEMENT_KIND_SUBSCRIBER, NO_INIT, fini_subscriber, subscribers, dds_sysdef_participant, ELEMENT_KIND_PARTICIPANT, pstate->current); + else if (ddsrt_strcasecmp (name, "data_reader") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_reader, ELEMENT_KIND_READER, NO_INIT, fini_reader, readers, dds_sysdef_subscriber, ELEMENT_KIND_SUBSCRIBER, pstate->current); + } + + if (pstate->scope & SYSDEF_SCOPE_APPLICATION_LIB) + { + // Application library + if (ddsrt_strcasecmp (name, "application_library") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_application_lib, ELEMENT_KIND_APPLICATION_LIB, NO_INIT, fini_application_lib, application_libs, dds_sysdef_system, ELEMENT_KIND_DDS, pstate->current); + else if (ddsrt_strcasecmp (name, "application") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_APPLICATION_LIB) + CREATE_NODE_LIST (pstate, dds_sysdef_application, ELEMENT_KIND_APPLICATION, NO_INIT, fini_application, applications, dds_sysdef_application_lib, ELEMENT_KIND_APPLICATION_LIB, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_APPLICATION_LIST) + CREATE_NODE_LIST (pstate, dds_sysdef_application_ref, ELEMENT_KIND_DEPLOYMENT_APPLICATION_REF, NO_INIT, NO_FINI, application_refs, dds_sysdef_application_list, ELEMENT_KIND_DEPLOYMENT_APPLICATION_LIST, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + } + + if (pstate->scope & SYSDEF_SCOPE_NODE_LIB) + { + // Node library + if (ddsrt_strcasecmp (name, "node_library") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_node_lib, ELEMENT_KIND_NODE_LIB, NO_INIT, fini_node_lib, node_libs, dds_sysdef_system, ELEMENT_KIND_DDS, pstate->current); + else if (ddsrt_strcasecmp (name, "node") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_NODE_LIB) + CREATE_NODE_LIST (pstate, dds_sysdef_node, ELEMENT_KIND_NODE, NO_INIT, fini_node, nodes, dds_sysdef_node_lib, ELEMENT_KIND_NODE_LIB, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_NODE_REF, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "hostname") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_NODE_HOSTNAME, NO_INIT, NO_FINI, ELEMENT_KIND_NODE, pstate->current); + else if (ddsrt_strcasecmp (name, "ipv4_address") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_NODE_IPV4_ADDRESS, NO_INIT, NO_FINI, ELEMENT_KIND_NODE, pstate->current); + else if (ddsrt_strcasecmp (name, "ipv6_address") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_NODE_IPV6_ADDRESS, NO_INIT, NO_FINI, ELEMENT_KIND_NODE, pstate->current); + else if (ddsrt_strcasecmp (name, "mac_address") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_NODE_MAC_ADDRESS, NO_INIT, NO_FINI, ELEMENT_KIND_NODE, pstate->current); + } + + if (pstate->scope & SYSDEF_SCOPE_DEPLOYMENT_LIB) + { + // Deployment library + if (ddsrt_strcasecmp (name, "deployment_library") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_deployment_lib, ELEMENT_KIND_DEPLOYMENT_LIB, NO_INIT, fini_deployment_lib, deployment_libs, dds_sysdef_system, ELEMENT_KIND_DDS, pstate->current); + else if (ddsrt_strcasecmp (name, "deployment") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_deployment, ELEMENT_KIND_DEPLOYMENT, NO_INIT, fini_deployment, deployments, dds_sysdef_deployment_lib, ELEMENT_KIND_DEPLOYMENT_LIB, pstate->current); + else if (ddsrt_strcasecmp (name, "application_list") == 0) + CREATE_NODE_SINGLE (pstate, dds_sysdef_application_list, ELEMENT_KIND_DEPLOYMENT_APPLICATION_LIST, NO_INIT, fini_application_list, application_list, dds_sysdef_deployment, ELEMENT_KIND_DEPLOYMENT, pstate->current); + else if (ddsrt_strcasecmp (name, "configuration") == 0) + CREATE_NODE_SINGLE (pstate, dds_sysdef_configuration, ELEMENT_KIND_DEPLOYMENT_CONF, NO_INIT, fini_conf, configuration, dds_sysdef_deployment, ELEMENT_KIND_DEPLOYMENT, pstate->current); + else if (ddsrt_strcasecmp (name, "tsn") == 0) + CREATE_NODE_SINGLE (pstate, dds_sysdef_tsn_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN, NO_INIT, fini_conf_tsn, tsn_configuration, dds_sysdef_configuration, ELEMENT_KIND_DEPLOYMENT_CONF, pstate->current); + else if (ddsrt_strcasecmp (name, "tsn_talker") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_talker_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER, NO_INIT, fini_conf_tsn_talker, tsn_talker_configurations, dds_sysdef_tsn_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN, pstate->current); + else if (ddsrt_strcasecmp (name, "tsn_listener") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_listener_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER, NO_INIT, fini_conf_tsn_listener, tsn_listener_configurations, dds_sysdef_tsn_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN, pstate->current); + else if (ddsrt_strcasecmp (name, "data_frame_specification") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_data_frame_specification, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC, NO_INIT, fini_conf_tsn_data_frame_specification, data_frame_specification, dds_sysdef_tsn_talker_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER, pstate->current); + else if (ddsrt_strcasecmp (name, "ipv4_tuple") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_ip_tuple, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, NO_INIT, fini_conf_tsn_ip_tuple, ipv4_tuple, dds_sysdef_tsn_data_frame_specification, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC, pstate->current); + else if (ddsrt_strcasecmp (name, "ipv6_tuple") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_ip_tuple, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, NO_INIT, fini_conf_tsn_ip_tuple, ipv6_tuple, dds_sysdef_tsn_data_frame_specification, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC, pstate->current); + else if (ddsrt_strcasecmp (name, "source_ip_address") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_SOURCE_IP_ADDRESS, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_SOURCE_IP_ADDRESS, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "destination_ip_address") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DESTINATION_IP_ADDRESS, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DESTINATION_IP_ADDRESS, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "dscp") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DSCP, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DSCP, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "protocol") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_PROTOCOL, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_PROTOCOL, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "source_port") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_SOURCE_PORT, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_SOURCE_PORT, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "destination_port") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE_DESTINATION_PORT, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV4_TUPLE, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE_DESTINATION_PORT, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_DATA_FRAME_SPEC_IPV6_TUPLE, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "traffic_specification") == 0) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_traffic_specification, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, NO_INIT, fini_conf_tsn_traffic_specification, traffic_specification, dds_sysdef_tsn_talker_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER, pstate->current); + else if (ddsrt_strcasecmp (name, "periodicity") == 0) + CREATE_NODE_DURATION (pstate, dds_sysdef_qos_duration_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_PERIODICITY, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, pstate->current); + else if (ddsrt_strcasecmp (name, "samples_per_period") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_SAMPLES_PER_PERIOD, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, pstate->current); + else if (ddsrt_strcasecmp (name, "max_bytes_per_sample") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_MAX_BYTES_PER_SAMPLE, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, pstate->current); + else if (ddsrt_strcasecmp (name, "transmission_selection") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TRANSMISSION_SELECTION, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, pstate->current); + else if (ddsrt_strcasecmp (name, "time_aware") == 0) + CREATE_NODE_SINGLE (pstate, dds_sysdef_tsn_time_aware, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, NO_INIT, NO_FINI, time_aware, dds_sysdef_tsn_traffic_specification, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC, pstate->current); + else if (ddsrt_strcasecmp (name, "earliest_transmit_offset") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_EARLIEST_TRANSMIT_OFFSET, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, pstate->current); + else if (ddsrt_strcasecmp (name, "latest_transmit_offset") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_LATEST_TRANSMIT_OFFSET, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, pstate->current); + else if (ddsrt_strcasecmp (name, "jitter") == 0) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE_JITTER, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_TRAFFIC_SPEC_TIME_AWARE, pstate->current); + else if (ddsrt_strcasecmp (name, "network_requirements") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_network_requirements, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS, NO_INIT, NO_FINI, network_requirements, dds_sysdef_tsn_talker_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER) + CREATE_NODE_LIST (pstate, dds_sysdef_tsn_network_requirements, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS, NO_INIT, NO_FINI, network_requirements, dds_sysdef_tsn_listener_configuration, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "num_seamless_trees") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS_NUM_SEAMLESS_TREES, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS_NUM_SEAMLESS_TREES, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + else if (ddsrt_strcasecmp (name, "max_latency") == 0) + { + if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS_MAX_LATENCY, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_TALKER_NETWORK_REQUIREMENTS, pstate->current); + else if (pstate->current->kind == ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS) + CREATE_NODE_CUSTOM (pstate, dds_sysdef_qos_generic_property, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS_MAX_LATENCY, NO_INIT, NO_FINI, ELEMENT_KIND_DEPLOYMENT_CONF_TSN_LISTENER_NETWORK_REQUIREMENTS, pstate->current); + else + PARSER_ERROR_INVALID_PARENT_KIND (); + } + } + } + + if (ret == SD_PARSE_RESULT_OK) + { + PARSER_ERROR (pstate, line, "Unknown element '%s'", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + + struct xml_element *e = pstate->current; + while (e != NULL) + { + struct xml_element *tmp = e->parent; + if (!e->retain) + free_node (e); + e = tmp; + } +status_ok: + return ret; +} + +static void proc_error (void *varg, const char *msg, int line) +{ + struct parse_sysdef_state * const pstate = varg; + if (!pstate->has_err) + { + PARSER_ERROR (pstate, line, "Syntax error '%s'", msg); + } +} + +static dds_return_t sysdef_parse(struct ddsrt_xmlp_state *xmlps, struct parse_sysdef_state *pstate, struct dds_sysdef_system **sysdef) +{ + dds_return_t ret = DDS_RETCODE_OK; + if ((ret = ddsrt_xmlp_parse (xmlps)) != SD_PARSE_RESULT_OK) + { + SYSDEF_ERROR ("Error parsing system definition XML: %s (error code %d, line %d)\n", pstate->err_msg, ret, pstate->err_line); + ret = DDS_RETCODE_ERROR; + if (pstate->sysdef != NULL) + dds_sysdef_fini_sysdef (pstate->sysdef); + } + else + { + *sysdef = pstate->sysdef; + } + + return ret; +} + +dds_return_t dds_sysdef_init_sysdef (FILE *fp, struct dds_sysdef_system **sysdef, uint32_t lib_scope) +{ + dds_return_t ret = DDS_RETCODE_OK; + struct parse_sysdef_state pstate = { .sysdef = NULL, .scope = lib_scope}; + struct ddsrt_xmlp_callbacks cb = { + .attr = proc_attr, + .elem_close = proc_elem_close, + .elem_data = proc_elem_data, + .elem_open = proc_elem_open, + .error = proc_error + }; + + struct ddsrt_xmlp_state *xmlps = ddsrt_xmlp_new_file (fp, &pstate, &cb); + ret = sysdef_parse(xmlps, &pstate, sysdef); + ddsrt_xmlp_free (xmlps); + return ret; +} + +dds_return_t dds_sysdef_init_sysdef_str (const char *raw, struct dds_sysdef_system **sysdef, uint32_t lib_scope) +{ + dds_return_t ret = DDS_RETCODE_OK; + struct parse_sysdef_state pstate = { .sysdef = NULL, .scope = lib_scope}; + struct ddsrt_xmlp_callbacks cb = { + .attr = proc_attr, + .elem_close = proc_elem_close, + .elem_data = proc_elem_data, + .elem_open = proc_elem_open, + .error = proc_error + }; + + struct ddsrt_xmlp_state *xmlps = ddsrt_xmlp_new_string (raw, &pstate, &cb); + ret = sysdef_parse(xmlps, &pstate, sysdef); + ddsrt_xmlp_free (xmlps); + return ret; +} + +void dds_sysdef_fini_sysdef (struct dds_sysdef_system *sysdef) +{ + free_node (sysdef); +} + +enum parse_type_scope { + PARSE_TYPE_SCOPE_ROOT, + PARSE_TYPE_SCOPE_TYPES, + PARSE_TYPE_SCOPE_TYPE_ENTRY, + PARSE_TYPE_SCOPE_TYPE_INFO, + PARSE_TYPE_SCOPE_TYPE_MAP +}; + +struct parse_type_state { + bool has_err; + int err_line; + char err_msg[MAX_ERRMSG_SZ]; + enum parse_type_scope scope; + struct dds_sysdef_type_metadata_admin *type_meta_data; + struct dds_sysdef_type_metadata *current; +}; + +static bool type_equal (const void *a, const void *b) +{ + const struct dds_sysdef_type_metadata *type_a = a, *type_b = b; + return memcmp (type_a->type_hash, type_b->type_hash, sizeof (TYPE_HASH_LENGTH)) == 0; +} + +static uint32_t type_hash (const void *t) +{ + const struct dds_sysdef_type_metadata *type = t; + uint32_t hash32; + memcpy (&hash32, type->type_hash, sizeof (hash32)); + return hash32; +} + +static void free_type_meta_data (struct dds_sysdef_type_metadata *tmd) +{ + if (tmd->type_hash != NULL) + ddsrt_free (tmd->type_hash); + if (tmd->type_info_cdr != NULL) + ddsrt_free (tmd->type_info_cdr); + if (tmd->type_map_cdr != NULL) + ddsrt_free (tmd->type_map_cdr); + ddsrt_free (tmd); +} + +static int proc_type_elem_open (void *varg, UNUSED_ARG (uintptr_t parentinfo), UNUSED_ARG (uintptr_t *eleminfo), const char *name, int line) +{ + struct parse_type_state * const pstate = varg; + int ret = SD_PARSE_RESULT_OK; + + if (ddsrt_strcasecmp (name, "types") == 0) + { + if (pstate->scope != PARSE_TYPE_SCOPE_ROOT) + { + PARSER_ERROR (pstate, line, "Unexpected element '%s'", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else + { + pstate->scope = PARSE_TYPE_SCOPE_TYPES; + pstate->type_meta_data = ddsrt_malloc (sizeof (*pstate->type_meta_data)); + pstate->type_meta_data->m = ddsrt_hh_new (1, type_hash, type_equal); + } + } + else if (ddsrt_strcasecmp (name, "type") == 0) + { + if (pstate->scope != PARSE_TYPE_SCOPE_TYPES) + { + PARSER_ERROR (pstate, line, "Unexpected element '%s'", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else + { + pstate->scope = PARSE_TYPE_SCOPE_TYPE_ENTRY; + struct dds_sysdef_type_metadata *t = ddsrt_calloc (1, sizeof (*t)); + if (t == NULL) + { + PARSER_ERROR (pstate, line, "Error allocating type meta-data"); + ret = SD_PARSE_RESULT_ERR; + } + else + { + pstate->current = t; + } + } + } + else if (ddsrt_strcasecmp (name, "type_info") == 0) + { + if (pstate->scope != PARSE_TYPE_SCOPE_TYPE_ENTRY) + { + PARSER_ERROR (pstate, line, "Unexpected element '%s'", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else + { + pstate->scope = PARSE_TYPE_SCOPE_TYPE_INFO; + } + } + else if (ddsrt_strcasecmp (name, "type_map") == 0) + { + if (pstate->scope != PARSE_TYPE_SCOPE_TYPE_ENTRY) + { + PARSER_ERROR (pstate, line, "Unexpected element '%s'", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + } + else + { + pstate->scope = PARSE_TYPE_SCOPE_TYPE_MAP; + } + } + else + { + PARSER_ERROR (pstate, line, "Unexpected element '%s'", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + if (pstate->scope == PARSE_TYPE_SCOPE_TYPE_ENTRY) + free_type_meta_data (pstate->current); + } + + return ret; +} + +static int proc_type_elem_close (void *varg, UNUSED_ARG (uintptr_t eleminfo), UNUSED_ARG (int line)) +{ + struct parse_type_state * const pstate = varg; + int ret = SD_PARSE_RESULT_OK; + if (pstate->scope == PARSE_TYPE_SCOPE_TYPE_INFO) + { + pstate->scope = PARSE_TYPE_SCOPE_TYPE_ENTRY; + } + else if (pstate->scope == PARSE_TYPE_SCOPE_TYPE_MAP) + { + pstate->scope = PARSE_TYPE_SCOPE_TYPE_ENTRY; + } + else if (pstate->scope == PARSE_TYPE_SCOPE_TYPE_ENTRY) + { + if (pstate->current->type_hash == NULL) + { + PARSER_ERROR (pstate, line, "Type identifier not set"); + ret = SD_PARSE_RESULT_ERR; + free_type_meta_data (pstate->current); + } + else if (pstate->current->type_info_cdr == NULL || pstate->current->type_map_cdr == NULL) + { + PARSER_ERROR (pstate, line, "Incomplete type meta-data"); + ret = SD_PARSE_RESULT_ERR; + free_type_meta_data (pstate->current); + } + else + { + ddsrt_hh_add (pstate->type_meta_data->m, pstate->current); + pstate->scope = PARSE_TYPE_SCOPE_TYPES; + } + pstate->current = NULL; + } + else if (pstate->scope == PARSE_TYPE_SCOPE_TYPES) + { + pstate->scope = PARSE_TYPE_SCOPE_ROOT; + } + return ret; +} + +static int proc_type_elem_data (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *value, int line) +{ + struct parse_type_state * const pstate = varg; + int ret = SD_PARSE_RESULT_OK; + + switch (pstate->scope) + { + case PARSE_TYPE_SCOPE_TYPE_INFO: + pstate->current->type_info_cdr_sz = strlen (value) / 2; + pstate->current->type_info_cdr = ddsrt_malloc (pstate->current->type_info_cdr_sz); + dds_sysdef_parse_hex (value, pstate->current->type_info_cdr); + break; + case PARSE_TYPE_SCOPE_TYPE_MAP: + pstate->current->type_map_cdr_sz = strlen (value) / 2; + pstate->current->type_map_cdr = ddsrt_malloc (pstate->current->type_map_cdr_sz); + dds_sysdef_parse_hex (value, pstate->current->type_map_cdr); + break; + default: + PARSER_ERROR (pstate, line, "Unexpected data"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + break; + } + return ret; +} + +static int proc_type_attr (void *varg, UNUSED_ARG (uintptr_t eleminfo), const char *name, const char *value, int line) +{ + struct parse_type_state * const pstate = varg; + int ret = SD_PARSE_RESULT_OK; + bool attr_processed = false; + + if (ddsrt_strcasecmp(name, "xmlns") == 0 || ddsrt_strcasecmp(name, "xmlns:xsi") == 0 || ddsrt_strcasecmp(name, "xsi:schemaLocation") == 0) + return ret; + + switch (pstate->scope) + { + case PARSE_TYPE_SCOPE_TYPE_ENTRY: + if (ddsrt_strcasecmp(name, "type_identifier") == 0) + { + if (strlen (value) != 2 * TYPE_HASH_LENGTH) + { + PARSER_ERROR (pstate, line, "Invalid type identifier length"); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + free_type_meta_data (pstate->current); + } + else + { + pstate->current->type_hash = ddsrt_malloc (TYPE_HASH_LENGTH); + if ((ret = dds_sysdef_parse_hex (value, pstate->current->type_hash)) != SD_PARSE_RESULT_OK) + { + PARSER_ERROR (pstate, line, "Invalid type identifier"); + free_type_meta_data (pstate->current); + } + else + attr_processed = true; + } + } + break; + default: + break; + } + + if (!attr_processed && ret == SD_PARSE_RESULT_OK) + { + PARSER_ERROR (pstate, line, "Unexpected attribute '%s'", name); + ret = SD_PARSE_RESULT_SYNTAX_ERR; + if (pstate->scope == PARSE_TYPE_SCOPE_TYPE_ENTRY || pstate->scope == PARSE_TYPE_SCOPE_TYPE_INFO || pstate->scope == PARSE_TYPE_SCOPE_TYPE_MAP) + free_type_meta_data (pstate->current); + } + + return ret; +} + +static void proc_type_error (void *varg, const char *msg, int line) +{ + struct parse_type_state * const pstate = varg; + if (!pstate->has_err) + { + if (pstate->current != NULL) + free_type_meta_data (pstate->current); + PARSER_ERROR (pstate, line, "Syntax error '%s'", msg); + } +} + +dds_return_t dds_sysdef_init_data_types (FILE *fp, struct dds_sysdef_type_metadata_admin **type_meta_data) +{ + struct parse_type_state pstate = { 0 }; + struct ddsrt_xmlp_callbacks cb = { + .attr = proc_type_attr, + .elem_close = proc_type_elem_close, + .elem_data = proc_type_elem_data, + .elem_open = proc_type_elem_open, + .error = proc_type_error + }; + + struct ddsrt_xmlp_state *xmlps = ddsrt_xmlp_new_file (fp, &pstate, &cb); + + dds_return_t ret = DDS_RETCODE_OK; + if ((ret = ddsrt_xmlp_parse (xmlps)) != SD_PARSE_RESULT_OK) { + SYSDEF_ERROR ("Error parsing data types XML: %s (error code %d, line %d)\n", pstate.err_msg, ret, pstate.err_line); + ret = DDS_RETCODE_ERROR; + if (pstate.type_meta_data != NULL) + dds_sysdef_fini_data_types (pstate.type_meta_data); + } + else + { + *type_meta_data = pstate.type_meta_data; + } + + ddsrt_xmlp_free (xmlps); + return ret; +} + +static void free_type_meta_data_wrap (void *vnode, void *varg) +{ + (void) varg; + struct dds_sysdef_type_metadata *tmd = (struct dds_sysdef_type_metadata *) vnode; + free_type_meta_data (tmd); +} + +void dds_sysdef_fini_data_types (struct dds_sysdef_type_metadata_admin *type_meta_data) +{ + if (type_meta_data->m) + { + ddsrt_hh_enum (type_meta_data->m, free_type_meta_data_wrap, NULL); + ddsrt_hh_free (type_meta_data->m); + } + ddsrt_free (type_meta_data); +} diff --git a/src/core/ddsc/src/dds_sysdef_validation.c b/src/core/ddsc/src/dds_sysdef_validation.c new file mode 100644 index 0000000000..604cee088a --- /dev/null +++ b/src/core/ddsc/src/dds_sysdef_validation.c @@ -0,0 +1,141 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + +#include "string.h" +#include "dds/ddsrt/heap.h" +#include "dds__qos.h" +#include "dds__sysdef_validation.h" +#include "dds__sysdef_parser.h" + +#define CHECK_DUPLICATE(lib,element_type,element,element_attr,element_descr) \ + do { \ + for (const struct element_type *e2 = lib; e2 != NULL; e2 = (struct element_type *) e2->xmlnode.next) \ + { \ + if (element != e2 && element->element_attr != NULL && e2->element_attr != NULL && strcmp (element->element_attr, e2->element_attr) == 0) { \ + SYSDEF_ERROR ("Duplicate %s '%s'\n", element_descr, element->element_attr); \ + goto failed; \ + } \ + } \ + } while (0) + +#define CHECK_NULL_ATTR(lib,element_type,element,element_attr,element_descr) \ + do { \ + if (element->element_attr == NULL) { \ + SYSDEF_ERROR ("%s Attribute "#element_attr" is 'NULL'\n", element_descr); \ + goto failed; \ + } \ + } while (0) + +static void free_partitions (uint32_t n_partitions, char **partitions) +{ + for (uint32_t i = 0; i < n_partitions; i++) + ddsrt_free (partitions[i]); + ddsrt_free (partitions); +} + +static int is_wildcard_partition (const char *str) +{ + return strchr (str, '*') || strchr (str, '?'); +} + +static dds_return_t validate_qos (dds_qos_t *qos, const char *qos_location) +{ + // History + dds_history_kind_t history_kind; + int32_t history_depth; + if (dds_qget_history (qos, &history_kind, &history_depth) && (history_kind != DDS_HISTORY_KEEP_LAST || history_depth < 0)) + { + SYSDEF_ERROR ("Unsupported history kind or depth (%s)\n", qos_location); + goto failed; + } + + // Partition + uint32_t n_partitions; + char **partitions; + if (dds_qget_partition (qos, &n_partitions, &partitions)) + { + for (uint32_t i = 0; i < n_partitions; i++) + { + if (is_wildcard_partition (partitions[i])) + { + SYSDEF_ERROR ("Wildcards in partition name not supported (%s)\n", qos_location); + free_partitions (n_partitions, partitions); + goto failed; + } + } + free_partitions (n_partitions, partitions); + } + return DDS_RETCODE_OK; + +failed: + return DDS_RETCODE_BAD_PARAMETER; +} + +dds_return_t dds_validate_qos_lib (const struct dds_sysdef_system *sysdef, uint64_t qos_mask) +{ + for (const struct dds_sysdef_qos_lib *qos_lib = sysdef->qos_libs; qos_lib != NULL; qos_lib = (struct dds_sysdef_qos_lib *) qos_lib->xmlnode.next) + { + CHECK_NULL_ATTR(sysdef->qos_libs, dds_sysdef_qos_lib, qos_lib, name, "QoS library"); + CHECK_DUPLICATE(sysdef->qos_libs, dds_sysdef_qos_lib, qos_lib, name, "QoS library"); + for (const struct dds_sysdef_qos_profile *qos_profile = qos_lib->qos_profiles; qos_profile != NULL; qos_profile = (struct dds_sysdef_qos_profile *) qos_profile->xmlnode.next) + { + CHECK_NULL_ATTR(qos_lib->qos_profiles, dds_sysdef_qos_profile, qos_profile, name, "QoS profile"); + CHECK_DUPLICATE(qos_lib->qos_profiles, dds_sysdef_qos_profile, qos_profile, name, "QoS profile"); + for (const struct dds_sysdef_qos *qos = qos_profile->qos; qos != NULL; qos = (struct dds_sysdef_qos *) qos->xmlnode.next) + { + CHECK_DUPLICATE(qos_profile->qos, dds_sysdef_qos, qos, name, "QoS"); + + uint64_t mask = ~(uint64_t)0U; + const char *kind; + switch (qos->kind) + { + case DDS_SYSDEF_TOPIC_QOS: + mask = DDS_TOPIC_QOS_MASK & qos_mask; + kind = "topic"; + break; + case DDS_SYSDEF_READER_QOS: + mask = DDS_READER_QOS_MASK & qos_mask; + kind = "reader"; + break; + case DDS_SYSDEF_WRITER_QOS: + mask = DDS_WRITER_QOS_MASK & qos_mask; + kind = "writer"; + break; + case DDS_SYSDEF_SUBSCRIBER_QOS: + mask = DDS_SUBSCRIBER_QOS_MASK & qos_mask; + kind = "subscriber"; + break; + case DDS_SYSDEF_PUBLISHER_QOS: + mask = DDS_PUBLISHER_QOS_MASK & qos_mask; + kind = "publisher"; + break; + case DDS_SYSDEF_PARTICIPANT_QOS: + mask = DDS_PARTICIPANT_QOS_MASK & qos_mask; + kind = "participant"; + break; + } + + // Unsupported policies + if (qos->qos->present & ~mask) + { + SYSDEF_ERROR ("Unsupported policy, non-allowed mask: %08" PRIx64 " (%s::%s, %s QoS%s%s)\n", qos->qos->present & ~mask, qos_lib->name, qos_profile->name, kind, (qos->name != NULL ? " " : ""), (qos->name != NULL ? qos->name : "")); + goto failed; + } + + if (validate_qos (qos->qos, qos_profile->name) != DDS_RETCODE_OK) + goto failed; + } + } + } + return DDS_RETCODE_OK; + +failed: + return DDS_RETCODE_BAD_PARAMETER; +} diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt index 91b8af18d8..7f246cb03c 100644 --- a/src/core/ddsc/tests/CMakeLists.txt +++ b/src/core/ddsc/tests/CMakeLists.txt @@ -151,6 +151,11 @@ if(ENABLE_TOPIC_DISCOVERY) "topic_find_global.c") endif() +if(ENABLE_QOS_PROVIDER) + list(APPEND ddsc_test_sources + "qos_provider.c") +endif() + add_cunit_executable(cunit_ddsc ${ddsc_test_sources}) target_include_directories( cunit_ddsc PRIVATE diff --git a/src/core/ddsc/tests/qos_provider.c b/src/core/ddsc/tests/qos_provider.c new file mode 100644 index 0000000000..edf261e699 --- /dev/null +++ b/src/core/ddsc/tests/qos_provider.c @@ -0,0 +1,1205 @@ +// Copyright(c) 2024 ZettaScale Technology and others +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License +// v. 1.0 which is available at +// http://www.eclipse.org/org/documents/edl-v10.php. +// +// SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause +#include "CUnit/Theory.h" +#include "dds/dds.h" + +#include "dds/ddsc/dds_public_qos_provider.h" + +#include "dds/ddsrt/hopscotch.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/random.h" +#include "dds/ddsrt/string.h" +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/io.h" + +#include "dds__qos.h" +#include "dds__sysdef_model.h" +#include "dds__qos_provider.h" + +#define DEF(libs) \ + "\n"libs"\n" +#define LIB(lib_name,profiles) \ + "\n "profiles"\n " +#define N_LIB(profiles) \ + "\n "profiles"\n " +#define PRO(prof_name,ents) \ + "\n "ents"\n " +#define N_PRO(ents) \ + "\n "ents"\n " +#define ENT(qos,kind) \ + "\n <" #kind "_qos>"qos"\n " +#define ENT_N(nm,qos,kind) \ + "\n <" #kind "_qos name=\""#nm"\">"qos"\n " + + +CU_TheoryDataPoints(qos_provider, create) = { + // The various of sysdef configuration files + CU_DataPoints(char *, + DEF(LIB(lib0,PRO(pro0,ENT("",datareader)ENT("",datawriter) + ENT("",publisher)ENT("",subscriber) + ENT("",domain_participant)ENT("",topic)))), + DEF(LIB(lib0,PRO(pro0,ENT("",datareader) + ENT_N(rd0,"",datareader)))), + DEF(LIB(lib0,PRO(pro0,ENT_N(rd0,"",datareader) + ENT_N(rd0,"",datareader)))), + DEF(LIB(lib0,PRO(pro0,ENT("",datareader) + ENT("",datareader)))), + DEF(LIB(lib0,PRO(pro0,ENT("",datareader)) + PRO(pro1,ENT("",datareader)))), + DEF(LIB(lib0,PRO(pro0,ENT("",datareader))) + LIB(lib1,PRO(pro0,ENT("",datareader)))), + DEF(LIB(lib0,PRO(pro0,ENT("",datareader)) + PRO(pro0,ENT("",datareader)))), + DEF(LIB(lib0,PRO(pro0,ENT("",datareader))) + LIB(lib0,PRO(pro1,ENT("",datareader)))), + DEF(LIB(lib0,N_PRO( ENT("",datareader)))), + DEF(N_LIB( PRO(pro0,ENT("",datareader)))), + ), + // Expected retcodes + CU_DataPoints(int32_t, + DDS_RETCODE_OK, + DDS_RETCODE_OK, + DDS_RETCODE_BAD_PARAMETER, + DDS_RETCODE_BAD_PARAMETER, + DDS_RETCODE_OK, + DDS_RETCODE_OK, + DDS_RETCODE_BAD_PARAMETER, + DDS_RETCODE_BAD_PARAMETER, + DDS_RETCODE_ERROR, + DDS_RETCODE_ERROR, + ) +}; +// @brief This tests creating qos_provider with different sysdef files. +CU_Theory((char *configuration, dds_return_t ret), qos_provider, create) +{ + dds_qos_provider_t *provider = NULL; + // init qos provider with given configuration file + dds_return_t ret_ac = dds_create_qos_provider(configuration, &provider); + if (ret_ac == DDS_RETCODE_OK) + dds_delete_qos_provider(provider); + CU_ASSERT_EQUAL(ret, ret_ac); +} + +#define NO_QOS_PROVIDER_CONF \ + DEF( \ + LIB(lib0, \ + PRO(pro00, \ + ENT("",datareader)ENT("",datawriter) \ + ENT_N(rd1,"",datareader) \ + ENT("",publisher)ENT("",subscriber) \ + ENT("",domain_participant)ENT("",topic)) \ + PRO(pro01, \ + ENT_N(rd0,"",datareader)ENT("",datawriter) \ + ENT("",publisher)ENT("",subscriber) \ + ENT("",domain_participant)ENT("",topic)) \ + PRO(pro02, \ + ENT_N(rd0,"",datareader)ENT_N(wr0,"",datawriter) \ + ENT("",publisher)ENT("",subscriber) \ + ENT("",domain_participant)ENT("",topic)) \ + PRO(pro03, \ + ENT_N(rd0,"",datareader)ENT_N(wr0,"",datawriter) \ + ENT_N(rd1,"",datareader)ENT_N(wr1,"",datawriter) \ + ENT_N(pb0,"",publisher)ENT("",subscriber) \ + ENT("",domain_participant)ENT("",topic)) \ + ) \ + LIB(lib1, \ + PRO(pro00, \ + ENT("",datareader)ENT("",datawriter) \ + ENT("",publisher)ENT("",subscriber) \ + ENT("",domain_participant)ENT("",topic)) \ + PRO(pro01, \ + ENT("",datareader)ENT("",datawriter) \ + ENT("",publisher)ENT("",subscriber) \ + ENT("",domain_participant)ENT_N(tp0,"",topic)) \ + PRO(pro02, \ + ENT("",datareader)ENT("",datawriter) \ + ENT("",publisher)ENT("",subscriber) \ + ENT_N(pp0,"",domain_participant)ENT_N(tp0,"",topic)) \ + PRO(pro03, \ + ENT("",datareader)ENT("",datawriter) \ + ENT("",publisher)ENT_N(sb0,"",subscriber) \ + ENT_N(pp0,"",domain_participant)ENT_N(tp0,"",topic)) \ + ) \ + LIB(lib2, \ + PRO(pro01, \ + ENT_N(rd0,"",datareader)ENT_N(tp0,"",topic)) \ + PRO(pro02, \ + ENT_N(rd0,"",datareader)ENT_N(wr0,"",datawriter) \ + ENT_N(pp0,"",domain_participant)ENT_N(tp0,"",topic)) \ + PRO(pro03, \ + ENT_N(rd0,"",datareader)ENT_N(wr0,"",datawriter) \ + ENT_N(pb0,"",publisher)ENT_N(sb0,"",subscriber) \ + ENT_N(pp0,"",domain_participant)ENT_N(tp0,"",topic)) \ + ) \ + ) \ + +typedef struct cscope_tokens +{ + char *scope; + char *expct; +} cscope_tokens_t; + +#define SCOPE(scp,exp) {.scope=scp, .expct=exp} +#define N NO_QOS_PROVIDER_CONF +CU_TheoryDataPoints(qos_provider, create_scope) = { + // The sysdef file with multiple libs/profiles/entity qos. + CU_DataPoints(char *, + N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N), + // The scopes for initialize qos_provider (scope) + // and pattern that all qos in qos_provider should match with (pattern) + // SCOPE(,) + CU_DataPoints(cscope_tokens_t, + SCOPE("*","::"), SCOPE("lib1","lib1::"), SCOPE("lib0::*","lib0::"), + SCOPE("lib0::pro00","lib0::pro00"), SCOPE("lib0::pro00::","lib0::pro00"), + SCOPE("*::","::"), SCOPE("*::pro00::*","::pro00"), SCOPE("::pro00","::pro00"), + SCOPE("*::*::rd0","::rd0"), SCOPE("::::::","::"), SCOPE("::","::"), + SCOPE("::::rd0","::rd0"), SCOPE("lib3",""), SCOPE("lib2::pro10",""), + SCOPE("lib0::pro01::rd0","lib0::pro01::rd0"), SCOPE("lib2::*::tp0","::tp0"), + SCOPE("lib2::*::sb0","lib2::pro03::sb0"), SCOPE("::pro03::rd0", "::pro03::rd0"), + SCOPE("**", "::"), SCOPE("::!:absolutely:***::wrong*scope;", "")), + // The number of expected qos that qos_provider contains when created with (scope) above. + CU_DataPoints(int32_t, + 63, 24, 27, + 7, 7, + 63, 13, 13, + 6, 63, 63, + 6, 0, 0, + 1, 3, + 1, 2, + 63, 0) +}; +#undef N +#undef SCOPE + +struct cscope_inspect_arg +{ + char *scope; + int32_t n; +}; + +static void inspect_qos_items(void *vnode, void *vargs) +{ + dds_qos_item_t *item = (dds_qos_item_t *) vnode; + struct cscope_inspect_arg *arg = (struct cscope_inspect_arg *)vargs; + CU_ASSERT_NOT_EQUAL(strstr(item->full_name, arg->scope), NULL); + --arg->n; +} + +// @brief This tests creating qos_provider with the same sysdef file but with different scope. +CU_Theory((char * configuration, cscope_tokens_t tok, int32_t n),qos_provider, create_scope) +{ + dds_qos_provider_t *provider = NULL; + // init qos provider with given scope + dds_return_t ret = dds_create_qos_provider_scope(configuration, &provider, tok.scope); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK); + struct cscope_inspect_arg arg = {.scope = tok.expct, .n = n}; + // examinate qos in qos provider + ddsrt_hh_enum(provider->keyed_qos, inspect_qos_items, &arg); + CU_ASSERT_EQUAL(arg.n, 0); + dds_delete_qos_provider(provider); +} + +#define N NO_QOS_PROVIDER_CONF +#define RD DDS_READER_QOS +#define WR DDS_WRITER_QOS +#define PP DDS_PARTICIPANT_QOS +#define PB DDS_PUBLISHER_QOS +#define SB DDS_SUBSCRIBER_QOS +#define TP DDS_TOPIC_QOS +#define OK DDS_RETCODE_OK +#define BAD DDS_RETCODE_BAD_PARAMETER +CU_TheoryDataPoints(qos_provider, get_qos) = { + // The sysdef file with multiple libs/profiles/entity qos + CU_DataPoints(char *, + N,N,N,N,N,N, + N,N,N,N,N, + N,N,N,N,N), + // Keys which qos we would like to get + CU_DataPoints(char *, + "lib0::pro00","lib0::pro00","lib0::pro00","lib0::pro00","lib0::pro00","lib0::pro00", + "lib0::pro00::pb0","lib2::pro01::sb0","lib0::pro01::rd0","lib0::pro03","lib0::pro03::rd1", + "lib0::pro00","lib0::*","*::pro00::rd1","*","lib2::pro01"), + // Type of entity for which qos we try to get + CU_DataPoints(dds_qos_kind_t, + RD,WR,PP,PB,SB,TP, + PB,SB,RD,RD,RD, + RD,WR,RD,PP,PP), + // Expected retcodes + CU_DataPoints(dds_return_t, + OK,OK,OK,OK,OK,OK, + BAD,BAD,OK,BAD,OK, + OK,BAD,BAD,BAD,BAD) +}; +#undef BAD +#undef OK +#undef TP +#undef SB +#undef PB +#undef PP +#undef WR +#undef RD +#undef N + +CU_Theory((char *configuration, char *key, dds_qos_kind_t kind, dds_return_t code),qos_provider, get_qos) +{ + dds_qos_provider_t *provider = NULL; + // init qos provider with provided configuration + dds_return_t ret = dds_create_qos_provider(configuration, &provider); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK); + const dds_qos_t *qos; + // try to get qos with `key`, `kind` + ret = dds_qos_provider_get_qos(provider, kind, key, &qos); + CU_ASSERT_EQUAL(ret, code); + // check that retcode eq to expected + dds_delete_qos_provider(provider); +} + +#define QOS_DURATION_FMT(unit) \ + "<"#unit">%lli" +#define QOS_DURATION_FMT_STR(unit) \ + "<"#unit">%s" +#define QOS_POLICY_DEADLINE_PERIOD_FMT(duration_fmt) \ + ""duration_fmt"" +#define QOS_POLICY_DEADLINE_FMT(unit) \ + ""QOS_POLICY_DEADLINE_PERIOD_FMT(unit)"" +#define QOS_POLICY_DESTINATION_ORDER_FMT(k) \ + ""#k"" +#define QOS_POLICY_DURABILITY_FMT(k) \ + ""#k"" +#define QOS_HISTORY_FMT(hk) \ + ""#hk"%d" +#define QOS_SERVICE_CLEANUP_DELAY_FMT(duration_fmt) \ + ""duration_fmt"" +#define QOS_RESOURCE_LIMITS_MS(ms_f) \ + ""ms_f"" +#define QOS_RESOURCE_LIMITS_MI(mi_f) \ + ""mi_f"" +#define QOS_RESOURCE_LIMITS_MSPI(mspi_f) \ + ""mspi_f"" +#define QOS_RESOURCE_LIMITS \ + "%s%s%s" +#define QOS_DURABILITY_SERVICE_HISTORY(hk) \ + ""#hk"%d" +#define QOS_POLICY_DURABILITY_SERVICE_FMT \ + "%s%s"QOS_RESOURCE_LIMITS"" +#define QOS_POLICY_ENTITYFACTORY_FMT(val) \ + "" \ + ""#val"" \ + "" +#define QOS_BASE64_VALUE \ + "%s" +#define QOS_POLICY_GOUPDATA_FMT \ + ""QOS_BASE64_VALUE"" +#define QOS_POLICY_HISTORY_FMT(hk) \ + QOS_HISTORY_FMT(hk) +#define QOS_POLICY_LATENCYBUDGET_FMT(duration_fmt) \ + ""duration_fmt"" +#define QOS_POLICY_LIFESPAN_FMT(duration_fmt) \ + ""duration_fmt"" +#define QOS_LIVELINESS_KIND(lk) \ + ""#lk"" +#define QOS_LIVELINESS_DURATION(duration_fmt) \ + ""duration_fmt"" +#define QOS_POLICY_LIVELINESS_FMT \ + "%s%s" +#define QOS_POLICY_OWNERSHIP_FMT(ok) \ + ""#ok"" +#define QOS_POLICY_OWNERSHIPSTRENGTH_FMT \ + "%d" +#define QOS_PARTITION_ELEMENT \ + "%s" +#define QOS_POLIC_PARTITION_FMT \ + "%s" +#define QOS_ACCESS_SCOPE_KIND(ask) \ + ""#ask"" +#define QOS_COHERENT_ACCESS(ca) \ + ""#ca"" +#define QOS_ORDERED_ACCESS(oa) \ + ""#oa"" +#define QOS_POLICY_PRESENTATION_FMT \ + "%s%s%s" +#define QOS_RELIABILITY_KIND(rk) \ + ""#rk"" +#define QOS_RELIABILITY_DURATION(duration_fmt) \ + ""duration_fmt"" +#define QOS_POLICY_RELIABILITY_FMT \ + "%s%s" +#define QOS_POLICY_RESOURCE_LIMITS_FMT \ + ""QOS_RESOURCE_LIMITS"" +#define QOS_POLICY_TIMEBASEDFILTER_FMT(duration_fmt) \ + "" \ + duration_fmt \ + "" +#define QOS_POLICY_TOPICDATA_FMT \ + ""QOS_BASE64_VALUE"" +#define QOS_POLICY_TRANSPORTPRIORITY_FMT \ + "%d" +#define QOS_POLICY_USERDATA_FMT \ + ""QOS_BASE64_VALUE"" +#define QOS_NOWRITER_DELAY(duration_fmt) \ + ""duration_fmt"" +#define QOS_DISPOSED_DELAY(duration_fmt) \ + "" \ + duration_fmt \ + "" +#define QOS_POLICY_READERDATALIFECYCLE_FMT \ + "%s%s" +#define QOS_POLICY_WRITERDATA_LIFECYCLE_FMT(aui) \ + "" \ + ""#aui"" \ + "" + +enum duration_unit +{ + sec = 0, + nsec = 1 +}; + +typedef struct sysdef_qos_conf +{ + enum duration_unit deadline_unit; + enum duration_unit durability_serv_unit; + enum duration_unit latency_budget_unit; + enum duration_unit lifespan_unit; + enum duration_unit liveliness_unit; + enum duration_unit reliability_unit; + enum duration_unit time_based_filter_unit; + enum duration_unit reader_data_lifecycle_nowriter_unit; + enum duration_unit reader_data_lifecycle_disposed_unit; +} sysdef_qos_conf_t; + +#define QOS_FORMAT " " +#define CHECK_RET_OK(ret) \ + if (ret < 0) goto fail; +static inline dds_return_t qos_to_conf(dds_qos_t *qos, const sysdef_qos_conf_t *conf, char **out, dds_qos_kind_t kind, uint64_t *validate_mask, const bool ignore_ent) +{ + char *sysdef_qos = ddsrt_strdup(""); + dds_return_t ret = DDS_RETCODE_OK; + if ((ignore_ent || (kind == DDS_TOPIC_QOS || kind == DDS_READER_QOS || kind == DDS_WRITER_QOS)) && + (ret >= 0) && (qos->present & DDSI_QP_DEADLINE)) + { + char *deadline; + if (qos->deadline.deadline == DDS_INFINITY) + { + if (conf->deadline_unit == sec) + ret = ddsrt_asprintf(&deadline, QOS_POLICY_DEADLINE_FMT(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&deadline, QOS_POLICY_DEADLINE_FMT(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->deadline_unit == sec) + ret = ddsrt_asprintf(&deadline, QOS_POLICY_DEADLINE_FMT(QOS_DURATION_FMT(sec)), + (long long)(qos->deadline.deadline/DDS_NSECS_IN_SEC)); + else + ret = ddsrt_asprintf(&deadline, QOS_POLICY_DEADLINE_FMT(QOS_DURATION_FMT(nanosec)), + (long long)qos->deadline.deadline); + } + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, deadline); + ddsrt_free(tmp); + ddsrt_free(deadline); + *validate_mask |= DDSI_QP_DEADLINE; + } + if ((ignore_ent || (kind == DDS_TOPIC_QOS || kind == DDS_READER_QOS || kind == DDS_WRITER_QOS)) && + (ret >= 0) && (qos->present & DDSI_QP_DESTINATION_ORDER)) + { + char *dest_order; + if (qos->destination_order.kind == DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP) + ret = ddsrt_asprintf(&dest_order, "%s", QOS_POLICY_DESTINATION_ORDER_FMT(BY_RECEPTION_TIMESTAMP_DESTINATIONORDER_QOS)); + else + ret = ddsrt_asprintf(&dest_order, "%s", QOS_POLICY_DESTINATION_ORDER_FMT(BY_SOURCE_TIMESTAMP_DESTINATIONORDER_QOS)); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, dest_order); + ddsrt_free(tmp); + ddsrt_free(dest_order); + *validate_mask |= DDSI_QP_DESTINATION_ORDER; + } + if ((ignore_ent || (kind != DDS_SUBSCRIBER_QOS && kind != DDS_PUBLISHER_QOS && kind != DDS_PARTICIPANT_QOS)) && + (ret >= 0) && (qos->present & DDSI_QP_DURABILITY)) + { + char *durability; + if (qos->durability.kind == DDS_DURABILITY_VOLATILE) + ret = ddsrt_asprintf(&durability, "%s", QOS_POLICY_DURABILITY_FMT(VOLATILE_DURABILITY_QOS)); + else if (qos->durability.kind == DDS_DURABILITY_TRANSIENT_LOCAL) + ret = ddsrt_asprintf(&durability, "%s", QOS_POLICY_DURABILITY_FMT(TRANSIENT_LOCAL_DURABILITY_QOS)); + else if (qos->durability.kind == DDS_DURABILITY_TRANSIENT) + ret = ddsrt_asprintf(&durability, "%s", QOS_POLICY_DURABILITY_FMT(TRANSIENT_DURABILITY_QOS)); + else + ret = ddsrt_asprintf(&durability, "%s", QOS_POLICY_DURABILITY_FMT(PERSISTENT_DURABILITY_QOS)); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, durability); + ddsrt_free(tmp); + ddsrt_free(durability); + *validate_mask |= DDSI_QP_DURABILITY; + } + if ((ignore_ent || (kind == DDS_WRITER_QOS || kind == DDS_TOPIC_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_DURABILITY_SERVICE) + { + char *service_cleanup_delay; + if (qos->durability_service.service_cleanup_delay == DDS_INFINITY) + { + if (conf->durability_serv_unit == sec) + ret = ddsrt_asprintf(&service_cleanup_delay, QOS_SERVICE_CLEANUP_DELAY_FMT(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&service_cleanup_delay, QOS_SERVICE_CLEANUP_DELAY_FMT(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->durability_serv_unit == sec) + ret = ddsrt_asprintf(&service_cleanup_delay, QOS_SERVICE_CLEANUP_DELAY_FMT(QOS_DURATION_FMT(sec)), + (long long)qos->durability_service.service_cleanup_delay/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&service_cleanup_delay, QOS_SERVICE_CLEANUP_DELAY_FMT(QOS_DURATION_FMT(nanosec)), + (long long)qos->durability_service.service_cleanup_delay); + } + CHECK_RET_OK(ret); + char *history; + if (qos->durability_service.history.kind == DDS_HISTORY_KEEP_LAST) + ret = ddsrt_asprintf(&history, QOS_DURABILITY_SERVICE_HISTORY(KEEP_LAST_HISTORY_QOS), qos->durability_service.history.depth); + else + ret = ddsrt_asprintf(&history, QOS_DURABILITY_SERVICE_HISTORY(KEEP_ALL_HISTORY_QOS), qos->durability_service.history.depth); + CHECK_RET_OK(ret); + char *durability_service; + int32_t ms,mi,mspi; + ms = qos->durability_service.resource_limits.max_samples; + mi = qos->durability_service.resource_limits.max_instances; + mspi = qos->durability_service.resource_limits.max_samples_per_instance; + char *ms_f,*mi_f,*mspi_f; + (void) ddsrt_asprintf(&ms_f,(ms<0? QOS_RESOURCE_LIMITS_MS(QOS_LENGTH_UNLIMITED): QOS_RESOURCE_LIMITS_MS("%d")), ms); + (void) ddsrt_asprintf(&mi_f,(mi<0? QOS_RESOURCE_LIMITS_MI(QOS_LENGTH_UNLIMITED): QOS_RESOURCE_LIMITS_MI("%d")), mi); + (void) ddsrt_asprintf(&mspi_f,(mspi<0? QOS_RESOURCE_LIMITS_MSPI(QOS_LENGTH_UNLIMITED): QOS_RESOURCE_LIMITS_MSPI("%d")), mspi); + ret = ddsrt_asprintf(&durability_service, QOS_POLICY_DURABILITY_SERVICE_FMT, service_cleanup_delay, history, ms_f, mi_f, mspi_f); + ddsrt_free(ms_f);ddsrt_free(mi_f);ddsrt_free(mspi_f); + ddsrt_free(service_cleanup_delay); + ddsrt_free(history); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, durability_service); + ddsrt_free(tmp); + ddsrt_free(durability_service); + *validate_mask |= DDSI_QP_DURABILITY_SERVICE; + } + if ((ignore_ent || (kind == DDS_PARTICIPANT_QOS || kind == DDS_PUBLISHER_QOS || kind == DDS_SUBSCRIBER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_ADLINK_ENTITY_FACTORY) + { + char *entity_factory; + if (qos->entity_factory.autoenable_created_entities == 0) + ret = ddsrt_asprintf(&entity_factory, "%s", QOS_POLICY_ENTITYFACTORY_FMT(false)); + else + ret = ddsrt_asprintf(&entity_factory, "%s", QOS_POLICY_ENTITYFACTORY_FMT(true)); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, entity_factory); + ddsrt_free(tmp); + ddsrt_free(entity_factory); + *validate_mask |= DDSI_QP_ADLINK_ENTITY_FACTORY; + } + if ((ignore_ent || (kind == DDS_PUBLISHER_QOS || kind == DDS_SUBSCRIBER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_GROUP_DATA) + { + if (qos->group_data.length > 0) + { + char *data = ddsrt_strdup(""); + for (uint32_t i = 0; i < qos->group_data.length; i++) { + char *tmp = data; + ret = ddsrt_asprintf(&data, "%s%c", data, qos->group_data.value[i]); + ddsrt_free(tmp); + CHECK_RET_OK(ret); + } + char *group_data; + ret = ddsrt_asprintf(&group_data, QOS_POLICY_GOUPDATA_FMT, data); + ddsrt_free(data); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, group_data); + ddsrt_free(tmp); + ddsrt_free(group_data); + *validate_mask |= DDSI_QP_GROUP_DATA; + } + } + if ((ignore_ent || (kind == DDS_TOPIC_QOS || kind == DDS_READER_QOS || kind == DDS_WRITER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_HISTORY) + { + char *history; + if (qos->history.kind == DDS_HISTORY_KEEP_LAST) + ret = ddsrt_asprintf(&history, QOS_POLICY_HISTORY_FMT(KEEP_LAST_HISTORY_QOS), qos->history.depth); + else + ret = ddsrt_asprintf(&history, QOS_POLICY_HISTORY_FMT(KEEP_ALL_HISTORY_QOS), qos->history.depth); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, history); + ddsrt_free(tmp); + ddsrt_free(history); + *validate_mask |= DDSI_QP_HISTORY; + } + if ((ignore_ent || (kind == DDS_TOPIC_QOS || kind == DDS_WRITER_QOS || kind == DDS_READER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_LATENCY_BUDGET) + { + char *latency_budget; + if (qos->latency_budget.duration == DDS_INFINITY) + { + if (conf->latency_budget_unit == sec) + ret = ddsrt_asprintf(&latency_budget, QOS_POLICY_LATENCYBUDGET_FMT(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&latency_budget, QOS_POLICY_LATENCYBUDGET_FMT(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->latency_budget_unit == sec) + ret = ddsrt_asprintf(&latency_budget, QOS_POLICY_LATENCYBUDGET_FMT(QOS_DURATION_FMT(sec)), + (long long)qos->latency_budget.duration/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&latency_budget, QOS_POLICY_LATENCYBUDGET_FMT(QOS_DURATION_FMT(nanosec)), + (long long)qos->latency_budget.duration); + } + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, latency_budget); + ddsrt_free(tmp); + ddsrt_free(latency_budget); + *validate_mask |= DDSI_QP_LATENCY_BUDGET; + } + if ((ignore_ent || (kind == DDS_WRITER_QOS || kind == DDS_TOPIC_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_LIFESPAN) + { + char *lifespan; + if (qos->lifespan.duration == DDS_INFINITY) + { + if (conf->lifespan_unit == sec) + ret = ddsrt_asprintf(&lifespan, QOS_POLICY_LIFESPAN_FMT(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&lifespan, QOS_POLICY_LIFESPAN_FMT(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->lifespan_unit == sec) + ret = ddsrt_asprintf(&lifespan, QOS_POLICY_LIFESPAN_FMT(QOS_DURATION_FMT(sec)), + (long long)qos->lifespan.duration/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&lifespan, QOS_POLICY_LIFESPAN_FMT(QOS_DURATION_FMT(nanosec)), + (long long)qos->lifespan.duration); + } + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, lifespan); + ddsrt_free(tmp); + ddsrt_free(lifespan); + *validate_mask |= DDSI_QP_LIFESPAN; + } + if ((ignore_ent || (kind != DDS_PUBLISHER_QOS && kind != DDS_SUBSCRIBER_QOS && kind != DDS_PARTICIPANT_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_LIVELINESS) + { + char *duration; + if (qos->liveliness.lease_duration == DDS_INFINITY) + { + if (conf->liveliness_unit == sec) + ret = ddsrt_asprintf(&duration, QOS_LIVELINESS_DURATION(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&duration, QOS_LIVELINESS_DURATION(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->liveliness_unit == sec) + ret = ddsrt_asprintf(&duration, QOS_LIVELINESS_DURATION(QOS_DURATION_FMT(sec)), + (long long)qos->liveliness.lease_duration/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&duration, QOS_LIVELINESS_DURATION(QOS_DURATION_FMT(nanosec)), + (long long)qos->liveliness.lease_duration); + } + CHECK_RET_OK(ret); + char *liveliness_kind; + if (qos->liveliness.kind == DDS_LIVELINESS_AUTOMATIC) + ret = ddsrt_asprintf(&liveliness_kind, "%s", QOS_LIVELINESS_KIND(AUTOMATIC_LIVELINESS_QOS)); + else if (qos->liveliness.kind == DDS_LIVELINESS_MANUAL_BY_PARTICIPANT) + ret = ddsrt_asprintf(&liveliness_kind, "%s", QOS_LIVELINESS_KIND(MANUAL_BY_PARTICIPANT_LIVELINESS_QOS)); + else + ret = ddsrt_asprintf(&liveliness_kind, "%s", QOS_LIVELINESS_KIND(MANUAL_BY_TOPIC_LIVELINESS_QOS)); + CHECK_RET_OK(ret); + char *liveliness; + ret = ddsrt_asprintf(&liveliness, QOS_POLICY_LIVELINESS_FMT, duration, liveliness_kind); + ddsrt_free(duration); + ddsrt_free(liveliness_kind); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, liveliness); + ddsrt_free(tmp); + ddsrt_free(liveliness); + *validate_mask |= DDSI_QP_LIVELINESS; + } + if ((ignore_ent || (kind != DDS_PUBLISHER_QOS && kind != DDS_SUBSCRIBER_QOS && kind != DDS_PARTICIPANT_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_OWNERSHIP) + { + char *ownership; + if (qos->ownership.kind == DDS_OWNERSHIP_SHARED) + ret = ddsrt_asprintf(&ownership, "%s", QOS_POLICY_OWNERSHIP_FMT(SHARED_OWNERSHIP_QOS)); + else + ret = ddsrt_asprintf(&ownership, "%s", QOS_POLICY_OWNERSHIP_FMT(EXCLUSIVE_OWNERSHIP_QOS)); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, ownership); + ddsrt_free(tmp); + ddsrt_free(ownership); + *validate_mask |= DDSI_QP_OWNERSHIP; + } + if ((ignore_ent || (kind == DDS_WRITER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_OWNERSHIP_STRENGTH) + { + char *ownership_strength; + ret = ddsrt_asprintf(&ownership_strength, QOS_POLICY_OWNERSHIPSTRENGTH_FMT, qos->ownership_strength.value); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, ownership_strength); + ddsrt_free(tmp); + ddsrt_free(ownership_strength); + *validate_mask |= DDSI_QP_OWNERSHIP_STRENGTH; + } + if ((ignore_ent || (kind == DDS_PUBLISHER_QOS || kind == DDS_SUBSCRIBER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_PARTITION) + { + if (qos->partition.n > 0) + { + char *part_elems = ddsrt_strdup(""); + for (uint32_t i = 0; i < qos->partition.n; i++) { + char *tmp = part_elems; + ret = ddsrt_asprintf(&part_elems, "%s"QOS_PARTITION_ELEMENT, part_elems, qos->partition.strs[i]); + CHECK_RET_OK(ret); + ddsrt_free(tmp); + } + CHECK_RET_OK(ret); + char *partition; + ret = ddsrt_asprintf(&partition, QOS_POLIC_PARTITION_FMT, part_elems); + ddsrt_free(part_elems); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, partition); + ddsrt_free(tmp); + ddsrt_free(partition); + *validate_mask |= DDSI_QP_PARTITION; + } + } + if ((ignore_ent || (kind == DDS_PUBLISHER_QOS || kind == DDS_SUBSCRIBER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_PRESENTATION) + { + char *access_scope_kind; + if (qos->presentation.access_scope == DDS_PRESENTATION_INSTANCE) + ret = ddsrt_asprintf(&access_scope_kind, QOS_ACCESS_SCOPE_KIND(INSTANCE_PRESENTATION_QOS)); + else if (qos->presentation.access_scope == DDS_PRESENTATION_TOPIC) + ret = ddsrt_asprintf(&access_scope_kind, QOS_ACCESS_SCOPE_KIND(TOPIC_PRESENTATION_QOS)); + else + ret = ddsrt_asprintf(&access_scope_kind, QOS_ACCESS_SCOPE_KIND(GROUP_PRESENTATION_QOS)); + CHECK_RET_OK(ret); + char *coherent_access; + if (qos->presentation.coherent_access) + ret = ddsrt_asprintf(&coherent_access, "%s", QOS_COHERENT_ACCESS(true)); + else + ret = ddsrt_asprintf(&coherent_access, "%s", QOS_COHERENT_ACCESS(false)); + CHECK_RET_OK(ret); + char *ordered_access; + if (qos->presentation.ordered_access) + ret = ddsrt_asprintf(&ordered_access, "%s", QOS_ORDERED_ACCESS(true)); + else + ret = ddsrt_asprintf(&ordered_access, "%s", QOS_ORDERED_ACCESS(false)); + CHECK_RET_OK(ret); + char *presentation; + ret = ddsrt_asprintf(&presentation, QOS_POLICY_PRESENTATION_FMT, access_scope_kind, coherent_access, ordered_access); + ddsrt_free(access_scope_kind); + ddsrt_free(coherent_access); + ddsrt_free(ordered_access); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, presentation); + ddsrt_free(tmp); + ddsrt_free(presentation); + *validate_mask |= DDSI_QP_PRESENTATION; + } + if ((ignore_ent || (kind == DDS_TOPIC_QOS || kind == DDS_READER_QOS || kind == DDS_WRITER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_RELIABILITY) + { + char *max_blocking_time; + if (qos->reliability.max_blocking_time == DDS_INFINITY) + { + if (conf->reliability_unit == sec) + ret = ddsrt_asprintf(&max_blocking_time, QOS_RELIABILITY_DURATION(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&max_blocking_time, QOS_RELIABILITY_DURATION(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->reliability_unit == sec) + ret = ddsrt_asprintf(&max_blocking_time, QOS_RELIABILITY_DURATION(QOS_DURATION_FMT(sec)), + (long long)qos->reliability.max_blocking_time/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&max_blocking_time, QOS_RELIABILITY_DURATION(QOS_DURATION_FMT(nanosec)), + (long long)qos->reliability.max_blocking_time); + } + CHECK_RET_OK(ret); + char *reliability_kind; + if (qos->reliability.kind == DDS_RELIABILITY_BEST_EFFORT) + ret = ddsrt_asprintf(&reliability_kind, "%s", QOS_RELIABILITY_KIND(BEST_EFFORT_RELIABILITY_QOS)); + else + ret = ddsrt_asprintf(&reliability_kind, "%s", QOS_RELIABILITY_KIND(RELIABLE_RELIABILITY_QOS)); + CHECK_RET_OK(ret); + char *reliability; + ret = ddsrt_asprintf(&reliability, QOS_POLICY_RELIABILITY_FMT, max_blocking_time, reliability_kind); + ddsrt_free(max_blocking_time); + ddsrt_free(reliability_kind); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, reliability); + ddsrt_free(tmp); + ddsrt_free(reliability); + *validate_mask |= DDSI_QP_RELIABILITY; + } + if ((ignore_ent || (kind == DDS_TOPIC_QOS || kind == DDS_READER_QOS || kind == DDS_WRITER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_RESOURCE_LIMITS) + { + int32_t ms,mi,mspi; + ms = qos->resource_limits.max_samples; + mi = qos->resource_limits.max_instances; + mspi = qos->resource_limits.max_samples_per_instance; + char *ms_f,*mi_f,*mspi_f; + (void) ddsrt_asprintf(&ms_f,(ms<0? QOS_RESOURCE_LIMITS_MS(QOS_LENGTH_UNLIMITED): QOS_RESOURCE_LIMITS_MS("%d")), ms); + (void) ddsrt_asprintf(&mi_f,(mi<0? QOS_RESOURCE_LIMITS_MI(QOS_LENGTH_UNLIMITED): QOS_RESOURCE_LIMITS_MI("%d")), mi); + (void) ddsrt_asprintf(&mspi_f,(mspi<0? QOS_RESOURCE_LIMITS_MSPI(QOS_LENGTH_UNLIMITED): QOS_RESOURCE_LIMITS_MSPI("%d")), mspi); + char *resource_limits; + ret = ddsrt_asprintf(&resource_limits, QOS_POLICY_RESOURCE_LIMITS_FMT, ms_f, mi_f, mspi_f); + ddsrt_free(ms_f);ddsrt_free(mi_f);ddsrt_free(mspi_f); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, resource_limits); + ddsrt_free(tmp); + ddsrt_free(resource_limits); + *validate_mask |= DDSI_QP_RESOURCE_LIMITS; + } + if ((ignore_ent || (kind == DDS_READER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_TIME_BASED_FILTER) + { + char *time_based_filter; + if (qos->time_based_filter.minimum_separation == DDS_INFINITY) + { + if (conf->time_based_filter_unit == sec) + ret = ddsrt_asprintf(&time_based_filter, QOS_POLICY_TIMEBASEDFILTER_FMT(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&time_based_filter, QOS_POLICY_TIMEBASEDFILTER_FMT(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->time_based_filter_unit == sec) + ret = ddsrt_asprintf(&time_based_filter, QOS_POLICY_TIMEBASEDFILTER_FMT(QOS_DURATION_FMT(sec)), + (long long)qos->time_based_filter.minimum_separation/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&time_based_filter, QOS_POLICY_TIMEBASEDFILTER_FMT(QOS_DURATION_FMT(nanosec)), + (long long)qos->time_based_filter.minimum_separation); + } + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, time_based_filter); + ddsrt_free(tmp); + ddsrt_free(time_based_filter); + *validate_mask |= DDSI_QP_TIME_BASED_FILTER; + } + if ((ignore_ent || (kind == DDS_TOPIC_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_TOPIC_DATA) + { + if (qos->topic_data.length > 0) + { + char *data = ddsrt_strdup(""); + for (uint32_t i = 0; i < qos->topic_data.length; i++) { + char *tmp = data; + ret = ddsrt_asprintf(&data, "%s%c", data, qos->topic_data.value[i]); + ddsrt_free(tmp); + CHECK_RET_OK(ret); + } + char *topic_data; + ret = ddsrt_asprintf(&topic_data, QOS_POLICY_TOPICDATA_FMT, data); + ddsrt_free(data); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, topic_data); + ddsrt_free(tmp); + ddsrt_free(topic_data); + *validate_mask |= DDSI_QP_TOPIC_DATA; + } + } + if ((ignore_ent || (kind == DDS_TOPIC_QOS || kind == DDS_WRITER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_TRANSPORT_PRIORITY) + { + char *priority; + ret = ddsrt_asprintf(&priority, QOS_POLICY_TRANSPORTPRIORITY_FMT, qos->transport_priority.value); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, priority); + ddsrt_free(tmp); + ddsrt_free(priority); + *validate_mask |= DDSI_QP_TRANSPORT_PRIORITY; + } + if ((ignore_ent || (kind == DDS_PARTICIPANT_QOS || kind == DDS_READER_QOS || kind == DDS_WRITER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_USER_DATA) + { + if (qos->user_data.length > 0) + { + char *data = ddsrt_strdup(""); + for (uint32_t i = 0; i < qos->user_data.length; i++) { + char *tmp = data; + ret = ddsrt_asprintf(&data, "%s%c", data, qos->user_data.value[i]); + ddsrt_free(tmp); + CHECK_RET_OK(ret); + } + char *user_data; + ret = ddsrt_asprintf(&user_data, QOS_POLICY_USERDATA_FMT, data); + ddsrt_free(data); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, user_data); + ddsrt_free(tmp); + ddsrt_free(user_data); + *validate_mask |= DDSI_QP_USER_DATA; + } + } + if ((ignore_ent || (kind == DDS_READER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_ADLINK_READER_DATA_LIFECYCLE) + { + char *nowriter_delay; + if (qos->reader_data_lifecycle.autopurge_nowriter_samples_delay == DDS_INFINITY) + { + if (conf->reader_data_lifecycle_nowriter_unit == sec) + ret = ddsrt_asprintf(&nowriter_delay, QOS_NOWRITER_DELAY(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&nowriter_delay, QOS_NOWRITER_DELAY(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->reader_data_lifecycle_nowriter_unit == sec) + ret = ddsrt_asprintf(&nowriter_delay, QOS_NOWRITER_DELAY(QOS_DURATION_FMT(sec)), + (long long)qos->reader_data_lifecycle.autopurge_nowriter_samples_delay/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&nowriter_delay, QOS_NOWRITER_DELAY(QOS_DURATION_FMT(nanosec)), + (long long)qos->reader_data_lifecycle.autopurge_nowriter_samples_delay); + } + CHECK_RET_OK(ret); + char *disposed_delay; + if (qos->reader_data_lifecycle.autopurge_disposed_samples_delay == DDS_INFINITY) + { + if (conf->reader_data_lifecycle_disposed_unit == sec) + ret = ddsrt_asprintf(&disposed_delay, QOS_DISPOSED_DELAY(QOS_DURATION_FMT_STR(sec)), + QOS_DURATION_INFINITY_SEC); + else + ret = ddsrt_asprintf(&disposed_delay, QOS_DISPOSED_DELAY(QOS_DURATION_FMT_STR(nanosec)), + QOS_DURATION_INFINITY_NSEC); + } else { + if (conf->reader_data_lifecycle_disposed_unit == sec) + ret = ddsrt_asprintf(&disposed_delay, QOS_DISPOSED_DELAY(QOS_DURATION_FMT(sec)), + (long long)qos->reader_data_lifecycle.autopurge_disposed_samples_delay/DDS_NSECS_IN_SEC); + else + ret = ddsrt_asprintf(&disposed_delay, QOS_DISPOSED_DELAY(QOS_DURATION_FMT(nanosec)), + (long long)qos->reader_data_lifecycle.autopurge_disposed_samples_delay); + } + CHECK_RET_OK(ret); + char *reader_data_lifecycle; + ret = ddsrt_asprintf(&reader_data_lifecycle, QOS_POLICY_READERDATALIFECYCLE_FMT, nowriter_delay, disposed_delay); + ddsrt_free(nowriter_delay); + ddsrt_free(disposed_delay); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, reader_data_lifecycle); + ddsrt_free(tmp); + ddsrt_free(reader_data_lifecycle); + *validate_mask |= DDSI_QP_ADLINK_READER_DATA_LIFECYCLE; + } + if ((ignore_ent || (kind == DDS_WRITER_QOS)) && + (ret >= 0) && qos->present & DDSI_QP_ADLINK_WRITER_DATA_LIFECYCLE) + { + char *writer_data_lifecycle; + if (qos->writer_data_lifecycle.autodispose_unregistered_instances) + ret = ddsrt_asprintf(&writer_data_lifecycle, "%s", QOS_POLICY_WRITERDATA_LIFECYCLE_FMT(true)); + else + ret = ddsrt_asprintf(&writer_data_lifecycle, "%s", QOS_POLICY_WRITERDATA_LIFECYCLE_FMT(false)); + CHECK_RET_OK(ret); + char *tmp = sysdef_qos; + ret = ddsrt_asprintf(&sysdef_qos, QOS_FORMAT"%s\n"QOS_FORMAT"%s", sysdef_qos, writer_data_lifecycle); + ddsrt_free(tmp); + ddsrt_free(writer_data_lifecycle); + *validate_mask |= DDSI_QP_ADLINK_WRITER_DATA_LIFECYCLE; + } + + *out = sysdef_qos; +fail: + return ret; +} + +#undef QOS_FORMAT + +static dds_qos_t get_supported_qos(dds_qos_t qos) +{ + qos.present &= ~DDSI_QP_ADLINK_ENTITY_FACTORY; + return qos; +} + +static dds_return_t get_single_configuration(dds_qos_t *qos, sysdef_qos_conf_t *conf, dds_qos_kind_t kind, char **out_conf, uint64_t *validate_mask) +{ + dds_return_t ret = DDS_RETCODE_OK; + char *qos_conf = NULL; + ret = qos_to_conf(qos, conf, &qos_conf, kind, validate_mask, false); + CU_ASSERT_TRUE(ret >= 0); + char *def = NULL; + switch(kind) + { + case DDS_PARTICIPANT_QOS: + def = DEF(LIB(lib1,PRO(pro00,ENT("%s",domain_participant)))); + break; + case DDS_PUBLISHER_QOS: + def = DEF(LIB(lib1,PRO(pro00,ENT("%s",publisher)))); + break; + case DDS_SUBSCRIBER_QOS: + def = DEF(LIB(lib1,PRO(pro00,ENT("%s",subscriber)))); + break; + case DDS_TOPIC_QOS: + def = DEF(LIB(lib1,PRO(pro00,ENT("%s",topic)))); + break; + case DDS_READER_QOS: + def = DEF(LIB(lib1,PRO(pro00,ENT("%s",datareader)))); + break; + case DDS_WRITER_QOS: + def = DEF(LIB(lib1,PRO(pro00,ENT("%s",datawriter)))); + break; + default: + ddsrt_free(qos_conf); + CU_FAIL("unsupported QOS_KIND"); + } + ret = ddsrt_asprintf(out_conf, def, qos_conf); + ddsrt_free(qos_conf); + CU_ASSERT_TRUE(ret >= 0); + + return ret; +} + +#define N nsec +#define S sec +CU_TheoryDataPoints(qos_provider, get_qos_default) = { + // The type of entity_qos that will be tested with it default qos. + CU_DataPoints(dds_qos_kind_t, + DDS_TOPIC_QOS,DDS_READER_QOS,DDS_WRITER_QOS), + // In which format / `duration` will be presented in sysdef file. + CU_DataPoints(sysdef_qos_conf_t, + {N,N,S,S,N,N,S,S,N},{S,S,S,S,S,N,S,S,N},{S,N,S,N,S,N,S,N,S}, + ), +}; +#undef N +#undef S + +// @brief This test check sysdef file qos created correctly by qos_provider (in this case with default qos). +CU_Theory((dds_qos_kind_t kind, sysdef_qos_conf_t dur_conf), qos_provider, get_qos_default) +{ + dds_return_t ret = DDS_RETCODE_OK; + char *full_configuration = NULL; + dds_qos_t qos; + switch(kind) + { + case DDS_PARTICIPANT_QOS: + qos = get_supported_qos(ddsi_default_qos_participant); + break; + case DDS_PUBLISHER_QOS: + qos = get_supported_qos(ddsi_default_qos_publisher_subscriber); + break; + case DDS_SUBSCRIBER_QOS: + qos = get_supported_qos(ddsi_default_qos_publisher_subscriber); + break; + case DDS_TOPIC_QOS: + qos = get_supported_qos(ddsi_default_qos_topic); + break; + case DDS_READER_QOS: + qos = get_supported_qos(ddsi_default_qos_reader); + break; + case DDS_WRITER_QOS: + qos = get_supported_qos(ddsi_default_qos_writer); + break; + default: + CU_FAIL("oops"); + break; + } + uint64_t validate_mask = 0; + // init configuraiton with qos of `kind` in sysdef format + ret = get_single_configuration(&qos, &dur_conf, kind, &full_configuration, &validate_mask); + CU_ASSERT_TRUE(ret >= 0); + dds_qos_provider_t *provider; + // init qos provider with create configuration + ret = dds_create_qos_provider(full_configuration, &provider); + ddsrt_free(full_configuration); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK); + const dds_qos_t *act_qos; + // get qos from provider + ret = dds_qos_provider_get_qos(provider, kind, "lib1::pro00", &act_qos); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK); + // calculate the difference between defined qos and qos from provider + uint64_t res = ddsi_xqos_delta(&qos, act_qos, validate_mask); + CU_ASSERT_EQUAL(act_qos->present, validate_mask); + CU_ASSERT_EQUAL(res, 0); + dds_delete_qos_provider(provider); + +} + +#define _C "abcdefghijklmnopqrstuvwxyz" +#define RND_UCHAR (unsigned char)(_C[ddsrt_random () % (uint32_t)(strlen(_C)-1)]) +#define RND_UCHAR3 (unsigned char[]){RND_UCHAR, RND_UCHAR, RND_UCHAR} +#define RND_CHAR (char)(_C[ddsrt_random () % (uint32_t)(strlen(_C)-1)]) +#define RND_CHAR4 (char[]){RND_CHAR, RND_CHAR, RND_CHAR, '\0'} +#define RND_CHAR3x4 (char *[]){RND_CHAR4, RND_CHAR4, RND_CHAR4} + +#define Q_DATA4(kind) .kind##_data={.value=RND_UCHAR3,.length=3}, +#define Q_DURABILITY(knd) .durability={.kind=knd}, +#define Q_DEADLINE(tm) .deadline={.deadline=tm}, +#define Q_LATENCYBUDGET(tm) .latency_budget={.duration=tm}, +#define Q_OWNERSHIP(knd) .ownership={.kind=knd}, +#define Q_LIVELINESS(knd,dur) .liveliness={.kind=knd,.lease_duration=dur}, +#define Q_RELIABILITY(knd,tm) .reliability={.kind=knd,.max_blocking_time=tm}, +#define Q_TRANSPORTPRIO(vl) .transport_priority={.value=vl}, +#define Q_LIFESPAN(dur) .lifespan={.duration=dur}, +#define Q_DESTINATIONORDER(knd) .destination_order={.kind=knd}, +#define Q_HISTORY(knd,dp) .history={.kind=knd,.depth=dp}, +#define Q_RESOURCELIMITS(ms,mi,mspmi) .resource_limits={.max_samples=ms,.max_instances=mi,.max_samples_per_instance=mspmi}, +#define Q_DATA3x4(kind) .kind={.strs=RND_CHAR3x4,.n=3}, +#define Q_PRESENATION(ask,oa,ca) .presentation={.access_scope=ask,.ordered_access=oa,.coherent_access=ca}, +#define Q_TIMEBASEDFILTER(dur) .time_based_filter={.minimum_separation=dur}, +#define Q_READERLIFECYCLE(adsd,ansd) .reader_data_lifecycle={.autopurge_disposed_samples_delay=adsd,.autopurge_nowriter_samples_delay=ansd}, +#define Q_OWNERSHIPSTRENGTH(vl) .ownership_strength={.value=vl}, +#define Q_WRITERLIFECYCLE(aui) .writer_data_lifecycle={.autodispose_unregistered_instances=aui}, +#define Q_DURABILITYSERVICE(dur,hk,hd,ms,mi,mspi) .durability_service={.service_cleanup_delay=dur,Q_HISTORY(hk,hd)Q_RESOURCELIMITS(ms,mi,mspi)}, + +#define QOS_ALL_PRESENT .present = DDSI_QP_TOPIC_DATA | DDSI_QP_DURABILITY | \ + DDSI_QP_DEADLINE | DDSI_QP_LATENCY_BUDGET | \ + DDSI_QP_OWNERSHIP | DDSI_QP_LIVELINESS | \ + DDSI_QP_RELIABILITY | DDSI_QP_TRANSPORT_PRIORITY | \ + DDSI_QP_LIFESPAN | DDSI_QP_DESTINATION_ORDER | \ + DDSI_QP_HISTORY | DDSI_QP_RESOURCE_LIMITS | \ + DDSI_QP_USER_DATA | DDSI_QP_PARTITION | \ + DDSI_QP_PRESENTATION | DDSI_QP_GROUP_DATA | \ + DDSI_QP_TIME_BASED_FILTER | DDSI_QP_ADLINK_READER_DATA_LIFECYCLE | \ + DDSI_QP_OWNERSHIP_STRENGTH | DDSI_QP_ADLINK_WRITER_DATA_LIFECYCLE | \ + DDSI_QP_DURABILITY_SERVICE, + +#define QOS_ALL_BASE { \ + QOS_ALL_PRESENT \ + Q_DATA4(topic)Q_DURABILITY(DDS_DURABILITY_VOLATILE) \ + Q_DEADLINE(DDS_SECS(1))Q_LATENCYBUDGET(DDS_SECS(1)) \ + Q_OWNERSHIP(DDS_OWNERSHIP_EXCLUSIVE)Q_LIVELINESS(DDS_LIVELINESS_AUTOMATIC,DDS_INFINITY) \ + Q_RELIABILITY(DDS_RELIABILITY_RELIABLE, DDS_SECS(1))Q_TRANSPORTPRIO(1000) \ + Q_LIFESPAN(DDS_SECS(1))Q_DESTINATIONORDER(DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP) \ + Q_HISTORY(DDS_HISTORY_KEEP_LAST,1)Q_RESOURCELIMITS(1,1,1) \ + Q_DATA4(user)Q_DATA3x4(partition) \ + Q_PRESENATION(DDS_PRESENTATION_TOPIC,1,1)Q_DATA4(group) \ + Q_TIMEBASEDFILTER(DDS_SECS(1))Q_READERLIFECYCLE(DDS_SECS(1), DDS_SECS(1)) \ + Q_OWNERSHIPSTRENGTH(100)Q_WRITERLIFECYCLE(1) \ + Q_DURABILITYSERVICE(DDS_SECS(1),DDS_HISTORY_KEEP_ALL,-1,1,1,1) \ + } + +CU_TheoryDataPoints(qos_provider, get_qos_all) = { + // The type of entity_qos that will be tested with custom qos. + CU_DataPoints(dds_qos_kind_t, + DDS_PARTICIPANT_QOS,DDS_PUBLISHER_QOS,DDS_SUBSCRIBER_QOS, + DDS_TOPIC_QOS,DDS_READER_QOS,DDS_WRITER_QOS), +}; + +#define Q QOS_ALL_BASE +// @brief This test check sysdef file qos created correctly by qos_provider +// (in this case with custom qos with all possible values presented). +CU_Theory((dds_qos_kind_t kind),qos_provider, get_qos_all) +{ + dds_return_t ret = DDS_RETCODE_OK; + char *full_configuration = NULL; + dds_qos_t qos = Q; + sysdef_qos_conf_t dur_conf = {sec,sec,sec,sec,sec,sec,sec,sec,sec}; + uint64_t validate_mask = 0; + // init configuraiton with qos of `kind` in sysdef format + ret = get_single_configuration(&qos, &dur_conf, kind, &full_configuration, &validate_mask); + CU_ASSERT_TRUE(ret >= 0); + dds_qos_provider_t *provider; + // init qos provider with create configuration + ret = dds_create_qos_provider(full_configuration, &provider); + ddsrt_free(full_configuration); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK); + const dds_qos_t *act_qos; + ret = dds_qos_provider_get_qos(provider, kind, "lib1::pro00", &act_qos); + CU_ASSERT_EQUAL(ret, DDS_RETCODE_OK); + // calculate the difference between defined qos and qos from provider + uint64_t res = ddsi_xqos_delta(&qos, act_qos, validate_mask); + CU_ASSERT_EQUAL(act_qos->present, validate_mask); + CU_ASSERT_EQUAL(res, 0); + dds_delete_qos_provider(provider); +} + +CU_TheoryDataPoints(qos_provider, create_wrong_qos) = { + // The type of entity_qos that will be tested with wrong qos + CU_DataPoints(dds_qos_kind_t, + DDS_PARTICIPANT_QOS,DDS_PUBLISHER_QOS,DDS_SUBSCRIBER_QOS, + DDS_TOPIC_QOS,DDS_READER_QOS,DDS_WRITER_QOS), + // Expected retcodes + CU_DataPoints(dds_return_t, + DDS_RETCODE_ERROR,DDS_RETCODE_ERROR,DDS_RETCODE_ERROR, + DDS_RETCODE_ERROR,DDS_RETCODE_ERROR,DDS_RETCODE_ERROR), +}; + +#define QOS_TO_CONF_SNGL(excl_msk,knd) \ + def = DEF(LIB(lib1,PRO(pro00,ENT("%s",knd)))); \ + qos.present ^= (excl_msk); \ + ret = qos_to_conf(&qos, &conf, &qos_conf, kind, &validate_mask, true); + +CU_Theory((dds_qos_kind_t kind, dds_return_t code),qos_provider, create_wrong_qos) +{ + dds_return_t ret = DDS_RETCODE_OK; + char *full_configuration = NULL; + dds_qos_t qos = Q; + sysdef_qos_conf_t conf = {sec,sec,sec,sec,sec,sec,sec,sec,sec}; + uint64_t validate_mask = 0; + char *def = NULL; + char *qos_conf = NULL; + // init sysdef configuration that contains qos that not related for this `kind` of entity + // (wrong for this entity kind) + switch(kind) + { + case DDS_PARTICIPANT_QOS: + QOS_TO_CONF_SNGL(DDS_PARTICIPANT_QOS_MASK,domain_participant); + break; + case DDS_PUBLISHER_QOS: + QOS_TO_CONF_SNGL(DDS_PUBLISHER_QOS_MASK,publisher); + break; + case DDS_SUBSCRIBER_QOS: + QOS_TO_CONF_SNGL(DDS_SUBSCRIBER_QOS_MASK,subscriber); + break; + case DDS_TOPIC_QOS: + QOS_TO_CONF_SNGL(DDS_TOPIC_QOS_MASK,topic); + break; + case DDS_READER_QOS: + QOS_TO_CONF_SNGL(DDS_READER_QOS_MASK,datareader); + break; + case DDS_WRITER_QOS: + QOS_TO_CONF_SNGL(DDS_WRITER_QOS_MASK,datawriter); + break; + default: + CU_FAIL("unsupported QOS_KIND"); + } + CU_ASSERT_TRUE(ret >= 0); + ret = ddsrt_asprintf(&full_configuration, def, qos_conf); + ddsrt_free(qos_conf); + CU_ASSERT_TRUE(ret >= 0); + dds_qos_provider_t *provider = NULL; + // init qos provider with create configuration + ret = dds_create_qos_provider(full_configuration, &provider); + ddsrt_free(full_configuration); + // check that retcode eq to expected + CU_ASSERT_EQUAL(ret, code); + // provider not initialized + CU_ASSERT_PTR_NULL(provider); +} +#undef QOS_TO_CONF_SNGL +#undef Q diff --git a/src/core/xtests/symbol_export/symbol_export.c b/src/core/xtests/symbol_export/symbol_export.c index c425a740d5..a6ef6a4970 100644 --- a/src/core/xtests/symbol_export/symbol_export.c +++ b/src/core/xtests/symbol_export/symbol_export.c @@ -63,6 +63,10 @@ #include "dds/security/core/dds_security_shared_secret.h" #endif +#ifdef DDS_HAS_QOS_PROVIDER +#include "dds/ddsc/dds_public_qos_provider.h" +#endif + #include "dds/ddsc/dds_internal_api.h" #include "dds/ddsc/dds_loaned_sample.h" #include "dds/ddsc/dds_rhc.h" @@ -615,6 +619,13 @@ int main (int argc, char **argv) DDS_Security_get_secret_size_from_secret_handle (1); #endif +#ifdef DDS_HAS_QOS_PROVIDER + dds_create_qos_provider(ptr,ptr); + dds_create_qos_provider_scope(ptr,ptr,ptr); + dds_qos_provider_get_qos(ptr,0,ptr,ptr); + dds_delete_qos_provider(ptr); +#endif + // ddsi_sertype.h struct dds_type_consistency_enforcement_qospolicy tce = { 0, false, false, false, false, false }; ddsi_sertype_v0 (ptr); diff --git a/src/ddsrt/CMakeLists.txt b/src/ddsrt/CMakeLists.txt index 94a724760b..441a5fbfdb 100644 --- a/src/ddsrt/CMakeLists.txt +++ b/src/ddsrt/CMakeLists.txt @@ -311,7 +311,7 @@ set(DDSRT_WITH_LWIP ${WITH_LWIP}) set(DDSRT_WITH_FREERTOS ${WITH_FREERTOS}) foreach(feature TCP_TLS SECURITY LIFESPAN DEADLINE_MISSED NETWORK_PARTITIONS - SSM TYPELIB TYPE_DISCOVERY TOPIC_DISCOVERY) + SSM TYPELIB TYPE_DISCOVERY TOPIC_DISCOVERY QOS_PROVIDER) set(DDS_HAS_${feature} ${ENABLE_${feature}}) endforeach() diff --git a/src/ddsrt/include/dds/ddsrt/log.h b/src/ddsrt/include/dds/ddsrt/log.h index 42f905f508..8e05864ff4 100644 --- a/src/ddsrt/include/dds/ddsrt/log.h +++ b/src/ddsrt/include/dds/ddsrt/log.h @@ -78,6 +78,10 @@ extern "C" { #define DDS_LC_CONTENT (131072u) /** Output full dump of malformed messages as warnings */ #define DDS_LC_MALFORMED (262144u) +/** Debug/trace messages related to sysdef parser. */ +#define DDS_LC_SYSDEF (524288u) +/** Debug/trace messages related to qos provider. */ +#define DDS_LC_QOSPROV (1048576u) /** All common trace categories. */ #define DDS_LC_ALL \ (DDS_LC_FATAL | DDS_LC_ERROR | DDS_LC_WARNING | DDS_LC_INFO | \ diff --git a/src/ddsrt/include/dds/features.h.in b/src/ddsrt/include/dds/features.h.in index 9f687d405d..1320863aaf 100644 --- a/src/ddsrt/include/dds/features.h.in +++ b/src/ddsrt/include/dds/features.h.in @@ -44,4 +44,8 @@ /* Not intended for general use, whether building a static library, specifically testing psmx and security */ #cmakedefine DDS_IS_STATIC_LIBRARY 1 +/* Whether or not support for qos provider is included */ +#cmakedefine DDS_HAS_QOS_PROVIDER 1 + + #endif