From 3322fc086d1e4bf9ae34686cf7d3ad94e41f10fd Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Wed, 29 May 2019 14:03:53 +0200 Subject: [PATCH] Table-driven parameter list handling The old parameter list parsing was a mess of custom code with tons of duplicated checks, even though parameter list parsing really is a fairly straightforward affair. This commit changes it to a mostly table-driven implementation, where the vast majority of the settings are handled by a generic deserializer and the irregular ones (like reliability, locators) are handled by custom functions. The crazy ones (IPv4 address and port rely on additional state and are completely special-cased). Given these tables, the serialization, finalisation, validation, merging, unalias'ing can all be handled by a very small amount of custom code and an appropriately defined generic function for the common cases. This also makes it possible to have all QoS validation in place, and so removes the need for the specialized implementations for the various entity kinds in the upper layer. QoS inapplicable to an entity were previously ignored, allowing one to have invalid values set in a QoS object when creating an entity, provided that the invalid values are irrelevant to that entity. Whether this is a good thing or not is debatable, but certainly it is a good thing to avoid copying in inapplicable QoS settings. That in turn means the behaviour of the API can remain the same. It does turn out that the code used to return "inconsistent QoS" also for invalid values. That has now been rectified, and it returns "inconsistent QoS" or "bad parameter" as appropriate. Tests have been updated accordingly. Signed-off-by: Erik Boasson --- .../ddsc/include/dds/ddsc/dds_public_qos.h | 3 +- src/core/ddsc/src/dds__qos.h | 10 - src/core/ddsc/src/dds_builtin.c | 18 +- src/core/ddsc/src/dds_entity.c | 4 +- src/core/ddsc/src/dds_participant.c | 21 +- src/core/ddsc/src/dds_publisher.c | 34 +- src/core/ddsc/src/dds_qos.c | 348 +- src/core/ddsc/src/dds_reader.c | 32 +- src/core/ddsc/src/dds_serdata_builtintopic.c | 5 +- src/core/ddsc/src/dds_subscriber.c | 30 +- src/core/ddsc/src/dds_topic.c | 31 +- src/core/ddsc/src/dds_writer.c | 22 +- src/core/ddsc/tests/reader.c | 4 +- src/core/ddsc/tests/subscriber.c | 2 +- src/core/ddsc/tests/topic.c | 4 +- .../include/dds/ddsi/ddsi_serdata_default.h | 2 +- src/core/ddsi/include/dds/ddsi/q_plist.h | 60 +- src/core/ddsi/include/dds/ddsi/q_protocol.h | 8 - src/core/ddsi/include/dds/ddsi/q_qosmatch.h | 8 +- src/core/ddsi/include/dds/ddsi/q_xmsg.h | 3 - src/core/ddsi/include/dds/ddsi/q_xqos.h | 6 +- src/core/ddsi/src/q_ddsi_discovery.c | 11 +- src/core/ddsi/src/q_entity.c | 13 +- src/core/ddsi/src/q_init.c | 5 +- src/core/ddsi/src/q_plist.c | 3882 +++++++---------- src/core/ddsi/src/q_qosmatch.c | 37 +- src/core/ddsi/src/q_receive.c | 6 +- src/core/ddsi/src/q_xmsg.c | 13 - src/core/xtests/rhc_torture/rhc_torture.c | 4 +- src/ddsrt/include/dds/ddsrt/attributes.h | 6 + src/mpt/tests/CMakeLists.txt | 2 +- src/mpt/tests/qosmatch/CMakeLists.txt | 23 + src/mpt/tests/qosmatch/procs/rw.c | 376 ++ src/mpt/tests/qosmatch/procs/rw.h | 41 + src/mpt/tests/qosmatch/procs/rwdata.idl | 8 + src/mpt/tests/qosmatch/qosmatch.c | 20 + 36 files changed, 2367 insertions(+), 2735 deletions(-) create mode 100644 src/mpt/tests/qosmatch/CMakeLists.txt create mode 100644 src/mpt/tests/qosmatch/procs/rw.c create mode 100644 src/mpt/tests/qosmatch/procs/rw.h create mode 100644 src/mpt/tests/qosmatch/procs/rwdata.idl create mode 100644 src/mpt/tests/qosmatch/qosmatch.c diff --git a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h index a699d34..503a567 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h @@ -374,7 +374,8 @@ dds_qset_durability_service ( * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the policy * @param[in] ignore - True if readers and writers owned by the same participant should be ignored */ -DDS_EXPORT void dds_qset_ignorelocal ( +DDS_EXPORT void +dds_qset_ignorelocal ( dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ignore); diff --git a/src/core/ddsc/src/dds__qos.h b/src/core/ddsc/src/dds__qos.h index 545d38e..4d66c67 100644 --- a/src/core/ddsc/src/dds__qos.h +++ b/src/core/ddsc/src/dds__qos.h @@ -14,21 +14,11 @@ #include "dds__entity.h" #include "dds/ddsi/q_xqos.h" -#include "dds/ddsi/q_time.h" -#include "dds/ddsi/q_plist.h" #if defined (__cplusplus) extern "C" { #endif -bool validate_deadline_and_timebased_filter (const dds_duration_t deadline, const dds_duration_t minimum_separation); -bool validate_entityfactory_qospolicy (const dds_entity_factory_qospolicy_t * entityfactory); -bool validate_octetseq (const ddsi_octetseq_t* seq); -bool validate_partition_qospolicy (const dds_partition_qospolicy_t * partition); -bool validate_reliability_qospolicy (const dds_reliability_qospolicy_t * reliability); -bool validate_stringseq (const ddsi_stringseq_t* seq); - -bool dds_qos_validate_common (const dds_qos_t *qos); dds_return_t dds_qos_validate_mutable_common (const dds_qos_t *qos); #if defined (__cplusplus) diff --git a/src/core/ddsc/src/dds_builtin.c b/src/core/ddsc/src/dds_builtin.c index 2f195a4..ba9c31d 100644 --- a/src/core/ddsc/src/dds_builtin.c +++ b/src/core/ddsc/src/dds_builtin.c @@ -11,9 +11,11 @@ */ #include #include +#include "dds/ddsrt/string.h" #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_plist.h" /* for nn_keyhash */ #include "dds__init.h" #include "dds__qos.h" #include "dds__domain.h" @@ -103,6 +105,7 @@ dds_entity_t dds__get_builtin_topic (dds_entity_t e, dds_entity_t topic) static bool qos_has_resource_limits (const dds_qos_t *qos) { + assert (qos->present & QP_RESOURCE_LIMITS); return (qos->resource_limits.max_samples != DDS_LENGTH_UNLIMITED || qos->resource_limits.max_instances != DDS_LENGTH_UNLIMITED || qos->resource_limits.max_samples_per_instance != DDS_LENGTH_UNLIMITED); @@ -115,8 +118,9 @@ bool dds__validate_builtin_reader_qos (dds_entity_t topic, const dds_qos_t *qos) return true; else { - /* failing writes on built-in topics are unwelcome complications, so we simply forbid the creation of - a reader matching a built-in topics writer that has resource limits */ + /* failing writes on built-in topics are unwelcome complications, so we simply + forbid the creation of a reader matching a built-in topics writer that has + resource limits */ struct local_orphan_writer *bwr; if (topic == DDS_BUILTIN_TOPIC_DCPSPARTICIPANT) { bwr = builtintopic_writer_participant; @@ -128,7 +132,15 @@ bool dds__validate_builtin_reader_qos (dds_entity_t topic, const dds_qos_t *qos) assert (0); return false; } - return !qos_match_p (qos, bwr->wr.xqos, NULL) && !qos_has_resource_limits (qos); + + /* FIXME: DDSI-level readers, writers have topic, type name in their QoS, but + DDSC-level ones don't and that gives an automatic mismatch when comparing + the full QoS object ... Here the two have the same topic by construction + so ignoring them in the comparison makes things work. The discrepancy + should be addressed one day. */ + const uint64_t qmask = ~(QP_TOPIC_NAME | QP_TYPE_NAME); + dds_qos_policy_id_t dummy; + return qos_match_mask_p (qos, bwr->wr.xqos, qmask, &dummy) && !qos_has_resource_limits (qos); } } diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c index 176a7eb..368f40c 100644 --- a/src/core/ddsc/src/dds_entity.c +++ b/src/core/ddsc/src/dds_entity.c @@ -20,6 +20,7 @@ #include "dds__reader.h" #include "dds__listener.h" #include "dds/version.h" +#include "dds/ddsi/q_xqos.h" extern inline dds_entity *dds_entity_from_handle_link (struct dds_handle_link *hdllink); extern inline bool dds_entity_is_enabled (const dds_entity *e); @@ -354,7 +355,8 @@ dds_return_t dds_get_qos (dds_entity_t entity, dds_qos_t *qos) else { dds_reset_qos (qos); - ret = dds_copy_qos (qos, e->m_qos); + nn_xqos_mergein_missing (qos, e->m_qos, ~(QP_TOPIC_NAME | QP_TYPE_NAME)); + ret = DDS_RETCODE_OK; } dds_entity_unlock(e); return ret; diff --git a/src/core/ddsc/src/dds_participant.c b/src/core/ddsc/src/dds_participant.c index b1269d6..614ec59 100644 --- a/src/core/ddsc/src/dds_participant.c +++ b/src/core/ddsc/src/dds_participant.c @@ -15,6 +15,7 @@ #include "dds/ddsi/q_entity.h" #include "dds/ddsi/q_thread.h" #include "dds/ddsi/q_config.h" +#include "dds/ddsi/q_plist.h" #include "dds__init.h" #include "dds__qos.h" #include "dds__domain.h" @@ -73,13 +74,10 @@ static dds_return_t dds_participant_qos_validate (const dds_qos_t *qos, bool ena static dds_return_t dds_participant_qos_validate (const dds_qos_t *qos, bool enabled) { + dds_return_t ret; (void)enabled; - - if ((qos->present & QP_USER_DATA) && !validate_octetseq (&qos->user_data)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PRISMTECH_ENTITY_FACTORY) && !validate_entityfactory_qospolicy (&qos->entity_factory)) - return DDS_RETCODE_INCONSISTENT_POLICY; - + if ((ret = nn_xqos_valid (qos)) < 0) + return ret; return DDS_RETCODE_OK; } @@ -112,13 +110,14 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ if ((ret = dds__check_domain (domain)) != DDS_RETCODE_OK) goto err_domain_check; - /* Validate qos or use default if NULL */ - if (qos && (ret = dds_participant_qos_validate (qos, false)) != DDS_RETCODE_OK) - goto err_qos_validation; +#define DDS_QOSMASK_PARTICIPANT (QP_USER_DATA | QP_PRISMTECH_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) new_qos = dds_create_qos (); if (qos != NULL) - (void) dds_copy_qos (new_qos, qos); + nn_xqos_mergein_missing (new_qos, qos, DDS_QOSMASK_PARTICIPANT); + /* Validate qos or use default if NULL */ + if ((ret = dds_participant_qos_validate (new_qos, false)) != DDS_RETCODE_OK) + goto err_qos_validation; /* Translate qos */ nn_plist_init_empty (&plist); @@ -157,8 +156,8 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ err_entity_init: dds_free (pp); err_new_participant: - dds_delete_qos (new_qos); err_qos_validation: + dds_delete_qos (new_qos); err_domain_check: dds_fini (); err_dds_init: diff --git a/src/core/ddsc/src/dds_publisher.c b/src/core/ddsc/src/dds_publisher.c index 8f68e12..bbaa4c5 100644 --- a/src/core/ddsc/src/dds_publisher.c +++ b/src/core/ddsc/src/dds_publisher.c @@ -17,6 +17,7 @@ #include "dds__publisher.h" #include "dds__qos.h" #include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_globals.h" #include "dds/version.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_publisher) @@ -37,14 +38,9 @@ static dds_return_t dds_publisher_qos_validate (const dds_qos_t *qos, bool enabl static dds_return_t dds_publisher_qos_validate (const dds_qos_t *qos, bool enabled) { - if ((qos->present & QP_GROUP_DATA) && !validate_octetseq (&qos->group_data)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PRESENTATION) && validate_presentation_qospolicy (&qos->presentation) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PARTITION) && !validate_stringseq (&qos->partition)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PRISMTECH_ENTITY_FACTORY) && !validate_entityfactory_qospolicy (&qos->entity_factory)) - return DDS_RETCODE_INCONSISTENT_POLICY; + dds_return_t ret; + if ((ret = nn_xqos_valid (qos)) < 0) + return ret; /* FIXME: Improve/check immutable check. */ if (enabled && (qos->present & QP_PRESENTATION)) return DDS_RETCODE_IMMUTABLE_POLICY; @@ -74,21 +70,25 @@ dds_entity_t dds_create_publisher (dds_entity_t participant, const dds_qos_t *qo dds_participant *par; dds_publisher *pub; dds_entity_t hdl; - dds_qos_t *new_qos = NULL; + dds_qos_t *new_qos; dds_return_t ret; - if (qos && (ret = dds_publisher_qos_validate (qos, false)) != DDS_RETCODE_OK) - return ret; - - if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK) - return ret; - +#define DDS_QOSMASK_PUBLISHER (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | QP_PRISMTECH_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) + new_qos = dds_create_qos (); if (qos) + nn_xqos_mergein_missing (new_qos, qos, DDS_QOSMASK_PUBLISHER); + nn_xqos_mergein_missing (new_qos, &gv.default_xqos_pub, ~(uint64_t)0); + if ((ret = dds_publisher_qos_validate (new_qos, false)) != DDS_RETCODE_OK) { - new_qos = dds_create_qos (); - (void) dds_copy_qos (new_qos, qos); + dds_delete_qos (new_qos); + return ret; } + if ((ret = dds_participant_lock (participant, &par)) != DDS_RETCODE_OK) + { + dds_delete_qos (new_qos); + return ret; + } pub = dds_alloc (sizeof (*pub)); hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, new_qos, listener, DDS_PUBLISHER_STATUS_MASK); pub->m_entity.m_deriver.set_qos = dds_publisher_qos_set; diff --git a/src/core/ddsc/src/dds_qos.c b/src/core/ddsc/src/dds_qos.c index 3d2ccb1..a67329e 100644 --- a/src/core/ddsc/src/dds_qos.c +++ b/src/core/ddsc/src/dds_qos.c @@ -12,21 +12,16 @@ #include #include #include "dds__qos.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" #include "dds/ddsi/q_config.h" -static void dds_qos_data_copy_in (ddsi_octetseq_t *data, const void * __restrict value, size_t sz) +static void dds_qos_data_copy_in (ddsi_octetseq_t *data, const void * __restrict value, size_t sz, bool overwrite) { - if (data->value) - { - dds_free (data->value); - data->value = NULL; - } + if (overwrite && data->value) + ddsrt_free (data->value); data->length = (uint32_t) sz; - if (sz && value) - { - data->value = dds_alloc (sz); - memcpy (data->value, value, sz); - } + data->value = ddsrt_memdup (value, sz); } static bool dds_qos_data_copy_out (const ddsi_octetseq_t *data, void **value, size_t *sz) @@ -52,57 +47,6 @@ static bool dds_qos_data_copy_out (const ddsi_octetseq_t *data, void **value, si return true; } -bool validate_octetseq (const ddsi_octetseq_t *seq) -{ - /* default value is NULL with length 0 */ - return ((seq->length == 0 && seq->value == NULL) || (seq->length > 0 && seq->length < UINT32_MAX)); -} - -bool validate_stringseq (const ddsi_stringseq_t *seq) -{ - if (seq->n == 0) - return (seq->strs == NULL); - else - { - for (uint32_t i = 0; i < seq->n; i++) - if (seq->strs[i] == NULL) - return false; - return true; - } -} - -bool validate_entityfactory_qospolicy (const dds_entity_factory_qospolicy_t *entityfactory) -{ - /* Bools must be 0 or 1, i.e., only the lsb may be set */ - return !(entityfactory->autoenable_created_entities & ~1); -} - -bool validate_reliability_qospolicy (const dds_reliability_qospolicy_t *reliability) -{ - return ((reliability->kind == DDS_RELIABILITY_BEST_EFFORT || reliability->kind == DDS_RELIABILITY_RELIABLE) && - (validate_duration (reliability->max_blocking_time) == 0)); -} - -bool validate_deadline_and_timebased_filter (const dds_duration_t deadline, const dds_duration_t minimum_separation) -{ - return (validate_duration (deadline) == DDS_RETCODE_OK && - validate_duration (minimum_separation) == DDS_RETCODE_OK && - minimum_separation <= deadline); -} - -bool dds_qos_validate_common (const dds_qos_t *qos) -{ - return !(((qos->present & QP_DURABILITY) && validate_durability_qospolicy (&qos->durability) != DDS_RETCODE_OK) || - ((qos->present & QP_DEADLINE) && validate_duration (qos->deadline.deadline) != DDS_RETCODE_OK) || - ((qos->present & QP_LATENCY_BUDGET) && validate_duration (qos->latency_budget.duration) != DDS_RETCODE_OK) || - ((qos->present & QP_OWNERSHIP) && validate_ownership_qospolicy (&qos->ownership) != DDS_RETCODE_OK) || - ((qos->present & QP_LIVELINESS) && validate_liveliness_qospolicy (&qos->liveliness) != DDS_RETCODE_OK) || - ((qos->present & QP_RELIABILITY) && ! validate_reliability_qospolicy (&qos->reliability)) || - ((qos->present & QP_DESTINATION_ORDER) && validate_destination_order_qospolicy (&qos->destination_order) != DDS_RETCODE_OK) || - ((qos->present & QP_HISTORY) && validate_history_qospolicy (&qos->history) != DDS_RETCODE_OK) || - ((qos->present & QP_RESOURCE_LIMITS) && validate_resource_limits_qospolicy (&qos->resource_limits) != DDS_RETCODE_OK)); -} - dds_return_t dds_qos_validate_mutable_common (const dds_qos_t *qos) { /* FIXME: Check whether immutable QoS are changed should actually incorporate change to current QoS */ @@ -123,44 +67,10 @@ dds_return_t dds_qos_validate_mutable_common (const dds_qos_t *qos) return DDS_RETCODE_OK; } -static void dds_qos_init_defaults (dds_qos_t * __restrict qos) ddsrt_nonnull_all; - -static void dds_qos_init_defaults (dds_qos_t * __restrict qos) -{ - assert (qos); - memset (qos, 0, sizeof (*qos)); - qos->durability.kind = DDS_DURABILITY_VOLATILE; - qos->deadline.deadline = DDS_INFINITY; - qos->durability_service.service_cleanup_delay = 0; - qos->durability_service.history.kind = DDS_HISTORY_KEEP_LAST; - qos->durability_service.history.depth = 1; - qos->durability_service.resource_limits.max_samples = DDS_LENGTH_UNLIMITED; - qos->durability_service.resource_limits.max_instances = DDS_LENGTH_UNLIMITED; - qos->durability_service.resource_limits.max_samples_per_instance = DDS_LENGTH_UNLIMITED; - qos->presentation.access_scope = DDS_PRESENTATION_INSTANCE; - qos->latency_budget.duration = 0; - qos->ownership.kind = DDS_OWNERSHIP_SHARED; - qos->liveliness.kind = DDS_LIVELINESS_AUTOMATIC; - qos->liveliness.lease_duration = DDS_INFINITY; - qos->time_based_filter.minimum_separation = 0; - qos->reliability.kind = DDS_RELIABILITY_BEST_EFFORT; - qos->reliability.max_blocking_time = DDS_MSECS (100); - qos->lifespan.duration = DDS_INFINITY; - qos->destination_order.kind = DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP; - qos->history.kind = DDS_HISTORY_KEEP_LAST; - qos->history.depth = 1; - qos->resource_limits.max_samples = DDS_LENGTH_UNLIMITED; - qos->resource_limits.max_instances = DDS_LENGTH_UNLIMITED; - qos->resource_limits.max_samples_per_instance = DDS_LENGTH_UNLIMITED; - qos->writer_data_lifecycle.autodispose_unregistered_instances = true; - qos->reader_data_lifecycle.autopurge_nowriter_samples_delay = DDS_INFINITY; - qos->reader_data_lifecycle.autopurge_disposed_samples_delay = DDS_INFINITY; -} - dds_qos_t *dds_create_qos (void) { - dds_qos_t *qos = dds_alloc (sizeof (dds_qos_t)); - dds_qos_init_defaults (qos); + dds_qos_t *qos = ddsrt_malloc (sizeof (dds_qos_t)); + nn_xqos_init_empty (qos); return qos; } @@ -174,7 +84,7 @@ void dds_reset_qos (dds_qos_t * __restrict qos) if (qos) { nn_xqos_fini (qos); - dds_qos_init_defaults (qos); + nn_xqos_init_empty (qos); } } @@ -187,8 +97,8 @@ void dds_delete_qos (dds_qos_t * __restrict qos) { if (qos) { - dds_reset_qos(qos); - dds_free(qos); + nn_xqos_fini (qos); + ddsrt_free (qos); } } @@ -214,7 +124,7 @@ void dds_merge_qos (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src { /* Copy qos from source to destination unless already set */ if (src != NULL && dst != NULL) - nn_xqos_mergein_missing (dst, src); + nn_xqos_mergein_missing (dst, src, ~(uint64_t)0); } void dds_qos_merge (dds_qos_t * __restrict dst, const dds_qos_t * __restrict src) @@ -235,155 +145,140 @@ bool dds_qos_equal (const dds_qos_t * __restrict a, const dds_qos_t * __restrict void dds_qset_userdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz) { - if (qos != NULL) - { - dds_qos_data_copy_in (&qos->user_data, value, sz); - qos->present |= QP_USER_DATA; - } + if (qos == NULL || (sz > 0 && value == NULL)) + return; + dds_qos_data_copy_in (&qos->user_data, value, sz, qos->present & QP_USER_DATA); + qos->present |= QP_USER_DATA; } void dds_qset_topicdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz) { - if (qos != NULL) - { - dds_qos_data_copy_in (&qos->topic_data, value, sz); - qos->present |= QP_TOPIC_DATA; - } + if (qos == NULL || (sz > 0 && value == NULL)) + return; + dds_qos_data_copy_in (&qos->topic_data, value, sz, qos->present & QP_TOPIC_DATA); + qos->present |= QP_TOPIC_DATA; } void dds_qset_groupdata (dds_qos_t * __restrict qos, const void * __restrict value, size_t sz) { - if (qos != NULL) - { - dds_qos_data_copy_in (&qos->group_data, value, sz); - qos->present |= QP_GROUP_DATA; - } + if (qos == NULL || (sz > 0 && value == NULL)) + return; + dds_qos_data_copy_in (&qos->group_data, value, sz, qos->present & QP_GROUP_DATA); + qos->present |= QP_GROUP_DATA; } void dds_qset_durability (dds_qos_t * __restrict qos, dds_durability_kind_t kind) { - if (qos != NULL) - { - qos->durability.kind = kind; - qos->present |= QP_DURABILITY; - } + if (qos == NULL) + return; + qos->durability.kind = kind; + qos->present |= QP_DURABILITY; } void dds_qset_history (dds_qos_t * __restrict qos, dds_history_kind_t kind, int32_t depth) { - if (qos != NULL) - { - qos->history.kind = kind; - qos->history.depth = depth; - qos->present |= QP_HISTORY; - } + if (qos == NULL) + return; + qos->history.kind = kind; + qos->history.depth = depth; + qos->present |= QP_HISTORY; } void dds_qset_resource_limits (dds_qos_t * __restrict qos, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance) { - if (qos != NULL) - { - qos->resource_limits.max_samples = max_samples; - qos->resource_limits.max_instances = max_instances; - qos->resource_limits.max_samples_per_instance = max_samples_per_instance; - qos->present |= QP_RESOURCE_LIMITS; - } + if (qos == NULL) + return; + qos->resource_limits.max_samples = max_samples; + qos->resource_limits.max_instances = max_instances; + qos->resource_limits.max_samples_per_instance = max_samples_per_instance; + qos->present |= QP_RESOURCE_LIMITS; } void dds_qset_presentation (dds_qos_t * __restrict qos, dds_presentation_access_scope_kind_t access_scope, bool coherent_access, bool ordered_access) { - if (qos != NULL) - { - qos->presentation.access_scope = access_scope; - qos->presentation.coherent_access = coherent_access; - qos->presentation.ordered_access = ordered_access; - qos->present |= QP_PRESENTATION; - } + if (qos == NULL) + return; + qos->presentation.access_scope = access_scope; + qos->presentation.coherent_access = coherent_access; + qos->presentation.ordered_access = ordered_access; + qos->present |= QP_PRESENTATION; } void dds_qset_lifespan (dds_qos_t * __restrict qos, dds_duration_t lifespan) { - if (qos != NULL) - { - qos->lifespan.duration = lifespan; - qos->present |= QP_LIFESPAN; - } + if (qos == NULL) + return; + qos->lifespan.duration = lifespan; + qos->present |= QP_LIFESPAN; } void dds_qset_deadline (dds_qos_t * __restrict qos, dds_duration_t deadline) { - if (qos != NULL) - { - qos->deadline.deadline = deadline; - qos->present |= QP_DEADLINE; - } + if (qos == NULL) + return; + qos->deadline.deadline = deadline; + qos->present |= QP_DEADLINE; } void dds_qset_latency_budget (dds_qos_t * __restrict qos, dds_duration_t duration) { - if (qos != NULL) - { - qos->latency_budget.duration = duration; - qos->present |= QP_LATENCY_BUDGET; - } + if (qos == NULL) + return; + qos->latency_budget.duration = duration; + qos->present |= QP_LATENCY_BUDGET; } void dds_qset_ownership (dds_qos_t * __restrict qos, dds_ownership_kind_t kind) { - if (qos != NULL) - { - qos->ownership.kind = kind; - qos->present |= QP_OWNERSHIP; - } + if (qos == NULL) + return; + qos->ownership.kind = kind; + qos->present |= QP_OWNERSHIP; } void dds_qset_ownership_strength (dds_qos_t * __restrict qos, int32_t value) { - if (qos != NULL) - { - qos->ownership_strength.value = value; - qos->present |= QP_OWNERSHIP_STRENGTH; - } + if (qos == NULL) + return; + qos->ownership_strength.value = value; + qos->present |= QP_OWNERSHIP_STRENGTH; } void dds_qset_liveliness (dds_qos_t * __restrict qos, dds_liveliness_kind_t kind, dds_duration_t lease_duration) { - if (qos != NULL) - { - qos->liveliness.kind = kind; - qos->liveliness.lease_duration = lease_duration; - qos->present |= QP_LIVELINESS; - } + if (qos == NULL) + return; + qos->liveliness.kind = kind; + qos->liveliness.lease_duration = lease_duration; + qos->present |= QP_LIVELINESS; } void dds_qset_time_based_filter (dds_qos_t * __restrict qos, dds_duration_t minimum_separation) { - if (qos != NULL) - { - qos->time_based_filter.minimum_separation = minimum_separation; - qos->present |= QP_TIME_BASED_FILTER; - } + if (qos == NULL) + return; + qos->time_based_filter.minimum_separation = minimum_separation; + qos->present |= QP_TIME_BASED_FILTER; } void dds_qset_partition (dds_qos_t * __restrict qos, uint32_t n, const char ** __restrict ps) { - if (qos == NULL || (n && ps == NULL)) + if (qos == NULL || (n > 0 && ps == NULL)) return; - - if (qos->partition.strs != NULL) + if (qos->present & QP_PARTITION) { for (uint32_t i = 0; i < qos->partition.n; i++) - dds_free (qos->partition.strs[i]); - dds_free (qos->partition.strs); - qos->partition.strs = NULL; + ddsrt_free (qos->partition.strs[i]); + ddsrt_free (qos->partition.strs); } - qos->partition.n = n; - if (n > 0) + if (qos->partition.n == 0) + qos->partition.strs = NULL; + else { - qos->partition.strs = dds_alloc (sizeof (char*) * n); + qos->partition.strs = ddsrt_malloc (n * sizeof (*qos->partition.strs)); for (uint32_t i = 0; i < n; i++) - qos->partition.strs[i] = dds_string_dup (ps[i]); + qos->partition.strs[i] = ddsrt_strdup (ps[i]); } qos->present |= QP_PARTITION; } @@ -398,72 +293,65 @@ void dds_qset_partition1 (dds_qos_t * __restrict qos, const char * __restrict na void dds_qset_reliability (dds_qos_t * __restrict qos, dds_reliability_kind_t kind, dds_duration_t max_blocking_time) { - if (qos != NULL) - { - qos->reliability.kind = kind; - qos->reliability.max_blocking_time = max_blocking_time; - qos->present |= QP_RELIABILITY; - } + if (qos == NULL) + return; + qos->reliability.kind = kind; + qos->reliability.max_blocking_time = max_blocking_time; + qos->present |= QP_RELIABILITY; } void dds_qset_transport_priority (dds_qos_t * __restrict qos, int32_t value) { - if (qos != NULL) - { - qos->transport_priority.value = value; - qos->present |= QP_TRANSPORT_PRIORITY; - } + if (qos == NULL) + return; + qos->transport_priority.value = value; + qos->present |= QP_TRANSPORT_PRIORITY; } void dds_qset_destination_order (dds_qos_t * __restrict qos, dds_destination_order_kind_t kind) { - if (qos != NULL) - { - qos->destination_order.kind = kind; - qos->present |= QP_DESTINATION_ORDER; - } + if (qos == NULL) + return; + qos->destination_order.kind = kind; + qos->present |= QP_DESTINATION_ORDER; } void dds_qset_writer_data_lifecycle (dds_qos_t * __restrict qos, bool autodispose) { - if (qos != NULL) - { - qos->writer_data_lifecycle.autodispose_unregistered_instances = autodispose; - qos->present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; - } + if (qos == NULL) + return; + qos->writer_data_lifecycle.autodispose_unregistered_instances = autodispose; + qos->present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; } void dds_qset_reader_data_lifecycle (dds_qos_t * __restrict qos, dds_duration_t autopurge_nowriter_samples_delay, dds_duration_t autopurge_disposed_samples_delay) { - if (qos != NULL) - { - qos->reader_data_lifecycle.autopurge_nowriter_samples_delay = autopurge_nowriter_samples_delay; - qos->reader_data_lifecycle.autopurge_disposed_samples_delay = autopurge_disposed_samples_delay; - qos->present |= QP_PRISMTECH_READER_DATA_LIFECYCLE; - } + if (qos == NULL) + return; + qos->reader_data_lifecycle.autopurge_nowriter_samples_delay = autopurge_nowriter_samples_delay; + qos->reader_data_lifecycle.autopurge_disposed_samples_delay = autopurge_disposed_samples_delay; + qos->present |= QP_PRISMTECH_READER_DATA_LIFECYCLE; } void dds_qset_durability_service (dds_qos_t * __restrict qos, dds_duration_t service_cleanup_delay, dds_history_kind_t history_kind, int32_t history_depth, int32_t max_samples, int32_t max_instances, int32_t max_samples_per_instance) { - if (qos != NULL) - { - qos->durability_service.service_cleanup_delay = service_cleanup_delay; - qos->durability_service.history.kind = history_kind; - qos->durability_service.history.depth = history_depth; - qos->durability_service.resource_limits.max_samples = max_samples; - qos->durability_service.resource_limits.max_instances = max_instances; - qos->durability_service.resource_limits.max_samples_per_instance = max_samples_per_instance; - qos->present |= QP_DURABILITY_SERVICE; - } + if (qos == NULL) + return; + qos->durability_service.service_cleanup_delay = service_cleanup_delay; + qos->durability_service.history.kind = history_kind; + qos->durability_service.history.depth = history_depth; + qos->durability_service.resource_limits.max_samples = max_samples; + qos->durability_service.resource_limits.max_instances = max_instances; + qos->durability_service.resource_limits.max_samples_per_instance = max_samples_per_instance; + qos->present |= QP_DURABILITY_SERVICE; } void dds_qset_ignorelocal (dds_qos_t * __restrict qos, dds_ignorelocal_kind_t ignore) { - if (qos != NULL) - { - qos->ignorelocal.value = ignore; - qos->present |= QP_CYCLONE_IGNORELOCAL; - } + if (qos == NULL) + return; + qos->ignorelocal.value = ignore; + qos->present |= QP_CYCLONE_IGNORELOCAL; } bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c index 6392124..f40dfe1 100644 --- a/src/core/ddsc/src/dds_reader.c +++ b/src/core/ddsc/src/dds_reader.c @@ -81,18 +81,9 @@ static dds_return_t dds_reader_qos_validate (const dds_qos_t *qos, bool enabled) static dds_return_t dds_reader_qos_validate (const dds_qos_t *qos, bool enabled) { - if (!dds_qos_validate_common (qos)) - return DDS_RETCODE_ERROR; - if ((qos->present & QP_USER_DATA) && !validate_octetseq (&qos->user_data)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PRISMTECH_READER_DATA_LIFECYCLE) && validate_reader_data_lifecycle (&qos->reader_data_lifecycle) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_TIME_BASED_FILTER) && validate_duration (qos->time_based_filter.minimum_separation) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_HISTORY) && (qos->present & QP_RESOURCE_LIMITS) && validate_history_and_resource_limits (&qos->history, &qos->resource_limits) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_TIME_BASED_FILTER) && (qos->present & QP_DEADLINE) && !validate_deadline_and_timebased_filter (qos->deadline.deadline, qos->time_based_filter.minimum_separation)) - return DDS_RETCODE_INCONSISTENT_POLICY; + dds_return_t ret; + if ((ret = nn_xqos_valid (qos)) < 0) + return ret; return (enabled ? dds_qos_validate_mutable_common (qos) : DDS_RETCODE_OK); } @@ -372,20 +363,15 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti /* Merge qos from topic and subscriber, dds_copy_qos only fails when it is passed a null argument, but that isn't the case here */ +#define DDS_QOSMASK_READER (QP_USER_DATA | QP_DURABILITY | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS | QP_PRISMTECH_READER_DATA_LIFECYCLE | QP_CYCLONE_IGNORELOCAL) rqos = dds_create_qos (); if (qos) - (void) dds_copy_qos (rqos, qos); - + nn_xqos_mergein_missing (rqos, qos, DDS_QOSMASK_READER); if (sub->m_entity.m_qos) - dds_merge_qos (rqos, sub->m_entity.m_qos); - + nn_xqos_mergein_missing (rqos, sub->m_entity.m_qos, ~(uint64_t)0); if (tp->m_entity.m_qos) - { - dds_merge_qos (rqos, tp->m_entity.m_qos); - /* reset the following qos policies if set during topic qos merge as they aren't applicable for reader */ - rqos->present &= ~(QP_DURABILITY_SERVICE | QP_TRANSPORT_PRIORITY | QP_LIFESPAN); - } - nn_xqos_mergein_missing (rqos, &gv.default_xqos_rd); + nn_xqos_mergein_missing (rqos, tp->m_entity.m_qos, ~(uint64_t)0); + nn_xqos_mergein_missing (rqos, &gv.default_xqos_rd, ~(uint64_t)0); if ((ret = dds_reader_qos_validate (rqos, false)) != DDS_RETCODE_OK) { @@ -397,7 +383,7 @@ dds_entity_t dds_create_reader (dds_entity_t participant_or_subscriber, dds_enti /* Additional checks required for built-in topics: we don't want to run into a resource limit on a built-in topic, it is a needless complication */ - if (internal_topic && !dds__validate_builtin_reader_qos (topic, qos)) + if (internal_topic && !dds__validate_builtin_reader_qos (topic, rqos)) { dds_delete_qos (rqos); reader = DDS_RETCODE_INCONSISTENT_POLICY; diff --git a/src/core/ddsc/src/dds_serdata_builtintopic.c b/src/core/ddsc/src/dds_serdata_builtintopic.c index 03b6409..b95df6e 100644 --- a/src/core/ddsc/src/dds_serdata_builtintopic.c +++ b/src/core/ddsc/src/dds_serdata_builtintopic.c @@ -19,6 +19,7 @@ #include "dds/ddsi/q_bswap.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_freelist.h" +#include "dds/ddsi/q_plist.h" #include "dds__stream.h" #include "dds__serdata_builtintopic.h" #include "dds/ddsi/ddsi_tkmap.h" @@ -193,7 +194,7 @@ static dds_qos_t *dds_qos_from_xqos_reuse (dds_qos_t *old, const dds_qos_t *src) old = ddsrt_malloc (sizeof (*old)); nn_xqos_init_empty (old); old->present |= QP_TOPIC_NAME | QP_TYPE_NAME; - nn_xqos_mergein_missing (old, src); + nn_xqos_mergein_missing (old, src, ~(uint64_t)0); old->present &= ~(QP_TOPIC_NAME | QP_TYPE_NAME); } else @@ -201,7 +202,7 @@ static dds_qos_t *dds_qos_from_xqos_reuse (dds_qos_t *old, const dds_qos_t *src) nn_xqos_fini (old); nn_xqos_init_empty (old); old->present |= QP_TOPIC_NAME | QP_TYPE_NAME; - nn_xqos_mergein_missing (old, src); + nn_xqos_mergein_missing (old, src, ~(uint64_t)0); old->present &= ~(QP_TOPIC_NAME | QP_TYPE_NAME); } return old; diff --git a/src/core/ddsc/src/dds_subscriber.c b/src/core/ddsc/src/dds_subscriber.c index 907f413..1054ef6 100644 --- a/src/core/ddsc/src/dds_subscriber.c +++ b/src/core/ddsc/src/dds_subscriber.c @@ -15,6 +15,7 @@ #include "dds__qos.h" #include "dds__subscriber.h" #include "dds/ddsi/q_entity.h" +#include "dds/ddsi/q_globals.h" #include "dds/version.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_subscriber) @@ -36,15 +37,9 @@ static dds_return_t dds__subscriber_qos_validate (const dds_qos_t *qos, bool ena static dds_return_t dds__subscriber_qos_validate (const dds_qos_t *qos, bool enabled) { - if ((qos->present & QP_GROUP_DATA) && !validate_octetseq (&qos->group_data)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PARTITION) && !validate_stringseq (&qos->partition)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PRESENTATION) && validate_presentation_qospolicy (&qos->presentation) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_PRISMTECH_ENTITY_FACTORY) && !validate_entityfactory_qospolicy (&qos->entity_factory)) - return DDS_RETCODE_INCONSISTENT_POLICY; - /* FIXME: Improve/check immutable check. */ + dds_return_t ret; + if ((ret = nn_xqos_valid (qos)) < 0) + return ret; return (enabled && (qos->present & QP_PRESENTATION)) ? DDS_RETCODE_IMMUTABLE_POLICY : DDS_RETCODE_OK; } @@ -73,16 +68,15 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, const dds_q dds_return_t ret; dds_qos_t *new_qos; - /* Validate qos */ - if (qos && (ret = dds__subscriber_qos_validate (qos, false)) != DDS_RETCODE_OK) - return ret; - - if (qos == NULL) - new_qos = NULL; - else +#define DDS_QOSMASK_SUBSCRIBER (QP_PARTITION | QP_PRESENTATION | QP_GROUP_DATA | QP_PRISMTECH_ENTITY_FACTORY | QP_CYCLONE_IGNORELOCAL) + new_qos = dds_create_qos (); + if (qos) + nn_xqos_mergein_missing (new_qos, qos, DDS_QOSMASK_SUBSCRIBER); + nn_xqos_mergein_missing (new_qos, &gv.default_xqos_sub, ~(uint64_t)0); + if ((ret = dds__subscriber_qos_validate (new_qos, false)) != DDS_RETCODE_OK) { - new_qos = dds_create_qos (); - (void) dds_copy_qos (new_qos, qos); + dds_delete_qos (new_qos); + return ret; } sub = dds_alloc (sizeof (*sub)); diff --git a/src/core/ddsc/src/dds_topic.c b/src/core/ddsc/src/dds_topic.c index 31390cf..7804a67 100644 --- a/src/core/ddsc/src/dds_topic.c +++ b/src/core/ddsc/src/dds_topic.c @@ -14,6 +14,8 @@ #include #include "dds/ddsrt/atomics.h" +#include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" #include "dds__topic.h" #include "dds__listener.h" #include "dds__qos.h" @@ -27,6 +29,8 @@ #include "dds/ddsi/ddsi_sertopic.h" #include "dds/ddsi/q_ddsi_discovery.h" #include "dds/ddsi/ddsi_iid.h" +#include "dds/ddsi/q_plist.h" +#include "dds/ddsi/q_globals.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_topic) @@ -182,17 +186,10 @@ static dds_return_t dds_topic_qos_validate (const dds_qos_t *qos, bool enabled) static dds_return_t dds_topic_qos_validate (const dds_qos_t *qos, bool enabled) { - if (!dds_qos_validate_common (qos)) - return DDS_RETCODE_BAD_PARAMETER; - if ((qos->present & QP_GROUP_DATA) && !validate_octetseq (&qos->group_data)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_DURABILITY_SERVICE) && validate_durability_service_qospolicy(&qos->durability_service) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_LIFESPAN) && validate_duration(qos->lifespan.duration) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_HISTORY) && (qos->present & QP_RESOURCE_LIMITS) && validate_history_and_resource_limits(&qos->history, &qos->resource_limits) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - return enabled ? dds_qos_validate_mutable_common(qos) : DDS_RETCODE_OK; + dds_return_t ret; + if ((ret = nn_xqos_valid (qos)) < 0) + return ret; + return enabled ? dds_qos_validate_mutable_common (qos) : DDS_RETCODE_OK; } @@ -333,8 +330,8 @@ dds_entity_t dds_create_topic (dds_entity_t participant, const dds_topic_descrip st->c.status_cb = dds_topic_status_cb; st->c.status_cb_entity = NULL; /* set by dds_create_topic_arbitrary */ st->c.name_type_name = key; - st->c.name = dds_string_dup (name); - st->c.type_name = dds_string_dup (typename); + st->c.name = ddsrt_strdup (name); + st->c.type_name = ddsrt_strdup (typename); st->c.ops = &ddsi_sertopic_ops_default; st->c.serdata_ops = desc->m_nkeys ? &ddsi_serdata_ops_cdr : &ddsi_serdata_ops_cdr_nokey; st->c.serdata_basehash = ddsi_sertopic_compute_serdata_basehash (st->c.serdata_ops); @@ -349,13 +346,15 @@ dds_entity_t dds_create_topic (dds_entity_t participant, const dds_topic_descrip st->opt_size = dds_stream_check_optimize (desc); } +#define DDS_QOSMASK_TOPIC (QP_TOPIC_DATA | QP_DURABILITY | QP_DURABILITY_SERVICE | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS) nn_plist_init_empty (&plist); if (new_qos) - dds_merge_qos (&plist.qos, new_qos); + nn_xqos_mergein_missing (&plist.qos, new_qos, DDS_QOSMASK_TOPIC); + nn_xqos_mergein_missing (&plist.qos, &gv.default_xqos_tp, DDS_QOSMASK_TOPIC); /* Set Topic meta data (for SEDP publication) */ - plist.qos.topic_name = dds_string_dup (st->c.name); - plist.qos.type_name = dds_string_dup (st->c.type_name); + plist.qos.topic_name = ddsrt_strdup (st->c.name); + plist.qos.type_name = ddsrt_strdup (st->c.type_name); plist.qos.present |= (QP_TOPIC_NAME | QP_TYPE_NAME); if (desc->m_meta) { diff --git a/src/core/ddsc/src/dds_writer.c b/src/core/ddsc/src/dds_writer.c index 542be62..847e85a 100644 --- a/src/core/ddsc/src/dds_writer.c +++ b/src/core/ddsc/src/dds_writer.c @@ -208,16 +208,9 @@ static dds_return_t dds_writer_delete (dds_entity *e) static dds_return_t dds_writer_qos_validate (const dds_qos_t *qos, bool enabled) { - if (!dds_qos_validate_common(qos)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_USER_DATA) && !validate_octetseq (&qos->user_data)) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_DURABILITY_SERVICE) && validate_durability_service_qospolicy (&qos->durability_service) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_LIFESPAN) && validate_duration (qos->lifespan.duration) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; - if ((qos->present & QP_HISTORY) && (qos->present & QP_RESOURCE_LIMITS) && validate_history_and_resource_limits(&qos->history, &qos->resource_limits) < 0) - return DDS_RETCODE_INCONSISTENT_POLICY; + dds_return_t ret; + if ((ret = nn_xqos_valid (qos)) < 0) + return ret; return enabled ? dds_qos_validate_mutable_common (qos) : DDS_RETCODE_OK; } @@ -316,14 +309,15 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit assert (pub->m_entity.m_domain == tp->m_entity.m_domain); /* Merge Topic & Publisher qos */ +#define DDS_QOSMASK_WRITER (QP_USER_DATA | QP_DURABILITY | QP_DURABILITY_SERVICE | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_OWNERSHIP_STRENGTH | QP_LIVELINESS | QP_RELIABILITY | QP_TRANSPORT_PRIORITY | QP_LIFESPAN | QP_DESTINATION_ORDER | QP_HISTORY | QP_RESOURCE_LIMITS | QP_PRISMTECH_WRITER_DATA_LIFECYCLE | QP_CYCLONE_IGNORELOCAL) wqos = dds_create_qos (); if (qos) - (void) dds_copy_qos (wqos, qos); + nn_xqos_mergein_missing (wqos, qos, DDS_QOSMASK_WRITER); if (pub->m_entity.m_qos) - dds_merge_qos (wqos, pub->m_entity.m_qos); + nn_xqos_mergein_missing (wqos, pub->m_entity.m_qos, ~(uint64_t)0); if (tp->m_entity.m_qos) - dds_merge_qos (wqos, tp->m_entity.m_qos); - nn_xqos_mergein_missing (wqos, &gv.default_xqos_wr); + nn_xqos_mergein_missing (wqos, tp->m_entity.m_qos, ~(uint64_t)0); + nn_xqos_mergein_missing (wqos, &gv.default_xqos_wr, ~(uint64_t)0); if ((rc = dds_writer_qos_validate (wqos, false)) != DDS_RETCODE_OK) { diff --git a/src/core/ddsc/tests/reader.c b/src/core/ddsc/tests/reader.c index bf8e9dc..2b53b99 100644 --- a/src/core/ddsc/tests/reader.c +++ b/src/core/ddsc/tests/reader.c @@ -241,7 +241,7 @@ CU_Test(ddsc_reader_create, invalid_qos_participant, .init=reader_init, .fini=re dds_qset_reader_data_lifecycle(qos, DDS_SECS(-1), DDS_SECS(-1)); DDSRT_WARNING_MSVC_ON(28020); rdr = dds_create_reader(g_participant, g_topic, qos, NULL); - CU_ASSERT_EQUAL_FATAL(rdr, DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(rdr, DDS_RETCODE_BAD_PARAMETER); dds_delete_qos(qos); } /*************************************************************************************************/ @@ -256,7 +256,7 @@ CU_Test(ddsc_reader_create, invalid_qos_subscriber, .init=reader_init, .fini=rea dds_qset_reader_data_lifecycle(qos, DDS_SECS(-1), DDS_SECS(-1)); DDSRT_WARNING_MSVC_ON(28020); rdr = dds_create_reader(g_subscriber, g_topic, qos, NULL); - CU_ASSERT_EQUAL_FATAL(rdr, DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(rdr, DDS_RETCODE_BAD_PARAMETER); dds_delete_qos(qos); } /*************************************************************************************************/ diff --git a/src/core/ddsc/tests/subscriber.c b/src/core/ddsc/tests/subscriber.c index cc9144a..02a8625 100644 --- a/src/core/ddsc/tests/subscriber.c +++ b/src/core/ddsc/tests/subscriber.c @@ -91,7 +91,7 @@ CU_Test(ddsc_subscriber, create) { sqos = dds_create_qos(); dds_qset_presentation(sqos, 123, 1, 1); /* Set invalid presentation policy */ subscriber = dds_create_subscriber(participant, sqos, NULL); - CU_ASSERT_EQUAL_FATAL(subscriber, DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(subscriber, DDS_RETCODE_BAD_PARAMETER); dds_delete_qos(sqos); /*** Verify listener parameter ***/ diff --git a/src/core/ddsc/tests/topic.c b/src/core/ddsc/tests/topic.c index 085926b..d71c8d5 100644 --- a/src/core/ddsc/tests/topic.c +++ b/src/core/ddsc/tests/topic.c @@ -105,7 +105,7 @@ CU_Test(ddsc_topic_create, invalid_qos, .init=ddsc_topic_init, .fini=ddsc_topic_ dds_entity_t topic; dds_qos_t *qos = dds_create_qos(); DDSRT_WARNING_MSVC_OFF(28020); /* Disable SAL warning on intentional misuse of the API */ - dds_qset_lifespan(qos, DDS_SECS(-1)); + dds_qset_resource_limits(qos, 1, 1, 2); DDSRT_WARNING_MSVC_OFF(28020); topic = dds_create_topic(g_participant, &RoundTripModule_DataType_desc, "inconsistent", qos, NULL); CU_ASSERT_EQUAL_FATAL(topic, DDS_RETCODE_INCONSISTENT_POLICY); @@ -417,7 +417,7 @@ CU_Test(ddsc_topic_set_qos, inconsistent, .init=ddsc_topic_init, .fini=ddsc_topi dds_qset_lifespan(g_qos, DDS_SECS(-1)); DDSRT_WARNING_MSVC_ON(28020); ret = dds_set_qos(g_topicRtmDataType, g_qos); - CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_INCONSISTENT_POLICY); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_BAD_PARAMETER); } /*************************************************************************************************/ diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h index 6c2bc29..e6e2f56 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_serdata_default.h @@ -13,7 +13,7 @@ #define DDSI_SERDATA_DEFAULT_H #include "dds/ddsrt/endian.h" -#include "dds/ddsi/q_plist.h" /* for nn_prismtech_writer_info */ +#include "dds/ddsi/q_protocol.h" /* for nn_parameterid_t */ #include "dds/ddsi/q_freelist.h" #include "dds/ddsrt/avl.h" #include "dds/ddsi/ddsi_serdata.h" diff --git a/src/core/ddsi/include/dds/ddsi/q_plist.h b/src/core/ddsi/include/dds/ddsi/q_plist.h index 98b9466..6028da8 100644 --- a/src/core/ddsi/include/dds/ddsi/q_plist.h +++ b/src/core/ddsi/include/dds/ddsi/q_plist.h @@ -46,22 +46,16 @@ extern "C" { #define PP_STATUSINFO ((uint64_t)1 << 22) #define PP_ORIGINAL_WRITER_INFO ((uint64_t)1 << 23) #define PP_ENDPOINT_GUID ((uint64_t)1 << 24) -#define PP_PRISMTECH_WRITER_INFO ((uint64_t)1 << 25) #define PP_PRISMTECH_PARTICIPANT_VERSION_INFO ((uint64_t)1 << 26) #define PP_PRISMTECH_NODE_NAME ((uint64_t)1 << 27) #define PP_PRISMTECH_EXEC_NAME ((uint64_t)1 << 28) #define PP_PRISMTECH_PROCESS_ID ((uint64_t)1 << 29) -#define PP_PRISMTECH_SERVICE_TYPE ((uint64_t)1 << 30) -#define PP_PRISMTECH_WATCHDOG_SCHEDULING ((uint64_t)1 << 31) -#define PP_PRISMTECH_LISTENER_SCHEDULING ((uint64_t)1 << 32) #define PP_PRISMTECH_BUILTIN_ENDPOINT_SET ((uint64_t)1 << 33) #define PP_PRISMTECH_TYPE_DESCRIPTION ((uint64_t)1 << 34) #define PP_COHERENT_SET ((uint64_t)1 << 37) -#define PP_PRISMTECH_EOTINFO ((uint64_t)1 << 38) #ifdef DDSI_INCLUDE_SSM #define PP_READER_FAVOURS_SSM ((uint64_t)1 << 39) #endif -#define PP_RTI_TYPECODE ((uint64_t)1 << 40) /* Security extensions. */ #define PP_IDENTITY_TOKEN ((uint64_t)1 << 41) #define PP_PERMISSIONS_TOKEN ((uint64_t)1 << 42) @@ -93,14 +87,14 @@ struct nn_locators_one { }; typedef struct nn_locators { - int n; + uint32_t n; struct nn_locators_one *first; struct nn_locators_one *last; } nn_locators_t; -typedef unsigned nn_ipv4address_t; +typedef uint32_t nn_ipv4address_t; -typedef unsigned nn_port_t; +typedef uint32_t nn_port_t; typedef struct nn_keyhash { unsigned char value[16]; @@ -109,15 +103,15 @@ typedef struct nn_keyhash { #ifdef DDSI_INCLUDE_SSM typedef struct nn_reader_favours_ssm { - unsigned state; /* default is false */ + uint32_t state; /* default is false */ } nn_reader_favours_ssm_t; #endif typedef struct nn_prismtech_participant_version_info { - unsigned version; - unsigned flags; - unsigned unused[3]; + uint32_t version; + uint32_t flags; + uint32_t unused[3]; char *internals; } nn_prismtech_participant_version_info_t; @@ -126,16 +120,9 @@ typedef struct nn_prismtech_eotgroup_tid { uint32_t transactionId; } nn_prismtech_eotgroup_tid_t; -typedef struct nn_prismtech_eotinfo { - uint32_t transactionId; - uint32_t n; - nn_prismtech_eotgroup_tid_t *tids; -} nn_prismtech_eotinfo_t; - typedef struct nn_plist { uint64_t present; uint64_t aliased; - int unalias_needs_bswap; dds_qos_t qos; @@ -150,7 +137,7 @@ typedef struct nn_plist { unsigned char expects_inline_qos; nn_count_t participant_manual_liveliness_count; - unsigned participant_builtin_endpoints; + uint32_t participant_builtin_endpoints; dds_duration_t participant_lease_duration; /* nn_content_filter_property_t content_filter_property; */ nn_guid_t participant_guid; @@ -160,21 +147,18 @@ typedef struct nn_plist { nn_entityid_t participant_entityid; nn_entityid_t group_entityid; #endif - unsigned builtin_endpoint_set; - unsigned prismtech_builtin_endpoint_set; + uint32_t builtin_endpoint_set; + uint32_t prismtech_builtin_endpoint_set; /* int type_max_size_serialized; */ char *entity_name; nn_keyhash_t keyhash; - unsigned statusinfo; + uint32_t statusinfo; nn_prismtech_participant_version_info_t prismtech_participant_version_info; char *node_name; char *exec_name; - unsigned char is_service; - unsigned service_type; - unsigned process_id; + uint32_t process_id; char *type_description; nn_sequence_number_t coherent_set_seqno; - nn_prismtech_eotinfo_t eotinfo; #ifdef DDSI_INCLUDE_SSM nn_reader_favours_ssm_t reader_favours_ssm; #endif @@ -192,8 +176,9 @@ typedef struct nn_plist_src { size_t bufsz; } nn_plist_src_t; +void nn_plist_init_tables (void); DDS_EXPORT void nn_plist_init_empty (nn_plist_t *dest); -DDS_EXPORT void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b); +DDS_EXPORT void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b, uint64_t pmask, uint64_t qmask); DDS_EXPORT void nn_plist_copy (nn_plist_t *dst, const nn_plist_t *src); DDS_EXPORT nn_plist_t *nn_plist_dup (const nn_plist_t *src); @@ -234,6 +219,9 @@ DDS_EXPORT nn_plist_t *nn_plist_dup (const nn_plist_t *src); * @retval DDS_RETCODE_OK * All parameters valid (or ignored), dest and *nextafterplist have been set * accordingly. + * @retval DDS_INCONSISTENT_POLICY + * All individual settings are valid, but there are inconsistencies between + * dependent settings. * @retval DDS_RETCODE_BAD_PARAMETER * Input contained invalid data; dest is cleared, *nextafterplist is NULL. * @retval DDS_RETCODE_UNSUPPORTED @@ -245,20 +233,6 @@ DDS_EXPORT void nn_plist_fini (nn_plist_t *ps); DDS_EXPORT void nn_plist_addtomsg (struct nn_xmsg *m, const nn_plist_t *ps, uint64_t pwanted, uint64_t qwanted); DDS_EXPORT void nn_plist_init_default_participant (nn_plist_t *plist); -DDS_EXPORT dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_durability_qospolicy (const dds_durability_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_history_and_resource_limits (const dds_history_qospolicy_t *qh, const dds_resource_limits_qospolicy_t *qr); -DDS_EXPORT dds_return_t validate_durability_service_qospolicy (const dds_durability_service_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_liveliness_qospolicy (const dds_liveliness_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_destination_order_qospolicy (const dds_destination_order_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_ownership_qospolicy (const dds_ownership_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_ownership_strength_qospolicy (const dds_ownership_strength_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_presentation_qospolicy (const dds_presentation_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_transport_priority_qospolicy (const dds_transport_priority_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_reader_data_lifecycle (const dds_reader_data_lifecycle_qospolicy_t *q); -DDS_EXPORT dds_return_t validate_duration (const dds_duration_t d); - struct nn_rmsg; struct nn_rsample_info; struct nn_rdata; diff --git a/src/core/ddsi/include/dds/ddsi/q_protocol.h b/src/core/ddsi/include/dds/ddsi/q_protocol.h index f8f65d6..e120f59 100644 --- a/src/core/ddsi/include/dds/ddsi/q_protocol.h +++ b/src/core/ddsi/include/dds/ddsi/q_protocol.h @@ -390,14 +390,6 @@ typedef struct ParticipantMessageData { #define PID_IDENTITY_TOKEN 0x1001u #define PID_PERMISSIONS_TOKEN 0x1002u -#define PID_RTI_TYPECODE (PID_VENDORSPECIFIC_FLAG | 0x4u) - -#ifdef DDSI_INCLUDE_SSM -/* To indicate whether a reader favours the use of SSM. Iff the - reader favours SSM, it will use SSM if available. */ -#define PID_READER_FAVOURS_SSM 0x72u -#endif - #ifdef DDSI_INCLUDE_SSM /* To indicate whether a reader favours the use of SSM. Iff the reader favours SSM, it will use SSM if available. */ diff --git a/src/core/ddsi/include/dds/ddsi/q_qosmatch.h b/src/core/ddsi/include/dds/ddsi/q_qosmatch.h index 7cfd371..bbf9b07 100644 --- a/src/core/ddsi/include/dds/ddsi/q_qosmatch.h +++ b/src/core/ddsi/include/dds/ddsi/q_qosmatch.h @@ -20,8 +20,14 @@ struct dds_qos; int partitions_match_p (const struct dds_qos *a, const struct dds_qos *b); -/* Returns -1 on success, or QoS id of first mismatch (>=0) */ +/* perform reader/writer QoS (and topic name, type name, partition) matching; + mask can be used to exclude some of these (including topic name and type + name, so be careful!) + reason will be set to the policy id of one of the mismatching QoS, or to + DDS_INVALID_QOS_POLICY_ID if there is no mismatch or if the mismatch is + in topic or type name (those are not really QoS and don't have a policy id) */ +bool qos_match_mask_p (const dds_qos_t *rd, const dds_qos_t *wr, uint64_t mask, dds_qos_policy_id_t *reason) ddsrt_nonnull_all; bool qos_match_p (const struct dds_qos *rd, const struct dds_qos *wr, dds_qos_policy_id_t *reason) ddsrt_nonnull ((1, 2)); #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/q_xmsg.h b/src/core/ddsi/include/dds/ddsi/q_xmsg.h index 9b7e1eb..b70a5c4 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xmsg.h +++ b/src/core/ddsi/include/dds/ddsi/q_xmsg.h @@ -28,8 +28,6 @@ struct proxy_reader; struct proxy_writer; struct nn_prismtech_participant_version_info; -struct nn_prismtech_writer_info; -struct nn_prismtech_eotinfo; struct nn_xmsgpool; struct nn_xmsg_data; struct nn_xmsg; @@ -139,7 +137,6 @@ void nn_xmsg_addpar_reader_data_lifecycle (struct nn_xmsg *m, nn_parameterid_t p void nn_xmsg_addpar_liveliness (struct nn_xmsg *m, nn_parameterid_t pid, const dds_liveliness_qospolicy_t *rq); void nn_xmsg_addpar_parvinfo (struct nn_xmsg *m, nn_parameterid_t pid, const struct nn_prismtech_participant_version_info *pvi); -void nn_xmsg_addpar_eotinfo (struct nn_xmsg *m, nn_parameterid_t pid, const struct nn_prismtech_eotinfo *txnid); void nn_xmsg_addpar_sentinel (struct nn_xmsg *m); int nn_xmsg_addpar_sentinel_ifparam (struct nn_xmsg *m); diff --git a/src/core/ddsi/include/dds/ddsi/q_xqos.h b/src/core/ddsi/include/dds/ddsi/q_xqos.h index 225e280..7b5e8ea 100644 --- a/src/core/ddsi/include/dds/ddsi/q_xqos.h +++ b/src/core/ddsi/include/dds/ddsi/q_xqos.h @@ -211,7 +211,6 @@ typedef struct dds_ignorelocal_qospolicy { #define QP_PRISMTECH_READER_LIFESPAN ((uint64_t)1 << 24) #define QP_PRISMTECH_SUBSCRIPTION_KEYS ((uint64_t)1 << 25) #define QP_PRISMTECH_ENTITY_FACTORY ((uint64_t)1 << 27) -#define QP_RTI_TYPECODE ((uint64_t)1 << 29) #define QP_CYCLONE_IGNORELOCAL ((uint64_t)1 << 30) /* Partition QoS is not RxO according to the specification (DDS 1.2, @@ -264,8 +263,6 @@ struct dds_qos { /*x xR*/dds_subscription_keys_qospolicy_t subscription_keys; /*x xR*/dds_reader_lifespan_qospolicy_t reader_lifespan; /* x */dds_ignorelocal_qospolicy_t ignorelocal; - - /* X*/ddsi_octetseq_t rti_typecode; }; struct nn_xmsg; @@ -280,7 +277,8 @@ DDS_EXPORT void nn_xqos_init_default_topic (dds_qos_t *xqos); DDS_EXPORT void nn_xqos_copy (dds_qos_t *dst, const dds_qos_t *src); DDS_EXPORT void nn_xqos_unalias (dds_qos_t *xqos); DDS_EXPORT void nn_xqos_fini (dds_qos_t *xqos); -DDS_EXPORT void nn_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b); +DDS_EXPORT dds_return_t nn_xqos_valid (const dds_qos_t *xqos); +DDS_EXPORT void nn_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b, uint64_t mask); DDS_EXPORT uint64_t nn_xqos_delta (const dds_qos_t *a, const dds_qos_t *b, uint64_t mask); DDS_EXPORT void nn_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted); DDS_EXPORT void nn_log_xqos (uint32_t cat, const dds_qos_t *xqos); diff --git a/src/core/ddsi/src/q_ddsi_discovery.c b/src/core/ddsi/src/q_ddsi_discovery.c index e9b6476..3973840 100644 --- a/src/core/ddsi/src/q_ddsi_discovery.c +++ b/src/core/ddsi/src/q_ddsi_discovery.c @@ -1085,7 +1085,7 @@ static struct proxy_participant *implicitly_create_proxypp (const nn_guid_t *ppg tmp_plist = *privpp->plist; tmp_plist.present = PP_PARTICIPANT_GUID | PP_PRISMTECH_PARTICIPANT_VERSION_INFO; tmp_plist.participant_guid = *ppguid; - nn_plist_mergein_missing (&pp_plist, &tmp_plist); + nn_plist_mergein_missing (&pp_plist, &tmp_plist, ~(uint64_t)0, ~(uint64_t)0); ddsrt_mutex_unlock (&privpp->e.lock); pp_plist.prismtech_participant_version_info.flags &= ~NN_PRISMTECH_FL_PARTICIPANT_IS_DDSI2; @@ -1146,11 +1146,11 @@ static void handle_SEDP_alive (const struct receiver_state *rst, nn_plist_t *dat xqos = &datap->qos; is_writer = is_writer_entityid (datap->endpoint_guid.entityid); if (!is_writer) - nn_xqos_mergein_missing (xqos, &gv.default_xqos_rd); + nn_xqos_mergein_missing (xqos, &gv.default_xqos_rd, ~(uint64_t)0); else if (vendor_is_eclipse_or_prismtech(vendorid)) - nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr); + nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr, ~(uint64_t)0); else - nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr_nad); + nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr_nad, ~(uint64_t)0); /* After copy + merge, should have at least the ones present in the input. Also verify reliability and durability are present, @@ -1434,8 +1434,7 @@ int sedp_write_cm_participant (struct participant *pp, int alive) { nn_plist_addtomsg (mpayload, pp->plist, PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID | - PP_PRISMTECH_WATCHDOG_SCHEDULING | PP_PRISMTECH_LISTENER_SCHEDULING | - PP_PRISMTECH_SERVICE_TYPE | PP_ENTITY_NAME, + PP_ENTITY_NAME, QP_PRISMTECH_ENTITY_FACTORY); } nn_xmsg_addpar_sentinel (mpayload); diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index a8eca66..d8e66fc 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -457,7 +457,7 @@ dds_return_t new_participant_guid (const nn_guid_t *ppguid, unsigned flags, cons pp->lease_duration = config.lease_duration; pp->plist = ddsrt_malloc (sizeof (*pp->plist)); nn_plist_copy (pp->plist, plist); - nn_plist_mergein_missing (pp->plist, &gv.default_plist_pp); + nn_plist_mergein_missing (pp->plist, &gv.default_plist_pp, ~(uint64_t)0, ~(uint64_t)0); if (dds_get_log_mask() & DDS_LC_DISCOVERY) { @@ -2684,7 +2684,7 @@ static void new_writer_guid_common_init (struct writer *wr, const struct ddsi_se wr->xqos = ddsrt_malloc (sizeof (*wr->xqos)); nn_xqos_copy (wr->xqos, xqos); - nn_xqos_mergein_missing (wr->xqos, &gv.default_xqos_wr); + nn_xqos_mergein_missing (wr->xqos, &gv.default_xqos_wr, ~(uint64_t)0); assert (wr->xqos->aliased == 0); set_topic_type_name (wr->xqos, topic); @@ -3222,7 +3222,7 @@ static dds_return_t new_reader_guid /* Copy QoS, merging in defaults */ rd->xqos = ddsrt_malloc (sizeof (*rd->xqos)); nn_xqos_copy (rd->xqos, xqos); - nn_xqos_mergein_missing (rd->xqos, &gv.default_xqos_rd); + nn_xqos_mergein_missing (rd->xqos, &gv.default_xqos_rd, ~(uint64_t)0); assert (rd->xqos->aliased == 0); set_topic_type_name (rd->xqos, topic); @@ -3660,7 +3660,7 @@ int update_proxy_participant_plist_locked (struct proxy_participant *proxypp, co nn_plist_t *new_plist; new_plist = nn_plist_dup (datap); - nn_plist_mergein_missing (new_plist, proxypp->plist); + nn_plist_mergein_missing (new_plist, proxypp->plist, ~(uint64_t)0, ~(uint64_t)0); nn_plist_fini (proxypp->plist); ddsrt_free (proxypp->plist); proxypp->plist = new_plist; @@ -3694,8 +3694,7 @@ int update_proxy_participant_plist (struct proxy_participant *proxypp, const str tmp = *datap; tmp.present &= PP_PRISMTECH_NODE_NAME | PP_PRISMTECH_EXEC_NAME | PP_PRISMTECH_PROCESS_ID | - PP_PRISMTECH_WATCHDOG_SCHEDULING | PP_PRISMTECH_LISTENER_SCHEDULING | - PP_PRISMTECH_SERVICE_TYPE | PP_ENTITY_NAME; + PP_ENTITY_NAME; tmp.qos.present &= QP_PRISMTECH_ENTITY_FACTORY; update_proxy_participant_plist_locked (proxypp, &tmp, source, timestamp); break; @@ -3993,7 +3992,7 @@ int new_proxy_group (const struct nn_guid *guid, const char *name, const struct DDS_LOG(DDS_LC_DISCOVERY, "new_proxy_group("PGUIDFMT"): setting name (%s) and qos\n", PGUID (*guid), name); pgroup->name = ddsrt_strdup (name); pgroup->xqos = nn_xqos_dup (xqos); - nn_xqos_mergein_missing (pgroup->xqos, is_sub ? &gv.default_xqos_sub : &gv.default_xqos_pub); + nn_xqos_mergein_missing (pgroup->xqos, is_sub ? &gv.default_xqos_sub : &gv.default_xqos_pub, ~(uint64_t)0); } out: ddsrt_mutex_unlock (&proxypp->e.lock); diff --git a/src/core/ddsi/src/q_init.c b/src/core/ddsi/src/q_init.c index e551bd0..e04b7fb 100644 --- a/src/core/ddsi/src/q_init.c +++ b/src/core/ddsi/src/q_init.c @@ -850,10 +850,11 @@ int rtps_init (void) uint32_t port_data_uc = 0; bool mc_available = true; + gv.tstart = now (); /* wall clock time, used in logs */ + ddsi_plugin_init (); ddsi_iid_init (); - - gv.tstart = now (); /* wall clock time, used in logs */ + nn_plist_init_tables (); gv.disc_conn_uc = NULL; gv.data_conn_uc = NULL; diff --git a/src/core/ddsi/src/q_plist.c b/src/core/ddsi/src/q_plist.c index 1e65ee5..7d396c3 100644 --- a/src/core/ddsi/src/q_plist.c +++ b/src/core/ddsi/src/q_plist.c @@ -17,6 +17,7 @@ #include "dds/ddsrt/log.h" #include "dds/ddsrt/heap.h" +#include "dds/ddsrt/string.h" #include "dds/ddsrt/static_assert.h" #include "dds/ddsi/q_log.h" @@ -26,6 +27,7 @@ #include "dds/ddsi/q_plist.h" #include "dds/ddsi/q_time.h" #include "dds/ddsi/q_xmsg.h" +#include "dds/ddsi/ddsi_vendor.h" #include "dds/ddsi/q_config.h" #include "dds/ddsi/q_globals.h" @@ -74,531 +76,1457 @@ struct dd { nn_vendorid_t vendorid; }; -struct cdroctetseq { - uint32_t len; - unsigned char value[1]; +#define PDF_QOS 1 /* part of dds_qos_t */ +#define PDF_FUNCTION 2 /* use special functions */ +#define PDF_ALLOWMULTI 4 /* allow multiple copies -- do not use with Z or memory will leak */ + +struct flagset { + uint64_t *present; + uint64_t *aliased; + uint64_t wanted; +}; + +/* Instructions for the generic serializer (&c) that handles most parameters. + The "packed" attribute means single-byte instructions on GCC and Clang. */ +enum pserop { + XSTOP, + XO, /* octet sequence */ + XS, /* string */ + XZ, /* string sequence */ + XE1, XE2, XE3, /* enum 0..1, 0..2, 0..3 */ + Xl, /* length, int32_t, -1 or >= 1 */ + Xi, Xix2, Xix3, Xix4, /* int32_t, 1 .. 4 in a row */ + Xu, Xux2, Xux3, Xux4, Xux5, /* uint32_t, 1 .. 5 in a row */ + XD, XDx2, /* duration, 1 .. 2 in a row */ + Xo, Xox2, /* octet, 1 .. 2 in a row */ + Xb, Xbx2, /* boolean, 1 .. 2 in a row */ + XbCOND, /* boolean: compare to ignore remainder if false (for use_... flags) */ + XG, /* GUID */ + XK /* keyhash */ +} ddsrt_attribute_packed; + +struct piddesc { + nn_parameterid_t pid; /* parameter id or PID_PAD if strictly local */ + uint16_t flags; /* see PDF_xxx flags */ + uint64_t present_flag; /* flag in plist.present / plist.qos.present */ + const char *name; /* name for reporting invalid input */ + size_t plist_offset; /* offset from start of nn_plist_t */ + size_t size; /* in-memory size for copying */ + union { + /* descriptor for generic code: 4 is enough for the current set of + parameters, compiler will warn if one ever tries to use more than + will fit; on non-GCC/Clang and 32-bits machines */ + const enum pserop desc[4]; + struct { + dds_return_t (*deser) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff); + dds_return_t (*ser) (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff); + dds_return_t (*unalias) (void * __restrict dst, size_t * __restrict dstoff); + dds_return_t (*fini) (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag); + dds_return_t (*valid) (const void *src, size_t srcoff); + bool (*equal) (const void *srcx, const void *srcy, size_t srcoff); + } f; + } op; + dds_return_t (*deser_validate_xform) (void * __restrict dst, const struct dd * __restrict dd); }; static void log_octetseq (uint32_t cat, uint32_t n, const unsigned char *xs); +static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q); +static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q); +static dds_return_t validate_history_and_resource_limits (const dds_history_qospolicy_t *qh, const dds_resource_limits_qospolicy_t *qr); +static dds_return_t validate_external_duration (const ddsi_duration_t *d); +static dds_return_t validate_durability_service_qospolicy_acceptzero (const dds_durability_service_qospolicy_t *q, bool acceptzero); +static dds_return_t do_locator (nn_locators_t *ls, uint64_t *present, uint64_t wanted, uint64_t fl, const struct dd *dd); +static dds_return_t final_validation_qos (const dds_qos_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid, bool *dursvc_accepted_allzero); +static int partitions_equal (const dds_partition_qospolicy_t *a, const dds_partition_qospolicy_t *b); -static size_t align4u (size_t x) +static size_t align4size (size_t x) { - return (x + 3u) & ~(size_t)3; + return (x + 3) & ~(size_t)3; } +static void *deser_generic_dst (void * __restrict dst, size_t *dstoff, size_t align) +{ + *dstoff = (*dstoff + align - 1) & ~(align - 1); + return (char *) dst + *dstoff; +} + +static const void *deser_generic_src (const void * __restrict src, size_t *srcoff, size_t align) +{ + *srcoff = (*srcoff + align - 1) & ~(align - 1); + return (const char *) src + *srcoff; +} + +static void *ser_generic_align4 (char * __restrict p, size_t * __restrict off) +{ + *off = align4size (*off); + return p + *off; +} + +static dds_return_t deser_uint32 (uint32_t *dst, const struct dd * __restrict dd, size_t * __restrict off) +{ + size_t off1 = (*off + 3) & ~(size_t)3; + uint32_t tmp; + if (off1 + 4 > dd->bufsz) + return DDS_RETCODE_BAD_PARAMETER; + tmp = *((uint32_t *) (dd->buf + off1)); + if (dd->bswap) + tmp = bswap4u (tmp); + *dst = tmp; + *off = off1 + 4; + return 0; +} + +#define alignof(type_) offsetof (struct { char c; type_ d; }, d) + +static dds_return_t deser_reliability (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff) +{ + DDSRT_STATIC_ASSERT (DDS_EXTERNAL_RELIABILITY_BEST_EFFORT == 1 && DDS_EXTERNAL_RELIABILITY_RELIABLE == 2 && + DDS_RELIABILITY_BEST_EFFORT == 0 && DDS_RELIABILITY_RELIABLE == 1); + dds_reliability_qospolicy_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_reliability_qospolicy_t)); + uint32_t kind, mbtsec, mbtfrac; + ddsi_duration_t mbt; + if (deser_uint32 (&kind, dd, srcoff) < 0 || deser_uint32 (&mbtsec, dd, srcoff) < 0 || deser_uint32 (&mbtfrac, dd, srcoff) < 0) + return DDS_RETCODE_BAD_PARAMETER; + if (kind < 1 || kind > 2) + return DDS_RETCODE_BAD_PARAMETER; + mbt.seconds = (int32_t) mbtsec; + mbt.fraction = mbtfrac; + if (validate_external_duration (&mbt) < 0) + return DDS_RETCODE_BAD_PARAMETER; + x->kind = (enum dds_reliability_kind) (kind - 1); + x->max_blocking_time = nn_from_ddsi_duration (mbt); + *dstoff += sizeof (*x); + *flagset->present |= flag; + return 0; +} + +static dds_return_t ser_reliability (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +{ + DDSRT_STATIC_ASSERT (DDS_EXTERNAL_RELIABILITY_BEST_EFFORT == 1 && DDS_EXTERNAL_RELIABILITY_RELIABLE == 2 && + DDS_RELIABILITY_BEST_EFFORT == 0 && DDS_RELIABILITY_RELIABLE == 1); + dds_reliability_qospolicy_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_reliability_qospolicy_t)); + ddsi_duration_t mbt = nn_to_ddsi_duration (x->max_blocking_time); + uint32_t * const p = nn_xmsg_addpar (xmsg, pid, 3 * sizeof (uint32_t)); + p[0] = 1 + (uint32_t) x->kind; + p[1] = (uint32_t) mbt.seconds; + p[2] = mbt.fraction; + return 0; +} + +static dds_return_t valid_reliability (const void *src, size_t srcoff) +{ + dds_reliability_qospolicy_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_reliability_qospolicy_t)); + if ((x->kind == DDS_RELIABILITY_BEST_EFFORT || x->kind == DDS_RELIABILITY_RELIABLE) && x->max_blocking_time >= 0) + return 0; + else + return DDS_RETCODE_BAD_PARAMETER; +} + +static bool equal_reliability (const void *srcx, const void *srcy, size_t srcoff) +{ + dds_reliability_qospolicy_t const * const x = deser_generic_src (srcx, &srcoff, alignof (dds_reliability_qospolicy_t)); + dds_reliability_qospolicy_t const * const y = deser_generic_src (srcy, &srcoff, alignof (dds_reliability_qospolicy_t)); + return x->kind == y->kind && x->max_blocking_time == y->max_blocking_time; +} + +static dds_return_t deser_statusinfo (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff) +{ + uint32_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_reliability_qospolicy_t)); + size_t srcoff1 = (*srcoff + 3) & ~(size_t)3; + if (srcoff1 + 4 > dd->bufsz) + return DDS_RETCODE_BAD_PARAMETER; + /* status info is always in BE format (it is an array of 4 octets according to the spec) -- + fortunately we have 4 byte alignment anyway -- and can have bits set we don't grok + (which we discard) */ + *x = fromBE4u (*((uint32_t *) (dd->buf + srcoff1))) & NN_STATUSINFO_STANDARDIZED; + *dstoff += sizeof (*x); + *srcoff = srcoff1 + 4; + *flagset->present |= flag; + return 0; +} + +static dds_return_t ser_statusinfo (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +{ + uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); + uint32_t * const p = nn_xmsg_addpar (xmsg, pid, sizeof (uint32_t)); + *p = toBE4u (*x); + return 0; +} + +static dds_return_t deser_locator (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff) +{ + nn_locators_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_locators_t)); + /* FIXME: don't want to modify do_locator just yet, and don't want to require that a + locator is the only thing in the descriptor string (even though it actually always is), + so do alignment explicitly, fake a temporary input buffer and advance the source buffer */ + *srcoff = (*srcoff + 3) & ~(size_t)3; + if (*srcoff > dd->bufsz || dd->bufsz - *srcoff < 24) + return DDS_RETCODE_BAD_PARAMETER; + struct dd tmpdd = *dd; + tmpdd.buf += *srcoff; + tmpdd.bufsz -= *srcoff; + if (do_locator (x, flagset->present, flagset->wanted, flag, &tmpdd) < 0) + return DDS_RETCODE_BAD_PARAMETER; + *srcoff += 24; + *dstoff += sizeof (*x); + *flagset->present |= flag; + return 0; +} + +static dds_return_t ser_locator (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff) +{ + nn_locators_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_locators_t)); + for (const struct nn_locators_one *l = x->first; l != NULL; l = l->next) + { + char * const p = nn_xmsg_addpar (xmsg, pid, sizeof (nn_locator_t)); + memcpy (p, &l->loc, sizeof (nn_locator_t)); + } + return 0; +} + +static dds_return_t unalias_locator (void * __restrict dst, size_t * __restrict dstoff) +{ + nn_locators_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_locators_t)); + nn_locators_t newlocs = { .n = x->n, .first = NULL, .last = NULL }; + struct nn_locators_one **pnext = &newlocs.first; + for (const struct nn_locators_one *lold = x->first; lold != NULL; lold = lold->next) + { + struct nn_locators_one *n = ddsrt_memdup (lold, sizeof (*n)); + *pnext = n; + pnext = &n->next; + } + newlocs.last = *pnext; + *pnext = NULL; + *x = newlocs; + *dstoff += sizeof (*x); + return 0; +} + +static dds_return_t fini_locator (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag) +{ + nn_locators_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_locators_t)); + if (!(*flagset->aliased &flag)) + { + while (x->first) + { + struct nn_locators_one *l = x->first; + x->first = l->next; + ddsrt_free (l); + } + } + return 0; +} + +static void fini_generic_partial (void * __restrict dst, size_t * __restrict dstoff, const enum pserop *desc, const enum pserop * const desc_end, bool aliased) +{ +#define COMPLEX(basecase_, type_, cleanup_unaliased_, cleanup_always_) do { \ + type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { \ + if (!aliased) do { cleanup_unaliased_; } while (0); \ + do { cleanup_always_; } while (0); \ + } \ + *dstoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_) COMPLEX (basecase_, type_, (void) 0, (void) 0) + while (desc != desc_end) + { + switch (*desc) + { + case XSTOP: return; + case XO: COMPLEX (XO, ddsi_octetseq_t, ddsrt_free (x->value), (void) 0); break; + case XS: COMPLEX (XS, char *, ddsrt_free (*x), (void) 0); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, { for (uint32_t i = 0; i < x->n; i++) ddsrt_free (x->strs[i]); }, ddsrt_free (x->strs)); break; + case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0, (void) 0); break; + case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int32_t); break; + case XD: case XDx2: SIMPLE (XD, dds_duration_t); break; + case Xo: case Xox2: SIMPLE (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break; + case XbCOND: SIMPLE (XbCOND, unsigned char); break; + case XG: SIMPLE (XG, nn_guid_t); break; + case XK: SIMPLE (XK, nn_keyhash_t); break; + } + desc++; + } +#undef SIMPLE +#undef COMPLEX +} + +static dds_return_t deser_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const struct dd * __restrict dd, size_t * __restrict srcoff, const enum pserop * __restrict desc) +{ + enum pserop const * const desc_in = desc; + size_t dstoff_in = *dstoff; + /* very large buffers run a risk with alignment calculations; such buffers basically + do not occur for discovery data, so checking makes sense */ + if (dd->bufsz >= SIZE_MAX - 8) + return DDS_RETCODE_BAD_PARAMETER; + while (true) + { + assert (*srcoff <= dd->bufsz); + switch (*desc) + { + case XSTOP: + *flagset->present |= flag; + return 0; + case XO: { /* octet sequence */ + ddsi_octetseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_octetseq_t)); + if (deser_uint32 (&x->length, dd, srcoff) < 0 || dd->bufsz - *srcoff < x->length) + goto fail; + x->value = x->length ? (unsigned char *) (dd->buf + *srcoff) : NULL; + *srcoff += x->length; + *dstoff += sizeof (*x); + *flagset->aliased |= flag; + break; + } + case XS: { /* string: alias as-if octet sequence, do additional checks and store as string */ + char ** const x = deser_generic_dst (dst, dstoff, alignof (char *)); + ddsi_octetseq_t tmp; + size_t tmpoff = 0; + if (deser_generic (&tmp, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XO, XSTOP }) < 0) + goto fail; + if (tmp.length < 1 || tmp.value[tmp.length - 1] != 0) + goto fail; + *x = (char *) tmp.value; + *dstoff += sizeof (*x); + break; + } + case XZ: { /* string sequence: repeatedly read a string */ + ddsi_stringseq_t * const x = deser_generic_dst (dst, dstoff, alignof (ddsi_stringseq_t)); + /* sequence of string: length length ..., where each length is aligned + to a multiple of 4 bytes and the lengths are all at least 1, therefore all but the + last entry need 8 bytes and the final one at least 5; checking this protects us + against allocating large amount of memory */ + if (deser_uint32 (&x->n, dd, srcoff) < 0 || x->n > (dd->bufsz - *srcoff + 7) / 8) + goto fail; + x->strs = x->n ? ddsrt_malloc (x->n * sizeof (*x->strs)) : NULL; + size_t tmpoff = 0; + for (uint32_t i = 0; i < x->n; i++) + if (deser_generic (x->strs, &tmpoff, flagset, flag, dd, srcoff, (enum pserop []) { XS, XSTOP }) < 0) + goto fail; + *dstoff += sizeof (*x); + break; + } + case XE1: case XE2: case XE3: { /* enum with max allowed value */ + unsigned * const x = deser_generic_dst (dst, dstoff, alignof (int)); + const uint32_t maxval = 1 + (uint32_t) (*desc - XE1); + uint32_t tmp; + if (deser_uint32 (&tmp, dd, srcoff) < 0 || tmp > maxval) + goto fail; + *x = (unsigned) tmp; + *dstoff += sizeof (*x); + break; + } + case Xi: case Xix2: case Xix3: case Xix4: { /* int32_t(s) */ + uint32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xi); + for (uint32_t i = 0; i < cnt; i++) + if (deser_uint32 (&x[i], dd, srcoff) < 0) + goto fail; + *dstoff += cnt * sizeof (*x); + break; + } + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: { /* uint32_t(s): treated the same */ + uint32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xu); + for (uint32_t i = 0; i < cnt; i++) + if (deser_uint32 (&x[i], dd, srcoff) < 0) + goto fail; + *dstoff += cnt * sizeof (*x); + break; + } + case Xl: { /* length(s): int32_t, -1 or >= 1 */ + int32_t * const x = deser_generic_dst (dst, dstoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xl); + for (uint32_t i = 0; i < cnt; i++) + if (deser_uint32 ((uint32_t *) &x[i], dd, srcoff) < 0 || (x[i] < 1 && x[i] != DDS_LENGTH_UNLIMITED)) + goto fail; + *dstoff += cnt * sizeof (*x); + break; + } + case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */ + dds_duration_t * const x = deser_generic_dst (dst, dstoff, alignof (dds_duration_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - XD); + for (uint32_t i = 0; i < cnt; i++) + { + ddsi_duration_t tmp; + if (deser_uint32 ((uint32_t *) &tmp.seconds, dd, srcoff) < 0 || deser_uint32 (&tmp.fraction, dd, srcoff) < 0) + goto fail; + if (validate_external_duration (&tmp)) + goto fail; + x[i] = nn_from_ddsi_duration (tmp); + } + *dstoff += cnt * sizeof (*x); + break; + } + case Xo: case Xox2: { /* octet(s) */ + unsigned char * const x = deser_generic_dst (dst, dstoff, alignof (unsigned char)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xo); + if (dd->bufsz - *srcoff < cnt) + goto fail; + memcpy (x, dd->buf + *srcoff, cnt); + *srcoff += cnt; + *dstoff += cnt * sizeof (*x); + break; + } + case Xb: case Xbx2: case XbCOND: { /* boolean(s) */ + unsigned char * const x = deser_generic_dst (dst, dstoff, alignof (unsigned char)); + const uint32_t cnt = (*desc == Xbx2) ? 2 : 1; /* <<<< beware! */ + if (dd->bufsz - *srcoff < cnt) + goto fail; + memcpy (x, dd->buf + *srcoff, cnt); + for (uint32_t i = 0; i < cnt; i++) + if (x[i] > 1) + goto fail; + *srcoff += cnt; + *dstoff += cnt * sizeof (*x); + break; + } + case XG: { /* GUID */ + nn_guid_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_guid_t)); + if (dd->bufsz - *srcoff < sizeof (*x)) + goto fail; + memcpy (x, dd->buf + *srcoff, sizeof (*x)); + *x = nn_ntoh_guid (*x); + *srcoff += sizeof (*x); + *dstoff += sizeof (*x); + break; + } + case XK: { /* keyhash */ + nn_keyhash_t * const x = deser_generic_dst (dst, dstoff, alignof (nn_keyhash_t)); + if (dd->bufsz - *srcoff < sizeof (*x)) + goto fail; + memcpy (x, dd->buf + *srcoff, sizeof (*x)); + *srcoff += sizeof (*x); + *dstoff += sizeof (*x); + break; + } + } + desc++; + } + +fail: + fini_generic_partial (dst, &dstoff_in, desc_in, desc, *flagset->aliased & flag); + *flagset->present &= ~flag; + *flagset->aliased &= ~flag; + return DDS_RETCODE_BAD_PARAMETER; +} + +static size_t ser_generic_size (const void *src, size_t srcoff, const enum pserop * __restrict desc) +{ + size_t dstoff = 0; +#define COMPLEX(basecase_, type_, dstoff_update_) do { \ + type_ const *x = deser_generic_src (src, &srcoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { dstoff_update_; } \ + srcoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE1(basecase_, type_) COMPLEX (basecase_, type_, dstoff = dstoff + sizeof (*x)) +#define SIMPLE4(basecase_, type_) COMPLEX (basecase_, type_, dstoff = align4size (dstoff) + sizeof (*x)) + while (true) + { + switch (*desc) + { + case XSTOP: return dstoff; + case XO: COMPLEX (XO, ddsi_octetseq_t, dstoff = align4size (dstoff) + 4 + x->length); break; + case XS: COMPLEX (XS, const char *, dstoff = align4size (dstoff) + 4 + strlen (*x) + 1); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, { + dstoff = align4size (dstoff) + 4; + for (uint32_t i = 0; i < x->n; i++) + dstoff = align4size (dstoff) + 4 + strlen (x->strs[i]) + 1; + }); break; + case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, dstoff = align4size (dstoff) + 4); break; + case Xi: case Xix2: case Xix3: case Xix4: SIMPLE4 (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE4 (Xu, uint32_t); break; + case Xl: SIMPLE4 (Xl, int32_t); break; + case XD: case XDx2: SIMPLE4 (XD, dds_duration_t); break; + case Xo: case Xox2: SIMPLE1 (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE1 (Xb, unsigned char); break; + case XbCOND: SIMPLE1 (XbCOND, unsigned char); break; + case XG: SIMPLE1 (XG, nn_guid_t); break; + case XK: SIMPLE1 (XK, nn_keyhash_t); break; + } + desc++; + } +#undef SIMPLE +#undef COMPLEX +} + +static dds_return_t ser_generic (struct nn_xmsg *xmsg, nn_parameterid_t pid, const void *src, size_t srcoff, const enum pserop * __restrict desc) +{ + char * const data = nn_xmsg_addpar (xmsg, pid, ser_generic_size (src, srcoff, desc)); + size_t dstoff = 0; + while (true) + { + switch (*desc) + { + case XSTOP: + return 0; + case XO: { /* octet sequence */ + ddsi_octetseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_octetseq_t)); + char * const p = ser_generic_align4 (data, &dstoff); + *((uint32_t *) p) = x->length; + if (x->length) memcpy (p + 4, x->value, x->length); + dstoff += 4 + x->length; + srcoff += sizeof (*x); + break; + } + case XS: { /* string */ + char const * const * const x = deser_generic_src (src, &srcoff, alignof (char *)); + const uint32_t size = (uint32_t) (strlen (*x) + 1); + char * const p = ser_generic_align4 (data, &dstoff); + *((uint32_t *) p) = size; + memcpy (p + 4, *x, size); + dstoff += 4 + size; + srcoff += sizeof (*x); + break; + } + case XZ: { /* string sequence */ + ddsi_stringseq_t const * const x = deser_generic_src (src, &srcoff, alignof (ddsi_stringseq_t)); + char * const p = ser_generic_align4 (data, &dstoff); + *((uint32_t *) p) = x->n; + dstoff += 4; + for (uint32_t i = 0; i < x->n; i++) + { + char * const q = ser_generic_align4 (data, &dstoff); + const uint32_t size = (uint32_t) (strlen (x->strs[i]) + 1); + *((uint32_t *) q) = size; + memcpy (q + 4, x->strs[i], size); + dstoff += 4 + size; + } + srcoff += sizeof (*x); + break; + } + case XE1: case XE2: case XE3: { /* enum */ + unsigned const * const x = deser_generic_src (src, &srcoff, alignof (unsigned)); + uint32_t * const p = ser_generic_align4 (data, &dstoff); + *p = (uint32_t) *x; + dstoff += 4; + srcoff += sizeof (*x); + break; + } + case Xi: case Xix2: case Xix3: case Xix4: { /* int32_t(s) */ + int32_t const * const x = deser_generic_src (src, &srcoff, alignof (int32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xi); + int32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + p[i] = x[i]; + dstoff += cnt * sizeof (*x); + srcoff += cnt * sizeof (*x); + break; + } + + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: { /* uint32_t(s) */ + uint32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xu); + uint32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + p[i] = x[i]; + dstoff += cnt * sizeof (*x); + srcoff += cnt * sizeof (*x); + break; + } + + case Xl: { /* int32_t(s) */ + int32_t const * const x = deser_generic_src (src, &srcoff, alignof (uint32_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xu); + int32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + p[i] = x[i]; + dstoff += cnt * sizeof (*x); + srcoff += cnt * sizeof (*x); + break; + } + case XD: case XDx2: { /* duration(s): int64_t <=> int32_t.uint32_t (seconds.fraction) */ + dds_duration_t const * const x = deser_generic_src (src, &srcoff, alignof (dds_duration_t)); + const uint32_t cnt = 1 + (uint32_t) (*desc - XD); + uint32_t * const p = ser_generic_align4 (data, &dstoff); + for (uint32_t i = 0; i < cnt; i++) + { + ddsi_duration_t tmp = nn_to_ddsi_duration (x[i]); + p[2 * i + 0] = (uint32_t) tmp.seconds; + p[2 * i + 1] = tmp.fraction; + } + dstoff += 2 * cnt * sizeof (uint32_t); + srcoff += cnt * sizeof (*x); + break; + } + case Xo: case Xox2: { /* octet(s) */ + unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char)); + const uint32_t cnt = 1 + (uint32_t) (*desc - Xo); + char * const p = data + dstoff; + memcpy (p, x, cnt); + dstoff += cnt; + srcoff += cnt * sizeof (*x); + break; + } + case Xb: case Xbx2: case XbCOND: { /* boolean(s) */ + unsigned char const * const x = deser_generic_src (src, &srcoff, alignof (unsigned char)); + const uint32_t cnt = (*desc == Xbx2) ? 2 : 1; /* <<<< beware! */ + char * const p = data + dstoff; + memcpy (p, x, cnt); + dstoff += cnt; + srcoff += cnt * sizeof (*x); + break; + } + case XG: { /* GUID */ + nn_guid_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_guid_t)); + const nn_guid_t xn = nn_hton_guid (*x); + char * const p = data + dstoff; + memcpy (p, &xn, sizeof (xn)); + dstoff += sizeof (xn); + srcoff += sizeof (*x); + break; + } + case XK: { /* keyhash */ + nn_keyhash_t const * const x = deser_generic_src (src, &srcoff, alignof (nn_keyhash_t)); + char * const p = data + dstoff; + memcpy (p, x, sizeof (*x)); + dstoff += sizeof (*x); + srcoff += sizeof (*x); + break; + } + } + desc++; + } +} + +static dds_return_t unalias_generic (void * __restrict dst, size_t * __restrict dstoff, const enum pserop * __restrict desc) +{ +#define COMPLEX(basecase_, type_, ...) do { \ + type_ *x = deser_generic_dst (dst, dstoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - basecase_); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { __VA_ARGS__; } \ + *dstoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_) COMPLEX (basecase_, type_, (void) 0) + while (true) + { + switch (*desc) + { + case XSTOP: + return 0; + case XO: COMPLEX (XO, ddsi_octetseq_t, x->value = ddsrt_memdup (x->value, x->length)); break; + case XS: COMPLEX (XS, char *, *x = ddsrt_strdup (*x)); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, { + x->strs = ddsrt_memdup (x->strs, x->n * sizeof (*x->strs)); + for (uint32_t i = 0; i < x->n; i++) + x->strs[i] = ddsrt_strdup (x->strs[i]); + }); break; + case XE1: case XE2: case XE3: COMPLEX (*desc, unsigned, (void) 0); break; + case Xi: case Xix2: case Xix3: case Xix4: SIMPLE (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: SIMPLE (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int32_t); break; + case XD: case XDx2: SIMPLE (XD, dds_duration_t); break; + case Xo: case Xox2: SIMPLE (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE (Xb, unsigned char); break; + case XbCOND: SIMPLE (XbCOND, unsigned char); break; + case XG: SIMPLE (XG, nn_guid_t); break; + case XK: SIMPLE (XK, nn_keyhash_t); break; + } + desc++; + } +#undef SIMPLE +#undef COMPLEX +} + +static bool unalias_generic_required (const enum pserop * __restrict desc) +{ + while (*desc != XSTOP) + { + switch (*desc++) + { + case XO: case XS: case XZ: + return true; + default: + break; + } + } + return false; +} + +static bool fini_generic_required (const enum pserop * __restrict desc) +{ + /* the two happen to be the same */ + return unalias_generic_required (desc); +} + +static dds_return_t fini_generic (void * __restrict dst, size_t * __restrict dstoff, struct flagset *flagset, uint64_t flag, const enum pserop * __restrict desc) +{ + fini_generic_partial (dst, dstoff, desc, NULL, *flagset->aliased & flag); + return 0; +} + +static dds_return_t valid_generic (const void *src, size_t srcoff, const enum pserop * __restrict desc) +{ +#define COMPLEX(basecase_, type_, cond_stmts_) do { \ + type_ const *x = deser_generic_src (src, &srcoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++) { cond_stmts_; } \ + srcoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_, cond_) COMPLEX (basecase_, type_, if (!(cond_)) return DDS_RETCODE_BAD_PARAMETER) +#define TRIVIAL(basecase_, type_) COMPLEX (basecase_, type_, (void) 0) + while (true) + { + switch (*desc) + { + case XSTOP: return 0; + case XO: SIMPLE (XO, ddsi_octetseq_t, (x->length == 0) == (x->value == NULL)); break; + case XS: SIMPLE (XS, const char *, *x != NULL); break; + case XZ: COMPLEX (XZ, ddsi_stringseq_t, { + if ((x->n == 0) != (x->strs == NULL)) + return DDS_RETCODE_BAD_PARAMETER; + for (uint32_t i = 0; i < x->n; i++) + if (x->strs[i] == NULL) + return DDS_RETCODE_BAD_PARAMETER; + }); break; + case XE1: case XE2: case XE3: SIMPLE (*desc, unsigned, *x <= 1 + (unsigned) *desc - XE1); break; + case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break; + case Xl: SIMPLE (Xl, int32_t, *x == DDS_LENGTH_UNLIMITED || *x > 1); break; + case XD: case XDx2: SIMPLE (XD, dds_duration_t, *x >= 0); break; + case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break; + case Xb: case Xbx2: SIMPLE (Xb, unsigned char, *x == 0 || *x == 1); break; + case XbCOND: SIMPLE (XbCOND, unsigned char, *x == 0 || *x == 1); break; + case XG: TRIVIAL (XG, nn_guid_t); break; + case XK: TRIVIAL (XK, nn_keyhash_t); break; + } + desc++; + } +#undef TRIVIAL +#undef SIMPLE +#undef COMPLEX +} + +static bool equal_generic (const void *srcx, const void *srcy, size_t srcoff, const enum pserop * __restrict desc) +{ +#define COMPLEX(basecase_, type_, cond_stmts_) do { \ + type_ const *x = deser_generic_src (srcx, &srcoff, alignof (type_)); \ + type_ const *y = deser_generic_src (srcy, &srcoff, alignof (type_)); \ + const uint32_t cnt = 1 + (uint32_t) (*desc - (basecase_)); \ + for (uint32_t xi = 0; xi < cnt; xi++, x++, y++) { cond_stmts_; } \ + srcoff += cnt * sizeof (*x); \ + } while (0) +#define SIMPLE(basecase_, type_, cond_) COMPLEX (basecase_, type_, if (!(cond_)) return false) +#define TRIVIAL(basecase_, type_) SIMPLE (basecase_, type_, *x == *y) + while (true) + { + switch (*desc) + { + case XSTOP: + return true; + case XO: + SIMPLE (XO, ddsi_octetseq_t, + (x->length == y->length) && + (x->length == 0 || memcmp (x->value, y->value, x->length) == 0)); + break; + case XS: + SIMPLE (XS, const char *, strcmp (*x, *y) == 0); + break; + case XZ: + COMPLEX (XZ, ddsi_stringseq_t, { + if (x->n != y->n) + return false; + for (uint32_t i = 0; i < x->n; i++) + if (strcmp (x->strs[i], y->strs[i]) != 0) + return false; + }); + break; + case XE1: case XE2: case XE3: TRIVIAL (*desc, unsigned); break; + case Xi: case Xix2: case Xix3: case Xix4: TRIVIAL (Xi, int32_t); break; + case Xu: case Xux2: case Xux3: case Xux4: case Xux5: TRIVIAL (Xu, uint32_t); break; + case Xl: TRIVIAL (Xl, int32_t); break; + case XD: case XDx2: TRIVIAL (XD, dds_duration_t); break; + case Xo: case Xox2: TRIVIAL (Xo, unsigned char); break; + case Xb: case Xbx2: TRIVIAL (Xb, unsigned char); break; + case XbCOND: + COMPLEX (XbCOND, unsigned char, { + if (*x != *y) + return false; + if (*x == false) + return true; + }); + break; + case XG: SIMPLE (XG, nn_guid_t, memcmp (x, y, sizeof (*x))); break; + case XK: SIMPLE (XK, nn_keyhash_t, memcmp (x, y, sizeof (*x))); break; + } + desc++; + } +#undef TRIVIAL +#undef SIMPLE +#undef COMPLEX +} + +#define membersize(type, member) sizeof (((type *) 0)->member) +#define ENTRY(PFX_, NAME_, member_, flag_, validate_, ...) \ + { PID_##NAME_, flag_, PFX_##_##NAME_, #NAME_, offsetof (struct nn_plist, member_), \ + membersize (struct nn_plist, member_), { .desc = { __VA_ARGS__, XSTOP } }, validate_ \ + } +#define QPV(NAME_, name_, ...) ENTRY(QP, NAME_, qos.name_, PDF_QOS, dvx_##name_, __VA_ARGS__) +#define PPV(NAME_, name_, ...) ENTRY(PP, NAME_, name_, 0, dvx_##name_, __VA_ARGS__) +#define QP(NAME_, name_, ...) ENTRY(QP, NAME_, qos.name_, PDF_QOS, 0, __VA_ARGS__) +#define PP(NAME_, name_, ...) ENTRY(PP, NAME_, name_, 0, 0, __VA_ARGS__) +#define PPM(NAME_, name_, ...) ENTRY(PP, NAME_, name_, PDF_ALLOWMULTI, 0, __VA_ARGS__) + static int protocol_version_is_newer (nn_protocol_version_t pv) { return (pv.major < RTPS_MAJOR) ? 0 : (pv.major > RTPS_MAJOR) ? 1 : (pv.minor > RTPS_MINOR); } -static dds_return_t validate_string (const struct dd *dd, size_t *len) +static dds_return_t dvx_durability_service (void * __restrict dst, const struct dd * __restrict dd) { - const struct cdrstring *x = (const struct cdrstring *) dd->buf; - if (dd->bufsz < sizeof (struct cdrstring)) - { - DDS_TRACE("plist/validate_string: buffer too small (header)\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - *len = dd->bswap ? bswap4u (x->length) : x->length; - if (*len < 1 || *len > dd->bufsz - offsetof (struct cdrstring, contents)) - { - DDS_TRACE("plist/validate_string: length %" PRIuSIZE " out of range\n", *len); - return DDS_RETCODE_BAD_PARAMETER; - } - if (x->contents[*len-1] != 0) - { - DDS_TRACE("plist/validate_string: terminator missing\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - return 0; + /* Accept all zero durability because of CoreDX, final_validation is more strict */ + (void) dd; + return validate_durability_service_qospolicy_acceptzero (dst, true); } -static dds_return_t alias_string (const unsigned char **ptr, const struct dd *dd, size_t *len) +static dds_return_t dvx_history (void * __restrict dst, const struct dd * __restrict dd) { - dds_return_t rc; - if ((rc = validate_string (dd, len)) < 0) - return rc; + (void) dd; + return validate_history_qospolicy (dst); +} + +static dds_return_t dvx_resource_limits (void * __restrict dst, const struct dd * __restrict dd) +{ + (void) dd; + return validate_resource_limits_qospolicy (dst); +} + +static dds_return_t dvx_participant_guid (void * __restrict dst, const struct dd * __restrict dd) +{ + const nn_guid_t *g = dst; + (void) dd; + if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) + return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; else - { - const struct cdrstring *x = (const struct cdrstring *) dd->buf; - *ptr = x->contents; - return 0; - } + return (g->entityid.u == NN_ENTITYID_PARTICIPANT) ? 0 : DDS_RETCODE_BAD_PARAMETER; } -static void unalias_string (char **str, int bswap) +static dds_return_t dvx_group_guid (void * __restrict dst, const struct dd * __restrict dd) { - const char *alias = *str; - uint32_t len; - if (bswap == 0 || bswap == 1) - { - const uint32_t *plen = (const uint32_t *) alias - 1; - len = bswap ? bswap4u (*plen) : *plen; - } + const nn_guid_t *g = dst; + (void) dd; + if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) + return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; else - { - len = (uint32_t) strlen (alias) + 1; - } - *str = ddsrt_malloc (len); - memcpy (*str, alias, len); + return (g->entityid.u != 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; } -static dds_return_t validate_octetseq (const struct dd *dd, size_t *len) +static dds_return_t dvx_endpoint_guid (void * __restrict dst, const struct dd * __restrict dd) { - const struct cdroctetseq *x = (const struct cdroctetseq *) dd->buf; - if (dd->bufsz < offsetof (struct cdroctetseq, value)) - return DDS_RETCODE_BAD_PARAMETER; - *len = dd->bswap ? bswap4u (x->len) : x->len; - if (*len > dd->bufsz - offsetof (struct cdroctetseq, value) || *len >= UINT32_MAX) - return DDS_RETCODE_BAD_PARAMETER; + nn_guid_t *g = dst; + if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) + return (g->entityid.u == 0) ? 0 : DDS_RETCODE_BAD_PARAMETER; + switch (g->entityid.u & NN_ENTITYID_KIND_MASK) + { + case NN_ENTITYID_KIND_WRITER_WITH_KEY: + case NN_ENTITYID_KIND_WRITER_NO_KEY: + case NN_ENTITYID_KIND_READER_NO_KEY: + case NN_ENTITYID_KIND_READER_WITH_KEY: + return 0; + default: + return (protocol_version_is_newer (dd->protocol_version) ? 0 : DDS_RETCODE_BAD_PARAMETER); + } +} + +#ifdef DDSI_INCLUDE_SSM +static dds_return_t dvx_reader_favours_ssm (void * __restrict dst, const struct dd * __restrict dd) +{ + uint32_t * const favours_ssm = dst; + (void) dd; + /* any unrecognized state: avoid SSM */ + if (*favours_ssm != 0 && *favours_ssm != 1) + *favours_ssm = 0; return 0; } - -static dds_return_t alias_octetseq (ddsi_octetseq_t *oseq, const struct dd *dd) -{ - size_t len; - dds_return_t rc; - if ((rc = validate_octetseq (dd, &len)) < 0) - return rc; - else - { - const struct cdroctetseq *x = (const struct cdroctetseq *) dd->buf; - assert(len < UINT32_MAX); /* it really is an uint32_t on the wire */ - oseq->length = (uint32_t)len; - oseq->value = (len == 0) ? NULL : (unsigned char *) x->value; - return 0; - } -} - -static dds_return_t alias_blob (ddsi_octetseq_t *oseq, const struct dd *dd) -{ - assert (dd->bufsz < UINT32_MAX); - oseq->length = (uint32_t)dd->bufsz; - oseq->value = (oseq->length == 0) ? NULL : (unsigned char *) dd->buf; - return 0; -} - -static void unalias_octetseq (ddsi_octetseq_t *oseq, UNUSED_ARG (int bswap)) -{ - if (oseq->length != 0) - { - unsigned char *vs; - vs = ddsrt_malloc (oseq->length); - memcpy (vs, oseq->value, oseq->length); - oseq->value = vs; - } -} - -static dds_return_t validate_stringseq (const struct dd *dd) -{ - const unsigned char *seq = dd->buf; - const unsigned char *seqend = seq + dd->bufsz; - struct dd dd1 = *dd; - int i, n; - if (dd->bufsz < sizeof (int)) - { - DDS_TRACE("plist/validate_stringseq: buffer too small (header)\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&n, seq, sizeof (n)); - if (dd->bswap) - n = bswap4 (n); - seq += sizeof (int); - if (n < 0) - { - DDS_TRACE("plist/validate_stringseq: length %d out of range\n", n); - return DDS_RETCODE_BAD_PARAMETER; - } - else if (n == 0) - { - return 0; - } - else - { - for (i = 0; i < n && seq <= seqend; i++) - { - size_t len1; - int rc; - dd1.buf = seq; - dd1.bufsz = (size_t) (seqend - seq); - if ((rc = validate_string (&dd1, &len1)) < 0) - { - DDS_TRACE("plist/validate_stringseq: invalid string\n"); - return rc; - } - seq += sizeof (uint32_t) + align4u (len1); - } - if (i < n) - { - DDS_TRACE("plist/validate_stringseq: buffer too small (contents)\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - } - /* Should I worry about junk between the last string & the end of - the parameter? */ - return 0; -} - -static dds_return_t alias_stringseq (ddsi_stringseq_t *strseq, const struct dd *dd) -{ - /* Not truly an alias: it allocates an array of pointers that alias - the individual null-terminated strings. Also: see - validate_stringseq */ - const unsigned char *seq = dd->buf; - const unsigned char *seqend = seq + dd->bufsz; - struct dd dd1 = *dd; - char **strs; - uint32_t i; - dds_return_t result; - if (dd->bufsz < sizeof (int)) - { - DDS_TRACE("plist/alias_stringseq: buffer too small (header)\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&strseq->n, seq, sizeof (strseq->n)); - if (dd->bswap) - strseq->n = bswap4u (strseq->n); - seq += sizeof (uint32_t); - if (strseq->n >= UINT_MAX / sizeof(*strs)) - { - DDS_TRACE("plist/alias_stringseq: length %"PRIu32" out of range\n", strseq->n); - return DDS_RETCODE_BAD_PARAMETER; - } - else if (strseq->n == 0) - { - strseq->strs = NULL; - } - else - { - strs = ddsrt_malloc (strseq->n * sizeof (*strs)); - for (i = 0; i < strseq->n && seq <= seqend; i++) - { - size_t len1; - dd1.buf = seq; - dd1.bufsz = (size_t)(seqend - seq); - /* (const char **) to silence the compiler, unfortunately strseq - can't have a const char **strs, that would require a const - and a non-const version of it. */ - if ((result = alias_string ((const unsigned char **) &strs[i], &dd1, &len1)) < 0) - { - DDS_TRACE("plist/alias_stringseq: invalid string\n"); - goto fail; - } - seq += sizeof (uint32_t) + align4u (len1); - } - if (i != strseq->n) - { - DDS_TRACE("plist/validate_stringseq: buffer too small (contents)\n"); - result = DDS_RETCODE_BAD_PARAMETER; - goto fail; - } - strseq->strs = strs; - } - return 0; - fail: - ddsrt_free (strs); - return result; -} - -static void free_stringseq (ddsi_stringseq_t *strseq) -{ - uint32_t i; - for (i = 0; i < strseq->n; i++) - if (strseq->strs[i]) - ddsrt_free (strseq->strs[i]); - ddsrt_free (strseq->strs); -} - -static dds_return_t unalias_stringseq (ddsi_stringseq_t *strseq, int bswap) -{ - uint32_t i; - char **strs; - if (strseq->n != 0) - { - strs = ddsrt_malloc (strseq->n * sizeof (*strs)); - for (i = 0; i < strseq->n; i++) - { - strs[i] = strseq->strs[i]; - unalias_string (&strs[i], bswap); - } - ddsrt_free (strseq->strs); - strseq->strs = strs; - } - return 0; -} - -static void duplicate_stringseq (ddsi_stringseq_t *dest, const ddsi_stringseq_t *src) -{ - uint32_t i; - dest->n = src->n; -assert (dest->strs == NULL); - if (dest->n == 0) - { - dest->strs = NULL; - return; - } - dest->strs = ddsrt_malloc (dest->n * sizeof (*dest->strs)); - for (i = 0; i < dest->n; i++) - { - dest->strs[i] = src->strs[i]; - unalias_string (&dest->strs[i], -1); - } -} - -static void free_locators (nn_locators_t *locs) -{ - while (locs->first) - { - struct nn_locators_one *l = locs->first; - locs->first = l->next; - ddsrt_free (l); - } -} - -static void unalias_locators (nn_locators_t *locs, UNUSED_ARG (int bswap)) -{ - nn_locators_t newlocs; - struct nn_locators_one *lold; - /* Copy it, without reversing the order. On failure, free the copy, - on success overwrite *locs. */ - newlocs.n = locs->n; - newlocs.first = NULL; - newlocs.last = NULL; - for (lold = locs->first; lold != NULL; lold = lold->next) - { - struct nn_locators_one *n; - n = ddsrt_malloc (sizeof (*n)); - n->next = NULL; - n->loc = lold->loc; - if (newlocs.first == NULL) - newlocs.first = n; - else - newlocs.last->next = n; - newlocs.last = n; - } - *locs = newlocs; -} - -static void unalias_eotinfo (nn_prismtech_eotinfo_t *txnid, UNUSED_ARG (int bswap)) -{ - if (txnid->n > 0) - { - nn_prismtech_eotgroup_tid_t *vs; - vs = ddsrt_malloc (txnid->n * sizeof (*vs)); - memcpy (vs, txnid->tids, txnid->n * sizeof (*vs)); - txnid->tids = vs; - } -} - -void nn_plist_fini (nn_plist_t *ps) -{ - struct t { uint64_t fl; size_t off; }; - static const struct t simple[] = { - { PP_ENTITY_NAME, offsetof (nn_plist_t, entity_name) }, - { PP_PRISMTECH_NODE_NAME, offsetof (nn_plist_t, node_name) }, - { PP_PRISMTECH_EXEC_NAME, offsetof (nn_plist_t, exec_name) }, - { PP_PRISMTECH_PARTICIPANT_VERSION_INFO, offsetof (nn_plist_t, prismtech_participant_version_info.internals) }, - { PP_PRISMTECH_TYPE_DESCRIPTION, offsetof (nn_plist_t, type_description) }, - { PP_PRISMTECH_EOTINFO, offsetof (nn_plist_t, eotinfo.tids) } - }; - static const struct t locs[] = { - { PP_UNICAST_LOCATOR, offsetof (nn_plist_t, unicast_locators) }, - { PP_MULTICAST_LOCATOR, offsetof (nn_plist_t, multicast_locators) }, - { PP_DEFAULT_UNICAST_LOCATOR, offsetof (nn_plist_t, default_unicast_locators) }, - { PP_DEFAULT_MULTICAST_LOCATOR, offsetof (nn_plist_t, default_multicast_locators) }, - { PP_METATRAFFIC_UNICAST_LOCATOR, offsetof (nn_plist_t, metatraffic_unicast_locators) }, - { PP_METATRAFFIC_MULTICAST_LOCATOR, offsetof (nn_plist_t, metatraffic_multicast_locators) } - }; - int i; - nn_xqos_fini (&ps->qos); - - /* The compiler doesn't understand how offsetof is used in the arrays. */ - DDSRT_WARNING_MSVC_OFF(6001); - for (i = 0; i < (int) (sizeof (simple) / sizeof (*simple)); i++) - { - if ((ps->present & simple[i].fl) && !(ps->aliased & simple[i].fl)) - { - void **pp = (void **) ((char *) ps + simple[i].off); - ddsrt_free (*pp); - } - } - for (i = 0; i < (int) (sizeof (locs) / sizeof (*locs)); i++) - { - if ((ps->present & locs[i].fl) && !(ps->aliased & locs[i].fl)) - free_locators ((nn_locators_t *) ((char *) ps + locs[i].off)); - } - DDSRT_WARNING_MSVC_ON(6001); - - ps->present = 0; -} - -#if 0 /* not currently needed */ -void nn_plist_unalias (nn_plist_t *ps) -{ -#define P(name_, func_, field_) do { \ - if ((ps->present & PP_##name_) && (ps->aliased & PP_##name_)) { \ - unalias_##func_ (&ps->field_, -1); \ - ps->aliased &= ~PP_##name_; \ - } \ - } while (0) - nn_xqos_unalias (&ps->qos); - P (ENTITY_NAME, string, entity_name); - P (UNICAST_LOCATOR, locators, unicast_locators); - P (MULTICAST_LOCATOR, locators, multicast_locators); - P (DEFAULT_UNICAST_LOCATOR, locators, default_unicast_locators); - P (DEFAULT_MULTICAST_LOCATOR, locators, default_multicast_locators); - P (METATRAFFIC_UNICAST_LOCATOR, locators, metatraffic_unicast_locators); - P (METATRAFFIC_MULTICAST_LOCATOR, locators, metatraffic_multicast_locators); - P (PRISMTECH_NODE_NAME, string, node_name); - P (PRISMTECH_EXEC_NAME, string, exec_name); - P (PRISMTECH_TYPE_DESCRIPTION, string, type_description); - P (PRISMTECH_EOTINFO, eotinfo, eotinfo); -#undef P - if ((ps->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO) && - (ps->aliased & PP_PRISMTECH_PARTICIPANT_VERSION_INFO)) - { - unalias_string (&ps->prismtech_participant_version_info.internals, -1); - ps->aliased &= ~PP_PRISMTECH_PARTICIPANT_VERSION_INFO; - } - - assert (ps->aliased == 0); -} #endif -static dds_return_t do_octetseq (ddsi_octetseq_t *dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) +/* Standardized parameters -- QoS _MUST_ come first (nn_plist_init_tables verifies this) because + it allows early-out when processing a dds_qos_t instead of an nn_plist_t */ +static const struct piddesc piddesc_omg[] = { + QP (USER_DATA, user_data, XO), + QP (TOPIC_NAME, topic_name, XS), + QP (TYPE_NAME, type_name, XS), + QP (TOPIC_DATA, topic_data, XO), + QP (GROUP_DATA, group_data, XO), + QP (DURABILITY, durability, XE3), + /* CoreDX's use of all-zero durability service QoS means we can't use l; interdependencies between QoS + values means we must validate the combination anyway */ + QPV (DURABILITY_SERVICE, durability_service, XD, XE1, Xix4), + QP (DEADLINE, deadline, XD), + QP (LATENCY_BUDGET, latency_budget, XD), + QP (LIVELINESS, liveliness, XE2, XD), + /* Reliability encoding does not follow the rules (best-effort/reliable map to 1/2 instead of 0/1 */ + { PID_RELIABILITY, PDF_QOS | PDF_FUNCTION, QP_RELIABILITY, "RELIABILITY", + offsetof (struct nn_plist, qos.reliability), membersize (struct nn_plist, qos.reliability), + { .f = { .deser = deser_reliability, .ser = ser_reliability, .valid = valid_reliability, .equal = equal_reliability } }, 0 }, + QP (LIFESPAN, lifespan, XD), + QP (DESTINATION_ORDER, destination_order, XE1), + /* History depth is ignored when kind = KEEP_ALL, and must be >= 1 when KEEP_LAST, so can't use "l" */ + QPV (HISTORY, history, XE1, Xi), + QPV (RESOURCE_LIMITS, resource_limits, Xix3), + QP (OWNERSHIP, ownership, XE1), + QP (OWNERSHIP_STRENGTH, ownership_strength, Xi), + QP (PRESENTATION, presentation, XE2, Xbx2), + QP (PARTITION, partition, XZ), + QP (TIME_BASED_FILTER, time_based_filter, XD), + QP (TRANSPORT_PRIORITY, transport_priority, Xi), + PP (PROTOCOL_VERSION, protocol_version, Xox2), + PP (VENDORID, vendorid, Xox2), + PP (EXPECTS_INLINE_QOS, expects_inline_qos, Xb), + PP (PARTICIPANT_MANUAL_LIVELINESS_COUNT, participant_manual_liveliness_count, Xi), + PP (PARTICIPANT_BUILTIN_ENDPOINTS, participant_builtin_endpoints, Xu), + PP (PARTICIPANT_LEASE_DURATION, participant_lease_duration, XD), + PPV (PARTICIPANT_GUID, participant_guid, XG), + PPV (GROUP_GUID, group_guid, XG), + PP (BUILTIN_ENDPOINT_SET, builtin_endpoint_set, Xu), + PP (ENTITY_NAME, entity_name, XS), + PP (KEYHASH, keyhash, XK), + PPV (ENDPOINT_GUID, endpoint_guid, XG), +#ifdef DDSI_INCLUDE_SSM + PPV (READER_FAVOURS_SSM, reader_favours_ssm, Xu), +#endif + { PID_STATUSINFO, PDF_FUNCTION, PP_STATUSINFO, "STATUSINFO", + offsetof (struct nn_plist, statusinfo), membersize (struct nn_plist, statusinfo), + { .f = { .deser = deser_statusinfo, .ser = ser_statusinfo } }, 0 }, + /* Locators are difficult to deal with because they can occur multi times to represent a set; + that is manageable for deser, unalias and fini, but it breaks ser because that one only + generates a single parameter header */ + { PID_UNICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_UNICAST_LOCATOR, "UNICAST_LOCATOR", + offsetof (struct nn_plist, unicast_locators), membersize (struct nn_plist, unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_MULTICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_MULTICAST_LOCATOR, "MULTICAST_LOCATOR", + offsetof (struct nn_plist, multicast_locators), membersize (struct nn_plist, multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_DEFAULT_UNICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_DEFAULT_UNICAST_LOCATOR, "DEFAULT_UNICAST_LOCATOR", + offsetof (struct nn_plist, default_unicast_locators), membersize (struct nn_plist, default_unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_DEFAULT_MULTICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_DEFAULT_MULTICAST_LOCATOR, "DEFAULT_MULTICAST_LOCATOR", + offsetof (struct nn_plist, default_multicast_locators), membersize (struct nn_plist, default_multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_METATRAFFIC_UNICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_METATRAFFIC_UNICAST_LOCATOR, "METATRAFFIC_UNICAST_LOCATOR", + offsetof (struct nn_plist, metatraffic_unicast_locators), membersize (struct nn_plist, metatraffic_unicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + { PID_METATRAFFIC_MULTICAST_LOCATOR, PDF_FUNCTION | PDF_ALLOWMULTI, + PP_METATRAFFIC_MULTICAST_LOCATOR, "METATRAFFIC_MULTICAST_LOCATOR", + offsetof (struct nn_plist, metatraffic_multicast_locators), membersize (struct nn_plist, metatraffic_multicast_locators), + { .f = { .deser = deser_locator, .ser = ser_locator, .unalias = unalias_locator, .fini = fini_locator } }, 0 }, + /* PID_..._{IPADDRESS,PORT} is impossible to deal with and are never generated, only accepted. + The problem is that there one needs additional state (and even then there is no clear + interpretation) ... So they'll have to be special-cased */ + { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 } +}; + +/* Understood parameters for Eclipse Foundation (Cyclone DDS) vendor code */ +static const struct piddesc piddesc_eclipse[] = { + QP (PRISMTECH_ENTITY_FACTORY, entity_factory, Xb), + QP (PRISMTECH_READER_LIFESPAN, reader_lifespan, Xb, XD), + QP (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle, Xb), + QP (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, XDx2), + QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XZ), + { PID_PAD, PDF_QOS, QP_CYCLONE_IGNORELOCAL, "CYCLONE_IGNORELOCAL", + offsetof (struct nn_plist, qos.ignorelocal), membersize (struct nn_plist, qos.ignorelocal), + { .desc = { XE2, XSTOP } }, 0 }, + PP (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set, Xu), + PP (PRISMTECH_PARTICIPANT_VERSION_INFO, prismtech_participant_version_info, Xux5, XS), + PP (PRISMTECH_EXEC_NAME, exec_name, XS), + PP (PRISMTECH_PROCESS_ID, process_id, Xu), + PP (PRISMTECH_NODE_NAME, node_name, XS), + PP (PRISMTECH_TYPE_DESCRIPTION, type_description, XS), + { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 } +}; + +/* Understood parameters for PrismTech vendor code */ +static const struct piddesc piddesc_prismtech[] = { + QP (PRISMTECH_ENTITY_FACTORY, entity_factory, Xb), + QP (PRISMTECH_READER_LIFESPAN, reader_lifespan, Xb, XD), + QP (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle, Xb), + QP (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, XDx2), + QP (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, XbCOND, XZ), + PP (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set, Xu), + PP (PRISMTECH_PARTICIPANT_VERSION_INFO, prismtech_participant_version_info, Xux5, XS), + PP (PRISMTECH_EXEC_NAME, exec_name, XS), + PP (PRISMTECH_PROCESS_ID, process_id, Xu), + PP (PRISMTECH_NODE_NAME, node_name, XS), + PP (PRISMTECH_TYPE_DESCRIPTION, type_description, XS), + { PID_SENTINEL, 0, 0, NULL, 0, 0, { .desc = { XSTOP } }, 0 } +}; + +#undef PPM +#undef PP +#undef QP +#undef PPV +#undef QPV +#undef ENTRY +#undef membersize + +/* Parameters to be included in messages we generate */ +static const struct piddesc *piddesc_tables_output[] = { + piddesc_omg, + piddesc_eclipse +}; + +/* All known parameters -- this can potentially include + parameters from other vendors that we never generate + but that we do recognize on input and store for some + purpose other than the internal workings of Cyclone, + and that require fini/unalias processing */ +static const struct piddesc *piddesc_tables_all[] = { + piddesc_omg, + piddesc_eclipse +}; + +struct piddesc_index { + size_t index_max; + const struct piddesc **index; + /* include source table for generating the index -- + it's easier to generate the index at startup then + to maintain in the source */ + const struct piddesc *table; +}; + +/* Vendor code to vendor-specific table mapping, with index + vendor codes are currently of the form 1.x with x a small + number > 0 (and that's not likely to change) so we have + a table for major = 1 and use index 0 for the standard + ones. + + Sizes are such that the highest PID (without flags) in + table are the last entry in the array. Checked by + nn_plist_init_tables. */ +static const struct piddesc *piddesc_omg_index[115]; +static const struct piddesc *piddesc_eclipse_index[19]; +static const struct piddesc *piddesc_prismtech_index[19]; + +#define INDEX_ANY(vendorid_, tab_) [vendorid_] = { \ + .index_max = sizeof (piddesc_##tab_##_index) / sizeof (piddesc_##tab_##_index[0]) - 1, \ + .index = (const struct piddesc **) piddesc_##tab_##_index, \ + .table = piddesc_##tab_ } +#define INDEX(VENDOR_, tab_) INDEX_ANY (NN_VENDORID_MINOR_##VENDOR_, tab_) + +static const struct piddesc_index piddesc_vendor_index[] = { + INDEX_ANY (0, omg), + INDEX (ECLIPSE, eclipse), + INDEX (PRISMTECH_OSPL, prismtech), + INDEX (PRISMTECH_JAVA, prismtech), + INDEX (PRISMTECH_LITE, prismtech), + INDEX (PRISMTECH_GATEWAY, prismtech), + INDEX (PRISMTECH_CLOUD, prismtech) +}; + +#undef INDEX +#undef INDEX_ANY + +/* List of entries that require unalias, fini processing; + initialized by nn_plist_init_tables; will assert when + table too small or too large */ +static const struct piddesc *piddesc_unalias[18]; +static const struct piddesc *piddesc_fini[18]; +static ddsrt_once_t table_init_control = DDSRT_ONCE_INIT; + +static nn_parameterid_t pid_without_flags (nn_parameterid_t pid) { - dds_return_t res; - size_t len; - if (!(wanted & fl)) - return NN_STRICT_P ? validate_octetseq (dd, &len) : 0; - if ((res = alias_octetseq (dst, dd)) >= 0) + return (nn_parameterid_t) (pid & ~(PID_VENDORSPECIFIC_FLAG | PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)); +} + +static int piddesc_cmp_qos_addr (const void *va, const void *vb) +{ + struct piddesc const * const *a = (struct piddesc const * const *) va; + struct piddesc const * const *b = (struct piddesc const * const *) vb; + /* QoS go first, then address */ + if (((*a)->flags & PDF_QOS) != ((*b)->flags & PDF_QOS)) + return ((*a)->flags & PDF_QOS) ? -1 : 1; + else + return ((uintptr_t) *a == (uintptr_t) *b) ? 0 : ((uintptr_t) *a < (uintptr_t) *b) ? -1 : 1; +} + +static void nn_plist_init_tables_real (void) +{ + /* make index of pid -> entry */ + for (size_t i = 0; i < sizeof (piddesc_vendor_index) / sizeof (piddesc_vendor_index[0]); i++) { - *present |= fl; - *aliased |= fl; + const struct piddesc *table = piddesc_vendor_index[i].table; + if (table == NULL) + continue; + struct piddesc const **index = piddesc_vendor_index[i].index; +#ifndef NDEBUG + nn_parameterid_t maxpid = 0; + bool only_qos_seen = true; +#endif + for (size_t j = 0; table[j].pid != PID_SENTINEL; j++) + { + nn_parameterid_t pid = pid_without_flags (table[j].pid); +#ifndef NDEBUG + /* Table must first list QoS, then other parameters */ + assert (only_qos_seen || !(table[j].flags & PDF_QOS)); + if (!(table[j].flags & PDF_QOS)) + only_qos_seen = false; + /* Track max PID so we can verify the table is no larger + than necessary */ + if (pid > maxpid) + maxpid = pid; +#endif + /* PAD is used for entries that are never visible on the wire + and the decoder assumes the PAD entries will be skipped + because they don't map to an entry */ + if (pid == PID_PAD) + continue; + assert (pid <= piddesc_vendor_index[i].index_max); + assert (index[pid] == NULL || index[pid] == &table[j]); + index[pid] = &table[j]; + } + assert (maxpid == piddesc_vendor_index[i].index_max); } - return res; -} -static dds_return_t do_blob (ddsi_octetseq_t *dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) -{ - dds_return_t res; - if (!(wanted & fl)) - return 0; - if ((res = alias_blob (dst, dd)) >= 0) + /* PIDs requiring unalias; there is overlap between the tables + (because of different vendor codes mapping to the same entry + in qos/plist). Use the "present" flags to filter out + duplicates. */ + uint64_t pf = 0, qf = 0; + size_t unalias_index = 0; + size_t fini_index = 0; + for (size_t i = 0; i < sizeof (piddesc_vendor_index) / sizeof (piddesc_vendor_index[0]); i++) { - *present |= fl; - *aliased |= fl; + const struct piddesc *table = piddesc_vendor_index[i].table; + if (table == NULL) + continue; + for (size_t j = 0; table[j].pid != PID_SENTINEL; j++) + { + uint64_t * const f = (table[j].flags & PDF_QOS) ? &qf : &pf; + if (*f & table[j].present_flag) + continue; + *f |= table[j].present_flag; + if (((table[j].flags & PDF_FUNCTION) && table[j].op.f.unalias) || + (!(table[j].flags & PDF_FUNCTION) && unalias_generic_required (table[j].op.desc))) + { + assert (unalias_index < sizeof (piddesc_unalias) / sizeof (piddesc_unalias[0])); + piddesc_unalias[unalias_index++] = &table[j]; + } + if (((table[j].flags & PDF_FUNCTION) && table[j].op.f.fini) || + (!(table[j].flags & PDF_FUNCTION) && fini_generic_required (table[j].op.desc))) + { + assert (fini_index < sizeof (piddesc_fini) / sizeof (piddesc_fini[0])); + piddesc_fini[fini_index++] = &table[j]; + } + } } - return res; -} - -static dds_return_t do_string (char **dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) -{ - dds_return_t res; - size_t len; - if (!(wanted & fl)) - return NN_STRICT_P ? validate_string (dd, &len) : 0; - if ((res = alias_string ((const unsigned char **) dst, dd, &len)) >= 0) + assert (unalias_index == sizeof (piddesc_unalias) / sizeof (piddesc_unalias[0]) && + fini_index == sizeof (piddesc_fini) / sizeof (piddesc_fini[0])); + qsort ((void *) piddesc_unalias, unalias_index, sizeof (piddesc_unalias[0]), piddesc_cmp_qos_addr); + qsort ((void *) piddesc_fini, fini_index, sizeof (piddesc_fini[0]), piddesc_cmp_qos_addr); +#ifndef NDEBUG { - *present |= fl; - *aliased |= fl; + size_t i; + for (i = 0; i < unalias_index; i++) + if (!(piddesc_unalias[i]->flags & PDF_QOS)) + break; + for (; i < unalias_index; i++) + assert (!(piddesc_unalias[i]->flags & PDF_QOS)); + for (i = 0; i < fini_index; i++) + if (!(piddesc_fini[i]->flags & PDF_QOS)) + break; + for (; i < fini_index; i++) + assert (!(piddesc_fini[i]->flags & PDF_QOS)); } - return res; +#endif } -static dds_return_t do_stringseq (ddsi_stringseq_t *dst, uint64_t *present, uint64_t *aliased, uint64_t wanted, uint64_t fl, const struct dd *dd) +void nn_plist_init_tables (void) { - dds_return_t res; - if (!(wanted & fl)) - return NN_STRICT_P ? validate_stringseq (dd) : 0; - if ((res = alias_stringseq (dst, dd)) >= 0) + ddsrt_once (&table_init_control, nn_plist_init_tables_real); +} + +static void plist_or_xqos_fini (void * __restrict dst, size_t shift) +{ + /* shift == 0: plist, shift > 0: just qos */ + struct flagset pfs, qfs; + /* DDS manipulation can be done without creating a participant, so we may + have to initialize tables just-in-time */ + if (piddesc_fini[0] == NULL) + nn_plist_init_tables (); + if (shift > 0) { - *present |= fl; - *aliased |= fl; + dds_qos_t *qos = dst; + pfs = (struct flagset) { 0 }; + qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased }; } - return res; -} - -static void bswap_time (ddsi_time_t *t) -{ - t->seconds = bswap4 (t->seconds); - t->fraction = bswap4u (t->fraction); -} - -static dds_return_t validate_time (const ddsi_time_t *t) -{ - /* Accepted are zero, positive, infinite or invalid as defined in - the DDS 2.1 spec, table 9.4. */ - if (t->seconds >= 0) - return 0; - else if (t->seconds == -1 && t->fraction == UINT32_MAX) - return 0; else { - DDS_TRACE("plist/validate_time: invalid timestamp (%08x.%08x)\n", t->seconds, t->fraction); - return DDS_RETCODE_BAD_PARAMETER; + nn_plist_t *plist = dst; + pfs = (struct flagset) { .present = &plist->present, .aliased = &plist->aliased }; + qfs = (struct flagset) { .present = &plist->qos.present, .aliased = &plist->qos.aliased }; + } + for (size_t i = 0; i < sizeof (piddesc_fini) / sizeof (piddesc_fini[0]); i++) + { + struct piddesc const * const entry = piddesc_fini[i]; + if (shift > 0 && !(entry->flags & PDF_QOS)) + break; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t dstoff = entry->plist_offset - shift; + struct flagset * const fs = (entry->flags & PDF_QOS) ? &qfs : &pfs; + if ((*fs->present & entry->present_flag)) + { + if (!(entry->flags & PDF_FUNCTION)) + fini_generic (dst, &dstoff, fs, entry->present_flag, entry->op.desc); + else if (entry->op.f.fini) + entry->op.f.fini (dst, &dstoff, fs, entry->present_flag); + } + } + if (pfs.present) { *pfs.present = *pfs.aliased = 0; } + *qfs.present = *qfs.aliased = 0; +} + +static void plist_or_xqos_unalias (void * __restrict dst, size_t shift) +{ + /* shift == 0: plist, shift > 0: just qos */ + struct flagset pfs, qfs; + /* DDS manipulation can be done without creating a participant, so we may + have to initialize tables just-in-time */ + if (piddesc_unalias[0] == NULL) + nn_plist_init_tables (); + if (shift > 0) + { + dds_qos_t *qos = dst; + pfs = (struct flagset) { 0 }; + qfs = (struct flagset) { .present = &qos->present, .aliased = &qos->aliased }; + } + else + { + nn_plist_t *plist = dst; + pfs = (struct flagset) { .present = &plist->present, .aliased = &plist->aliased }; + qfs = (struct flagset) { .present = &plist->qos.present, .aliased = &plist->qos.aliased }; + } + for (size_t i = 0; i < sizeof (piddesc_unalias) / sizeof (piddesc_unalias[0]); i++) + { + struct piddesc const * const entry = piddesc_unalias[i]; + if (shift > 0 && !(entry->flags & PDF_QOS)) + break; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t dstoff = entry->plist_offset - shift; + struct flagset * const fs = (entry->flags & PDF_QOS) ? &qfs : &pfs; + if ((*fs->present & entry->present_flag) && (*fs->aliased & entry->present_flag)) + { + if (!(entry->flags & PDF_FUNCTION)) + unalias_generic (dst, &dstoff, entry->op.desc); + else if (entry->op.f.unalias) + entry->op.f.unalias (dst, &dstoff); + *fs->aliased &= ~entry->present_flag; + } + } + assert (pfs.aliased == NULL || *pfs.aliased == 0); + assert (*qfs.aliased == 0); +} + +static void plist_or_xqos_mergein_missing (void * __restrict dst, const void * __restrict src, size_t shift, uint64_t pmask, uint64_t qmask) +{ + /* shift == 0: plist, shift > 0: just qos */ + struct flagset pfs_src, qfs_src; + struct flagset pfs_dst, qfs_dst; +#ifndef NDEBUG + const uint64_t aliased_dst_inp = (shift == 0) ? ((nn_plist_t *) dst)->aliased : 0; + const uint64_t aliased_dst_inq = (shift == 0) ? ((nn_plist_t *) dst)->qos.aliased : ((dds_qos_t *) dst)->aliased; +#endif + if (shift > 0) + { + dds_qos_t *qos_dst = dst; + const dds_qos_t *qos_src = src; + pfs_dst = (struct flagset) { 0 }; + qfs_dst = (struct flagset) { .present = &qos_dst->present, .aliased = &qos_dst->aliased }; + pfs_src = (struct flagset) { 0 }; + qfs_src = (struct flagset) { .present = (uint64_t *) &qos_src->present, .aliased = (uint64_t *) &qos_src->aliased }; + } + else + { + nn_plist_t *plist_dst = dst; + const nn_plist_t *plist_src = src; + pfs_dst = (struct flagset) { .present = &plist_dst->present, .aliased = &plist_dst->aliased }; + qfs_dst = (struct flagset) { .present = &plist_dst->qos.present, .aliased = &plist_dst->qos.aliased }; + pfs_src = (struct flagset) { .present = (uint64_t *) &plist_src->present, .aliased = (uint64_t *) &plist_src->aliased }; + qfs_src = (struct flagset) { .present = (uint64_t *) &plist_src->qos.present, .aliased = (uint64_t *) &plist_src->qos.aliased }; + } + /* aliased may never have any bits set that are clear in present */ + assert (pfs_dst.present == NULL || (aliased_dst_inp & ~ *pfs_dst.present) == 0); + assert ((aliased_dst_inq & ~ *qfs_dst.present) == 0); + for (size_t k = 0; k < sizeof (piddesc_tables_all) / sizeof (piddesc_tables_all[0]); k++) + { + struct piddesc const * const table = piddesc_tables_all[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (shift > 0 && !(entry->flags & PDF_QOS)) + break; + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t dstoff = entry->plist_offset - shift; + struct flagset * const fs_dst = (entry->flags & PDF_QOS) ? &qfs_dst : &pfs_dst; + struct flagset * const fs_src = (entry->flags & PDF_QOS) ? &qfs_src : &pfs_src; + uint64_t const mask = (entry->flags & PDF_QOS) ? qmask : pmask; + /* skip if already present in dst or absent in src */ + if (!(*fs_dst->present & entry->present_flag) && (*fs_src->present & mask & entry->present_flag)) + { + /* bitwise copy, mark as aliased & unalias; have to unalias fields one-by-one rather than + do this for all fields and call "unalias" on the entire object because fields that are + already present may be aliased, and it would be somewhat impolite to change that. + + Note: dst & src have the same type, so offset in src is the same; + Note: unalias may have to look at */ + memcpy ((char *) dst + dstoff, (const char *) src + dstoff, entry->size); + *fs_dst->present |= entry->present_flag; + if (!(entry->flags & PDF_FUNCTION)) + unalias_generic (dst, &dstoff, entry->op.desc); + else if (entry->op.f.unalias) + entry->op.f.unalias (dst, &dstoff); + } + } + } + /* all entries in src should be present in dst (but there may be more) */ + assert (pfs_dst.present == NULL || (*pfs_src.present & pmask & ~ *pfs_dst.present) == 0); + assert ((*qfs_src.present & qmask & ~ *qfs_dst.present) == 0); + /* the only aliased entries in dst may be ones that were aliased on input */ + assert (pfs_dst.aliased == NULL || (*pfs_dst.aliased & ~ aliased_dst_inp) == 0); + assert ((*qfs_dst.aliased & ~ aliased_dst_inq) == 0); +} + +static void plist_or_xqos_addtomsg (struct nn_xmsg *xmsg, const void * __restrict src, size_t shift, uint64_t pwanted, uint64_t qwanted) +{ + /* shift == 0: plist, shift > 0: just qos */ + uint64_t pw, qw; + if (shift > 0) + { + const dds_qos_t *qos = src; + pw = 0; + qw = qos->present & qwanted; + } + else + { + const nn_plist_t *plist = src; + pw = plist->present & pwanted; + qw = plist->qos.present & qwanted; + } + for (size_t k = 0; k < sizeof (piddesc_tables_output) / sizeof (piddesc_tables_output[0]); k++) + { + struct piddesc const * const table = piddesc_tables_output[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (entry->pid == PID_PAD) + continue; + if (((entry->flags & PDF_QOS) ? qw : pw) & entry->present_flag) + { + assert (entry->plist_offset >= shift); + assert (shift == 0 || entry->plist_offset - shift < sizeof (dds_qos_t)); + size_t srcoff = entry->plist_offset - shift; + if (!(entry->flags & PDF_FUNCTION)) + ser_generic (xmsg, entry->pid, src, srcoff, entry->op.desc); + else + entry->op.f.ser (xmsg, entry->pid, src, srcoff); + } + } } } -static void bswap_external_duration (ddsi_duration_t *d) +void nn_plist_fini (nn_plist_t *plist) { - bswap_time (d); + plist_or_xqos_fini (plist, 0); +} + +void nn_plist_unalias (nn_plist_t *plist) +{ + plist_or_xqos_unalias (plist, 0); +} + +dds_return_t nn_xqos_valid (const dds_qos_t *xqos) +{ + dds_return_t ret; + if (piddesc_unalias[0] == NULL) + nn_plist_init_tables (); + for (size_t k = 0; k < sizeof (piddesc_tables_all) / sizeof (piddesc_tables_all[0]); k++) + { + struct piddesc const * const table = piddesc_tables_all[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (!(entry->flags & PDF_QOS)) + break; + if (xqos->present & entry->present_flag) + { + const size_t srcoff = entry->plist_offset - offsetof (nn_plist_t, qos); + if (!(entry->flags & PDF_FUNCTION)) + ret = valid_generic (xqos, srcoff, entry->op.desc); + else + ret = entry->op.f.valid (xqos, srcoff); + if (ret < 0) + { + DDS_LOG (DDS_LC_PLIST, "nn_xqos_valid: %s invalid\n", entry->name); + return ret; + } + } + } + } + if ((ret = final_validation_qos (xqos, (nn_protocol_version_t) { RTPS_MAJOR, RTPS_MINOR }, NN_VENDORID_ECLIPSE, NULL)) < 0) + { + DDS_LOG (DDS_LC_PLIST, "nn_xqos_valid: final validation failed\n"); + } + return ret; +} + +uint64_t nn_xqos_delta (const dds_qos_t *x, const dds_qos_t *y, uint64_t mask) +{ + if (piddesc_unalias[0] == NULL) + nn_plist_init_tables (); + /* Returns QP_... set for settings where x differs from y; if + present in x but not in y (or in y but not in x) it counts as a + difference. */ + uint64_t delta = (x->present ^ y->present) & mask; + const uint64_t check = (x->present & y->present) & mask; + for (size_t k = 0; k < sizeof (piddesc_tables_all) / sizeof (piddesc_tables_all[0]); k++) + { + struct piddesc const * const table = piddesc_tables_all[k]; + for (uint32_t i = 0; table[i].pid != PID_SENTINEL; i++) + { + struct piddesc const * const entry = &table[i]; + if (!(entry->flags & PDF_QOS)) + break; + if (check & entry->present_flag) + { + const size_t srcoff = entry->plist_offset - offsetof (nn_plist_t, qos); + bool equal; + /* Partition is special-cased because it is a set (with a special rules + for empty sets and empty strings to boot), and normal string sequence + comparison requires the ordering to be the same */ + if (entry->pid == PID_PARTITION) + equal = partitions_equal (&x->partition, &y->partition); + else if (!(entry->flags & PDF_FUNCTION)) + equal = equal_generic (x, y, srcoff, entry->op.desc); + else + equal = entry->op.f.equal (x, y, srcoff); + if (!equal) + delta |= entry->present_flag; + } + } + } + return delta; } static dds_return_t validate_external_duration (const ddsi_duration_t *d) { - return validate_time (d); -} - -dds_return_t validate_duration (const dds_duration_t d) -{ - return (d >= 0 && d <= DDS_INFINITY) ? DDS_RETCODE_OK : DDS_RETCODE_BAD_PARAMETER; -} - -static dds_return_t do_duration (dds_duration_t *q, uint64_t *present, uint64_t fl, const struct dd *dd) -{ - ddsi_duration_t extq; - dds_return_t res; - if (dd->bufsz < sizeof (extq)) - { - DDS_TRACE("plist/do_duration: buffer too small\n"); + /* Accepted are zero, positive, infinite or invalid as defined in + the DDS 2.1 spec, table 9.4. */ + if (d->seconds >= 0) + return 0; + else if (d->seconds == -1 && d->fraction == UINT32_MAX) + return 0; + else return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&extq, dd->buf, sizeof (extq)); - if (dd->bswap) - bswap_external_duration (&extq); - if ((res = validate_external_duration (&extq)) < 0) - return res; - *q = nn_from_ddsi_duration (extq); - *present |= fl; - return 0; -} - -static void bswap_durability_qospolicy (dds_durability_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); -} - -dds_return_t validate_durability_qospolicy (const dds_durability_qospolicy_t *q) -{ - switch (q->kind) - { - case DDS_DURABILITY_VOLATILE: - case DDS_DURABILITY_TRANSIENT_LOCAL: - case DDS_DURABILITY_TRANSIENT: - case DDS_DURABILITY_PERSISTENT: - break; - default: - DDS_TRACE("plist/validate_durability_qospolicy: invalid kind (%d)\n", (int) q->kind); - return DDS_RETCODE_BAD_PARAMETER; - } - return 0; -} - -static void bswap_history_qospolicy (dds_history_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); - q->depth = bswap4 (q->depth); } static int history_qospolicy_allzero (const dds_history_qospolicy_t *q) @@ -606,7 +1534,7 @@ static int history_qospolicy_allzero (const dds_history_qospolicy_t *q) return q->kind == DDS_HISTORY_KEEP_LAST && q->depth == 0; } -dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q) +static dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q) { /* Validity of history setting and of resource limits are dependent, but we don't have access to the resource limits here ... the @@ -621,110 +1549,63 @@ dds_return_t validate_history_qospolicy (const dds_history_qospolicy_t *q) case DDS_HISTORY_KEEP_ALL: break; default: - DDS_TRACE("plist/validate_history_qospolicy: invalid kind (%d)\n", (int) q->kind); return DDS_RETCODE_BAD_PARAMETER; } /* Accept all values for depth if kind = ALL */ - if (q->kind == DDS_HISTORY_KEEP_LAST) - { - if (q->depth < 1) - { - DDS_TRACE("plist/validate_history_qospolicy: invalid depth (%d)\n", (int) q->depth); - return DDS_RETCODE_BAD_PARAMETER; - } - } + if (q->kind == DDS_HISTORY_KEEP_LAST && q->depth < 1) + return DDS_RETCODE_BAD_PARAMETER; return 0; } -static void bswap_resource_limits_qospolicy (dds_resource_limits_qospolicy_t *q) -{ - q->max_samples = bswap4 (q->max_samples); - q->max_instances = bswap4 (q->max_instances); - q->max_samples_per_instance = bswap4 (q->max_samples_per_instance); -} - static int resource_limits_qospolicy_allzero (const dds_resource_limits_qospolicy_t *q) { return q->max_samples == 0 && q->max_instances == 0 && q->max_samples_per_instance == 0; } -dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q) +static dds_return_t validate_resource_limits_qospolicy (const dds_resource_limits_qospolicy_t *q) { - const int unlimited = DDS_LENGTH_UNLIMITED; /* Note: dependent on history setting as well (see validate_history_qospolicy). Verifying only the internal consistency of the resource limits. */ - if (q->max_samples < 1 && q->max_samples != unlimited) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_samples invalid (%d)\n", (int) q->max_samples); + if (q->max_samples < 1 && q->max_samples != DDS_LENGTH_UNLIMITED) return DDS_RETCODE_BAD_PARAMETER; - } - if (q->max_instances < 1 && q->max_instances != unlimited) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_instances invalid (%d)\n", (int) q->max_instances); + if (q->max_instances < 1 && q->max_instances != DDS_LENGTH_UNLIMITED) return DDS_RETCODE_BAD_PARAMETER; - } - if (q->max_samples_per_instance < 1 && q->max_samples_per_instance != unlimited) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_samples_per_instance invalid (%d)\n", (int) q->max_samples_per_instance); + if (q->max_samples_per_instance < 1 && q->max_samples_per_instance != DDS_LENGTH_UNLIMITED) return DDS_RETCODE_BAD_PARAMETER; - } - if (q->max_samples != unlimited && q->max_samples_per_instance != unlimited) + if (q->max_samples != DDS_LENGTH_UNLIMITED && q->max_samples_per_instance != DDS_LENGTH_UNLIMITED) { /* Interpreting 7.1.3.19 as if "unlimited" is meant to mean "don't care" and any conditions related to it must be ignored. */ if (q->max_samples < q->max_samples_per_instance) - { - DDS_TRACE("plist/validate_resource_limits_qospolicy: max_samples (%d) and max_samples_per_instance (%d) incompatible\n", (int) q->max_samples, (int) q->max_samples_per_instance); - return DDS_RETCODE_BAD_PARAMETER; - } + return DDS_RETCODE_INCONSISTENT_POLICY; } return 0; } -dds_return_t validate_history_and_resource_limits (const dds_history_qospolicy_t *qh, const dds_resource_limits_qospolicy_t *qr) +static dds_return_t validate_history_and_resource_limits (const dds_history_qospolicy_t *qh, const dds_resource_limits_qospolicy_t *qr) { - const int unlimited = DDS_LENGTH_UNLIMITED; dds_return_t res; if ((res = validate_history_qospolicy (qh)) < 0) - { - DDS_TRACE("plist/validate_history_and_resource_limits: history policy invalid\n"); return res; - } if ((res = validate_resource_limits_qospolicy (qr)) < 0) - { - DDS_TRACE("plist/validate_history_and_resource_limits: resource_limits policy invalid\n"); return res; - } switch (qh->kind) { case DDS_HISTORY_KEEP_ALL: #if 0 /* See comment in validate_resource_limits, ref'ing 7.1.3.19 */ - if (qr->max_samples_per_instance != unlimited) - { - DDS_TRACE("plist/validate_history_and_resource_limits: max_samples_per_instance (%d) incompatible with KEEP_ALL policy\n", (int) qr->max_samples_per_instance); + if (qr->max_samples_per_instance != DDS_LENGTH_UNLIMITED) return DDS_RETCODE_BAD_PARAMETER; - } #endif break; case DDS_HISTORY_KEEP_LAST: - if (qr->max_samples_per_instance != unlimited && qh->depth > qr->max_samples_per_instance) - { - DDS_TRACE("plist/validate_history_and_resource_limits: depth (%d) and max_samples_per_instance (%d) incompatible with KEEP_LAST policy\n", (int) qh->depth, (int) qr->max_samples_per_instance); - return DDS_RETCODE_BAD_PARAMETER; - } + if (qr->max_samples_per_instance != DDS_LENGTH_UNLIMITED && qh->depth > qr->max_samples_per_instance) + return DDS_RETCODE_INCONSISTENT_POLICY; break; } return 0; } -static void bswap_external_durability_service_qospolicy (dds_external_durability_service_qospolicy_t *q) -{ - bswap_external_duration (&q->service_cleanup_delay); - bswap_history_qospolicy (&q->history); - bswap_resource_limits_qospolicy (&q->resource_limits); -} - static int durability_service_qospolicy_allzero (const dds_durability_service_qospolicy_t *q) { return (history_qospolicy_allzero (&q->history) && @@ -732,184 +1613,15 @@ static int durability_service_qospolicy_allzero (const dds_durability_service_qo q->service_cleanup_delay == 0); } -static int external_durability_service_qospolicy_allzero (const dds_external_durability_service_qospolicy_t *q) -{ - return (history_qospolicy_allzero (&q->history) && - resource_limits_qospolicy_allzero (&q->resource_limits) && - q->service_cleanup_delay.seconds == 0 && q->service_cleanup_delay.fraction == 0); -} - -static dds_return_t validate_external_durability_service_qospolicy_acceptzero (const dds_external_durability_service_qospolicy_t *q, bool acceptzero) +static dds_return_t validate_durability_service_qospolicy_acceptzero (const dds_durability_service_qospolicy_t *q, bool acceptzero) { dds_return_t res; - if (acceptzero && external_durability_service_qospolicy_allzero (q)) + if (acceptzero && durability_service_qospolicy_allzero (q)) return 0; - if ((res = validate_external_duration (&q->service_cleanup_delay)) < 0) - { - DDS_TRACE("plist/validate_durability_service_qospolicy: duration invalid\n"); - return res; - } + if (q->service_cleanup_delay < 0) + return DDS_RETCODE_BAD_PARAMETER; if ((res = validate_history_and_resource_limits (&q->history, &q->resource_limits)) < 0) - { - DDS_TRACE("plist/validate_durability_service_qospolicy: invalid history and/or resource limits\n"); return res; - } - return 0; -} - -dds_return_t validate_durability_service_qospolicy (const dds_durability_service_qospolicy_t *q) -{ - dds_external_durability_service_qospolicy_t qext; - qext.history = q->history; - qext.resource_limits = q->resource_limits; - qext.service_cleanup_delay = nn_to_ddsi_duration (q->service_cleanup_delay); - return validate_external_durability_service_qospolicy_acceptzero (&qext, false); -} - -static void bswap_external_liveliness_qospolicy (dds_external_liveliness_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); - bswap_external_duration (&q->lease_duration); -} - -static dds_return_t validate_external_liveliness_qospolicy (const dds_external_liveliness_qospolicy_t *q) -{ - dds_return_t res; - switch (q->kind) - { - case DDS_LIVELINESS_AUTOMATIC: - case DDS_LIVELINESS_MANUAL_BY_PARTICIPANT: - case DDS_LIVELINESS_MANUAL_BY_TOPIC: - if ((res = validate_external_duration (&q->lease_duration)) < 0) - DDS_TRACE("plist/validate_liveliness_qospolicy: invalid lease duration\n"); - return res; - default: - DDS_TRACE("plist/validate_liveliness_qospolicy: invalid kind (%d)\n", (int) q->kind); - return DDS_RETCODE_BAD_PARAMETER; - } -} - -dds_return_t validate_liveliness_qospolicy (const dds_liveliness_qospolicy_t *q) -{ - dds_external_liveliness_qospolicy_t qext; - qext.kind = q->kind; - qext.lease_duration = nn_to_ddsi_duration (q->lease_duration); - return validate_external_liveliness_qospolicy (&qext); -} - -static void bswap_external_reliability_qospolicy (dds_external_reliability_qospolicy_t *qext) -{ - qext->kind = bswap4u (qext->kind); - bswap_external_duration (&qext->max_blocking_time); -} - -static dds_return_t validate_xform_reliability_qospolicy (dds_reliability_qospolicy_t *qdst, const dds_external_reliability_qospolicy_t *qext) -{ - dds_return_t res; - qdst->max_blocking_time = nn_from_ddsi_duration (qext->max_blocking_time); - switch (qext->kind) - { - case DDS_EXTERNAL_RELIABILITY_BEST_EFFORT: - qdst->kind = DDS_RELIABILITY_BEST_EFFORT; - return 0; - case DDS_EXTERNAL_RELIABILITY_RELIABLE: - qdst->kind = DDS_RELIABILITY_RELIABLE; - if ((res = validate_external_duration (&qext->max_blocking_time)) < 0) - DDS_TRACE("plist/validate_xform_reliability_qospolicy[!pedantic]: max_blocking time invalid\n"); - return res; - default: - DDS_TRACE("plist/validate_xform_reliability_qospolicy[!pedantic]: invalid kind (%d)\n", (int) qext->kind); - return DDS_RETCODE_BAD_PARAMETER; - } -} - -static void bswap_destination_order_qospolicy (dds_destination_order_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); -} - -dds_return_t validate_destination_order_qospolicy (const dds_destination_order_qospolicy_t *q) -{ - switch (q->kind) - { - case DDS_DESTINATIONORDER_BY_RECEPTION_TIMESTAMP: - case DDS_DESTINATIONORDER_BY_SOURCE_TIMESTAMP: - return 0; - default: - DDS_TRACE("plist/validate_destination_order_qospolicy: invalid kind (%d)\n", (int) q->kind); - return DDS_RETCODE_BAD_PARAMETER; - } -} - -static void bswap_ownership_qospolicy (dds_ownership_qospolicy_t *q) -{ - q->kind = bswap4u (q->kind); -} - -dds_return_t validate_ownership_qospolicy (const dds_ownership_qospolicy_t *q) -{ - switch (q->kind) - { - case DDS_OWNERSHIP_SHARED: - case DDS_OWNERSHIP_EXCLUSIVE: - return 0; - default: - DDS_TRACE("plist/validate_ownership_qospolicy: invalid kind (%d)\n", (int) q->kind); - return DDS_RETCODE_BAD_PARAMETER; - } -} - -static void bswap_ownership_strength_qospolicy (dds_ownership_strength_qospolicy_t *q) -{ - q->value = bswap4 (q->value); -} - -dds_return_t validate_ownership_strength_qospolicy (UNUSED_ARG (const dds_ownership_strength_qospolicy_t *q)) -{ - return 0; -} - -static void bswap_presentation_qospolicy (dds_presentation_qospolicy_t *q) -{ - q->access_scope = bswap4u (q->access_scope); -} - -dds_return_t validate_presentation_qospolicy (const dds_presentation_qospolicy_t *q) -{ - switch (q->access_scope) - { - case DDS_PRESENTATION_INSTANCE: - case DDS_PRESENTATION_TOPIC: - case DDS_PRESENTATION_GROUP: - break; - default: - DDS_TRACE("plist/validate_presentation_qospolicy: invalid access_scope (%d)\n", (int) q->access_scope); - return DDS_RETCODE_BAD_PARAMETER; - } - /* Bools must be 0 or 1, i.e., only the lsb may be set */ - if (q->coherent_access & ~1) - { - DDS_TRACE("plist/validate_presentation_qospolicy: coherent_access invalid (%d)\n", (int) q->coherent_access); - return DDS_RETCODE_BAD_PARAMETER; - } - if (q->ordered_access & ~1) - { - DDS_TRACE("plist/validate_presentation_qospolicy: ordered_access invalid (%d)\n", (int) q->ordered_access); - return DDS_RETCODE_BAD_PARAMETER; - } - /* coherent_access & ordered_access are a bit irrelevant for - instance presentation qos, but it appears as if their values are - not prescribed in that case. */ - return 0; -} - -static void bswap_transport_priority_qospolicy (dds_transport_priority_qospolicy_t *q) -{ - q->value = bswap4 (q->value); -} - -dds_return_t validate_transport_priority_qospolicy (UNUSED_ARG (const dds_transport_priority_qospolicy_t *q)) -{ return 0; } @@ -957,22 +1669,13 @@ static int locator_address_zero (const nn_locator_t *loc) return (u[0] == 0 && u[1] == 0 && u[2] == 0 && u[3] == 0); } -static dds_return_t do_locator -( - nn_locators_t *ls, - uint64_t *present, - uint64_t wanted, - uint64_t fl, - const struct dd *dd -) +static dds_return_t do_locator (nn_locators_t *ls, uint64_t *present, uint64_t wanted, uint64_t fl, const struct dd *dd) { nn_locator_t loc; if (dd->bufsz < sizeof (loc)) - { - DDS_TRACE("plist/do_locator: buffer too small\n"); return DDS_RETCODE_BAD_PARAMETER; - } + memcpy (&loc, dd->buf, sizeof (loc)); if (dd->bswap) { @@ -984,58 +1687,36 @@ static dds_return_t do_locator case NN_LOCATOR_KIND_UDPv4: case NN_LOCATOR_KIND_TCPv4: if (loc.port <= 0 || loc.port > 65535) - { - DDS_TRACE("plist/do_locator[kind=IPv4]: invalid port (%d)\n", (int) loc.port); return DDS_RETCODE_BAD_PARAMETER; - } if (!locator_address_prefix12_zero (&loc)) - { - DDS_TRACE("plist/do_locator[kind=IPv4]: junk in address prefix\n"); return DDS_RETCODE_BAD_PARAMETER; - } break; case NN_LOCATOR_KIND_UDPv6: case NN_LOCATOR_KIND_TCPv6: if (loc.port <= 0 || loc.port > 65535) - { - DDS_TRACE("plist/do_locator[kind=IPv6]: invalid port (%d)\n", (int) loc.port); return DDS_RETCODE_BAD_PARAMETER; - } break; case NN_LOCATOR_KIND_UDPv4MCGEN: { const nn_udpv4mcgen_address_t *x = (const nn_udpv4mcgen_address_t *) loc.address; - if (!ddsi_factory_supports(gv.m_factory, NN_LOCATOR_KIND_UDPv4)) + if (!ddsi_factory_supports (gv.m_factory, NN_LOCATOR_KIND_UDPv4)) return 0; if (loc.port <= 0 || loc.port > 65536) - { - DDS_TRACE("plist/do_locator[kind=IPv4MCGEN]: invalid port (%d)\n", (int) loc.port); return DDS_RETCODE_BAD_PARAMETER; - } - if ((int)x->base + x->count >= 28 || x->count == 0 || x->idx >= x->count) - { - DDS_TRACE("plist/do_locator[kind=IPv4MCGEN]: invalid base/count/idx (%u,%u,%u)\n", x->base, x->count, x->idx); + if ((uint32_t) x->base + x->count >= 28 || x->count == 0 || x->idx >= x->count) return DDS_RETCODE_BAD_PARAMETER; - } break; } case NN_LOCATOR_KIND_INVALID: if (!locator_address_zero (&loc)) - { - DDS_TRACE("plist/do_locator[kind=INVALID]: junk in address\n"); return DDS_RETCODE_BAD_PARAMETER; - } if (loc.port != 0) - { - DDS_TRACE("plist/do_locator[kind=INVALID]: junk in port\n"); return DDS_RETCODE_BAD_PARAMETER; - } /* silently dropped correctly formatted "invalid" locators. */ return 0; case NN_LOCATOR_KIND_RESERVED: /* silently dropped "reserved" locators. */ return 0; default: - DDS_TRACE("plist/do_locator: invalid kind (%d)\n", (int) loc.kind); return NN_PEDANTIC_P ? DDS_RETCODE_BAD_PARAMETER : 0; } return add_locator (ls, present, wanted, fl, &loc); @@ -1057,10 +1738,7 @@ static dds_return_t do_ipv4address (nn_plist_t *dest, nn_ipaddress_params_tmp_t uint32_t fl1_tmp; uint64_t fldest; if (dd->bufsz < sizeof (*a)) - { - DDS_TRACE("plist/do_ipv4address: buffer too small\n"); return DDS_RETCODE_BAD_PARAMETER; - } switch (fl_tmp) { case PPTMP_MULTICAST_IPADDRESS: @@ -1127,10 +1805,7 @@ static dds_return_t do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_t uint64_t fldest; uint32_t fl1_tmp; if (dd->bufsz < sizeof (*p)) - { - DDS_TRACE("plist/do_port: buffer too small\n"); return DDS_RETCODE_BAD_PARAMETER; - } switch (fl_tmp) { case PPTMP_DEFAULT_UNICAST_PORT: @@ -1161,10 +1836,7 @@ static dds_return_t do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_t if (dd->bswap) *p = bswap4u (*p); if (*p <= 0 || *p > 65535) - { - DDS_TRACE("plist/do_port: invalid port (%d)\n", (int) *p); return DDS_RETCODE_BAD_PARAMETER; - } dest_tmp->present |= fl_tmp; if ((dest_tmp->present & (fl_tmp | fl1_tmp)) == (fl_tmp | fl1_tmp)) { @@ -1182,1055 +1854,133 @@ static dds_return_t do_port (nn_plist_t *dest, nn_ipaddress_params_tmp_t *dest_t } } -static dds_return_t valid_participant_guid (const nn_guid_t *g, UNUSED_ARG (const struct dd *dd)) +static dds_return_t return_unrecognized_pid (nn_plist_t *plist, nn_parameterid_t pid) { - /* All 0 is GUID_UNKNOWN, which is a defined GUID */ - if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) - { - if (g->entityid.u == 0) - return 0; - else - { - DDS_TRACE("plist/valid_participant_guid: prefix is 0 but entityid is not (%"PRIu32")\n", g->entityid.u); - return DDS_RETCODE_BAD_PARAMETER; - } - } - else if (g->entityid.u == NN_ENTITYID_PARTICIPANT) - { + if (!(pid & PID_UNRECOGNIZED_INCOMPATIBLE_FLAG)) return 0; - } else { - DDS_TRACE("plist/valid_participant_guid: entityid not a participant entityid (%"PRIu32")\n", g->entityid.u); - return DDS_RETCODE_BAD_PARAMETER; + plist->present |= PP_INCOMPATIBLE; + return DDS_RETCODE_UNSUPPORTED; } } -static dds_return_t valid_group_guid (const nn_guid_t *g, UNUSED_ARG (const struct dd *dd)) +static dds_return_t init_one_parameter (nn_plist_t *plist, nn_ipaddress_params_tmp_t *dest_tmp, uint64_t pwanted, uint64_t qwanted, uint16_t pid, const struct dd *dd) { - /* All 0 is GUID_UNKNOWN, which is a defined GUID */ - if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) - { - if (g->entityid.u == 0) - return 0; - else - { - DDS_TRACE("plist/valid_group_guid: prefix is 0 but entityid is not (%"PRIu32")\n", g->entityid.u); - return DDS_RETCODE_BAD_PARAMETER; - } - } - else if (g->entityid.u != 0) - { - /* accept any entity id */ - return 0; - } - else - { - DDS_TRACE("plist/valid_group_guid: entityid is 0\n"); - return DDS_RETCODE_BAD_PARAMETER; - } -} - -static dds_return_t valid_endpoint_guid (const nn_guid_t *g, const struct dd *dd) -{ - /* All 0 is GUID_UNKNOWN, which is a defined GUID */ - if (g->prefix.u[0] == 0 && g->prefix.u[1] == 0 && g->prefix.u[2] == 0) - { - if (g->entityid.u == 0) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid: prefix is 0 but entityid is not (%"PRIx32")\n", g->entityid.u); - return DDS_RETCODE_BAD_PARAMETER; - } - } - switch (g->entityid.u & NN_ENTITYID_SOURCE_MASK) - { - case NN_ENTITYID_SOURCE_USER: - switch (g->entityid.u & NN_ENTITYID_KIND_MASK) - { - case NN_ENTITYID_KIND_WRITER_WITH_KEY: - case NN_ENTITYID_KIND_WRITER_NO_KEY: - case NN_ENTITYID_KIND_READER_NO_KEY: - case NN_ENTITYID_KIND_READER_WITH_KEY: - return 0; - default: - if (protocol_version_is_newer (dd->protocol_version)) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid[src=USER,proto=%u.%u]: invalid kind (%"PRIx32")\n", - dd->protocol_version.major, dd->protocol_version.minor, - g->entityid.u & NN_ENTITYID_KIND_MASK); - return DDS_RETCODE_BAD_PARAMETER; - } - } - case NN_ENTITYID_SOURCE_BUILTIN: - switch (g->entityid.u) - { - case NN_ENTITYID_SEDP_BUILTIN_TOPIC_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_TOPIC_READER: - case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER: - case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER: - case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER: - case NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER: - case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER: - case NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER: - return 0; - default: - if (protocol_version_is_newer (dd->protocol_version)) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid[src=BUILTIN,proto=%u.%u]: invalid entityid (%"PRIx32")\n", - dd->protocol_version.major, dd->protocol_version.minor, g->entityid.u); - return DDS_RETCODE_BAD_PARAMETER; - } - } - case NN_ENTITYID_SOURCE_VENDOR: - if (!vendor_is_eclipse (dd->vendorid)) - return 0; - else - { - switch (g->entityid.u) - { - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_PARTICIPANT_READER: - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_PUBLISHER_READER: - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_WRITER: - case NN_ENTITYID_SEDP_BUILTIN_CM_SUBSCRIBER_READER: - return 0; - default: - if (protocol_version_is_newer (dd->protocol_version)) - return 0; - else - { - DDS_TRACE("plist/valid_endpoint_guid[src=VENDOR,proto=%u.%u]: unexpected entityid (%"PRIx32")\n", - dd->protocol_version.major, dd->protocol_version.minor, g->entityid.u); - return 0; - } - } - } - default: - DDS_TRACE("plist/valid_endpoint_guid: invalid source (%"PRIx32")\n", g->entityid.u); - return DDS_RETCODE_BAD_PARAMETER; - } -} - -static dds_return_t do_guid (nn_guid_t *dst, uint64_t *present, uint64_t fl, int (*valid) (const nn_guid_t *g, const struct dd *dd), const struct dd *dd) -{ - if (dd->bufsz < sizeof (*dst)) - { - DDS_TRACE("plist/do_guid: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (dst, dd->buf, sizeof (*dst)); - *dst = nn_ntoh_guid (*dst); - if (valid (dst, dd) < 0) - { - /* CoreDX once upon a time used to send out PARTICIPANT_GUID parameters with a 0 entity id, but it - that has long since changed (even if I don't know exactly when) */ - if (fl == PP_PARTICIPANT_GUID && vendor_is_twinoaks (dd->vendorid) && dst->entityid.u == 0 && ! NN_STRICT_P) - { - DDS_LOG(DDS_LC_DISCOVERY, "plist(vendor %u.%u): rewriting invalid participant guid "PGUIDFMT, - dd->vendorid.id[0], dd->vendorid.id[1], PGUID (*dst)); - dst->entityid.u = NN_ENTITYID_PARTICIPANT; - } - else - { - return DDS_RETCODE_BAD_PARAMETER; - } - } - *present |= fl; - return 0; -} - - -static void bswap_prismtech_participant_version_info (nn_prismtech_participant_version_info_t *pvi) -{ - int i; - pvi->version = bswap4u (pvi->version); - pvi->flags = bswap4u (pvi->flags); - for (i = 0; i < 3; i++) - pvi->unused[i] = bswap4u (pvi->unused[i]); -} - -static dds_return_t do_prismtech_participant_version_info (nn_prismtech_participant_version_info_t *pvi, uint64_t *present, uint64_t *aliased, const struct dd *dd) -{ - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else if (dd->bufsz < NN_PRISMTECH_PARTICIPANT_VERSION_INFO_FIXED_CDRSIZE) - { - DDS_TRACE("plist/do_prismtech_participant_version_info[pid=PRISMTECH_PARTICIPANT_VERSION_INFO]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - dds_return_t res; - uint32_t sz = NN_PRISMTECH_PARTICIPANT_VERSION_INFO_FIXED_CDRSIZE - sizeof(uint32_t); - uint32_t *pu = (uint32_t *)dd->buf; - size_t len; - struct dd dd1 = *dd; - - memcpy (pvi, dd->buf, sz); - if (dd->bswap) - bswap_prismtech_participant_version_info(pvi); - - dd1.buf = (unsigned char *) &pu[5]; - dd1.bufsz = dd->bufsz - sz; - if ((res = alias_string ((const unsigned char **) &pvi->internals, &dd1, &len)) >= 0) { - *present |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; - *aliased |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; - res = 0; - } - - return res; - } -} - -static dds_return_t do_subscription_keys_qospolicy (dds_subscription_keys_qospolicy_t *q, uint64_t *present, uint64_t *aliased, uint64_t fl, const struct dd *dd) -{ - struct dd dd1; - dds_return_t res; - if (dd->bufsz < 4) - { - DDS_TRACE("plist/do_subscription_keys: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - q->use_key_list = (unsigned char) dd->buf[0]; - if (q->use_key_list != 0 && q->use_key_list != 1) - { - DDS_TRACE("plist/do_subscription_keys: invalid use_key_list (%d)\n", (int) q->use_key_list); - return DDS_RETCODE_BAD_PARAMETER; - } - dd1 = *dd; - dd1.buf += 4; - dd1.bufsz -= 4; - if ((res = alias_stringseq (&q->key_list, &dd1)) >= 0) - { - *present |= fl; - *aliased |= fl; - } - return res; -} - -static dds_return_t unalias_subscription_keys_qospolicy (dds_subscription_keys_qospolicy_t *q, int bswap) -{ - return unalias_stringseq (&q->key_list, bswap); -} - -static dds_return_t do_reader_lifespan_qospolicy (dds_reader_lifespan_qospolicy_t *q, uint64_t *present, uint64_t fl, const struct dd *dd) -{ - dds_external_reader_lifespan_qospolicy_t qext; - dds_return_t res; - if (dd->bufsz < sizeof (qext)) - { - DDS_TRACE("plist/do_reader_lifespan: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&qext, dd->buf, sizeof (qext)); - if (dd->bswap) - bswap_external_duration (&qext.duration); - if (qext.use_lifespan != 0 && qext.use_lifespan != 1) - { - DDS_TRACE("plist/do_reader_lifespan: invalid use_lifespan (%d)\n", (int) qext.use_lifespan); - return DDS_RETCODE_BAD_PARAMETER; - } - if ((res = validate_external_duration (&qext.duration)) < 0) - return res; - q->use_lifespan = qext.use_lifespan; - q->duration = nn_from_ddsi_duration (qext.duration); - *present |= fl; - return 0; -} - -static dds_return_t do_entity_factory_qospolicy (dds_entity_factory_qospolicy_t *q, uint64_t *present, uint64_t fl, const struct dd *dd) -{ - if (dd->bufsz < sizeof (*q)) - { - DDS_TRACE("plist/do_entity_factory: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - q->autoenable_created_entities = dd->buf[0]; - if (q->autoenable_created_entities != 0 && q->autoenable_created_entities != 1) - { - DDS_TRACE("plist/do_entity_factory: invalid autoenable_created_entities (%d)\n", (int) q->autoenable_created_entities); - return DDS_RETCODE_BAD_PARAMETER; - } - *present |= fl; - return 0; -} - -static dds_return_t validate_external_reader_data_lifecycle (const dds_external_reader_data_lifecycle_qospolicy_t *q) -{ - if (validate_external_duration (&q->autopurge_nowriter_samples_delay) < 0 || - validate_external_duration (&q->autopurge_disposed_samples_delay) < 0) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_READER_DATA_LIFECYCLE]: invalid autopurge_nowriter_sample_delay or autopurge_disposed_samples_delay\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - return 0; -} - -dds_return_t validate_reader_data_lifecycle (const dds_reader_data_lifecycle_qospolicy_t *q) -{ - dds_external_reader_data_lifecycle_qospolicy_t qext; - qext.autopurge_disposed_samples_delay = nn_to_ddsi_duration (q->autopurge_disposed_samples_delay); - qext.autopurge_nowriter_samples_delay = nn_to_ddsi_duration (q->autopurge_nowriter_samples_delay); - return validate_external_reader_data_lifecycle (&qext); -} - -static dds_return_t do_reader_data_lifecycle (dds_reader_data_lifecycle_qospolicy_t *q, const struct dd *dd) -{ - dds_external_reader_data_lifecycle_qospolicy_t qext; - dds_return_t ret; - memcpy (&qext, dd->buf, sizeof (qext)); - if (dd->bswap) - { - bswap_external_duration (&qext.autopurge_nowriter_samples_delay); - bswap_external_duration (&qext.autopurge_disposed_samples_delay); - } - if ((ret = validate_external_reader_data_lifecycle (&qext)) < 0) - return ret; - q->autopurge_disposed_samples_delay = nn_from_ddsi_duration (qext.autopurge_disposed_samples_delay); - q->autopurge_nowriter_samples_delay = nn_from_ddsi_duration (qext.autopurge_nowriter_samples_delay); - return 0; -} - -static dds_return_t init_one_parameter -( - nn_plist_t *dest, - nn_ipaddress_params_tmp_t *dest_tmp, - uint64_t pwanted, - uint64_t qwanted, - uint16_t pid, - const struct dd *dd -) -{ - dds_return_t res; + /* special-cased ipv4address and port, because they have state beyond that what gets + passed into the generic code */ switch (pid) { - case PID_PAD: - case PID_SENTINEL: - return 0; - - /* Extended QoS data: */ -#define Q(NAME_, prefix_, name_) case PID_##NAME_: \ - if (dd->bufsz < sizeof (prefix_##_##name_##_qospolicy_t)) \ - { \ - DDS_TRACE("plist/init_one_parameter[pid=%s]: buffer too small\n", #NAME_); \ - return DDS_RETCODE_BAD_PARAMETER; \ - } \ - else \ - { \ - prefix_##_##name_##_qospolicy_t *q = &dest->qos.name_; \ - memcpy (q, dd->buf, sizeof (*q)); \ - if (dd->bswap) bswap_##name_##_qospolicy (q); \ - if ((res = validate_##name_##_qospolicy (q)) < 0) \ - return res; \ - dest->qos.present |= QP_##NAME_; \ - } \ - return 0 - Q (DURABILITY, dds, durability); - Q (DESTINATION_ORDER, dds, destination_order); - Q (HISTORY, dds, history); - Q (RESOURCE_LIMITS, dds, resource_limits); - Q (OWNERSHIP, dds, ownership); - Q (OWNERSHIP_STRENGTH, dds, ownership_strength); - Q (PRESENTATION, dds, presentation); - Q (TRANSPORT_PRIORITY, dds, transport_priority); -#undef Q - - case PID_LIVELINESS: - if (dd->bufsz < sizeof (dds_external_liveliness_qospolicy_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=LIVELINESS]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - dds_external_liveliness_qospolicy_t qext; - dds_liveliness_qospolicy_t *q = &dest->qos.liveliness; - memcpy (&qext, dd->buf, sizeof (qext)); - if (dd->bswap) - bswap_external_liveliness_qospolicy (&qext); - if ((res = validate_external_liveliness_qospolicy (&qext)) < 0) - return res; - q->kind = qext.kind; - q->lease_duration = nn_from_ddsi_duration (qext.lease_duration); - dest->qos.present |= QP_LIVELINESS; - } - return 0; - - case PID_DURABILITY_SERVICE: - if (dd->bufsz < sizeof (dds_external_durability_service_qospolicy_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=DURABILITY_SERVICE]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - dds_external_durability_service_qospolicy_t qext; - dds_durability_service_qospolicy_t *q = &dest->qos.durability_service; - /* All-zero durability service is illegal, but at least CoreDX sometimes advertises - it in some harmless cases. So accept all-zero durability service, then handle it - in final_validation, where we can determine whether it really is harmless or not */ - memcpy (&qext, dd->buf, sizeof (qext)); - if (dd->bswap) - bswap_external_durability_service_qospolicy (&qext); - if ((res = validate_external_durability_service_qospolicy_acceptzero (&qext, true)) < 0) - return res; - q->history = qext.history; - q->resource_limits = qext.resource_limits; - q->service_cleanup_delay = nn_from_ddsi_duration (qext.service_cleanup_delay); - dest->qos.present |= QP_DURABILITY_SERVICE; - } - return 0; - - /* PID_RELIABILITY handled differently because it (formally, for - static typing reasons) has a different type on the network - than internally, with the transformation between the two - dependent on wheter we are being pedantic. If that weren't - the case, it would've been an ordinary Q (RELIABILITY, - reliability). */ - case PID_RELIABILITY: - if (dd->bufsz < sizeof (dds_external_reliability_qospolicy_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=RELIABILITY]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - dds_reliability_qospolicy_t *q = &dest->qos.reliability; - dds_external_reliability_qospolicy_t qext; - memcpy (&qext, dd->buf, sizeof (qext)); - if (dd->bswap) - bswap_external_reliability_qospolicy (&qext); - if ((res = validate_xform_reliability_qospolicy (q, &qext)) < 0) - return res; - dest->qos.present |= QP_RELIABILITY; - } - return 0; - - case PID_TOPIC_NAME: - return do_string (&dest->qos.topic_name, &dest->qos.present, &dest->qos.aliased, qwanted, QP_TOPIC_NAME, dd); - case PID_TYPE_NAME: - return do_string (&dest->qos.type_name, &dest->qos.present, &dest->qos.aliased, qwanted, QP_TYPE_NAME, dd); - - case PID_USER_DATA: - return do_octetseq (&dest->qos.user_data, &dest->qos.present, &dest->qos.aliased, qwanted, QP_USER_DATA, dd); - case PID_GROUP_DATA: - return do_octetseq (&dest->qos.group_data, &dest->qos.present, &dest->qos.aliased, qwanted, QP_GROUP_DATA, dd); - case PID_TOPIC_DATA: - return do_octetseq (&dest->qos.topic_data, &dest->qos.present, &dest->qos.aliased, qwanted, QP_TOPIC_DATA, dd); - - case PID_DEADLINE: - return do_duration (&dest->qos.deadline.deadline, &dest->qos.present, QP_DEADLINE, dd); - case PID_LATENCY_BUDGET: - return do_duration (&dest->qos.latency_budget.duration, &dest->qos.present, QP_LATENCY_BUDGET, dd); - case PID_LIFESPAN: - return do_duration (&dest->qos.lifespan.duration, &dest->qos.present, QP_LIFESPAN, dd); - case PID_TIME_BASED_FILTER: - return do_duration (&dest->qos.time_based_filter.minimum_separation, &dest->qos.present, QP_TIME_BASED_FILTER, dd); - - case PID_PARTITION: - return do_stringseq (&dest->qos.partition, &dest->qos.present, &dest->qos.aliased, qwanted, QP_PARTITION, dd); - - case PID_PRISMTECH_READER_DATA_LIFECYCLE: /* PrismTech specific */ - { - dds_return_t ret; - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - if (dd->bufsz >= sizeof (dds_external_reader_data_lifecycle_qospolicy_t)) - ret = do_reader_data_lifecycle (&dest->qos.reader_data_lifecycle, dd); - else - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_READER_DATA_LIFECYCLE]: buffer too small\n"); - ret = DDS_RETCODE_BAD_PARAMETER; - } - if (ret >= 0) - dest->qos.present |= QP_PRISMTECH_READER_DATA_LIFECYCLE; - return ret; - } - case PID_PRISMTECH_WRITER_DATA_LIFECYCLE: /* PrismTech specific */ - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else - { - dds_writer_data_lifecycle_qospolicy_t *q = &dest->qos.writer_data_lifecycle; - if (dd->bufsz < sizeof (*q)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_WRITER_DATA_LIFECYCLE]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - q->autodispose_unregistered_instances = dd->buf[0]; - if (q->autodispose_unregistered_instances & ~1) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_WRITER_DATA_LIFECYCLE]: invalid autodispose_unregistered_instances (%d)\n", (int) q->autodispose_unregistered_instances); - return DDS_RETCODE_BAD_PARAMETER; - } - dest->qos.present |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; - return 0; - } - - /* Other plist */ - case PID_PROTOCOL_VERSION: - if (dd->bufsz < sizeof (nn_protocol_version_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=PROTOCOL_VERSION]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&dest->protocol_version, dd->buf, sizeof (dest->protocol_version)); - if (NN_STRICT_P && - (dest->protocol_version.major != dd->protocol_version.major || - dest->protocol_version.minor != dd->protocol_version.minor)) - { - /* Not accepting a submessage advertising a protocol version - other than that advertised by the message header, unless I - have good reason to, at least not when being strict. */ - DDS_TRACE("plist/init_one_parameter[pid=PROTOCOL_VERSION,mode=STRICT]: version (%u.%u) mismatch with message (%u.%u)\n", - dest->protocol_version.major, dest->protocol_version.minor, - dd->protocol_version.major, dd->protocol_version.minor); - return DDS_RETCODE_BAD_PARAMETER; - } - dest->present |= PP_PROTOCOL_VERSION; - return 0; - - case PID_VENDORID: - if (dd->bufsz < sizeof (nn_vendorid_t)) - return DDS_RETCODE_BAD_PARAMETER; - memcpy (&dest->vendorid, dd->buf, sizeof (dest->vendorid)); - if (NN_STRICT_P && - (dest->vendorid.id[0] != dd->vendorid.id[0] || - dest->vendorid.id[1] != dd->vendorid.id[1])) - { - /* see PROTOCOL_VERSION */ - DDS_TRACE("plist/init_one_parameter[pid=VENDORID,mode=STRICT]: vendor (%u.%u) mismatch with message (%u.%u)\n", - dest->vendorid.id[0], dest->vendorid.id[1], dd->vendorid.id[0], dd->vendorid.id[1]); - return DDS_RETCODE_BAD_PARAMETER; - } - dest->present |= PP_VENDORID; - return 0; - - /* Locators: there may be lists, so we have to allocate memory for them */ -#define XL(NAME_, name_) case PID_##NAME_##_LOCATOR: return do_locator (&dest->name_##_locators, &dest->present, pwanted, PP_##NAME_##_LOCATOR, dd) - XL (UNICAST, unicast); - XL (MULTICAST, multicast); - XL (DEFAULT_UNICAST, default_unicast); - XL (DEFAULT_MULTICAST, default_multicast); - XL (METATRAFFIC_UNICAST, metatraffic_unicast); - XL (METATRAFFIC_MULTICAST, metatraffic_multicast); -#undef XL - - /* IPADDRESS + PORT entries are a nuisance ... I'd prefer - converting them to locators right away, so that the rest of - the code only has to deal with locators, but that is - impossible because the locators require both the address & - the port to be known. - - The wireshark dissector suggests IPvAdress_t is just the 32 - bits of the IP address but it doesn't say so anywhere - ... Similarly for ports, but contrary to the expections they - seem to be 32-bits, too. Apparently in host-endianness. - - And, to be honest, I have no idea what port to use for - MULTICAST_IPADDRESS ... */ -#define XA(NAME_) case PID_##NAME_##_IPADDRESS: return do_ipv4address (dest, dest_tmp, pwanted, PPTMP_##NAME_##_IPADDRESS, dd) -#define XP(NAME_) case PID_##NAME_##_PORT: return do_port (dest, dest_tmp, pwanted, PPTMP_##NAME_##_PORT, dd) - XA (MULTICAST); - XA (DEFAULT_UNICAST); - XP (DEFAULT_UNICAST); - XA (METATRAFFIC_UNICAST); - XP (METATRAFFIC_UNICAST); - XA (METATRAFFIC_MULTICAST); - XP (METATRAFFIC_MULTICAST); +#define XA(NAME_) case PID_##NAME_##_IPADDRESS: return do_ipv4address (plist, dest_tmp, pwanted, PPTMP_##NAME_##_IPADDRESS, dd) +#define XP(NAME_) case PID_##NAME_##_PORT: return do_port (plist, dest_tmp, pwanted, PPTMP_##NAME_##_PORT, dd) + XA (MULTICAST); + XA (DEFAULT_UNICAST); + XP (DEFAULT_UNICAST); + XA (METATRAFFIC_UNICAST); + XP (METATRAFFIC_UNICAST); + XA (METATRAFFIC_MULTICAST); + XP (METATRAFFIC_MULTICAST); #undef XP #undef XA - - case PID_EXPECTS_INLINE_QOS: - if (dd->bufsz < sizeof (dest->expects_inline_qos)) - { - DDS_TRACE("plist/init_one_parameter[pid=EXPECTS_INLINE_QOS]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - dest->expects_inline_qos = dd->buf[0]; - /* boolean: only lsb may be set */ - if (dest->expects_inline_qos & ~1) - { - DDS_TRACE("plist/init_one_parameter[pid=EXPECTS_INLINE_QOS]: invalid expects_inline_qos (%d)\n", - (int) dest->expects_inline_qos); - return DDS_RETCODE_BAD_PARAMETER; - } - dest->present |= PP_EXPECTS_INLINE_QOS; - return 0; - - case PID_PARTICIPANT_MANUAL_LIVELINESS_COUNT: - /* Spec'd as "incremented monotonically" (DDSI 2.1, table 8.13), - but 32 bits signed is not such a smart choice for that. We'll - simply accept any value. */ - if (dd->bufsz < sizeof (dest->participant_manual_liveliness_count)) - { - DDS_TRACE("plist/init_one_parameter[pid=PARTICIPANT_MANUAL_LIVELINESS_COUNT]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&dest->participant_manual_liveliness_count, dd->buf, sizeof (dest->participant_manual_liveliness_count)); - if (dd->bswap) - dest->participant_manual_liveliness_count = bswap4 (dest->participant_manual_liveliness_count); - dest->present |= PP_PARTICIPANT_MANUAL_LIVELINESS_COUNT; - return 0; - - case PID_PARTICIPANT_LEASE_DURATION: - return do_duration (&dest->participant_lease_duration, &dest->present, PP_PARTICIPANT_LEASE_DURATION, dd); - - case PID_CONTENT_FILTER_PROPERTY: - /* FIXME */ - return 0; - - case PID_PARTICIPANT_GUID: - return do_guid (&dest->participant_guid, &dest->present, PP_PARTICIPANT_GUID, valid_participant_guid, dd); - - case PID_GROUP_GUID: - return do_guid (&dest->group_guid, &dest->present, PP_GROUP_GUID, valid_group_guid, dd); - - case PID_PARTICIPANT_ENTITYID: - case PID_GROUP_ENTITYID: - /* DDSI 2.1 table 9.13: reserved for future use */ - return 0; - - case PID_PARTICIPANT_BUILTIN_ENDPOINTS: - /* FIXME: I assume it is the same as the BUILTIN_ENDPOINT_SET, - which is the set that DDSI2 has been using so far. */ - /* FALLS THROUGH */ - case PID_BUILTIN_ENDPOINT_SET: - if (dd->bufsz < sizeof (dest->builtin_endpoint_set)) - { - DDS_TRACE("plist/init_one_parameter[pid=BUILTIN_ENDPOINT_SET(%u)]: buffer too small\n", pid); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&dest->builtin_endpoint_set, dd->buf, sizeof (dest->builtin_endpoint_set)); - if (dd->bswap) - dest->builtin_endpoint_set = bswap4u (dest->builtin_endpoint_set); - if (NN_STRICT_P && !protocol_version_is_newer (dd->protocol_version) && - (dest->builtin_endpoint_set & ~(NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_TOPIC_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_TOPIC_DETECTOR | - /* undefined ones: */ - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_PROXY_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_PROXY_DETECTOR | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_STATE_ANNOUNCER | - NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_STATE_DETECTOR | - /* defined ones again: */ - NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER | - NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER)) != 0) - { - DDS_TRACE("plist/init_one_parameter[pid=BUILTIN_ENDPOINT_SET(%u),mode=STRICT,proto=%u.%u]: invalid set (0x%x)\n", - pid, dd->protocol_version.major, dd->protocol_version.minor, dest->builtin_endpoint_set); - return DDS_RETCODE_BAD_PARAMETER; - } - dest->present |= PP_BUILTIN_ENDPOINT_SET; - return 0; - - case PID_PRISMTECH_BUILTIN_ENDPOINT_SET: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - else if (dd->bufsz < sizeof (dest->prismtech_builtin_endpoint_set)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_BUILTIN_ENDPOINT_SET(%u)]: buffer too small\n", pid); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - memcpy (&dest->prismtech_builtin_endpoint_set, dd->buf, sizeof (dest->prismtech_builtin_endpoint_set)); - if (dd->bswap) - dest->prismtech_builtin_endpoint_set = bswap4u (dest->prismtech_builtin_endpoint_set); - dest->present |= PP_PRISMTECH_BUILTIN_ENDPOINT_SET; - } - return 0; - - case PID_PROPERTY_LIST: - case PID_TYPE_MAX_SIZE_SERIALIZED: - /* FIXME */ - return 0; - - case PID_ENTITY_NAME: - return do_string (&dest->entity_name, &dest->present, &dest->aliased, pwanted, PP_ENTITY_NAME, dd); - - case PID_KEYHASH: - if (dd->bufsz < sizeof (dest->keyhash)) - { - DDS_TRACE("plist/init_one_parameter[pid=KEYHASH]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&dest->keyhash, dd->buf, sizeof (dest->keyhash)); - dest->present |= PP_KEYHASH; - return 0; - - case PID_STATUSINFO: - if (dd->bufsz < sizeof (dest->statusinfo)) - { - DDS_TRACE("plist/init_one_parameter[pid=STATUSINFO]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&dest->statusinfo, dd->buf, sizeof (dest->statusinfo)); - dest->statusinfo = fromBE4u (dest->statusinfo); - if (NN_STRICT_P && !protocol_version_is_newer (dd->protocol_version) && - (dest->statusinfo & ~NN_STATUSINFO_STANDARDIZED)) - { - /* Spec says I may not interpret the reserved bits. But no-one - may use them in this version of the specification */ - DDS_TRACE("plist/init_one_parameter[pid=STATUSINFO,mode=STRICT,proto=%u.%u]: invalid statusinfo (0x%x)\n", - dd->protocol_version.major, dd->protocol_version.minor, dest->statusinfo); - return DDS_RETCODE_BAD_PARAMETER; - } - /* Clear all bits we don't understand, then add the extended bits if present */ - dest->statusinfo &= NN_STATUSINFO_STANDARDIZED; - if (dd->bufsz >= 2 * sizeof (dest->statusinfo) && vendor_is_eclipse_or_opensplice(dd->vendorid)) - { - uint32_t statusinfox; - DDSRT_STATIC_ASSERT_CODE (sizeof(statusinfox) == sizeof(dest->statusinfo)); - memcpy (&statusinfox, dd->buf + sizeof (dest->statusinfo), sizeof (statusinfox)); - statusinfox = fromBE4u (statusinfox); - if (statusinfox & NN_STATUSINFOX_OSPL_AUTO) - dest->statusinfo |= NN_STATUSINFO_OSPL_AUTO; - } - dest->present |= PP_STATUSINFO; - return 0; - - case PID_COHERENT_SET: - if (dd->bufsz < sizeof (dest->coherent_set_seqno)) - { - DDS_TRACE("plist/init_one_parameter[pid=COHERENT_SET]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - nn_sequence_number_t *q = &dest->coherent_set_seqno; - seqno_t seqno; - memcpy (q, dd->buf, sizeof (*q)); - if (dd->bswap) - { - q->high = bswap4 (q->high); - q->low = bswap4u (q->low); - } - seqno = fromSN(dest->coherent_set_seqno); - if (seqno <= 0 && seqno != NN_SEQUENCE_NUMBER_UNKNOWN) - { - DDS_TRACE("plist/init_one_parameter[pid=COHERENT_SET]: invalid sequence number (%" PRId64 ")\n", seqno); - return DDS_RETCODE_BAD_PARAMETER; - } - dest->present |= PP_COHERENT_SET; - return 0; - } - - case PID_CONTENT_FILTER_INFO: - case PID_DIRECTED_WRITE: - case PID_ORIGINAL_WRITER_INFO: - /* FIXME */ - return 0; - - case PID_ENDPOINT_GUID: - if (NN_PEDANTIC_P && !protocol_version_is_newer (dd->protocol_version)) - { - /* ENDPOINT_GUID is not specified in the 2.1 standard, so - reject it: in (really) strict mode we do not accept - undefined things, even though we are -arguably- supposed to - ignore it. */ - DDS_TRACE("plist/init_one_parameter[pid=ENDPOINT_GUID,mode=PEDANTIC,proto=%u.%u]: undefined pid\n", - dd->protocol_version.major, dd->protocol_version.minor); - return DDS_RETCODE_BAD_PARAMETER; - } - return do_guid (&dest->endpoint_guid, &dest->present, PP_ENDPOINT_GUID, valid_endpoint_guid, dd); - - case PID_PRISMTECH_ENDPOINT_GUID: /* case PID_RTI_TYPECODE: */ - if (vendor_is_eclipse_or_prismtech (dd->vendorid)) - { - /* PrismTech specific variant of ENDPOINT_GUID, for strict compliancy */ - return do_guid (&dest->endpoint_guid, &dest->present, PP_ENDPOINT_GUID, valid_endpoint_guid, dd); - } - else if (vendor_is_rti (dd->vendorid)) - { - /* For RTI it is a typecode */ - return do_blob (&dest->qos.rti_typecode, &dest->qos.present, &dest->qos.aliased, qwanted, QP_RTI_TYPECODE, dd); - - } - else - { - return 0; - } - - case PID_PRISMTECH_PARTICIPANT_VERSION_INFO: - return do_prismtech_participant_version_info(&dest->prismtech_participant_version_info, &dest->present, &dest->aliased, dd); - - case PID_PRISMTECH_SUBSCRIPTION_KEYS: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_subscription_keys_qospolicy (&dest->qos.subscription_keys, &dest->qos.present, &dest->qos.aliased, QP_PRISMTECH_SUBSCRIPTION_KEYS, dd); - - case PID_PRISMTECH_READER_LIFESPAN: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_reader_lifespan_qospolicy (&dest->qos.reader_lifespan, &dest->qos.present, QP_PRISMTECH_READER_LIFESPAN, dd); - - case PID_PRISMTECH_ENTITY_FACTORY: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_entity_factory_qospolicy (&dest->qos.entity_factory, &dest->qos.present, QP_PRISMTECH_ENTITY_FACTORY, dd); - - case PID_PRISMTECH_NODE_NAME: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_string (&dest->node_name, &dest->present, &dest->aliased, pwanted, PP_PRISMTECH_NODE_NAME, dd); - - case PID_PRISMTECH_EXEC_NAME: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_string (&dest->exec_name, &dest->present, &dest->aliased, pwanted, PP_PRISMTECH_EXEC_NAME, dd); - - case PID_PRISMTECH_SERVICE_TYPE: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - if (dd->bufsz < sizeof (dest->service_type)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_SERVICE_TYPE]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&dest->service_type, dd->buf, sizeof (dest->service_type)); - if (dd->bswap) - dest->service_type = bswap4u (dest->service_type); - dest->present |= PP_PRISMTECH_SERVICE_TYPE; - return 0; - - case PID_PRISMTECH_PROCESS_ID: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - if (dd->bufsz < sizeof (dest->process_id)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_PROCESS_ID]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - memcpy (&dest->process_id, dd->buf, sizeof (dest->process_id)); - if (dd->bswap) - dest->process_id = bswap4u (dest->process_id); - dest->present |= PP_PRISMTECH_PROCESS_ID; - return 0; - - case PID_PRISMTECH_TYPE_DESCRIPTION: - if (!vendor_is_eclipse_or_prismtech (dd->vendorid)) - return 0; - return do_string (&dest->type_description, &dest->present, &dest->aliased, pwanted, PP_PRISMTECH_TYPE_DESCRIPTION, dd); - - case PID_PRISMTECH_EOTINFO: - if (!vendor_is_eclipse_or_opensplice (dd->vendorid)) - return 0; - else if (dd->bufsz < 2*sizeof (uint32_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_EOTINFO]: buffer too small (1)\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - nn_prismtech_eotinfo_t *q = &dest->eotinfo; - uint32_t i; - q->transactionId = ((const uint32_t *) dd->buf)[0]; - q->n = ((const uint32_t *) dd->buf)[1]; - if (dd->bswap) - { - q->n = bswap4u (q->n); - q->transactionId = bswap4u (q->transactionId); - } - if (q->n > (dd->bufsz - 2*sizeof (uint32_t)) / sizeof (nn_prismtech_eotgroup_tid_t)) - { - DDS_TRACE("plist/init_one_parameter[pid=PRISMTECH_EOTINFO]: buffer too small (2)\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - if (q->n == 0) - q->tids = NULL; - else - q->tids = (nn_prismtech_eotgroup_tid_t *) (dd->buf + 2*sizeof (uint32_t)); - for (i = 0; i < q->n; i++) - { - q->tids[i].writer_entityid.u = fromBE4u (q->tids[i].writer_entityid.u); - if (dd->bswap) - q->tids[i].transactionId = bswap4u (q->tids[i].transactionId); - } - dest->present |= PP_PRISMTECH_EOTINFO; - dest->aliased |= PP_PRISMTECH_EOTINFO; - if (dds_get_log_mask() & DDS_LC_PLIST) - { - DDS_LOG(DDS_LC_PLIST, "eotinfo: txn %"PRIu32" {", q->transactionId); - for (i = 0; i < q->n; i++) - DDS_LOG(DDS_LC_PLIST, " %"PRIx32":%"PRIu32, q->tids[i].writer_entityid.u, q->tids[i].transactionId); - DDS_LOG(DDS_LC_PLIST, " }\n"); - } - return 0; - } - -#ifdef DDSI_INCLUDE_SSM - case PID_READER_FAVOURS_SSM: - if (dd->bufsz < sizeof (dest->reader_favours_ssm)) - { - DDS_TRACE("plist/init_one_parameter[pid=READER_FAVOURS_SSM]: buffer too small\n"); - return DDS_RETCODE_BAD_PARAMETER; - } - else - { - nn_reader_favours_ssm_t *rfssm = &dest->reader_favours_ssm; - memcpy (rfssm, dd->buf, sizeof (*rfssm)); - if (dd->bswap) - rfssm->state = bswap4u (rfssm->state); - if (rfssm->state != 0 && rfssm->state != 1) - { - DDS_TRACE("plist/init_one_parameter[pid=READER_FAVOURS_SSM]: unsupported value: %u\n", rfssm->state); - rfssm->state = 0; - } - dest->present |= PP_READER_FAVOURS_SSM; - return 0; - } -#endif - - /* Deprecated ones (used by RTI, but not relevant to DDSI) */ - case PID_PERSISTENCE: - case PID_TYPE_CHECKSUM: - case PID_TYPE2_NAME: - case PID_TYPE2_CHECKSUM: - case PID_EXPECTS_ACK: - case PID_MANAGER_KEY: - case PID_SEND_QUEUE_SIZE: - case PID_RELIABILITY_ENABLED: - case PID_VARGAPPS_SEQUENCE_NUMBER_LAST: - case PID_RECV_QUEUE_SIZE: - case PID_RELIABILITY_OFFERED: - return 0; - - default: - /* Ignore unrecognised parameters (disregarding vendor-specific - ones, of course) if the protocol version is newer than the - one implemented, and fail it if it isn't. I know all RFPs say - to be tolerant in what is accepted, but that is where the - bugs & the buffer overflows originate! */ - if (pid & PID_UNRECOGNIZED_INCOMPATIBLE_FLAG) { - dest->present |= PP_INCOMPATIBLE; - return DDS_RETCODE_UNSUPPORTED; - } else if (pid & PID_VENDORSPECIFIC_FLAG) { - return 0; - } else if (!protocol_version_is_newer (dd->protocol_version) && NN_STRICT_P) { - DDS_TRACE("plist/init_one_parameter[pid=%u,mode=STRICT,proto=%u.%u]: undefined paramter id\n", - pid, dd->protocol_version.major, dd->protocol_version.minor); - return DDS_RETCODE_BAD_PARAMETER; - } else { - return 0; - } } - assert (0); - DDS_TRACE("plist/init_one_parameter: can't happen\n"); - return DDS_RETCODE_BAD_PARAMETER; -} + const struct piddesc_index *index; + if (!(pid & PID_VENDORSPECIFIC_FLAG)) + index = &piddesc_vendor_index[0]; + else if (dd->vendorid.id[0] != 1 || dd->vendorid.id[1] < 1) + return return_unrecognized_pid (plist, pid); + else if (dd->vendorid.id[1] >= sizeof (piddesc_vendor_index) / sizeof (piddesc_vendor_index[0])) + return return_unrecognized_pid (plist, pid); + else if (piddesc_vendor_index[dd->vendorid.id[1]].index == NULL) + return return_unrecognized_pid (plist, pid); + else + index = &piddesc_vendor_index[dd->vendorid.id[1]]; -static void default_resource_limits (dds_resource_limits_qospolicy_t *q) -{ - q->max_instances = DDS_LENGTH_UNLIMITED; - q->max_samples = DDS_LENGTH_UNLIMITED; - q->max_samples_per_instance = DDS_LENGTH_UNLIMITED; -} - -static void default_history (dds_history_qospolicy_t *q) -{ - q->kind = DDS_HISTORY_KEEP_LAST; - q->depth = 1; -} - -void nn_plist_init_empty (nn_plist_t *dest) -{ -#ifndef NDEBUG - memset (dest, 0, sizeof (*dest)); -#endif - dest->present = dest->aliased = 0; - nn_xqos_init_empty (&dest->qos); -} - -void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b) -{ - /* Adds entries's from B to A (duplicating memory) (only those not - present in A, obviously) */ - - /* Simple ones (that don't need memory): everything but topic, type, - partition, {group,topic|user} data */ -#define CQ(fl_, name_) do { \ - if (!(a->present & PP_##fl_) && (b->present & PP_##fl_)) { \ - a->name_ = b->name_; \ - a->present |= PP_##fl_; \ - } \ - } while (0) - CQ (PROTOCOL_VERSION, protocol_version); - CQ (VENDORID, vendorid); - CQ (EXPECTS_INLINE_QOS, expects_inline_qos); - CQ (PARTICIPANT_MANUAL_LIVELINESS_COUNT, participant_manual_liveliness_count); - CQ (PARTICIPANT_BUILTIN_ENDPOINTS, participant_builtin_endpoints); - CQ (PARTICIPANT_LEASE_DURATION, participant_lease_duration); - CQ (PARTICIPANT_GUID, participant_guid); - CQ (ENDPOINT_GUID, endpoint_guid); - CQ (GROUP_GUID, group_guid); - CQ (BUILTIN_ENDPOINT_SET, builtin_endpoint_set); - CQ (KEYHASH, keyhash); - CQ (STATUSINFO, statusinfo); - CQ (COHERENT_SET, coherent_set_seqno); - CQ (PRISMTECH_SERVICE_TYPE, service_type); - CQ (PRISMTECH_PROCESS_ID, process_id); - CQ (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set); -#ifdef DDSI_INCLUDE_SSM - CQ (READER_FAVOURS_SSM, reader_favours_ssm); -#endif -#undef CQ - - /* For allocated ones it is Not strictly necessary to use tmp, as - a->name_ may only be interpreted if the present flag is set, but - this keeps a clean on failure and may thereby save us from a - nasty surprise. */ -#define CQ(fl_, name_, type_, tmp_type_) do { \ - if (!(a->present & PP_##fl_) && (b->present & PP_##fl_)) { \ - tmp_type_ tmp = b->name_; \ - unalias_##type_ (&tmp, -1); \ - a->name_ = tmp; \ - a->present |= PP_##fl_; \ - } \ - } while (0) - CQ (UNICAST_LOCATOR, unicast_locators, locators, nn_locators_t); - CQ (MULTICAST_LOCATOR, unicast_locators, locators, nn_locators_t); - CQ (DEFAULT_UNICAST_LOCATOR, default_unicast_locators, locators, nn_locators_t); - CQ (DEFAULT_MULTICAST_LOCATOR, default_multicast_locators, locators, nn_locators_t); - CQ (METATRAFFIC_UNICAST_LOCATOR, metatraffic_unicast_locators, locators, nn_locators_t); - CQ (METATRAFFIC_MULTICAST_LOCATOR, metatraffic_multicast_locators, locators, nn_locators_t); - CQ (ENTITY_NAME, entity_name, string, char *); - CQ (PRISMTECH_NODE_NAME, node_name, string, char *); - CQ (PRISMTECH_EXEC_NAME, exec_name, string, char *); - CQ (PRISMTECH_TYPE_DESCRIPTION, type_description, string, char *); - CQ (PRISMTECH_EOTINFO, eotinfo, eotinfo, nn_prismtech_eotinfo_t); -#undef CQ - if (!(a->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO) && - (b->present & PP_PRISMTECH_PARTICIPANT_VERSION_INFO)) + const struct piddesc *entry; + if (pid_without_flags (pid) > index->index_max || (entry = index->index[pid_without_flags (pid)]) == NULL) + return return_unrecognized_pid (plist, pid); + assert (pid_without_flags (pid) == pid_without_flags (entry->pid)); + if (pid != entry->pid) { - nn_prismtech_participant_version_info_t tmp = b->prismtech_participant_version_info; - unalias_string (&tmp.internals, -1); - a->prismtech_participant_version_info = tmp; - a->present |= PP_PRISMTECH_PARTICIPANT_VERSION_INFO; + DDS_LOG (DDS_LC_ERROR, "error processing parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" mapped to pid %"PRIx16"\n", + dd->vendorid.id[0], dd->vendorid.id[1], + dd->protocol_version.major, dd->protocol_version.minor, + pid, entry->pid); + return return_unrecognized_pid (plist, pid); + } + assert (pid != PID_PAD); + + struct flagset flagset; + if (entry->flags & PDF_QOS) + { + flagset.present = &plist->qos.present; + flagset.aliased = &plist->qos.aliased; + flagset.wanted = qwanted; + } + else + { + flagset.present = &plist->present; + flagset.aliased = &plist->aliased; + flagset.wanted = pwanted; } - nn_xqos_mergein_missing (&a->qos, &b->qos); + /* Disallow multiple copies of the same parameter unless explicit allowed + (which is needed for handling locators). String sequences will leak + memory if deserialized repeatedly */ + if ((*flagset.present & entry->present_flag) && !(entry->flags & PDF_ALLOWMULTI)) + { + DDS_LOG (DDS_LC_WARNING, "invalid parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" (%s) multiply defined\n", + dd->vendorid.id[0], dd->vendorid.id[1], + dd->protocol_version.major, dd->protocol_version.minor, + pid, entry->name); + return DDS_RETCODE_BAD_PARAMETER; + } + if (!(flagset.wanted & entry->present_flag)) + { + /* skip don't cares -- the point of skipping them is performance and + avoiding unnecessary allocations, so validating them would be silly */ + return 0; + } + + /* String sequences are not allowed in parameters that may occur multiple + times because they will leak the arrays of pointers. Fixing this is + not worth the bother as long as such parameters don't exist. */ + dds_return_t ret; + void * const dst = (char *) plist + entry->plist_offset; + size_t dstoff = 0; + size_t srcoff = 0; + if (entry->flags & PDF_FUNCTION) + ret = entry->op.f.deser (dst, &dstoff, &flagset, entry->present_flag, dd, &srcoff); + else + ret = deser_generic (dst, &dstoff, &flagset, entry->present_flag, dd, &srcoff, entry->op.desc); + if (ret == 0 && entry->deser_validate_xform) + ret = entry->deser_validate_xform (dst, dd); + if (ret < 0) + { + DDS_LOG (DDS_LC_WARNING, "invalid parameter list (vendor %u.%u, version %u.%u): pid %"PRIx16" (%s) invalid, input = ", + dd->vendorid.id[0], dd->vendorid.id[1], + dd->protocol_version.major, dd->protocol_version.minor, + pid, entry->name); + log_octetseq (DDS_LC_WARNING, (uint32_t) dd->bufsz, dd->buf); + DDS_LOG (DDS_LC_WARNING, "\n"); + } + return ret; +} + +void nn_plist_mergein_missing (nn_plist_t *a, const nn_plist_t *b, uint64_t pmask, uint64_t qmask) +{ + plist_or_xqos_mergein_missing (a, b, 0, pmask, qmask); +} + +void nn_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b, uint64_t mask) +{ + plist_or_xqos_mergein_missing (a, b, offsetof (nn_plist_t, qos), 0, mask); } void nn_plist_copy (nn_plist_t *dst, const nn_plist_t *src) { nn_plist_init_empty (dst); - nn_plist_mergein_missing (dst, src); + nn_plist_mergein_missing (dst, src, ~(uint64_t)0, ~(uint64_t)0); } nn_plist_t *nn_plist_dup (const nn_plist_t *src) @@ -2242,28 +1992,45 @@ nn_plist_t *nn_plist_dup (const nn_plist_t *src) return dst; } -static dds_return_t final_validation (nn_plist_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid) +void nn_plist_init_empty (nn_plist_t *dest) { +#ifndef NDEBUG + memset (dest, 0, sizeof (*dest)); +#endif + dest->present = dest->aliased = 0; + nn_xqos_init_empty (&dest->qos); +} + +static dds_return_t final_validation_qos (const dds_qos_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid, bool *dursvc_accepted_allzero) +{ + /* input is const, but we need to validate the combination of + history & resource limits: so use a copy of those two policies */ + dds_history_qospolicy_t tmphist = { + .kind = DDS_HISTORY_KEEP_LAST, + .depth = 1 + }; + dds_resource_limits_qospolicy_t tmpreslim = { + .max_samples = DDS_LENGTH_UNLIMITED, + .max_instances = DDS_LENGTH_UNLIMITED, + .max_samples_per_instance = DDS_LENGTH_UNLIMITED + }; + dds_return_t res; + /* Resource limits & history are related, so if only one is given, set the other to the default, claim it has been provided & validate the combination. They can't be changed afterward, so this is a reasonable interpretation. */ - if ((dest->qos.present & QP_HISTORY) && !(dest->qos.present & QP_RESOURCE_LIMITS)) + if (dest->present & QP_HISTORY) + tmphist = dest->history; + if (dest->present & QP_RESOURCE_LIMITS) + tmpreslim = dest->resource_limits; + if ((res = validate_history_and_resource_limits (&tmphist, &tmpreslim)) < 0) + return res; + + if ((dest->present & QP_DEADLINE) && (dest->present & QP_TIME_BASED_FILTER)) { - default_resource_limits (&dest->qos.resource_limits); - dest->qos.present |= QP_RESOURCE_LIMITS; - } - if (!(dest->qos.present & QP_HISTORY) && (dest->qos.present & QP_RESOURCE_LIMITS)) - { - default_history (&dest->qos.history); - dest->qos.present |= QP_HISTORY; - } - if (dest->qos.present & (QP_HISTORY | QP_RESOURCE_LIMITS)) - { - dds_return_t res; - assert ((dest->qos.present & (QP_HISTORY | QP_RESOURCE_LIMITS)) == (QP_HISTORY | QP_RESOURCE_LIMITS)); - if ((res = validate_history_and_resource_limits (&dest->qos.history, &dest->qos.resource_limits)) < 0) - return res; + if (dest->deadline.deadline < dest->time_based_filter.minimum_separation) + return DDS_RETCODE_INCONSISTENT_POLICY; } /* Durability service is sort-of accepted if all zeros, but only @@ -2272,14 +2039,19 @@ static dds_return_t final_validation (nn_plist_t *dest, nn_protocol_version_t pr parsed we know the setting of the durability QoS (the default is always VOLATILE), and hence we can verify that the setting is valid or delete it if irrelevant. */ - if (dest->qos.present & QP_DURABILITY_SERVICE) + if (dursvc_accepted_allzero) + *dursvc_accepted_allzero = false; + if (dest->present & QP_DURABILITY_SERVICE) { - const dds_durability_kind_t durkind = (dest->qos.present & QP_DURABILITY) ? dest->qos.durability.kind : DDS_DURABILITY_VOLATILE; + const dds_durability_kind_t durkind = (dest->present & QP_DURABILITY) ? dest->durability.kind : DDS_DURABILITY_VOLATILE; bool acceptzero; + bool check_dursvc = true; /* Use a somewhat convoluted rule to decide whether or not to "accept" an all-zero durability service setting, to find a reasonable mix of strictness and compatibility */ - if (protocol_version_is_newer (protocol_version)) + if (dursvc_accepted_allzero == NULL) + acceptzero = false; + else if (protocol_version_is_newer (protocol_version)) acceptzero = true; else if (NN_STRICT_P) acceptzero = vendor_is_twinoaks (vendorid); @@ -2289,33 +2061,29 @@ static dds_return_t final_validation (nn_plist_t *dest, nn_protocol_version_t pr { case DDS_DURABILITY_VOLATILE: case DDS_DURABILITY_TRANSIENT_LOCAL: - /* pretend we never saw it if it is all zero */ - if (acceptzero && durability_service_qospolicy_allzero (&dest->qos.durability_service)) - dest->qos.present &= ~QP_DURABILITY_SERVICE; + /* let caller now if we accepted all-zero: our input is const and we can't patch it out */ + if (acceptzero && durability_service_qospolicy_allzero (&dest->durability_service) && dursvc_accepted_allzero) + { + *dursvc_accepted_allzero = true; + check_dursvc = false; + } break; case DDS_DURABILITY_TRANSIENT: case DDS_DURABILITY_PERSISTENT: break; } - /* if it is still present, it must be valid */ - if (dest->qos.present & QP_DURABILITY_SERVICE) - { - dds_return_t res; - if ((res = validate_durability_service_qospolicy (&dest->qos.durability_service)) < 0) - return res; - } + if (check_dursvc && (res = validate_durability_service_qospolicy_acceptzero (&dest->durability_service, false)) < 0) + return res; } return 0; } -dds_return_t nn_plist_init_frommsg -( - nn_plist_t *dest, - char **nextafterplist, - uint64_t pwanted, - uint64_t qwanted, - const nn_plist_src_t *src -) +static dds_return_t final_validation (nn_plist_t *dest, nn_protocol_version_t protocol_version, nn_vendorid_t vendorid, bool *dursvc_accepted_allzero) +{ + return final_validation_qos (&dest->qos, protocol_version, vendorid, dursvc_accepted_allzero); +} + +dds_return_t nn_plist_init_frommsg (nn_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const nn_plist_src_t *src) { const unsigned char *pl; struct dd dd; @@ -2351,7 +2119,6 @@ dds_return_t nn_plist_init_frommsg return DDS_RETCODE_BAD_PARAMETER; } nn_plist_init_empty (dest); - dest->unalias_needs_bswap = dd.bswap; dest_tmp.present = 0; DDS_LOG(DDS_LC_PLIST, "NN_PLIST_INIT (bswap %d)\n", dd.bswap); @@ -2371,14 +2138,19 @@ dds_return_t nn_plist_init_frommsg if (pid == PID_SENTINEL) { /* Sentinel terminates list, the length is ignored, DDSI 9.4.2.11. */ + bool dursvc_accepted_allzero; DDS_LOG(DDS_LC_PLIST, "%4"PRIx32" PID %"PRIx16"\n", (uint32_t) (pl - src->buf), pid); - if ((res = final_validation (dest, src->protocol_version, src->vendorid)) < 0) + if ((res = final_validation (dest, src->protocol_version, src->vendorid, &dursvc_accepted_allzero)) < 0) { nn_plist_fini (dest); - return DDS_RETCODE_BAD_PARAMETER; + return res; } else { + /* If we accepted an all-zero durability service, that's awfully friendly of ours, + but we'll pretend we never saw it */ + if (dursvc_accepted_allzero) + dest->qos.present &= ~QP_DURABILITY_SERVICE; pl += sizeof (*par); if (nextafterplist) *nextafterplist = (char *) pl; @@ -2510,16 +2282,16 @@ unsigned char *nn_plist_quickscan (struct nn_rsample_info *dest, const struct nn } else { + /* can only represent 2 LSBs of statusinfo in "dest", so if others are set, + mark it as a "complex_qos" and accept the hit of parsing the data completely. */ uint32_t stinfo = fromBE4u (*((uint32_t *) pl)); - uint32_t stinfox = (length < 8 || !vendor_is_eclipse_or_opensplice(src->vendorid)) ? 0 : fromBE4u (*((uint32_t *) pl + 1)); -#if (NN_STATUSINFO_DISPOSE | NN_STATUSINFO_UNREGISTER) != 3 -#error "expected dispose/unregister to be in lowest 2 bits" -#endif dest->statusinfo = stinfo & 3u; - if ((stinfo & ~3u) || stinfox) + if ((stinfo & ~3u)) dest->complex_qos = 1; } break; + case PID_KEYHASH: + break; default: DDS_LOG(DDS_LC_PLIST, "(pid=%"PRIx16" complex_qos=1)", pid); dest->complex_qos = 1; @@ -2691,7 +2463,6 @@ void nn_xqos_init_default_subscriber (dds_qos_t *xqos) xqos->present |= QP_PRISMTECH_ENTITY_FACTORY; xqos->entity_factory.autoenable_created_entities = 1; - xqos->present |= QP_PARTITION; xqos->partition.n = 0; xqos->partition.strs = NULL; @@ -2709,146 +2480,20 @@ void nn_xqos_init_default_publisher (dds_qos_t *xqos) xqos->partition.strs = NULL; } -void nn_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b) -{ - /* Adds QoS's from B to A (duplicating memory) (only those not - present in A, obviously) */ - - /* Simple ones (that don't need memory): everything but topic, type, - partition, {group,topic|user} data */ -#define CQ(fl_, name_) do { \ - if (!(a->present & QP_##fl_) && (b->present & QP_##fl_)) { \ - a->name_ = b->name_; \ - a->present |= QP_##fl_; \ - } \ - } while (0) - CQ (PRESENTATION, presentation); - CQ (DURABILITY, durability); - CQ (DURABILITY_SERVICE, durability_service); - CQ (DEADLINE, deadline); - CQ (LATENCY_BUDGET, latency_budget); - CQ (LIVELINESS, liveliness); - CQ (RELIABILITY, reliability); - CQ (DESTINATION_ORDER, destination_order); - CQ (HISTORY, history); - CQ (RESOURCE_LIMITS, resource_limits); - CQ (TRANSPORT_PRIORITY, transport_priority); - CQ (LIFESPAN, lifespan); - CQ (OWNERSHIP, ownership); - CQ (OWNERSHIP_STRENGTH, ownership_strength); - CQ (TIME_BASED_FILTER, time_based_filter); - CQ (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle); - CQ (PRISMTECH_WRITER_DATA_LIFECYCLE, writer_data_lifecycle); - CQ (PRISMTECH_READER_LIFESPAN, reader_lifespan); - CQ (PRISMTECH_ENTITY_FACTORY, entity_factory); - CQ (CYCLONE_IGNORELOCAL, ignorelocal); -#undef CQ - - /* For allocated ones it is Not strictly necessary to use tmp, as - a->name_ may only be interpreted if the present flag is set, but - this keeps a clean on failure and may thereby save us from a - nasty surprise. */ -#define CQ(fl_, name_, type_, tmp_type_) do { \ - if (!(a->present & QP_##fl_) && (b->present & QP_##fl_)) { \ - tmp_type_ tmp = b->name_; \ - unalias_##type_ (&tmp, -1); \ - a->name_ = tmp; \ - a->present |= QP_##fl_; \ - } \ - } while (0) - CQ (GROUP_DATA, group_data, octetseq, ddsi_octetseq_t); - CQ (TOPIC_DATA, topic_data, octetseq, ddsi_octetseq_t); - CQ (USER_DATA, user_data, octetseq, ddsi_octetseq_t); - CQ (TOPIC_NAME, topic_name, string, char *); - CQ (TYPE_NAME, type_name, string, char *); - CQ (RTI_TYPECODE, rti_typecode, octetseq, ddsi_octetseq_t); -#undef CQ - if (!(a->present & QP_PRISMTECH_SUBSCRIPTION_KEYS) && (b->present & QP_PRISMTECH_SUBSCRIPTION_KEYS)) - { - a->subscription_keys.use_key_list = b->subscription_keys.use_key_list; - duplicate_stringseq (&a->subscription_keys.key_list, &b->subscription_keys.key_list); - a->present |= QP_PRISMTECH_SUBSCRIPTION_KEYS; - } - if (!(a->present & QP_PARTITION) && (b->present & QP_PARTITION)) - { - duplicate_stringseq (&a->partition, &b->partition); - a->present |= QP_PARTITION; - } -} - void nn_xqos_copy (dds_qos_t *dst, const dds_qos_t *src) { nn_xqos_init_empty (dst); - nn_xqos_mergein_missing (dst, src); -} - -void nn_xqos_unalias (dds_qos_t *xqos) -{ - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_UNALIAS\n"); -#define Q(name_, func_, field_) do { \ - if ((xqos->present & QP_##name_) && (xqos->aliased & QP_##name_)) { \ - unalias_##func_ (&xqos->field_, -1); \ - xqos->aliased &= ~QP_##name_; \ - } \ - } while (0) - Q (GROUP_DATA, octetseq, group_data); - Q (TOPIC_DATA, octetseq, topic_data); - Q (USER_DATA, octetseq, user_data); - Q (TOPIC_NAME, string, topic_name); - Q (TYPE_NAME, string, type_name); - Q (PARTITION, stringseq, partition); - Q (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys_qospolicy, subscription_keys); - Q (RTI_TYPECODE, octetseq, rti_typecode); -#undef Q - assert (xqos->aliased == 0); + nn_xqos_mergein_missing (dst, src, ~(uint64_t)0); } void nn_xqos_fini (dds_qos_t *xqos) { - struct t { uint64_t fl; size_t off; }; - static const struct t qos_simple[] = { - { QP_GROUP_DATA, offsetof (dds_qos_t, group_data.value) }, - { QP_TOPIC_DATA, offsetof (dds_qos_t, topic_data.value) }, - { QP_USER_DATA, offsetof (dds_qos_t, user_data.value) }, - { QP_TOPIC_NAME, offsetof (dds_qos_t, topic_name) }, - { QP_TYPE_NAME, offsetof (dds_qos_t, type_name) }, - { QP_RTI_TYPECODE, offsetof (dds_qos_t, rti_typecode.value) } - }; - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI\n"); - for (size_t i = 0; i < sizeof (qos_simple) / sizeof (*qos_simple); i++) - { - if ((xqos->present & qos_simple[i].fl) && !(xqos->aliased & qos_simple[i].fl)) - { - void **pp = (void **) ((char *) xqos + qos_simple[i].off); - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI free %p\n", *pp); - ddsrt_free (*pp); - } - } - if (xqos->present & QP_PARTITION) - { - if (!(xqos->aliased & QP_PARTITION)) - { - free_stringseq (&xqos->partition); - } - else - { - /* until proper message buffers arrive */ - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI free %p\n", (void *) xqos->partition.strs); - ddsrt_free (xqos->partition.strs); - } - } - if (xqos->present & QP_PRISMTECH_SUBSCRIPTION_KEYS) - { - if (!(xqos->aliased & QP_PRISMTECH_SUBSCRIPTION_KEYS)) - free_stringseq (&xqos->subscription_keys.key_list); - else - { - /* until proper message buffers arrive */ - DDS_LOG(DDS_LC_PLIST, "NN_XQOS_FINI free %p\n", (void *) xqos->subscription_keys.key_list.strs); - ddsrt_free (xqos->subscription_keys.key_list.strs); - } - } - xqos->present = 0; + plist_or_xqos_fini (xqos, offsetof (nn_plist_t, qos)); +} + +void nn_xqos_unalias (dds_qos_t *xqos) +{ + plist_or_xqos_unalias (xqos, offsetof (nn_plist_t, qos)); } dds_qos_t * nn_xqos_dup (const dds_qos_t *src) @@ -2859,33 +2504,6 @@ dds_qos_t * nn_xqos_dup (const dds_qos_t *src) return dst; } -static int octetseqs_differ (const ddsi_octetseq_t *a, const ddsi_octetseq_t *b) -{ - return (a->length != b->length || memcmp (a->value, b->value, a->length) != 0); -} - -static int stringseqs_differ (const ddsi_stringseq_t *a, const ddsi_stringseq_t *b) -{ - uint32_t i; - if (a->n != b->n) - return 1; - for (i = 0; i < a->n; i++) - if (strcmp (a->strs[i], b->strs[i])) - return 1; - return 0; -} - -static int histories_differ (const dds_history_qospolicy_t *a, const dds_history_qospolicy_t *b) -{ - return (a->kind != b->kind || (a->kind == DDS_HISTORY_KEEP_LAST && a->depth != b->depth)); -} - -static int resource_limits_differ (const dds_resource_limits_qospolicy_t *a, const dds_resource_limits_qospolicy_t *b) -{ - return (a->max_samples != b->max_samples || a->max_instances != b->max_instances || - a->max_samples_per_instance != b->max_samples_per_instance); -} - static int partition_is_default (const dds_partition_qospolicy_t *a) { uint32_t i; @@ -2909,9 +2527,11 @@ static int partitions_equal_n2 (const dds_partition_qospolicy_t *a, const dds_pa return 1; } -static int strcmp_wrapper (const void *a, const void *b) +static int strcmp_wrapper (const void *va, const void *vb) { - return strcmp (a, b); + char const * const *a = va; + char const * const *b = vb; + return strcmp (*a, *b); } static int partitions_equal_nlogn (const dds_partition_qospolicy_t *a, const dds_partition_qospolicy_t *b) @@ -2929,7 +2549,7 @@ static int partitions_equal_nlogn (const dds_partition_qospolicy_t *a, const dds tab[i] = a->strs[i]; qsort (tab, a->n, sizeof (*tab), strcmp_wrapper); for (i = 0; i < b->n; i++) - if (bsearch (b->strs[i], tab, a->n, sizeof (*tab), strcmp_wrapper) == NULL) + if (bsearch (&b->strs[i], tab, a->n, sizeof (*tab), strcmp_wrapper) == NULL) { equal = 0; break; @@ -2977,289 +2597,16 @@ static int partitions_equal (const dds_partition_qospolicy_t *a, const dds_parti } } -uint64_t nn_xqos_delta (const dds_qos_t *a, const dds_qos_t *b, uint64_t mask) -{ - /* Returns QP_... set for RxO settings where a differs from b; if - present in a but not in b (or in b but not in a) it counts as a - difference. */ - uint64_t delta = (a->present ^ b->present) & mask; - uint64_t check = (a->present & b->present) & mask; - if (check & QP_TOPIC_NAME) { - if (strcmp (a->topic_name, b->topic_name)) - delta |= QP_TOPIC_NAME; - } - if (check & QP_TYPE_NAME) { - if (strcmp (a->type_name, b->type_name)) - delta |= QP_TYPE_NAME; - } - if (check & QP_PRESENTATION) { - if (a->presentation.access_scope != b->presentation.access_scope || - a->presentation.coherent_access != b->presentation.coherent_access || - a->presentation.ordered_access != b->presentation.ordered_access) - delta |= QP_PRESENTATION; - } - if (check & QP_PARTITION) { - if (!partitions_equal (&a->partition, &b->partition)) - delta |= QP_PARTITION; - } - if (check & QP_GROUP_DATA) { - if (octetseqs_differ (&a->group_data, &b->group_data)) - delta |= QP_GROUP_DATA; - } - if (check & QP_TOPIC_DATA) { - if (octetseqs_differ (&a->topic_data, &b->topic_data)) - delta |= QP_TOPIC_DATA; - } - if (check & QP_DURABILITY) { - if (a->durability.kind != b->durability.kind) - delta |= QP_DURABILITY; - } - if (check & QP_DURABILITY_SERVICE) - { - const dds_durability_service_qospolicy_t *qa = &a->durability_service; - const dds_durability_service_qospolicy_t *qb = &b->durability_service; - if (qa->service_cleanup_delay != qb->service_cleanup_delay || - histories_differ (&qa->history, &qb->history) || - resource_limits_differ (&qa->resource_limits, &qb->resource_limits)) - delta |= QP_DURABILITY_SERVICE; - } - if (check & QP_DEADLINE) { - if (a->deadline.deadline != b->deadline.deadline) - delta |= QP_DEADLINE; - } - if (check & QP_LATENCY_BUDGET) { - if (a->latency_budget.duration != b->latency_budget.duration) - delta |= QP_LATENCY_BUDGET; - } - if (check & QP_LIVELINESS) { - if (a->liveliness.kind != b->liveliness.kind || a->liveliness.lease_duration != b->liveliness.lease_duration) - delta |= QP_LIVELINESS; - } - if (check & QP_RELIABILITY) { - if (a->reliability.kind != b->reliability.kind || a->reliability.max_blocking_time != b->reliability.max_blocking_time) - delta |= QP_RELIABILITY; - } - if (check & QP_DESTINATION_ORDER) { - if (a->destination_order.kind != b->destination_order.kind) - delta |= QP_DESTINATION_ORDER; - } - if (check & QP_HISTORY) { - if (histories_differ (&a->history, &b->history)) - delta |= QP_HISTORY; - } - if (check & QP_RESOURCE_LIMITS) { - if (resource_limits_differ (&a->resource_limits, &b->resource_limits)) - delta |= QP_RESOURCE_LIMITS; - } - if (check & QP_TRANSPORT_PRIORITY) { - if (a->transport_priority.value != b->transport_priority.value) - delta |= QP_TRANSPORT_PRIORITY; - } - if (check & QP_LIFESPAN) { - if (a->lifespan.duration != b->lifespan.duration) - delta |= QP_LIFESPAN; - } - if (check & QP_USER_DATA) { - if (octetseqs_differ (&a->user_data, &b->user_data)) - delta |= QP_USER_DATA; - } - if (check & QP_OWNERSHIP) { - if (a->ownership.kind != b->ownership.kind) - delta |= QP_OWNERSHIP; - } - if (check & QP_OWNERSHIP_STRENGTH) { - if (a->ownership_strength.value != b->ownership_strength.value) - delta |= QP_OWNERSHIP_STRENGTH; - } - if (check & QP_TIME_BASED_FILTER) { - if (a->time_based_filter.minimum_separation != b->time_based_filter.minimum_separation) - delta |= QP_TIME_BASED_FILTER; - } - if (check & QP_PRISMTECH_READER_DATA_LIFECYCLE) { - if (a->reader_data_lifecycle.autopurge_disposed_samples_delay != b->reader_data_lifecycle.autopurge_disposed_samples_delay || - a->reader_data_lifecycle.autopurge_nowriter_samples_delay != b->reader_data_lifecycle.autopurge_nowriter_samples_delay) - delta |= QP_PRISMTECH_READER_DATA_LIFECYCLE; - } - if (check & QP_PRISMTECH_WRITER_DATA_LIFECYCLE) { - if (a->writer_data_lifecycle.autodispose_unregistered_instances != - b->writer_data_lifecycle.autodispose_unregistered_instances) - delta |= QP_PRISMTECH_WRITER_DATA_LIFECYCLE; - } - if (check & QP_PRISMTECH_READER_LIFESPAN) { - /* Note: the conjunction need not test both a & b for having use_lifespan set */ - if (a->reader_lifespan.use_lifespan != b->reader_lifespan.use_lifespan || - (a->reader_lifespan.use_lifespan && b->reader_lifespan.use_lifespan && - a->reader_lifespan.duration != b->reader_lifespan.duration)) - delta |= QP_PRISMTECH_READER_LIFESPAN; - } - if (check & QP_PRISMTECH_SUBSCRIPTION_KEYS) { - /* Note: the conjunction need not test both a & b for having use_lifespan set */ - if (a->subscription_keys.use_key_list != b->subscription_keys.use_key_list || - (a->subscription_keys.use_key_list && b->subscription_keys.use_key_list && - stringseqs_differ (&a->subscription_keys.key_list, &b->subscription_keys.key_list))) - delta |= QP_PRISMTECH_SUBSCRIPTION_KEYS; - } - if (check & QP_PRISMTECH_ENTITY_FACTORY) { - if (a->entity_factory.autoenable_created_entities != - b->entity_factory.autoenable_created_entities) - delta |= QP_PRISMTECH_ENTITY_FACTORY; - } - if (check & QP_RTI_TYPECODE) { - if (octetseqs_differ (&a->rti_typecode, &b->rti_typecode)) - delta |= QP_RTI_TYPECODE; - } - if (check & QP_CYCLONE_IGNORELOCAL) { - if (a->ignorelocal.value != b->ignorelocal.value) - delta |= QP_CYCLONE_IGNORELOCAL; - } - return delta; -} - /*************************/ void nn_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted) { - /* Returns new nn_xmsg pointer (currently, reallocs may happen) */ - - uint64_t w = xqos->present & wanted; - char *tmp; -#define SIMPLE(name_, prefix_, field_) \ - do { \ - if (w & QP_##name_) { \ - tmp = nn_xmsg_addpar (m, PID_##name_, sizeof (xqos->field_)); \ - *((prefix_##_##field_##_qospolicy_t *) tmp) = xqos->field_; \ - } \ - } while (0) -#define FUNC_BY_REF(name_, field_, func_) \ - do { \ - if (w & QP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, &xqos->field_); \ - } \ - } while (0) -#define FUNC_BY_VAL(name_, field_, func_) \ - do { \ - if (w & QP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, xqos->field_); \ - } \ - } while (0) - - FUNC_BY_VAL (TOPIC_NAME, topic_name, string); - FUNC_BY_VAL (TYPE_NAME, type_name, string); - SIMPLE (PRESENTATION, dds, presentation); - FUNC_BY_REF (PARTITION, partition, stringseq); - FUNC_BY_REF (GROUP_DATA, group_data, octetseq); - FUNC_BY_REF (TOPIC_DATA, topic_data, octetseq); - SIMPLE (DURABILITY, dds, durability); - FUNC_BY_REF (DURABILITY_SERVICE, durability_service, durability_service); - FUNC_BY_VAL (DEADLINE, deadline.deadline, duration); - FUNC_BY_VAL (LATENCY_BUDGET, latency_budget.duration, duration); - FUNC_BY_REF (LIVELINESS, liveliness, liveliness); - FUNC_BY_REF (RELIABILITY, reliability, reliability); - SIMPLE (DESTINATION_ORDER, dds, destination_order); - SIMPLE (HISTORY, dds, history); - SIMPLE (RESOURCE_LIMITS, dds, resource_limits); - SIMPLE (TRANSPORT_PRIORITY, dds, transport_priority); - FUNC_BY_VAL (LIFESPAN, lifespan.duration, duration); - FUNC_BY_REF (USER_DATA, user_data, octetseq); - SIMPLE (OWNERSHIP, dds, ownership); - SIMPLE (OWNERSHIP_STRENGTH, dds, ownership_strength); - FUNC_BY_VAL (TIME_BASED_FILTER, time_based_filter.minimum_separation, duration); - FUNC_BY_REF (PRISMTECH_READER_DATA_LIFECYCLE, reader_data_lifecycle, reader_data_lifecycle); - SIMPLE (PRISMTECH_WRITER_DATA_LIFECYCLE, dds, writer_data_lifecycle); - FUNC_BY_REF (PRISMTECH_READER_LIFESPAN, reader_lifespan, reader_lifespan); - FUNC_BY_REF (PRISMTECH_SUBSCRIPTION_KEYS, subscription_keys, subscription_keys); - SIMPLE (PRISMTECH_ENTITY_FACTORY, dds, entity_factory); - FUNC_BY_REF (RTI_TYPECODE, rti_typecode, octetseq); - /* CYCLONE_IGNORELOCAL is not visible on the wire */ -#undef FUNC_BY_REF -#undef FUNC_BY_VAL -#undef SIMPLE -} - -static void add_locators (struct nn_xmsg *m, uint64_t present, uint64_t flag, const nn_locators_t *ls, nn_parameterid_t pid) -{ - const struct nn_locators_one *l; - if (present & flag) - { - for (l = ls->first; l != NULL; l = l->next) - { - char *tmp = nn_xmsg_addpar (m, pid, sizeof (nn_locator_t)); - memcpy (tmp, &l->loc, sizeof (nn_locator_t)); - } - } + plist_or_xqos_addtomsg (m, xqos, offsetof (struct nn_plist, qos), 0, wanted); } void nn_plist_addtomsg (struct nn_xmsg *m, const nn_plist_t *ps, uint64_t pwanted, uint64_t qwanted) { - /* Returns new nn_xmsg pointer (currently, reallocs may happen), or NULL - on out-of-memory. (In which case the original nn_xmsg is freed, cos - that is then required anyway */ - uint64_t w = ps->present & pwanted; - char *tmp; -#define SIMPLE_TYPE(name_, field_, type_) \ - do { \ - if (w & PP_##name_) { \ - tmp = nn_xmsg_addpar (m, PID_##name_, sizeof (ps->field_)); \ - *((type_ *) tmp) = ps->field_; \ - } \ - } while (0) -#define FUNC_BY_VAL(name_, field_, func_) \ - do { \ - if (w & PP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, ps->field_); \ - } \ - } while (0) -#define FUNC_BY_REF(name_, field_, func_) \ - do { \ - if (w & PP_##name_) { \ - nn_xmsg_addpar_##func_ (m, PID_##name_, &ps->field_); \ - } \ - } while (0) - - nn_xqos_addtomsg (m, &ps->qos, qwanted); - SIMPLE_TYPE (PROTOCOL_VERSION, protocol_version, nn_protocol_version_t); - SIMPLE_TYPE (VENDORID, vendorid, nn_vendorid_t); - - add_locators (m, ps->present, PP_UNICAST_LOCATOR, &ps->unicast_locators, PID_UNICAST_LOCATOR); - add_locators (m, ps->present, PP_MULTICAST_LOCATOR, &ps->multicast_locators, PID_MULTICAST_LOCATOR); - add_locators (m, ps->present, PP_DEFAULT_UNICAST_LOCATOR, &ps->default_unicast_locators, PID_DEFAULT_UNICAST_LOCATOR); - add_locators (m, ps->present, PP_DEFAULT_MULTICAST_LOCATOR, &ps->default_multicast_locators, PID_DEFAULT_MULTICAST_LOCATOR); - add_locators (m, ps->present, PP_METATRAFFIC_UNICAST_LOCATOR, &ps->metatraffic_unicast_locators, PID_METATRAFFIC_UNICAST_LOCATOR); - add_locators (m, ps->present, PP_METATRAFFIC_MULTICAST_LOCATOR, &ps->metatraffic_multicast_locators, PID_METATRAFFIC_MULTICAST_LOCATOR); - - SIMPLE_TYPE (EXPECTS_INLINE_QOS, expects_inline_qos, unsigned char); - FUNC_BY_VAL (PARTICIPANT_LEASE_DURATION, participant_lease_duration, duration); - FUNC_BY_REF (PARTICIPANT_GUID, participant_guid, guid); - SIMPLE_TYPE (BUILTIN_ENDPOINT_SET, builtin_endpoint_set, unsigned); - SIMPLE_TYPE (KEYHASH, keyhash, nn_keyhash_t); - if (w & PP_STATUSINFO) - nn_xmsg_addpar_statusinfo (m, ps->statusinfo); - SIMPLE_TYPE (COHERENT_SET, coherent_set_seqno, nn_sequence_number_t); - if (! NN_PEDANTIC_P) - FUNC_BY_REF (ENDPOINT_GUID, endpoint_guid, guid); - else - { - if (w & PP_ENDPOINT_GUID) - { - nn_xmsg_addpar_guid (m, PID_PRISMTECH_ENDPOINT_GUID, &ps->endpoint_guid); - } - } - FUNC_BY_REF (GROUP_GUID, group_guid, guid); - SIMPLE_TYPE (PRISMTECH_BUILTIN_ENDPOINT_SET, prismtech_builtin_endpoint_set, unsigned); - FUNC_BY_REF (PRISMTECH_PARTICIPANT_VERSION_INFO, prismtech_participant_version_info, parvinfo); - FUNC_BY_VAL (ENTITY_NAME, entity_name, string); - FUNC_BY_VAL (PRISMTECH_NODE_NAME, node_name, string); - FUNC_BY_VAL (PRISMTECH_EXEC_NAME, exec_name, string); - SIMPLE_TYPE (PRISMTECH_PROCESS_ID, process_id, unsigned); - SIMPLE_TYPE (PRISMTECH_SERVICE_TYPE, service_type, unsigned); - FUNC_BY_VAL (PRISMTECH_TYPE_DESCRIPTION, type_description, string); - FUNC_BY_REF (PRISMTECH_EOTINFO, eotinfo, eotinfo); -#ifdef DDSI_INCLUDE_SSM - SIMPLE_TYPE (READER_FAVOURS_SSM, reader_favours_ssm, nn_reader_favours_ssm_t); -#endif -#undef FUNC_BY_REF -#undef FUNC_BY_VAL -#undef SIMPLE + plist_or_xqos_addtomsg (m, ps, 0, pwanted, qwanted); } /*************************/ @@ -3267,7 +2614,7 @@ void nn_plist_addtomsg (struct nn_xmsg *m, const nn_plist_t *ps, uint64_t pwante static uint32_t isprint_runlen (uint32_t n, const unsigned char *xs) { uint32_t m; - for (m = 0; m < n && xs[m] != '"' && isprint (xs[m]); m++) + for (m = 0; m < n && xs[m] != '"' && isprint (xs[m]) && xs[m] < 127; m++) ; return m; } @@ -3278,10 +2625,10 @@ static void log_octetseq (uint32_t cat, uint32_t n, const unsigned char *xs) uint32_t i = 0; while (i < n) { - uint32_t m = isprint_runlen(n - i, xs); - if (m >= 4) + uint32_t m = isprint_runlen (n - i, xs); + if (m >= 4 || (i == 0 && m == n)) { - DDS_LOG(cat, "%s\"%*.*s\"", i == 0 ? "" : ",", m, m, xs); + DDS_LOG (cat, "%s\"%*.*s\"", i == 0 ? "" : ",", m, m, xs); xs += m; i += m; } @@ -3291,7 +2638,7 @@ static void log_octetseq (uint32_t cat, uint32_t n, const unsigned char *xs) m = 1; while (m--) { - DDS_LOG(cat, "%s%u", i == 0 ? "" : ",", *xs++); + DDS_LOG (cat, "%s%u", i == 0 ? "" : ",", *xs++); i++; } } @@ -3369,11 +2716,6 @@ void nn_log_xqos (uint32_t cat, const dds_qos_t *xqos) DDS_LOG(cat, "}}"); }); DO (PRISMTECH_ENTITY_FACTORY, { LOGB1 ("entity_factory=%u", xqos->entity_factory.autoenable_created_entities); }); - DO (RTI_TYPECODE, { - LOGB1 ("rti_typecode=%"PRIu32"<", xqos->rti_typecode.length); - log_octetseq (cat, xqos->rti_typecode.length, xqos->rti_typecode.value); - DDS_LOG(cat, ">"); - }); DO (CYCLONE_IGNORELOCAL, { LOGB1 ("ignorelocal=%u", xqos->ignorelocal.value); }); #undef PRINTARG_DUR diff --git a/src/core/ddsi/src/q_qosmatch.c b/src/core/ddsi/src/q_qosmatch.c index 70b02fe..721a010 100644 --- a/src/core/ddsi/src/q_qosmatch.c +++ b/src/core/ddsi/src/q_qosmatch.c @@ -64,66 +64,65 @@ int partitions_match_p (const dds_qos_t *a, const dds_qos_t *b) } } -static bool qos_match_internal_p (const dds_qos_t *rd, const dds_qos_t *wr, dds_qos_policy_id_t *reason) ddsrt_nonnull_all; - -static bool qos_match_internal_p (const dds_qos_t *rd, const dds_qos_t *wr, dds_qos_policy_id_t *reason) +bool qos_match_mask_p (const dds_qos_t *rd, const dds_qos_t *wr, uint64_t mask, dds_qos_policy_id_t *reason) { #ifndef NDEBUG - unsigned musthave = (QP_RXO_MASK | QP_PARTITION | QP_TOPIC_NAME | QP_TYPE_NAME); + unsigned musthave = (QP_RXO_MASK | QP_PARTITION | QP_TOPIC_NAME | QP_TYPE_NAME) & mask; assert ((rd->present & musthave) == musthave); assert ((wr->present & musthave) == musthave); #endif + mask &= rd->present & wr->present; *reason = DDS_INVALID_QOS_POLICY_ID; - if (strcmp (rd->topic_name, wr->topic_name) != 0) + if ((mask & QP_TOPIC_NAME) && strcmp (rd->topic_name, wr->topic_name) != 0) return false; - if (strcmp (rd->type_name, wr->type_name) != 0) + if ((mask & QP_TYPE_NAME) && strcmp (rd->type_name, wr->type_name) != 0) return false; - if (rd->reliability.kind > wr->reliability.kind) { + if ((mask & QP_RELIABILITY) && rd->reliability.kind > wr->reliability.kind) { *reason = DDS_RELIABILITY_QOS_POLICY_ID; return false; } - if (rd->durability.kind > wr->durability.kind) { + if ((mask & QP_DURABILITY) && rd->durability.kind > wr->durability.kind) { *reason = DDS_DURABILITY_QOS_POLICY_ID; return false; } - if (rd->presentation.access_scope > wr->presentation.access_scope) { + if ((mask & QP_PRESENTATION) && rd->presentation.access_scope > wr->presentation.access_scope) { *reason = DDS_PRESENTATION_QOS_POLICY_ID; return false; } - if (rd->presentation.coherent_access > wr->presentation.coherent_access) { + if ((mask & QP_PRESENTATION) && rd->presentation.coherent_access > wr->presentation.coherent_access) { *reason = DDS_PRESENTATION_QOS_POLICY_ID; return false; } - if (rd->presentation.ordered_access > wr->presentation.ordered_access) { + if ((mask & QP_PRESENTATION) && rd->presentation.ordered_access > wr->presentation.ordered_access) { *reason = DDS_PRESENTATION_QOS_POLICY_ID; return false; } - if (rd->deadline.deadline < wr->deadline.deadline) { + if ((mask & QP_DEADLINE) && rd->deadline.deadline < wr->deadline.deadline) { *reason = DDS_DEADLINE_QOS_POLICY_ID; return false; } - if (rd->latency_budget.duration < wr->latency_budget.duration) { + if ((mask & QP_LATENCY_BUDGET) && rd->latency_budget.duration < wr->latency_budget.duration) { *reason = DDS_LATENCYBUDGET_QOS_POLICY_ID; return false; } - if (rd->ownership.kind != wr->ownership.kind) { + if ((mask & QP_OWNERSHIP) && rd->ownership.kind != wr->ownership.kind) { *reason = DDS_OWNERSHIP_QOS_POLICY_ID; return false; } - if (rd->liveliness.kind > wr->liveliness.kind) { + if ((mask & QP_LIVELINESS) && rd->liveliness.kind > wr->liveliness.kind) { *reason = DDS_LIVELINESS_QOS_POLICY_ID; return false; } - if (rd->liveliness.lease_duration < wr->liveliness.lease_duration) { + if ((mask & QP_LIVELINESS) && rd->liveliness.lease_duration < wr->liveliness.lease_duration) { *reason = DDS_LIVELINESS_QOS_POLICY_ID; return false; } - if (rd->destination_order.kind > wr->destination_order.kind) { + if ((mask & QP_DESTINATION_ORDER) && rd->destination_order.kind > wr->destination_order.kind) { *reason = DDS_DESTINATIONORDER_QOS_POLICY_ID; return false; } - if (!partitions_match_p (rd, wr)) { + if ((mask & QP_PARTITION) && !partitions_match_p (rd, wr)) { *reason = DDS_PARTITION_QOS_POLICY_ID; return false; } @@ -133,5 +132,5 @@ static bool qos_match_internal_p (const dds_qos_t *rd, const dds_qos_t *wr, dds_ bool qos_match_p (const dds_qos_t *rd, const dds_qos_t *wr, dds_qos_policy_id_t *reason) { dds_qos_policy_id_t dummy; - return qos_match_internal_p (rd, wr, reason ? reason : &dummy); + return qos_match_mask_p (rd, wr, ~(uint64_t)0, reason ? reason : &dummy); } diff --git a/src/core/ddsi/src/q_receive.c b/src/core/ddsi/src/q_receive.c index 60bdab7..8ec7197 100644 --- a/src/core/ddsi/src/q_receive.c +++ b/src/core/ddsi/src/q_receive.c @@ -1952,7 +1952,7 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st src.encoding = (msg->smhdr.flags & SMFLAG_ENDIANNESS) ? PL_CDR_LE : PL_CDR_BE; src.buf = NN_RMSG_PAYLOADOFF (fragchain->rmsg, qos_offset); src.bufsz = NN_RDATA_PAYLOAD_OFF (fragchain) - qos_offset; - if ((plist_ret = nn_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH | PP_COHERENT_SET | PP_PRISMTECH_EOTINFO, 0, &src)) < 0) + if ((plist_ret = nn_plist_init_frommsg (&qos, NULL, PP_STATUSINFO | PP_KEYHASH | PP_COHERENT_SET, 0, &src)) < 0) { if (plist_ret != DDS_RETCODE_UNSUPPORTED) DDS_WARNING ("data(application, vendor %u.%u): "PGUIDFMT" #%"PRId64": invalid inline qos\n", @@ -1980,9 +1980,7 @@ static int deliver_user_data (const struct nn_rsample_info *sampleinfo, const st } /* Generate the DDS_SampleInfo (which is faked to some extent - because we don't actually have a data reader); also note that - the PRISMTECH_WRITER_INFO thing is completely meaningless to - us */ + because we don't actually have a data reader) */ struct ddsi_tkmap_instance * tk; if ((tk = ddsi_tkmap_lookup_instance_ref(payload)) != NULL) { diff --git a/src/core/ddsi/src/q_xmsg.c b/src/core/ddsi/src/q_xmsg.c index 7e8d77d..8f942b0 100644 --- a/src/core/ddsi/src/q_xmsg.c +++ b/src/core/ddsi/src/q_xmsg.c @@ -1029,19 +1029,6 @@ void nn_xmsg_addpar_parvinfo (struct nn_xmsg *m, nn_parameterid_t pid, const str memcpy(ps->contents, pvi->internals, slen); } -void nn_xmsg_addpar_eotinfo (struct nn_xmsg *m, nn_parameterid_t pid, const struct nn_prismtech_eotinfo *txnid) -{ - uint32_t *pu, i; - pu = nn_xmsg_addpar (m, pid, 2 * sizeof (uint32_t) + txnid->n * sizeof (txnid->tids[0])); - pu[0] = txnid->transactionId; - pu[1] = txnid->n; - for (i = 0; i < txnid->n; i++) - { - pu[2*i + 2] = toBE4u (txnid->tids[i].writer_entityid.u); - pu[2*i + 3] = txnid->tids[i].transactionId; - } -} - /* XMSG_CHAIN ---------------------------------------------------------- Xpacks refer to xmsgs and need to release these after having been diff --git a/src/core/xtests/rhc_torture/rhc_torture.c b/src/core/xtests/rhc_torture/rhc_torture.c index f743c12..1254b5e 100644 --- a/src/core/xtests/rhc_torture/rhc_torture.c +++ b/src/core/xtests/rhc_torture/rhc_torture.c @@ -147,7 +147,7 @@ static struct proxy_writer *mkwr (bool auto_dispose) wr_iid = ddsi_iid_gen (); memset (pwr, 0, sizeof (*pwr)); nn_xqos_init_empty (xqos); - nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr); + nn_xqos_mergein_missing (xqos, &gv.default_xqos_wr, ~(uint64_t)0); xqos->ownership_strength.value = 0; xqos->writer_data_lifecycle.autodispose_unregistered_instances = auto_dispose; pwr->e.iid = wr_iid; @@ -170,7 +170,7 @@ static struct rhc *mkrhc (dds_reader *rd, dds_history_kind_t hk, int32_t hdepth, rqos.history.kind = hk; rqos.history.depth = hdepth; rqos.destination_order.kind = dok; - nn_xqos_mergein_missing (&rqos, &gv.default_xqos_rd); + nn_xqos_mergein_missing (&rqos, &gv.default_xqos_rd, ~(uint64_t)0); thread_state_awake (lookup_thread_state ()); rhc = dds_rhc_new (rd, mdtopic); dds_rhc_set_qos(rhc, &rqos); diff --git a/src/ddsrt/include/dds/ddsrt/attributes.h b/src/ddsrt/include/dds/ddsrt/attributes.h index c91584d..25ab3b1 100644 --- a/src/ddsrt/include/dds/ddsrt/attributes.h +++ b/src/ddsrt/include/dds/ddsrt/attributes.h @@ -105,4 +105,10 @@ # define ddsrt_attribute_assume_aligned(params) #endif +#if ddsrt_has_attribute(packed) +# define ddsrt_attribute_packed __attribute__ ((__packed__)) +#else +# define ddsrt_attribute_packed +#endif + #endif /* DDSRT_ATTRIBUTES_H */ diff --git a/src/mpt/tests/CMakeLists.txt b/src/mpt/tests/CMakeLists.txt index 91a9183..63e786b 100644 --- a/src/mpt/tests/CMakeLists.txt +++ b/src/mpt/tests/CMakeLists.txt @@ -16,4 +16,4 @@ if(MPT_ENABLE_SELFTEST) endif() add_subdirectory(basic) - +add_subdirectory(qosmatch) diff --git a/src/mpt/tests/qosmatch/CMakeLists.txt b/src/mpt/tests/qosmatch/CMakeLists.txt new file mode 100644 index 0000000..efa3324 --- /dev/null +++ b/src/mpt/tests/qosmatch/CMakeLists.txt @@ -0,0 +1,23 @@ +# +# Copyright(c) 2006 to 2018 ADLINK Technology Limited 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(${MPT_CMAKE}) + +set(sources + "procs/rw.c" + "qosmatch.c") + +add_compile_options("-I${PROJECT_SOURCE_DIR}/core/ddsi/include") +add_mpt_executable(mpt_qosmatch ${sources}) + +idlc_generate(mpt_qosmatch_rwdata_lib "procs/rwdata.idl") +target_link_libraries(mpt_qosmatch PRIVATE mpt_qosmatch_rwdata_lib) + diff --git a/src/mpt/tests/qosmatch/procs/rw.c b/src/mpt/tests/qosmatch/procs/rw.c new file mode 100644 index 0000000..b4720ff --- /dev/null +++ b/src/mpt/tests/qosmatch/procs/rw.c @@ -0,0 +1,376 @@ +#include +#include +#include + +#include "mpt/mpt.h" + +#include "dds/dds.h" +#include "rwdata.h" + +#include "dds/ddsrt/time.h" +#include "dds/ddsrt/process.h" +#include "dds/ddsrt/sockets.h" +#include "dds/ddsrt/heap.h" + +#include "dds/ddsi/q_xqos.h" + +#define NPUB 10 +#define NWR_PUB 2 + +void rw_init (void) +{ +} + +void rw_fini (void) +{ +} + +static void setqos (dds_qos_t *q, size_t i, bool isrd, bool create) +{ + size_t psi = i - (i % NWR_PUB); + /* Participant, publisher & topic get created with i == 0, + so make sure those have some crazy data set. The writers + should inherit the topic and group data, but the user data + should be updated for each writer */ + if (create) + { + if (psi == 1) + { + dds_qset_userdata (q, NULL, 0); + dds_qset_topicdata (q, NULL, 0); + dds_qset_groupdata (q, NULL, 0); + } + else + { + char buf[20]; + snprintf (buf, sizeof (buf), "ud%zu%c", i, isrd ? 'r' : 'w'); + dds_qset_userdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "td%zu", i); + dds_qset_topicdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "gd%zu", psi); + dds_qset_groupdata (q, buf, strlen (buf)); + } + } + else + { + if (psi == 1) + { + dds_qset_userdata (q, NULL, 0); + dds_qset_topicdata (q, NULL, 0); + dds_qset_groupdata (q, NULL, 0); + } + else + { + char buf[20]; + snprintf (buf, sizeof (buf), "ud%zu%c", i, isrd ? 'r' : 'w'); + dds_qset_userdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "td%zu", (size_t) 0); + dds_qset_topicdata (q, buf, strlen (buf)); + snprintf (buf, sizeof (buf), "gd%zu", psi); + dds_qset_groupdata (q, buf, strlen (buf)); + } + } + + /* Cyclone's accepting unimplemented QoS settings is a bug, but it does allow + us to feed it all kinds of nonsense and see whether discovery manages it */ + + /* this makes topic transient-local, keep-last 1 */ + dds_qset_durability (q, (dds_durability_kind_t) ((i + 1) % 4)); + dds_qset_history (q, (dds_history_kind_t) ((i + 1) % 2), (int32_t) (i + 1)); + dds_qset_resource_limits (q, (int32_t) i + 3, (int32_t) i + 2, (int32_t) i + 1); + dds_qset_presentation (q, (dds_presentation_access_scope_kind_t) ((psi + 1) % 3), 1, 1); + dds_qset_lifespan (q, INT64_C (23456789012345678) + (int32_t) i); + dds_qset_deadline (q, INT64_C (67890123456789012) + (int32_t) i); + dds_qset_latency_budget (q, INT64_C (45678901234567890) + (int32_t) i); + dds_qset_ownership (q, (dds_ownership_kind_t) ((i + 1) % 2)); + dds_qset_ownership_strength (q, 0x12345670 + (int32_t) i); + dds_qset_liveliness (q, (dds_liveliness_kind_t) ((i + i) % 2), INT64_C (456789012345678901) + (int32_t) i); + dds_qset_time_based_filter (q, INT64_C (34567890123456789) + (int32_t) i); /* must be <= deadline */ + if (psi == 0) + dds_qset_partition1 (q, "p"); + else if (psi == 1) + dds_qset_partition (q, 0, NULL); + else + { + char **ps = ddsrt_malloc (psi * sizeof (*ps)); + for (size_t j = 0; j < psi; j++) + { + const size_t n = 40; + ps[j] = ddsrt_malloc (n); + snprintf (ps[j], n, "p%zu_%zu", psi, isrd ? (psi-j-1) : j); + } + dds_qset_partition (q, (uint32_t) psi, (const char **) ps); + for (size_t j = 0; j < psi; j++) + ddsrt_free (ps[j]); + ddsrt_free (ps); + } + dds_qset_reliability (q, (dds_reliability_kind_t) ((i + 1) % 2), INT64_C (890123456789012345) + (int32_t) i); + dds_qset_transport_priority (q, 0x23456701 + (int32_t) i); + dds_qset_destination_order (q, (dds_destination_order_kind_t) ((i + 1) % 2)); + dds_qset_writer_data_lifecycle (q, ((i + 1) % 2) != 0); + dds_qset_reader_data_lifecycle (q, INT64_C (41234567890123456) + (int32_t) i, INT64_C (912345678901234567) + (int32_t) i); + dds_qset_durability_service (q, INT64_C (123456789012345678) + (int32_t) i, (dds_history_kind_t) ((i + 1) % 2), (int32_t) (i + 1), (int32_t) i + 3, (int32_t) i + 2, (int32_t) i + 1); +} + +static bool pubsub_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) +{ + dds_qos_t *b = dds_create_qos (); + dds_get_qos (ent, b); + /* internal interface is more luxurious that a simple compare for equality, and + using that here saves us a ton of code */ + uint64_t delta = nn_xqos_delta (a, b, QP_GROUP_DATA | QP_PRESENTATION | QP_PARTITION); + if (delta) + { + DDS_LOG (DDS_LC_ERROR, "pub/sub: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, a); DDS_LOG (DDS_LC_ERROR, "\n"); + nn_log_xqos (DDS_LC_ERROR, b); DDS_LOG (DDS_LC_ERROR, "\n"); + } + dds_delete_qos (b); + return delta == 0; +} + +static uint64_t reader_qos_delta (const dds_qos_t *a, const dds_qos_t *b) +{ + return nn_xqos_delta (a, b, QP_USER_DATA | QP_TOPIC_DATA | QP_GROUP_DATA | QP_DURABILITY | QP_HISTORY | QP_RESOURCE_LIMITS | QP_PRESENTATION | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_LIVELINESS | QP_TIME_BASED_FILTER | QP_PARTITION | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_PRISMTECH_READER_DATA_LIFECYCLE); +} + +static bool reader_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) +{ + dds_qos_t *b = dds_create_qos (); + dds_get_qos (ent, b); + uint64_t delta = reader_qos_delta (a, b); + if (delta) + { + DDS_LOG (DDS_LC_ERROR, "reader: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, a); DDS_LOG (DDS_LC_ERROR, "\n"); + nn_log_xqos (DDS_LC_ERROR, b); DDS_LOG (DDS_LC_ERROR, "\n"); + } + dds_delete_qos (b); + return delta == 0; +} + +static uint64_t writer_qos_delta (const dds_qos_t *a, const dds_qos_t *b) +{ + return nn_xqos_delta (a, b, QP_USER_DATA | QP_TOPIC_DATA | QP_GROUP_DATA | QP_DURABILITY | QP_HISTORY | QP_RESOURCE_LIMITS | QP_PRESENTATION | QP_LIFESPAN | QP_DEADLINE | QP_LATENCY_BUDGET | QP_OWNERSHIP | QP_OWNERSHIP_STRENGTH | QP_LIVELINESS | QP_PARTITION | QP_RELIABILITY | QP_DESTINATION_ORDER | QP_PRISMTECH_WRITER_DATA_LIFECYCLE); +} + +static bool writer_qos_eq_h (const dds_qos_t *a, dds_entity_t ent) +{ + dds_qos_t *b = dds_create_qos (); + dds_get_qos (ent, b); + uint64_t delta = writer_qos_delta (a, b); + if (delta) + { + DDS_LOG (DDS_LC_ERROR, "writer: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, a); DDS_LOG (DDS_LC_ERROR, "\n"); + nn_log_xqos (DDS_LC_ERROR, b); DDS_LOG (DDS_LC_ERROR, "\n"); + } + dds_delete_qos (b); + return delta == 0; +} + +MPT_ProcessEntry (rw_publisher, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)) +{ + dds_entity_t dp; + dds_entity_t tp; + dds_entity_t pub[NPUB]; + dds_entity_t wr[NPUB][NWR_PUB]; + bool chk[NPUB][NWR_PUB] = { { false } }; + dds_return_t rc; + dds_qos_t *qos; + int id = (int) ddsrt_getpid (); + + printf ("=== [Publisher(%d)] Start(%d) ...\n", id, (int) domainid); + + qos = dds_create_qos (); + setqos (qos, 0, false, true); + dp = dds_create_participant (domainid, NULL, NULL); + MPT_ASSERT_FATAL_GT (dp, 0, "Could not create participant: %s\n", dds_strretcode (dp)); + + tp = dds_create_topic (dp, &RWData_Msg_desc, topic_name, qos, NULL); + MPT_ASSERT_FATAL_GT (tp, 0, "Could not create topic: %s\n", dds_strretcode (tp)); + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, false, true); + pub[i] = dds_create_publisher (dp, qos, NULL); + MPT_ASSERT_FATAL_GT (pub[i], 0, "Could not create publisher %zu: %s\n", i, dds_strretcode (pub[i])); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, false, true); + wr[i][j] = dds_create_writer (pub[i], tp, qos, NULL); + MPT_ASSERT_FATAL_GT (wr[i][j], 0, "Could not create writer %zu %zu: %s\n", i, j, dds_strretcode (wr[i][j])); + } + } + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, false, false); + MPT_ASSERT (pubsub_qos_eq_h (qos, pub[i]), "publisher %zu QoS mismatch\n", i); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, false, false); + MPT_ASSERT (writer_qos_eq_h (qos, wr[i][j]), "writer %zu %zu QoS mismatch\n", i, j); + } + } + + /* Each writer should match exactly one reader */ + uint32_t nchk = 0; + while (nchk != NPUB * NWR_PUB) + { + for (size_t i = 0; i < NPUB; i++) + { + for (size_t j = 0; j < NWR_PUB; j++) + { + if (chk[i][j]) + continue; + dds_instance_handle_t ih; + dds_builtintopic_endpoint_t *ep; + rc = dds_get_matched_subscriptions (wr[i][j], &ih, 1); + MPT_ASSERT (rc == 0 || rc == 1, "Unexpected return from get_matched_subscriptions for writer %zu %zu: %s\n", + i, j, dds_strretcode (rc)); + if (rc == 1) + { + ep = dds_get_matched_subscription_data (wr[i][j], ih); + MPT_ASSERT (ep != NULL, "Failed to retrieve matched subscription data for writer %zu %zu\n", i, j); + setqos (qos, i * NWR_PUB + j, true, false); + uint64_t delta = reader_qos_delta (qos, ep->qos); + if (delta) + { + DDS_LOG (DDS_LC_ERROR, "matched reader: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, qos); DDS_LOG (DDS_LC_ERROR, "\n"); + nn_log_xqos (DDS_LC_ERROR, ep->qos); DDS_LOG (DDS_LC_ERROR, "\n"); + } + MPT_ASSERT (delta == 0, "writer %zu %zu matched reader QoS mismatch\n", i, j); + dds_delete_qos (ep->qos); + dds_free (ep->topic_name); + dds_free (ep->type_name); + dds_free (ep); + chk[i][j] = true; + nchk++; + } + } + } + dds_sleepfor (DDS_MSECS (100)); + } + + /* Wait until subscribers terminate */ + while (true) + { + for (size_t i = 0; i < NPUB; i++) + { + for (size_t j = 0; j < NWR_PUB; j++) + { + dds_publication_matched_status_t st; + rc = dds_get_publication_matched_status (wr[i][j], &st); + MPT_ASSERT_FATAL_EQ (rc, DDS_RETCODE_OK, "dds_get_matched_publication_status failed for writer %zu %zu: %s\n", + i, j, dds_strretcode (rc)); + if (st.current_count) + goto have_matches; + } + } + break; + have_matches: + ; + } + + dds_delete_qos (qos); + rc = dds_delete (dp); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "teardown failed\n"); + printf ("=== [Publisher(%d)] Done\n", id); +} + +MPT_ProcessEntry (rw_subscriber, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)) +{ + dds_entity_t dp; + dds_entity_t tp; + dds_entity_t sub[NPUB]; + dds_entity_t rd[NPUB][NWR_PUB]; + bool chk[NPUB][NWR_PUB] = { { false } }; + dds_return_t rc; + dds_qos_t *qos; + int id = (int) ddsrt_getpid (); + + printf ("=== [Subscriber(%d)] Start(%d) ...\n", id, (int) domainid); + + qos = dds_create_qos (); + setqos (qos, 0, true, true); + dp = dds_create_participant (domainid, NULL, NULL); + MPT_ASSERT_FATAL_GT (dp, 0, "Could not create participant: %s\n", dds_strretcode (dp)); + + tp = dds_create_topic (dp, &RWData_Msg_desc, topic_name, qos, NULL); + MPT_ASSERT_FATAL_GT (tp, 0, "Could not create topic: %s\n", dds_strretcode (tp)); + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, true, true); + sub[i] = dds_create_subscriber (dp, qos, NULL); + MPT_ASSERT_FATAL_GT (sub[i], 0, "Could not create subscriber %zu: %s\n", i, dds_strretcode (sub[i])); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, true, true); + rd[i][j] = dds_create_reader (sub[i], tp, qos, NULL); + MPT_ASSERT_FATAL_GT (rd[i][j], 0, "Could not create reader %zu %zu: %s\n", i, j, dds_strretcode (rd[i][j])); + } + } + + for (size_t i = 0; i < NPUB; i++) + { + setqos (qos, i * NWR_PUB, true, false); + MPT_ASSERT (pubsub_qos_eq_h (qos, sub[i]), "subscriber %zu QoS mismatch\n", i); + for (size_t j = 0; j < NWR_PUB; j++) + { + setqos (qos, i * NWR_PUB + j, true, false); + MPT_ASSERT (reader_qos_eq_h (qos, rd[i][j]), "reader %zu %zu QoS mismatch\n", i, j); + } + } + + /* Each writer should match exactly one reader */ + uint32_t nchk = 0; + while (nchk != NPUB * NWR_PUB) + { + for (size_t i = 0; i < NPUB; i++) + { + for (size_t j = 0; j < NWR_PUB; j++) + { + if (chk[i][j]) + continue; + dds_instance_handle_t ih; + dds_builtintopic_endpoint_t *ep; + rc = dds_get_matched_publications (rd[i][j], &ih, 1); + MPT_ASSERT (rc == 0 || rc == 1, "Unexpected return from get_matched_publications for writer %zu %zu: %s\n", + i, j, dds_strretcode (rc)); + if (rc == 1) + { + ep = dds_get_matched_publication_data (rd[i][j], ih); + MPT_ASSERT (ep != NULL, "Failed to retrieve matched publication data for writer %zu %zu\n", i, j); + setqos (qos, i * NWR_PUB + j, false, false); + uint64_t delta = writer_qos_delta (qos, ep->qos); + if (delta) + { + DDS_LOG (DDS_LC_ERROR, "matched writer: delta = %"PRIx64"\n", delta); + nn_log_xqos (DDS_LC_ERROR, qos); DDS_LOG (DDS_LC_ERROR, "\n"); + nn_log_xqos (DDS_LC_ERROR, ep->qos); DDS_LOG (DDS_LC_ERROR, "\n"); + } + MPT_ASSERT (delta == 0, "reader %zu %zu matched writer QoS mismatch\n", i, j); + dds_delete_qos (ep->qos); + dds_free (ep->topic_name); + dds_free (ep->type_name); + dds_free (ep); + chk[i][j] = true; + nchk++; + } + } + } + dds_sleepfor (DDS_MSECS (100)); + } + + dds_delete_qos (qos); + rc = dds_delete (dp); + MPT_ASSERT_EQ (rc, DDS_RETCODE_OK, "teardown failed\n"); + printf ("=== [Subscriber(%d)] Done\n", id); +} diff --git a/src/mpt/tests/qosmatch/procs/rw.h b/src/mpt/tests/qosmatch/procs/rw.h new file mode 100644 index 0000000..851ee20 --- /dev/null +++ b/src/mpt/tests/qosmatch/procs/rw.h @@ -0,0 +1,41 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited 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 MPT_QOSMATCH_PROCS_RW_H +#define MPT_QOSMATCH_PROCS_RW_H + +#include +#include + +#include "dds/dds.h" +#include "mpt/mpt.h" + +#if defined (__cplusplus) +extern "C" { +#endif + +void rw_init (void); +void rw_fini (void); + +MPT_ProcessEntry (rw_publisher, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)); + +MPT_ProcessEntry (rw_subscriber, + MPT_Args (dds_domainid_t domainid, + const char *topic_name)); + +#if defined (__cplusplus) +} +#endif + +#endif diff --git a/src/mpt/tests/qosmatch/procs/rwdata.idl b/src/mpt/tests/qosmatch/procs/rwdata.idl new file mode 100644 index 0000000..7722451 --- /dev/null +++ b/src/mpt/tests/qosmatch/procs/rwdata.idl @@ -0,0 +1,8 @@ +module RWData +{ + struct Msg + { + long k; + }; + #pragma keylist Msg k +}; diff --git a/src/mpt/tests/qosmatch/qosmatch.c b/src/mpt/tests/qosmatch/qosmatch.c new file mode 100644 index 0000000..b249b35 --- /dev/null +++ b/src/mpt/tests/qosmatch/qosmatch.c @@ -0,0 +1,20 @@ +#include "mpt/mpt.h" +#include "procs/rw.h" + + +/* + * Tests to check communication between multiple publisher(s) and subscriber(s). + */ + + +/* + * The publisher expects 2 publication matched. + * The subscribers expect 1 sample each. + */ +#define TEST_PUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_qosmatch") +#define TEST_SUB_ARGS MPT_ArgValues(DDS_DOMAIN_DEFAULT, "multi_qosmatch") +MPT_TestProcess(qosmatch, qosmatch, pub, rw_publisher, TEST_PUB_ARGS); +MPT_TestProcess(qosmatch, qosmatch, sub, rw_subscriber, TEST_SUB_ARGS); +MPT_Test(qosmatch, qosmatch, .init=rw_init, .fini=rw_fini); +#undef TEST_SUB_ARGS +#undef TEST_PUB_ARGS