diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h index 95e4bb3ee9..3c410aafa7 100644 --- a/src/core/ddsc/include/dds/dds.h +++ b/src/core/ddsc/include/dds/dds.h @@ -224,28 +224,18 @@ dds_builtintopic_endpoint_t; */ /** - * @brief Enable entity. + * @brief Enable an entity. * - * @note Delayed entity enabling is not supported yet (CHAM-96). + * Entities can be created in an enabled or disabled state. + * Enabled entities are immediately activated at creation time, and + * their immutable QoS settings cannot be changed. + * Disabled entities are not yet activated at creation time, + * so it is still possible to change their immutable QoS settings. * - * This operation enables the dds_entity_t. Created dds_entity_t objects can start in - * either an enabled or disabled state. This is controlled by the value of the - * entityfactory policy on the corresponding parent entity for the given - * entity. Enabled entities are immediately activated at creation time meaning - * all their immutable QoS settings can no longer be changed. Disabled Entities are not - * yet activated, so it is still possible to change their immutable QoS settings. However, - * once activated the immutable QoS settings can no longer be changed. - * Creating disabled entities can make sense when the creator of the DDS_Entity - * does not yet know which QoS settings to apply, thus allowing another piece of code - * to set the QoS later on. - * - * The default setting of DDS_EntityFactoryQosPolicy is such that, by default, - * entities are created in an enabled state so that it is not necessary to explicitly call - * dds_enable on newly-created entities. - * - * The dds_enable operation produces the same results no matter how - * many times it is performed. Calling dds_enable on an already - * enabled DDS_Entity returns DDS_RETCODE_OK and has no effect. + * Typically, subscribers, publishers, readers and writers can be created in a disabled state. + * This is controlled by the value of the DDS_EntityFactoryQosPolicy of the parent + * of the entity. The default setting of DDS_EntityFactoryQosPolicy is such that + * entities are created in an enabled state. * * If an Entity has not yet been enabled, the only operations that can be invoked * on it are: the ones to set, get or copy the QosPolicy settings, the ones that set @@ -253,17 +243,31 @@ dds_builtintopic_endpoint_t; * operation (although the status of a disabled entity never changes). Other operations * will return the error DDS_RETCODE_NOT_ENABLED. * - * Entities created with a parent that is disabled, are created disabled regardless of - * the setting of the entityfactory policy. - * - * If the entityfactory policy has autoenable_created_entities - * set to TRUE, the dds_enable operation on the parent will - * automatically enable all child entities created with the parent. - * * The Listeners associated with an Entity are not called until the * Entity is enabled. Conditions associated with an Entity that * is not enabled are "inactive", that is, have a trigger_value which is FALSE. * + * Entities created with a parent that is disabled, are created disabled regardless of + * the setting of the DDS_EntityFactoryQosPolicy. + * + * Calling dds_enable() on a disabled DDS_Entity enables the DDS_Entity only if its + * parent entity is enabled. When the DDS Entity is enabled, the dds_enable() operation + * will also automatically enable all child entities of the DDS_Entity that have been + * created when the DDS_EntityFactoryQosPolicy of the DDS_Entity has + * autoenable_created_entities set to TRUE. For example, if a disabled subscriber + * which has its autoenable_created_entities set to TRUE is used to create 3 readers, + * then these 3 readers will be enabled automatically as soon as the subscriber is + * enabled. + * + * The dds_enable() operation will return DDS_RETCODE_OK if an entity and all its + * autoenabled children have been enabled successfully. In case one or more of + * its autoenabled children could not be enabled, an error code is returned. + * It is the responsibility of the application to find out which of the children + * code were enabled, and which not enabled. + * + * Calling dds_enable() on an already enabled DDS_Entity returns DDS_RETCODE_OK and + * has no effect. + * * @param[in] entity The entity to enable. * * @returns A dds_return_t indicating success or failure. @@ -279,6 +283,8 @@ dds_builtintopic_endpoint_t; * The entity has already been deleted. * @retval DDS_RETCODE_PRECONDITION_NOT_MET * The parent of the given Entity is not enabled. + * @retval DDS_RETCODE_NOT_ALLOWED_BY_SECURITY + * The security plugin prevents enabling of the Entity. */ DDS_EXPORT dds_return_t dds_enable(dds_entity_t entity); @@ -1521,6 +1527,16 @@ dds_wait_for_acks(dds_entity_t publisher_or_writer, dds_duration_t timeout); * A valid reader handle. * @retval DDS_RETCODE_ERROR * An internal error occurred. + * @retval DDS_RETCODE_ILLEGAL_OPERATION + * The provided entity is not a participant or subscriber. + * @retval DDS_RETCODE_BAD_PARAMETER + * One of the given arguments is not valid. + * @retval DDS_RETCODE_INCONSISTENT_POLICY + * The provided qos is not allowed. + * @retval DDS_RETCODE_NOT_ALLOWED_BY_SECURITY + * The security plugin prevents creation of the reader. + * @retval DDS_RETCODE_OUT_OF_RESOURCES + * There are not enough resources available to create the reader. */ /* TODO: Complete list of error codes */ DDS_EXPORT dds_entity_t @@ -1593,9 +1609,21 @@ dds_reader_wait_for_historical_data( * @returns A valid writer handle or an error code. * * @returns >0 - * A valid writer handle. + * A valid writer handle. * @returns DDS_RETCODE_ERROR - * An internal error occurred. + * An internal error occurred. + * @retval DDS_RETCODE_ERROR + * An internal error occurred. + * @retval DDS_RETCODE_ILLEGAL_OPERATION + * The provided entity is not a participant or subscriber. + * @retval DDS_RETCODE_BAD_PARAMETER + * One of the given arguments is not valid. + * @retval DDS_RETCODE_INCONSISTENT_POLICY + * The provided qos is not allowed. + * @retval DDS_RETCODE_NOT_ALLOWED_BY_SECURITY + * The security plugin prevents creation of the writer. + * @retval DDS_RETCODE_OUT_OF_RESOURCES + * There are not enough resources available to create the writer. */ /* TODO: Complete list of error codes */ DDS_EXPORT dds_entity_t 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 0a2e4e2309..746caf28eb 100644 --- a/src/core/ddsc/include/dds/ddsc/dds_public_qos.h +++ b/src/core/ddsc/include/dds/ddsc/dds_public_qos.h @@ -452,6 +452,17 @@ dds_qunset_bprop ( dds_qos_t * __restrict qos, const char * name); +/* @brief Set the entity-factory policy of a qos structure + * + * @param[in,out] qos - Pointer to a dds_qos_t structure that will store the policy + * @param[in] autoenable - True iff entities that are created from the factory for which + * this qos is applied are enabled + */ +DDS_EXPORT void +dds_qset_entity_factory ( + dds_qos_t * __restrict qos, + bool autoenable); + /** * @brief Set the type consistency enforcement policy of a qos structure * @@ -866,6 +877,18 @@ dds_qget_type_consistency ( bool *prevent_type_widening, bool *force_type_validation); +/* @brief Get the entity-factory qos policy + * + * @param[in] qos - Pointer to a dds_qos_t structure storing the policy + * @param[in,out] autoenable - Pointer that will store whether to enable child entities when created + * + * @returns - false iff any of the arguments is invalid or the requested qos value is not + * present in the qos object + */ +DDS_EXPORT bool dds_qget_entity_factory ( + const dds_qos_t * __restrict qos, + bool *autoenable); + #if defined (__cplusplus) } #endif diff --git a/src/core/ddsc/src/dds__entity.h b/src/core/ddsc/src/dds__entity.h index c94ff3e4cc..3f1b2ef46d 100644 --- a/src/core/ddsc/src/dds__entity.h +++ b/src/core/ddsc/src/dds__entity.h @@ -19,6 +19,8 @@ extern "C" { #endif +DDS_EXPORT dds_return_t dds_entity_autoenable_children (dds_entity *entity); + DDS_EXPORT dds_entity_t dds_entity_init( dds_entity * e, @@ -68,7 +70,7 @@ DDS_EXPORT inline dds_entity *dds_entity_from_handle_link (struct dds_handle_lin } DDS_EXPORT inline bool dds_entity_is_enabled (const dds_entity *e) { - return (e->m_flags & DDS_ENTITY_ENABLED) != 0; + return ((e->m_flags & DDS_ENTITY_ENABLED) != 0); } DDS_EXPORT void dds_entity_status_set (dds_entity *e, status_mask_t t); @@ -176,6 +178,9 @@ dds_generic_unimplemented_operation( dds_entity_t handle, dds_entity_kind_t kind); +DDS_EXPORT bool +dds_entity_creation_allowed ( + const dds_return_t rc); #if defined (__cplusplus) } diff --git a/src/core/ddsc/src/dds__types.h b/src/core/ddsc/src/dds__types.h index c8c99ab770..35458a2212 100644 --- a/src/core/ddsc/src/dds__types.h +++ b/src/core/ddsc/src/dds__types.h @@ -91,8 +91,10 @@ struct dds_listener { /* Entity flag values */ -#define DDS_ENTITY_ENABLED ((uint32_t) 0x1) /* DDS "enabled" state */ -#define DDS_ENTITY_IMPLICIT ((uint32_t) 0x2) /* implicit ones get deleted when the last child is deleted */ +#define DDS_ENTITY_ENABLED ((uint32_t) 0x1) /* DDS "enabled" state */ +#define DDS_ENTITY_IMPLICIT ((uint32_t) 0x2) /* implicit ones get deleted when the last child is deleted */ +#define DDS_ENTITY_ENABLE_ON_PARENT ((uint32_t) 0x4) /* flag that indicates that the entity was created by a parent + with autoenable=true while the parent was disabled */ struct dds_domain; struct dds_entity; @@ -108,6 +110,7 @@ typedef struct dds_entity_deriver { dds_return_t (*validate_status) (uint32_t mask); struct dds_statistics * (*create_statistics) (const struct dds_entity *e); void (*refresh_statistics) (const struct dds_entity *e, struct dds_statistics *s); + dds_return_t (*enable) (struct dds_entity *e) ddsrt_nonnull_all; } dds_entity_deriver; struct dds_waitset; @@ -182,6 +185,7 @@ dds_return_t dds_entity_deriver_dummy_set_qos (struct dds_entity *e, const dds_q dds_return_t dds_entity_deriver_dummy_validate_status (uint32_t mask); struct dds_statistics *dds_entity_deriver_dummy_create_statistics (const struct dds_entity *e); void dds_entity_deriver_dummy_refresh_statistics (const struct dds_entity *e, struct dds_statistics *s); +dds_return_t dds_entity_deriver_dummy_enable (struct dds_entity *e); inline void dds_entity_deriver_interrupt (struct dds_entity *e) { (dds_entity_deriver_table[e->m_kind]->interrupt) (e); @@ -210,6 +214,9 @@ inline struct dds_statistics *dds_entity_deriver_create_statistics (const struct inline void dds_entity_deriver_refresh_statistics (const struct dds_entity *e, struct dds_statistics *s) { dds_entity_deriver_table[e->m_kind]->refresh_statistics (e, s); } +inline dds_return_t dds_entity_deriver_enable (struct dds_entity *e) { + return dds_entity_deriver_table[e->m_kind]->enable (e); +} typedef struct dds_cyclonedds_entity { struct dds_entity m_entity; diff --git a/src/core/ddsc/src/dds_builtin.c b/src/core/ddsc/src/dds_builtin.c index 0c048ec31e..d44261101a 100644 --- a/src/core/ddsc/src/dds_builtin.c +++ b/src/core/ddsc/src/dds_builtin.c @@ -202,6 +202,23 @@ static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry (const struct dd return tk; } +static struct ddsi_tkmap_instance *dds__builtin_get_tkmap_entry_with_iid (const struct ddsi_guid *guid, const uint64_t iid, void *vdomain) +{ + struct dds_domain *domain = vdomain; + struct ddsi_tkmap_instance *tk; + struct ddsi_serdata *sd; + union { ddsi_guid_t guid; struct ddsi_keyhash keyhash; } x; + x.guid = nn_hton_guid (*guid); + /* any random builtin topic will do (provided it has a GUID for a key), because what matters is the "class" + of the topic, not the actual topic; also, this is called early in the initialisation of the entity with + this GUID, which simply causes serdata_from_keyhash to create a key-only serdata because the key lookup + fails. */ + sd = ddsi_serdata_from_keyhash (domain->builtin_participant_type, &x.keyhash); + tk = ddsi_tkmap_find_with_iid (domain->gv.m_tkmap, sd, iid, true); + ddsi_serdata_unref (sd); + return tk; +} + struct ddsi_serdata *dds__builtin_make_sample (const struct entity_common *e, ddsrt_wctime_t timestamp, bool alive) { /* initialize to avoid gcc warning ultimately caused by C's horrible type system */ @@ -273,6 +290,7 @@ void dds__builtin_init (struct dds_domain *dom) dom->btif.arg = dom; dom->btif.builtintopic_get_tkmap_entry = dds__builtin_get_tkmap_entry; + dom->btif.builtintopic_get_tkmap_entry_with_iid = dds__builtin_get_tkmap_entry_with_iid; dom->btif.builtintopic_is_builtintopic = dds__builtin_is_builtintopic; dom->btif.builtintopic_is_visible = dds__builtin_is_visible; dom->btif.builtintopic_write = dds__builtin_write; diff --git a/src/core/ddsc/src/dds_entity.c b/src/core/ddsc/src/dds_entity.c index d4394df24d..e624dd0d86 100644 --- a/src/core/ddsc/src/dds_entity.c +++ b/src/core/ddsc/src/dds_entity.c @@ -68,6 +68,9 @@ struct dds_statistics *dds_entity_deriver_dummy_create_statistics (const struct void dds_entity_deriver_dummy_refresh_statistics (const struct dds_entity *e, struct dds_statistics *s) { (void) e; (void) s; } +dds_return_t dds_entity_deriver_dummy_enable (struct dds_entity *e) { + (void) e; return DDS_RETCODE_ILLEGAL_OPERATION; +} extern inline void dds_entity_deriver_interrupt (struct dds_entity *e); extern inline void dds_entity_deriver_close (struct dds_entity *e); @@ -78,6 +81,7 @@ extern inline bool dds_entity_supports_set_qos (struct dds_entity *e); extern inline bool dds_entity_supports_validate_status (struct dds_entity *e); extern inline struct dds_statistics *dds_entity_deriver_create_statistics (const struct dds_entity *e); extern inline void dds_entity_deriver_refresh_statistics (const struct dds_entity *e, struct dds_statistics *s); +extern inline dds_return_t dds_entity_deriver_enable (struct dds_entity *e); static int compare_instance_handle (const void *va, const void *vb) { @@ -196,6 +200,46 @@ static bool entity_kind_has_qos (dds_entity_kind_t kind) } #endif +dds_return_t dds_entity_autoenable_children (dds_entity *e) +{ + struct dds_entity *c; + ddsrt_avl_iter_t it; + dds_return_t rc = DDS_RETCODE_OK, ret; + + assert(e); + assert(e->m_flags & DDS_ENTITY_ENABLED); + + /* enable all disabled children with the flag DDS_ENTITY_ENABLE_ON_PARENT */ + for (c = ddsrt_avl_iter_first (&dds_entity_children_td, &e->m_children, &it); c != NULL; c = ddsrt_avl_iter_next (&it)) { + if ((!(c->m_flags & DDS_ENTITY_ENABLED)) && (c->m_flags & DDS_ENTITY_ENABLE_ON_PARENT)) { + ret = dds_enable((dds_entity_t)c->m_hdllink.hdl); + if ((rc == DDS_RETCODE_OK) && (ret < 0)) { + rc = ret; + } + } + } + return rc; +} + +static void dds_entity_init_mflags (dds_entity *e, dds_entity *parent, bool implicit) +{ + assert (e); + + if (implicit) + e->m_flags |= DDS_ENTITY_IMPLICIT; + /* entity is enabled by default unless parent is not enabled or parent has + * autoenable_created_entities set to false */ + e->m_flags |= DDS_ENTITY_ENABLED; + if (parent) { + if (parent->m_qos && parent->m_qos->entity_factory.autoenable_created_entities) + /* parent has autoenable set to true */ + e->m_flags |= DDS_ENTITY_ENABLE_ON_PARENT; + /* do not enable if parent is not enabled or no autoenable */ + if ((!(parent->m_flags & DDS_ENTITY_ENABLED)) || ((e->m_flags & DDS_ENTITY_ENABLE_ON_PARENT) == 0)) + e->m_flags &= ~DDS_ENTITY_ENABLED; + } +} + dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind_t kind, bool implicit, dds_qos_t *qos, const dds_listener_t *listener, status_mask_t mask) { dds_handle_t handle; @@ -211,10 +255,10 @@ dds_entity_t dds_entity_init (dds_entity *e, dds_entity *parent, dds_entity_kind e->m_cb_pending_count = 0; e->m_observers = NULL; - /* TODO: CHAM-96: Implement dynamic enabling of entity. */ - e->m_flags |= DDS_ENTITY_ENABLED; - if (implicit) - e->m_flags |= DDS_ENTITY_IMPLICIT; + /* All entities are enabled by default, except if the parent is not enabled or + * if the parent's entity factory qos indicates that children of this parent + * should not be enabled when created */ + dds_entity_init_mflags (e, parent, implicit); /* set the status enable based on kind */ if (entity_has_status (e)) @@ -1059,15 +1103,11 @@ dds_return_t dds_enable (dds_entity_t entity) if ((rc = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) return rc; - + /* only enable entities that are not yet enabled */ if ((e->m_flags & DDS_ENTITY_ENABLED) == 0) - { - /* TODO: Really enable. */ - e->m_flags |= DDS_ENTITY_ENABLED; - DDS_CERROR (&e->m_domain->gv.logconfig, "Delayed entity enabling is not supported\n"); - } + rc = dds_entity_deriver_enable(e); dds_entity_unlock (e); - return DDS_RETCODE_OK; + return rc; } dds_return_t dds_get_status_changes (dds_entity_t entity, uint32_t *status) @@ -1327,10 +1367,15 @@ dds_return_t dds_triggered (dds_entity_t entity) if ((ret = dds_entity_lock (entity, DDS_KIND_DONTCARE, &e)) != DDS_RETCODE_OK) return ret; + if (!dds_entity_is_enabled(e)) { + ret = DDS_RETCODE_NOT_ENABLED; + goto err_enabled; + } if (entity_has_status (e)) ret = ((ddsrt_atomic_ld32 (&e->m_status.m_status_and_mask) & SAM_STATUS_MASK) != 0); else ret = (ddsrt_atomic_ld32 (&e->m_status.m_trigger) != 0); +err_enabled: dds_entity_unlock (e); return ret; } @@ -1546,3 +1591,13 @@ dds_return_t dds_assert_liveliness (dds_entity_t entity) dds_entity_unpin (e); return rc; } + +bool dds_entity_creation_allowed (const dds_return_t rc) +{ + switch (rc) { + case DDS_RETCODE_NOT_ALLOWED_BY_SECURITY: + return false; + default: + return true; + } +} diff --git a/src/core/ddsc/src/dds_participant.c b/src/core/ddsc/src/dds_participant.c index d089c1e2f0..e9fbe76bf5 100644 --- a/src/core/ddsc/src/dds_participant.c +++ b/src/core/ddsc/src/dds_participant.c @@ -80,6 +80,17 @@ static dds_return_t dds_participant_qos_set (dds_entity *e, const dds_qos_t *qos return DDS_RETCODE_OK; } +static dds_return_t dds_participant_enable (struct dds_entity *e) +{ + struct dds_participant *pp = (struct dds_participant *) e; + + assert (dds_entity_kind (e) == DDS_KIND_PARTICIPANT); + + /* Participants are always enabled */ + pp->m_entity.m_flags |= DDS_ENTITY_ENABLED; + return DDS_RETCODE_OK; +} + const struct dds_entity_deriver dds_entity_deriver_participant = { .interrupt = dds_entity_deriver_dummy_interrupt, .close = dds_entity_deriver_dummy_close, @@ -87,7 +98,8 @@ const struct dds_entity_deriver dds_entity_deriver_participant = { .set_qos = dds_participant_qos_set, .validate_status = dds_participant_status_validate, .create_statistics = dds_entity_deriver_dummy_create_statistics, - .refresh_statistics = dds_entity_deriver_dummy_refresh_statistics + .refresh_statistics = dds_entity_deriver_dummy_refresh_statistics, + .enable = dds_participant_enable }; dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_t *qos, const dds_listener_t *listener) @@ -120,8 +132,11 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ ddsi_plist_init_empty (&plist); dds_merge_qos (&plist.qos, new_qos); + /* Participants are always enabled because there is + * no factory for participants that has + * autoenable=false participants */ thread_state_awake (lookup_thread_state (), &dom->gv); - ret = new_participant (&guid, &dom->gv, 0, &plist); + ret = new_participant (&guid, &dom->gv, 0, &plist, 0); thread_state_asleep (lookup_thread_state ()); ddsi_plist_fini (&plist); if (ret < 0) @@ -133,19 +148,19 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_ pp = dds_alloc (sizeof (*pp)); if ((ret = dds_entity_init (&pp->m_entity, &dom->m_entity, DDS_KIND_PARTICIPANT, false, new_qos, listener, DDS_PARTICIPANT_STATUS_MASK)) < 0) goto err_entity_init; - pp->m_entity.m_guid = guid; pp->m_entity.m_iid = get_entity_instance_id (&dom->gv, &guid); pp->m_entity.m_domain = dom; pp->m_builtin_subscriber = 0; ddsrt_avl_init (&participant_ktopics_treedef, &pp->m_ktopics); - /* Add participant to extent */ - ddsrt_mutex_lock (&dom->m_entity.m_mutex); - dds_entity_register_child (&dom->m_entity, &pp->m_entity); - ddsrt_mutex_unlock (&dom->m_entity.m_mutex); + (void)dds_participant_enable(&pp->m_entity); + ddsrt_mutex_lock (&pp->m_entity.m_domain->m_entity.m_mutex); + dds_entity_register_child (&pp->m_entity.m_domain->m_entity, &pp->m_entity); + ddsrt_mutex_unlock (&pp->m_entity.m_domain->m_entity.m_mutex); dds_entity_init_complete (&pp->m_entity); + /* drop temporary extra ref to domain, dds_init */ dds_entity_unpin_and_drop_ref (&dom->m_entity); dds_entity_unpin_and_drop_ref (&dds_global.m_entity); diff --git a/src/core/ddsc/src/dds_publisher.c b/src/core/ddsc/src/dds_publisher.c index 17109b2ba2..8aa7f74a86 100644 --- a/src/core/ddsc/src/dds_publisher.c +++ b/src/core/ddsc/src/dds_publisher.c @@ -38,6 +38,21 @@ static dds_return_t dds_publisher_status_validate (uint32_t mask) return (mask & ~DDS_PUBLISHER_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; } +static dds_return_t dds_publisher_enable (struct dds_entity *e) +{ + struct dds_publisher *pub = (struct dds_publisher *) e; + + assert (dds_entity_kind (e) == DDS_KIND_PUBLISHER); + + /* calling enable on an entity whose factory is not enabled + * returns PRECONDITION_NOT_MET */ + if ((pub->m_entity.m_parent != NULL) && !dds_entity_is_enabled(pub->m_entity.m_parent)) + return DDS_RETCODE_PRECONDITION_NOT_MET; + pub->m_entity.m_flags |= DDS_ENTITY_ENABLED; + /* enable the entity and all its children that were created with autoenable=true */ + return dds_entity_autoenable_children(&pub->m_entity); +} + const struct dds_entity_deriver dds_entity_deriver_publisher = { .interrupt = dds_entity_deriver_dummy_interrupt, .close = dds_entity_deriver_dummy_close, @@ -45,7 +60,8 @@ const struct dds_entity_deriver dds_entity_deriver_publisher = { .set_qos = dds_publisher_qos_set, .validate_status = dds_publisher_status_validate, .create_statistics = dds_entity_deriver_dummy_create_statistics, - .refresh_statistics = dds_entity_deriver_dummy_refresh_statistics + .refresh_statistics = dds_entity_deriver_dummy_refresh_statistics, + .enable = dds_publisher_enable }; dds_entity_t dds__create_publisher_l (dds_participant *par, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener) @@ -54,6 +70,7 @@ dds_entity_t dds__create_publisher_l (dds_participant *par, bool implicit, const dds_entity_t hdl; dds_qos_t *new_qos; dds_return_t ret; + bool autoenable; new_qos = dds_create_qos (); if (qos) @@ -65,9 +82,15 @@ dds_entity_t dds__create_publisher_l (dds_participant *par, bool implicit, const return ret; } + /* get the autoenable setting of the parent + * this setting determines if the entity must be enabled or not */ + dds_qget_entity_factory(par->m_entity.m_qos, &autoenable); + pub = dds_alloc (sizeof (*pub)); hdl = dds_entity_init (&pub->m_entity, &par->m_entity, DDS_KIND_PUBLISHER, implicit, new_qos, listener, DDS_PUBLISHER_STATUS_MASK); pub->m_entity.m_iid = ddsi_iid_gen (); + if (autoenable) + (void)dds_publisher_enable(&pub->m_entity); dds_entity_register_child (&par->m_entity, &pub->m_entity); dds_entity_init_complete (&pub->m_entity); return hdl; diff --git a/src/core/ddsc/src/dds_qos.c b/src/core/ddsc/src/dds_qos.c index 77f96754be..c01565fb90 100644 --- a/src/core/ddsc/src/dds_qos.c +++ b/src/core/ddsc/src/dds_qos.c @@ -455,6 +455,14 @@ void dds_qset_type_consistency (dds_qos_t * __restrict qos, dds_type_consistency qos->present |= QP_TYPE_CONSISTENCY_ENFORCEMENT; } +void dds_qset_entity_factory (dds_qos_t * __restrict qos, bool autoenable) +{ + if (qos == NULL) + return; + qos->entity_factory.autoenable_created_entities = autoenable; + qos->present |= QP_ADLINK_ENTITY_FACTORY; +} + bool dds_qget_userdata (const dds_qos_t * __restrict qos, void **value, size_t *sz) { if (qos == NULL || !(qos->present & QP_USER_DATA)) @@ -768,3 +776,12 @@ bool dds_qget_type_consistency (const dds_qos_t * __restrict qos, dds_type_consi *force_type_validation = qos->type_consistency.force_type_validation; return true; } + +bool dds_qget_entity_factory (const dds_qos_t * __restrict qos, bool *autoenable) +{ + if (qos == NULL || !(qos->present & QP_ADLINK_ENTITY_FACTORY)) + return false; + if (autoenable) + *autoenable = qos->entity_factory.autoenable_created_entities; + return true; +} diff --git a/src/core/ddsc/src/dds_read.c b/src/core/ddsc/src/dds_read.c index 309f3de539..2c4bb49090 100644 --- a/src/core/ddsc/src/dds_read.c +++ b/src/core/ddsc/src/dds_read.c @@ -60,6 +60,9 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, cond = (dds_readcond *) entity; } + if (!dds_entity_is_enabled (entity)) + goto fail_enabled; + thread_state_awake (ts1, &entity->m_domain->gv); /* Allocate samples if not provided (assuming all or none provided) */ @@ -135,6 +138,8 @@ static dds_return_t dds_read_impl (bool take, dds_entity_t reader_or_condition, #undef NC_FREE_BUF #undef NC_RESET_BUF +fail_enabled: + ret = DDS_RETCODE_NOT_ENABLED; fail_pinned: dds_entity_unpin (entity); fail: @@ -162,6 +167,9 @@ static dds_return_t dds_readcdr_impl (bool take, dds_entity_t reader_or_conditio rd = (dds_reader *) entity->m_parent; } + if (!dds_entity_is_enabled (entity)) + goto fail_enabled; + thread_state_awake (ts1, &entity->m_domain->gv); /* read/take resets data available status -- must reset before reading because @@ -201,6 +209,10 @@ static dds_return_t dds_readcdr_impl (bool take, dds_entity_t reader_or_conditio dds_entity_unpin (entity); thread_state_asleep (ts1); return ret; + +fail_enabled: + dds_entity_unpin (entity); + return DDS_RETCODE_NOT_ENABLED; } dds_return_t dds_read (dds_entity_t rd_or_cnd, void **buf, dds_sample_info_t *si, size_t bufsz, uint32_t maxs) @@ -498,6 +510,9 @@ dds_return_t dds_return_loan (dds_entity_t reader_or_condition, void **buf, int3 rd = (dds_reader *) entity->m_parent; } + if (!dds_entity_is_enabled (entity)) + goto fail_enabled; + if (bufsz <= 0) { /* No data whatsoever, or an invocation following a failed read/take call. Read/take @@ -543,4 +558,8 @@ dds_return_t dds_return_loan (dds_entity_t reader_or_condition, void **buf, int3 ddsrt_mutex_unlock (&rd->m_entity.m_mutex); dds_entity_unpin (entity); return DDS_RETCODE_OK; + +fail_enabled: + dds_entity_unpin (entity); + return DDS_RETCODE_NOT_ENABLED; } diff --git a/src/core/ddsc/src/dds_reader.c b/src/core/ddsc/src/dds_reader.c index 5ac6108d18..078624c9a5 100644 --- a/src/core/ddsc/src/dds_reader.c +++ b/src/core/ddsc/src/dds_reader.c @@ -33,6 +33,7 @@ #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/ddsi_security_omg.h" #include "dds/ddsi/ddsi_statistics.h" +#include "dds/ddsi/ddsi_iid.h" DECL_ENTITY_LOCK_UNLOCK (extern inline, dds_reader) @@ -50,16 +51,18 @@ static void dds_reader_close (dds_entity *e) ddsrt_nonnull_all; static void dds_reader_close (dds_entity *e) { struct dds_reader * const rd = (struct dds_reader *) e; - assert (rd->m_rd != NULL); - thread_state_awake (lookup_thread_state (), &e->m_domain->gv); - (void) delete_reader (&e->m_domain->gv, &e->m_guid); - thread_state_asleep (lookup_thread_state ()); + /* nothing to close if there was no ddsi reader */ + if (rd->m_rd != NULL) { + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + (void) delete_reader (&e->m_domain->gv, &e->m_guid); + thread_state_asleep (lookup_thread_state ()); - ddsrt_mutex_lock (&e->m_mutex); - while (rd->m_rd != NULL) - ddsrt_cond_wait (&e->m_cond, &e->m_mutex); - ddsrt_mutex_unlock (&e->m_mutex); + ddsrt_mutex_lock (&e->m_mutex); + while (rd->m_rd != NULL) + ddsrt_cond_wait (&e->m_cond, &e->m_mutex); + ddsrt_mutex_unlock (&e->m_mutex); + } } static dds_return_t dds_reader_delete (dds_entity *e) ddsrt_nonnull_all; @@ -69,7 +72,8 @@ static dds_return_t dds_reader_delete (dds_entity *e) dds_reader * const rd = (dds_reader *) e; dds_free (rd->m_loan); thread_state_awake (lookup_thread_state (), &e->m_domain->gv); - dds_rhc_free (rd->m_rhc); + if (rd->m_rhc) + dds_rhc_free (rd->m_rhc); thread_state_asleep (lookup_thread_state ()); dds_entity_drop_ref (&rd->m_topic->m_entity); return DDS_RETCODE_OK; @@ -391,6 +395,74 @@ static void dds_reader_refresh_statistics (const struct dds_entity *entity, stru ddsi_get_reader_stats (rd->m_rd, &stat->kv[0].u.u64); } +static dds_return_t dds_reader_enable (struct dds_entity *e) +{ + struct dds_reader *rd = (struct dds_reader *) e; + dds_return_t rc; + const struct ddsi_guid * ppguid; + struct participant * pp; + bool rhc_created = false; + + assert (dds_entity_kind (e) == DDS_KIND_READER); + + /* calling enable on an entity whose factory is not enabled + * returns PRECONDITION_NOT_MET */ + if ((rd->m_entity.m_parent != NULL) && !dds_entity_is_enabled(rd->m_entity.m_parent)) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + + ppguid = dds_entity_participant_guid (rd->m_entity.m_parent); + pp = entidx_lookup_participant_guid (e->m_domain->gv.entity_index, ppguid); + /* When deleting a participant, the child handles (that include the subscriber) + are removed before removing the DDSI participant. So at this point, within + the subscriber lock, we can assert that the participant exists. */ + assert (pp != NULL); + +#ifdef DDS_HAS_SECURITY + /* Check if DDS Security is enabled */ + if (q_omg_participant_is_secure (pp)) + { + /* ask to access control security plugin for create reader permissions */ + if (!q_omg_security_check_create_reader (pp, e->m_domain->gv.config.domainId, rd->m_topic->m_name, rd->m_entity.m_qos)) + { + rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + goto err_not_allowed; + } + } +#endif + + rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED; + if (rd->m_rhc == NULL) { + rd->m_rhc = dds_rhc_default_new (rd, rd->m_topic->m_stype); + rhc_created = true; + } + if (dds_rhc_associate (rd->m_rhc, rd, rd->m_topic->m_stype, rd->m_entity.m_domain->gv.m_tkmap) < 0) + { + /* FIXME: see also create_querycond, need to be able to undo entity_init */ + abort (); + } + + /* the entity is enabled, so we can create a ddsi representative for this reader + * discovery of this reader will occur after the reader has been registered successfully */ + if ((rc = new_reader (&rd->m_rd, &rd->m_entity.m_guid, NULL, pp, rd->m_topic->m_name, rd->m_topic->m_stype, rd->m_entity.m_qos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd, rd->m_entity.m_iid)) != DDS_RETCODE_OK) + goto err_new_reader; + rd->m_entity.m_flags |= DDS_ENTITY_ENABLED; + +#ifdef DDS_HAS_SECURITY +err_not_allowed: +#endif + +thread_state_asleep (lookup_thread_state ()); +return rc; + +err_new_reader: + if (rhc_created) + dds_rhc_free (rd->m_rhc); + thread_state_asleep (lookup_thread_state ()); + return rc; +} + const struct dds_entity_deriver dds_entity_deriver_reader = { .interrupt = dds_entity_deriver_dummy_interrupt, .close = dds_reader_close, @@ -398,7 +470,8 @@ const struct dds_entity_deriver dds_entity_deriver_reader = { .set_qos = dds_reader_qos_set, .validate_status = dds_reader_status_validate, .create_statistics = dds_reader_create_statistics, - .refresh_statistics = dds_reader_refresh_statistics + .refresh_statistics = dds_reader_refresh_statistics, + .enable = dds_reader_enable }; static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscriber, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener, struct dds_rhc *rhc) @@ -410,6 +483,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe dds_return_t rc; dds_entity_t pseudo_topic = 0; bool created_implicit_sub = false; + bool autoenable; switch (topic) { @@ -464,7 +538,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe } /* Prevent set_qos on the topic until reader has been created and registered: we can't - allow a TOPIC_DATA change to ccur before the reader has been created because that + allow a TOPIC_DATA change to occur before the reader has been created because that change would then not be published in the discovery/built-in topics. Don't keep the participant (which protects the topic's QoS) locked because that @@ -497,63 +571,38 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe goto err_bad_qos; } - thread_state_awake (lookup_thread_state (), gv); - const struct ddsi_guid * ppguid = dds_entity_participant_guid (&sub->m_entity); - struct participant * pp = entidx_lookup_participant_guid (gv->entity_index, ppguid); - - /* When deleting a participant, the child handles (that include the subscriber) - are removed before removing the DDSI participant. So at this point, within - the subscriber lock, we can assert that the participant exists. */ - assert (pp != NULL); - -#ifdef DDS_HAS_SECURITY - /* Check if DDS Security is enabled */ - if (q_omg_participant_is_secure (pp)) - { - /* ask to access control security plugin for create reader permissions */ - if (!q_omg_security_check_create_reader (pp, gv->config.domainId, tp->m_name, rqos)) - { - rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; - goto err_not_allowed; - } - } -#endif + /* get the autoenable setting of the parent + * this setting determines if the entity must be enabled or not */ + dds_qget_entity_factory(sub->m_entity.m_qos, &autoenable); /* Create reader and associated read cache (if not provided by caller) */ struct dds_reader * const rd = dds_alloc (sizeof (*rd)); const dds_entity_t reader = dds_entity_init (&rd->m_entity, &sub->m_entity, DDS_KIND_READER, false, rqos, listener, DDS_READER_STATUS_MASK); - rd->m_sample_rejected_status.last_reason = DDS_NOT_REJECTED; rd->m_topic = tp; rd->m_wrapped_sertopic = (tp->m_stype->wrapped_sertopic != NULL) ? 1 : 0; - rd->m_rhc = rhc ? rhc : dds_rhc_default_new (rd, tp->m_stype); - if (dds_rhc_associate (rd->m_rhc, rd, tp->m_stype, rd->m_entity.m_domain->gv.m_tkmap) < 0) - { - /* FIXME: see also create_querycond, need to be able to undo entity_init */ - abort (); - } + rd->m_rhc = rhc; dds_entity_add_ref_locked (&tp->m_entity); - /* FIXME: listeners can come too soon ... should set mask based on listeners then atomically set the listeners, save the mask to a pending set and clear it; and then invoke those listeners that are in the pending set */ + rd->m_entity.m_iid = ddsi_iid_gen(); dds_entity_init_complete (&rd->m_entity); - - rc = new_reader (&rd->m_rd, &rd->m_entity.m_guid, NULL, pp, tp->m_name, tp->m_stype, rqos, &rd->m_rhc->common.rhc, dds_reader_status_cb, rd); - assert (rc == DDS_RETCODE_OK); /* FIXME: can be out-of-resources at the very least */ - thread_state_asleep (lookup_thread_state ()); - - rd->m_entity.m_iid = get_entity_instance_id (&rd->m_entity.m_domain->gv, &rd->m_entity.m_guid); - dds_entity_register_child (&sub->m_entity, &rd->m_entity); - + if (autoenable) { + rc = dds_reader_enable (&rd->m_entity); + } + dds_entity_register_child (rd->m_entity.m_parent, &rd->m_entity); dds_topic_allow_set_qos (tp); dds_topic_unpin (tp); dds_subscriber_unlock (sub); + /* Destroy the reader and return DDS_RETCODE_NOT_ALLOWED_BY_SECURITY + * when no credentials could be obtained in case of auto_enabled=true */ + if (!dds_entity_creation_allowed (rc)) + goto err_not_allowed; return reader; -#ifdef DDS_HAS_SECURITY err_not_allowed: - thread_state_asleep (lookup_thread_state ()); -#endif + (void) dds_delete (reader); + goto del_implicit_sub; err_bad_qos: dds_delete_qos (rqos); dds_topic_allow_set_qos (tp); @@ -561,6 +610,7 @@ static dds_entity_t dds_create_reader_int (dds_entity_t participant_or_subscribe dds_topic_unpin (tp); err_pin_topic: dds_subscriber_unlock (sub); +del_implicit_sub: if (created_implicit_sub) (void) dds_delete (subscriber); return rc; @@ -646,6 +696,10 @@ dds_return_t dds_reader_wait_for_historical_data (dds_entity_t reader, dds_durat (void) max_wait; if ((ret = dds_reader_lock (reader, &rd)) != DDS_RETCODE_OK) return ret; + if (!dds_entity_is_enabled((dds_entity *)rd)) { + ret = DDS_RETCODE_NOT_ENABLED; + goto err_enable; + } switch (rd->m_entity.m_qos->durability.kind) { case DDS_DURABILITY_VOLATILE: @@ -657,6 +711,7 @@ dds_return_t dds_reader_wait_for_historical_data (dds_entity_t reader, dds_durat case DDS_DURABILITY_PERSISTENT: break; } +err_enable: dds_reader_unlock(rd); return ret; } diff --git a/src/core/ddsc/src/dds_subscriber.c b/src/core/ddsc/src/dds_subscriber.c index 3c9748b552..59cd10b123 100644 --- a/src/core/ddsc/src/dds_subscriber.c +++ b/src/core/ddsc/src/dds_subscriber.c @@ -37,6 +37,21 @@ static dds_return_t dds_subscriber_status_validate (uint32_t mask) return (mask & ~DDS_SUBSCRIBER_STATUS_MASK) ? DDS_RETCODE_BAD_PARAMETER : DDS_RETCODE_OK; } +static dds_return_t dds_subscriber_enable (struct dds_entity *e) +{ + struct dds_subscriber *sub = (struct dds_subscriber *) e; + + assert (dds_entity_kind (e) == DDS_KIND_SUBSCRIBER); + + /* calling enable on an entity whose factory is not enabled + * returns PRECONDITION_NOT_MET */ + if ((sub->m_entity.m_parent != NULL) && !dds_entity_is_enabled(sub->m_entity.m_parent)) + return DDS_RETCODE_PRECONDITION_NOT_MET; + /* enable the entity and all its children that were created with autoenable=true */ + sub->m_entity.m_flags |= DDS_ENTITY_ENABLED; + return dds_entity_autoenable_children(&sub->m_entity); +} + const struct dds_entity_deriver dds_entity_deriver_subscriber = { .interrupt = dds_entity_deriver_dummy_interrupt, .close = dds_entity_deriver_dummy_close, @@ -44,7 +59,8 @@ const struct dds_entity_deriver dds_entity_deriver_subscriber = { .set_qos = dds_subscriber_qos_set, .validate_status = dds_subscriber_status_validate, .create_statistics = dds_entity_deriver_dummy_create_statistics, - .refresh_statistics = dds_entity_deriver_dummy_refresh_statistics + .refresh_statistics = dds_entity_deriver_dummy_refresh_statistics, + .enable = dds_subscriber_enable }; dds_entity_t dds__create_subscriber_l (dds_participant *participant, bool implicit, const dds_qos_t *qos, const dds_listener_t *listener) @@ -54,6 +70,7 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, bool implic dds_entity_t subscriber; dds_return_t ret; dds_qos_t *new_qos; + bool autoenable; new_qos = dds_create_qos (); if (qos) @@ -65,12 +82,26 @@ dds_entity_t dds__create_subscriber_l (dds_participant *participant, bool implic return ret; } + /* get the autoenable setting of the parent + * this setting determines if the entity must be enabled or not */ + dds_qget_entity_factory(participant->m_entity.m_qos, &autoenable); + sub = dds_alloc (sizeof (*sub)); - subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, implicit, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK); + if ((subscriber = dds_entity_init (&sub->m_entity, &participant->m_entity, DDS_KIND_SUBSCRIBER, implicit, new_qos, listener, DDS_SUBSCRIBER_STATUS_MASK)) < 0) + goto err_entity_init; sub->m_entity.m_iid = ddsi_iid_gen (); - dds_entity_register_child (&participant->m_entity, &sub->m_entity); + + if (autoenable) + (void)dds_subscriber_enable(&sub->m_entity); + + dds_entity_register_child (sub->m_entity.m_parent, &sub->m_entity); dds_entity_init_complete (&sub->m_entity); + return subscriber; + +err_entity_init: + dds_free(sub); + return DDS_HANDLE_NIL; } dds_entity_t dds_create_subscriber (dds_entity_t participant, const dds_qos_t *qos, const dds_listener_t *listener) diff --git a/src/core/ddsc/src/dds_writer.c b/src/core/ddsc/src/dds_writer.c index dbe3fcdcd5..1ec0bde85b 100644 --- a/src/core/ddsc/src/dds_writer.c +++ b/src/core/ddsc/src/dds_writer.c @@ -21,6 +21,7 @@ #include "dds/ddsi/q_xmsg.h" #include "dds/ddsi/ddsi_entity_index.h" #include "dds/ddsi/ddsi_security_omg.h" +#include "dds/ddsi/ddsi_iid.h" #include "dds__writer.h" #include "dds__listener.h" #include "dds__init.h" @@ -180,10 +181,15 @@ static void dds_writer_interrupt (dds_entity *e) ddsrt_nonnull_all; static void dds_writer_interrupt (dds_entity *e) { + struct dds_writer * const wr = (struct dds_writer *) e; struct ddsi_domaingv * const gv = &e->m_domain->gv; - thread_state_awake (lookup_thread_state (), gv); - unblock_throttled_writer (gv, &e->m_guid); - thread_state_asleep (lookup_thread_state ()); + + /* no need to unblock if there is no ddsi writer */ + if (wr->m_wr) { + thread_state_awake (lookup_thread_state (), gv); + unblock_throttled_writer (gv, &e->m_guid); + thread_state_asleep (lookup_thread_state ()); + } } static void dds_writer_close (dds_entity *e) ddsrt_nonnull_all; @@ -193,15 +199,20 @@ static void dds_writer_close (dds_entity *e) struct dds_writer * const wr = (struct dds_writer *) e; struct ddsi_domaingv * const gv = &e->m_domain->gv; struct thread_state1 * const ts1 = lookup_thread_state (); - thread_state_awake (ts1, gv); - nn_xpack_send (wr->m_xp, false); - (void) delete_writer (gv, &e->m_guid); - thread_state_asleep (ts1); - - ddsrt_mutex_lock (&e->m_mutex); - while (wr->m_wr != NULL) - ddsrt_cond_wait (&e->m_cond, &e->m_mutex); - ddsrt_mutex_unlock (&e->m_mutex); + + /* nothing to close if there was no ddsi writer */ + if (wr->m_wr) { + thread_state_awake (ts1, gv); + nn_xpack_send (wr->m_xp, false); + (void) delete_writer (gv, &e->m_guid); + nn_xpack_free(wr->m_xp); + thread_state_asleep (ts1); + + ddsrt_mutex_lock (&e->m_mutex); + while (wr->m_wr != NULL) + ddsrt_cond_wait (&e->m_cond, &e->m_mutex); + ddsrt_mutex_unlock (&e->m_mutex); + } } static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all; @@ -209,10 +220,12 @@ static dds_return_t dds_writer_delete (dds_entity *e) ddsrt_nonnull_all; static dds_return_t dds_writer_delete (dds_entity *e) { dds_writer * const wr = (dds_writer *) e; - /* FIXME: not freeing WHC here because it is owned by the DDSI entity */ + + /* not freeing WHC here because it is owned by the DDSI entity */ +#if 0 thread_state_awake (lookup_thread_state (), &e->m_domain->gv); - nn_xpack_free (wr->m_xp); thread_state_asleep (lookup_thread_state ()); +#endif dds_entity_drop_ref (&wr->m_topic->m_entity); return DDS_RETCODE_OK; } @@ -274,6 +287,69 @@ static void dds_writer_refresh_statistics (const struct dds_entity *entity, stru ddsi_get_writer_stats (wr->m_wr, &stat->kv[0].u.u64, &stat->kv[1].u.u32, &stat->kv[2].u.u64, &stat->kv[3].u.u64); } +static dds_return_t dds_writer_enable (struct dds_entity *e) +{ + struct dds_writer *wr = (struct dds_writer *) e; + const struct ddsi_guid * ppguid; + struct participant * pp; + dds_return_t rc; + + assert (dds_entity_kind (e) == DDS_KIND_WRITER); + + /* calling enable on an entity whose factory is not enabled + * returns PRECONDITION_NOT_MET */ + if ((wr->m_entity.m_parent != NULL) && !dds_entity_is_enabled(wr->m_entity.m_parent)) + return DDS_RETCODE_PRECONDITION_NOT_MET; + + thread_state_awake (lookup_thread_state (), &e->m_domain->gv); + + ppguid = dds_entity_participant_guid (wr->m_entity.m_parent); + pp = entidx_lookup_participant_guid (e->m_domain->gv.entity_index, ppguid); + /* When deleting a participant, the child handles (that include the publisher) + are removed before removing the DDSI participant. So at this point, within + the publisher lock, we can assert that the participant exists. */ + assert (pp != NULL); + +#ifdef DDS_HAS_SECURITY + /* Check if DDS Security is enabled */ + if (q_omg_participant_is_secure (pp)) + { + /* ask to access control security plugin for create writer permissions */ + if (!q_omg_security_check_create_writer (pp, e->m_domain->gv.config.domainId, wr->m_topic->m_name, wr->m_entity.m_qos)) + { + rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; + goto err_not_allowed; + } + } +#endif + struct whc_writer_info *wrinfo; + struct ddsi_domaingv *gv = &e->m_domain->gv; + ddsi_tran_conn_t conn = gv->xmit_conn; + + wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wr->m_entity.m_qos->transport_priority), gv->config.xpack_send_async); + wrinfo = whc_make_wrinfo (wr, wr->m_entity.m_qos); + wr->m_whc = whc_new (gv, wrinfo); + whc_free_wrinfo (wrinfo); + + /* the entity is enabled, so we can create a ddsi representative for this writer + * discovery of this writer will occur after the writer has been registered */ + if ((rc = new_writer (&wr->m_wr, &wr->m_entity.m_guid, NULL, pp, wr->m_topic->m_name, wr->m_topic->m_stype, wr->m_entity.m_qos, wr->m_whc, dds_writer_status_cb, wr, wr->m_entity.m_iid)) != DDS_RETCODE_OK) + goto err_new_writer; + wr->m_entity.m_flags |= DDS_ENTITY_ENABLED; +#ifdef DDS_HAS_SECURITY +err_not_allowed: +#endif + + thread_state_asleep (lookup_thread_state ()); + return rc; + +err_new_writer: + whc_free (wr->m_whc); + nn_xpack_free (wr->m_xp); + thread_state_asleep (lookup_thread_state ()); + return rc; +} + const struct dds_entity_deriver dds_entity_deriver_writer = { .interrupt = dds_writer_interrupt, .close = dds_writer_close, @@ -281,7 +357,8 @@ const struct dds_entity_deriver dds_entity_deriver_writer = { .set_qos = dds_writer_qos_set, .validate_status = dds_writer_status_validate, .create_statistics = dds_writer_create_statistics, - .refresh_statistics = dds_writer_refresh_statistics + .refresh_statistics = dds_writer_refresh_statistics, + .enable = dds_writer_enable }; dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entity_t topic, const dds_qos_t *qos, const dds_listener_t *listener) @@ -291,8 +368,8 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_publisher *pub = NULL; dds_topic *tp; dds_entity_t publisher; - struct whc_writer_info *wrinfo; bool created_implicit_pub = false; + bool autoenable; { dds_entity *p_or_p; @@ -350,57 +427,33 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit if ((rc = ddsi_xqos_valid (&gv->logconfig, wqos)) < 0 || (rc = validate_writer_qos(wqos)) != DDS_RETCODE_OK) goto err_bad_qos; - thread_state_awake (lookup_thread_state (), gv); - const struct ddsi_guid *ppguid = dds_entity_participant_guid (&pub->m_entity); - struct participant *pp = entidx_lookup_participant_guid (gv->entity_index, ppguid); - /* When deleting a participant, the child handles (that include the publisher) - are removed before removing the DDSI participant. So at this point, within - the publisher lock, we can assert that the participant exists. */ - assert (pp != NULL); - -#ifdef DDS_HAS_SECURITY - /* Check if DDS Security is enabled */ - if (q_omg_participant_is_secure (pp)) - { - /* ask to access control security plugin for create writer permissions */ - if (!q_omg_security_check_create_writer (pp, gv->config.domainId, tp->m_name, wqos)) - { - rc = DDS_RETCODE_NOT_ALLOWED_BY_SECURITY; - goto err_not_allowed; - } - } -#endif + /* get the autoenable setting of the parent + * this setting determines if the entity must be enabled or not */ + dds_qget_entity_factory(pub->m_entity.m_qos, &autoenable); /* Create writer */ - ddsi_tran_conn_t conn = gv->xmit_conn; struct dds_writer * const wr = dds_alloc (sizeof (*wr)); const dds_entity_t writer = dds_entity_init (&wr->m_entity, &pub->m_entity, DDS_KIND_WRITER, false, wqos, listener, DDS_WRITER_STATUS_MASK); wr->m_topic = tp; dds_entity_add_ref_locked (&tp->m_entity); - wr->m_xp = nn_xpack_new (conn, get_bandwidth_limit (wqos->transport_priority), gv->config.xpack_send_async); - wrinfo = whc_make_wrinfo (wr, wqos); - wr->m_whc = whc_new (gv, wrinfo); - whc_free_wrinfo (wrinfo); wr->whc_batch = gv->config.whc_batch; - - rc = new_writer (&wr->m_wr, &wr->m_entity.m_guid, NULL, pp, tp->m_name, tp->m_stype, wqos, wr->m_whc, dds_writer_status_cb, wr); - assert(rc == DDS_RETCODE_OK); - thread_state_asleep (lookup_thread_state ()); - - wr->m_entity.m_iid = get_entity_instance_id (&wr->m_entity.m_domain->gv, &wr->m_entity.m_guid); - dds_entity_register_child (&pub->m_entity, &wr->m_entity); - + wr->m_entity.m_iid = ddsi_iid_gen(); dds_entity_init_complete (&wr->m_entity); - + if (autoenable) { + rc = dds_writer_enable (&wr->m_entity); + } + dds_entity_register_child (wr->m_entity.m_parent, &wr->m_entity); dds_topic_allow_set_qos (tp); dds_topic_unpin (tp); dds_publisher_unlock (pub); + /* destroy the writer when needed */ + if (!dds_entity_creation_allowed (rc)) + goto err_not_allowed; return writer; -#ifdef DDS_HAS_SECURITY err_not_allowed: - thread_state_asleep (lookup_thread_state ()); -#endif + (void) dds_delete (writer); + goto del_implicit_pub; err_bad_qos: dds_delete_qos(wqos); dds_topic_allow_set_qos (tp); @@ -408,6 +461,7 @@ dds_entity_t dds_create_writer (dds_entity_t participant_or_publisher, dds_entit dds_topic_unpin (tp); err_pin_topic: dds_publisher_unlock (pub); +del_implicit_pub: if (created_implicit_pub) (void) dds_delete (publisher); return rc; diff --git a/src/core/ddsc/tests/participant.c b/src/core/ddsc/tests/participant.c index 70697a5618..ff0b338a48 100644 --- a/src/core/ddsc/tests/participant.c +++ b/src/core/ddsc/tests/participant.c @@ -16,6 +16,7 @@ #include "config_env.h" #include "dds/version.h" #include "dds/ddsrt/environ.h" +#include "test_common.h" CU_Test(ddsc_participant, create_and_delete) { @@ -343,3 +344,157 @@ CU_Test(ddsc_participant_lookup, deleted) { dds_delete (participant); } + +/* This test verifies that participants are enabled by default */ +CU_Test(ddsc_participant, enable_by_default) { + dds_entity_t participant; + dds_return_t ret; + dds_qos_t *pqos; + bool autoenable; + + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + pqos = dds_create_qos(); + /* validate that the autoenable is set to true by default */ + ret = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(ret, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* enabling an already enabled entity is a noop */ + ret = dds_enable (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* we should actually check that the participant is really + * enabled by trying to set a qos that cannot be changed once + * the participant is enabled. However, such qos is not + * available on the participant and therefore we cannot really + * verify if the participant is enabled */ + ret = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pqos); +} + +CU_Test(ddsc_participant, autoenable_false) { + dds_entity_t participant; + dds_qos_t *pqos; + bool autoenable; + bool status; + dds_return_t ret; + + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant and check that the + * autoenable property is really disabled */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + ret = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + /* enable the participant and check that the + * autoenable property is not affected */ + ret = dds_enable(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + /* change the autoenable property of the participant + * and verify that it is set to true */ + dds_qset_entity_factory(pqos, true); + ret = dds_set_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + ret = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pqos); +} + +/* The following test validates return codes for operations + * on a participant with autoenable=false + */ +CU_Test(ddsc_participant, not_autoenabled) { + dds_entity_t participant, publisher, subscriber, topic, ftopic, gcond, ws, reader, writer; + dds_qos_t *pqos, *wqos, *rqos; + bool autoenable; + bool status; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + + pqos = dds_create_qos(); + rqos = dds_create_qos(); + wqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a disabled participant */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + /* dds_get_qos */ + ret = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + /* dds_create_publisher */ + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + /* dds_delete_publisher */ + ret = dds_delete(publisher); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* dds_create_subscriber */ + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + /* dds_delete_subscriber */ + ret = dds_delete(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* dds_create_topic */ + topic = dds_create_topic(participant, &Space_Type1_desc, "ddsc_participant_disabled", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + /* dds_create_topic_arbitrary */ + /* dds_create_guardcondition */ + gcond = dds_create_guardcondition(participant); + CU_ASSERT_FATAL(gcond > 0); + /* dds_create_waitset */ + ws = dds_create_waitset(participant); + CU_ASSERT_FATAL(ws > 0); + /* dds_find_topic */ + ftopic = dds_find_topic(participant, "ddsc_participant_disabled"); + CU_ASSERT_FATAL(ftopic > 0); + /* dds_create_reader */ + reader = dds_create_reader(participant, ftopic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(reader, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* dds_delete */ + ret = dds_delete(reader); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* dds_create_writer */ + writer = dds_create_writer(participant, ftopic, NULL, NULL); + CU_ASSERT_FATAL(writer > 0); + dds_qset_history(wqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(wqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* dds_delete */ + ret = dds_delete(writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* dds_enable */ + ret = dds_enable(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* Done */ + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pqos); + dds_delete_qos(wqos); + dds_delete_qos(rqos); +} diff --git a/src/core/ddsc/tests/publisher.c b/src/core/ddsc/tests/publisher.c index 2035e4af42..d6beadaaa5 100644 --- a/src/core/ddsc/tests/publisher.c +++ b/src/core/ddsc/tests/publisher.c @@ -267,6 +267,157 @@ CU_Test(ddsc_publisher, wait_for_acks) return; } +CU_Test(ddsc_publisher, enable_by_default) +{ + dds_entity_t participant, publisher; + dds_return_t status, status1; + dds_qos_t *pqos, *pubqos; + bool autoenable; + + /* create a default publisher and check that autoenable=true */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + pqos = dds_create_qos(); + status = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + pubqos = dds_create_qos(); + status = dds_get_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pubqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* enabling an already enabled entity is a noop */ + status1 = dds_enable (publisher); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); + /* check that the publisher is really enabled + * by trying to set a qos that cannot be changed once + * the subscriber is enabled. We use the presentation qos + * for that purpose */ + dds_qset_presentation(pubqos, DDS_PRESENTATION_TOPIC, true, true); + status = dds_set_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_IMMUTABLE_POLICY); + status = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + dds_delete_qos(pubqos); + dds_delete_qos(pqos); + + /* create a participant with autoenable=false + * check that a default publisher is disabled and has autoenable=true */ + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + status = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + pubqos = dds_create_qos(); + status = dds_get_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pubqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* the publisher should be disabled because the participant + * has autoenable=false. To check that the publisher is really + * disabled we try to set an immutable qos. We use the presentation + * qos for that purpose. Setting it should succeed. */ + dds_qset_presentation(pubqos, DDS_PRESENTATION_TOPIC, true, true); + status = dds_set_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + dds_delete_qos(pubqos); + dds_delete_qos(pqos); +} + +CU_Test(ddsc_publisher, disabled_publisher_enable_later) +{ + dds_entity_t participant, publisher; + dds_qos_t *pqos, *pubqos; + bool autoenable; + bool status; + dds_return_t ret; + bool c_access, o_access; + dds_presentation_access_scope_kind_t pr_kind; + + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant with autoenable=false */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a default publisher that should be disabled */ + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + /* get the autoenable value for this publisher */ + pubqos = dds_create_qos(); + ret = dds_get_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pubqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* the autoenable is true, but the publisher should + * not be enabled because the participant was not enabled + * Because there is no explicit call to find out if an entity + * is enabled we do this by trying to set an immutable qos + * on the publisher. This should succeed if the publisher + * is not yet enabled, and fail if it is */ + dds_qset_presentation(pubqos, DDS_PRESENTATION_GROUP, true, true); + ret = dds_set_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that qos is really changed */ + dds_qget_presentation(pubqos, &pr_kind,&c_access, &o_access); + CU_ASSERT_EQUAL_FATAL(pr_kind, DDS_PRESENTATION_GROUP); + CU_ASSERT_EQUAL_FATAL(c_access, true); + CU_ASSERT_EQUAL_FATAL(o_access, true); + /* now enable the publisher and try again to set the + * presentation qos. This should now result in IMMUTABLE_POLICY + * because the publisher is already enabled */ + ret = dds_enable(publisher); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qset_presentation(pubqos, DDS_PRESENTATION_INSTANCE, false, false); + ret = dds_set_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + /* TODO: + * the following operations should all be available on a + * disabled entity: set_qos, get_qos, get_status_condition, + * factory operations, get_status_changes, lookup operations + */ + ret = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pubqos); + dds_delete_qos(pqos); +} + +CU_Test(ddsc_publisher, delete_disabled_publisher) +{ + dds_entity_t participant, publisher; + dds_qos_t *pqos; + dds_return_t ret; + + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant with autoenable=false */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a default publisher that should be disabled */ + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + /* delete the participant */ + ret = dds_delete(publisher); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pqos); +} + CU_Test(ddsc_publisher, coherency) { return; diff --git a/src/core/ddsc/tests/reader.c b/src/core/ddsc/tests/reader.c index ca5d9fe66f..684078a360 100644 --- a/src/core/ddsc/tests/reader.c +++ b/src/core/ddsc/tests/reader.c @@ -3182,4 +3182,405 @@ CU_Test(ddsc_take_mask_wl, combination_of_states, .init=reader_init, .fini=reade ret = samples_cnt(); CU_ASSERT_EQUAL_FATAL(ret, MAX_SAMPLES - expected_cnt); } -/*************************************************************************************************/ + +/* This test verifies that readers are enabled by default */ +CU_Test(ddsc_reader, enable_by_default) { + dds_entity_t participant, subscriber, reader, topic; + dds_return_t ret; + dds_qos_t *rqos; + dds_history_kind_t hist_kind; + int32_t hist_depth; + + rqos = dds_create_qos(); + /* check that default autoenable setting of participant is true */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + /* check that default autoenable setting of subscriber is true */ + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(subscriber > 0); + topic = dds_create_topic(participant, &Space_Type1_desc, "ddsc_reader_enable_defaults", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + reader = dds_create_reader(subscriber, topic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + /* get the default history qos */ + ret = dds_get_qos(reader, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_LAST); + CU_ASSERT_EQUAL_FATAL(hist_depth, 1); + /* try to change the immutable immutable qos, this should fail */ + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(reader, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + ret = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(rqos); +} + +/* This test validates various combinations of auto_enabled_created_entities + * in combination with the enabled or disabled entities. The following + * matrix shows the combinations for the subscriber + * + * autoenable + * false | true + * -------------------------- + * false| 1. 2. + * enabled | + * true | 4. 3. + * + * Case 1 is the case where the subscriber is disabled and has autoenable=false. + * In this case the reader that is created for this subscriber is disabled + * when calling dds_enable() on the subscriber followed by calling dds_enable() + * on the reader. + * + * Case 2 is the case where the subscriber is disabled and has autoenable=true. + * In this case the reader that is created for this subscriber is disabled + * and will be enabled when calling dds_enable() on the subscriber. + * + * Case 3 is the case where the subscriber is enabled but has autoenable=false. + * In this case the reader that is created for this subscriber is disabled, and + * will be enabled when calling dds_enable() on the reader. + * + * Case 4 is the case where the subscriber is enabled and has autoenable=true. + * In this case a reader that is created for this subscriber must be enabled + * upon creation. + * + * The test uses a single subscriber to demonstrate that starts disabled + * to test case 1 and 2, and then changes to enabled to test cases 3 and 4. + * The autoenable qos is a mutable qos that is changed throughout the test. + */ +CU_Test(ddsc_reader, enable_reader) { + dds_qos_t *pqos, *sqos, *rqos; + bool autoenable; + bool status; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + dds_entity_t participant, subscriber1, subscriber2, topic, reader1, reader2, reader3, reader4; + dds_presentation_access_scope_kind_t access_scope; + bool coherent_access; + bool ordered_access; + + /* create a participant with autoenable=false */ + pqos = dds_create_qos(); + sqos = dds_create_qos(); + rqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + ret = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + /* create topic */ + topic = dds_create_topic(participant, &Space_Type1_desc, "ddsc_reader_enable_disable", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + + /* case 1: create a disabled subscriber with autoenable=false */ + dds_qset_entity_factory(sqos, false); + subscriber1 = dds_create_subscriber(participant, sqos, NULL); + CU_ASSERT_FATAL(subscriber1 > 0); + ret = dds_get_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(sqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + /* check that the subscriber is disabled by trying to set + * an immutable qos. We use the presentation qos for that purpose */ + dds_qset_presentation(sqos, DDS_PRESENTATION_GROUP, true, true); + ret = dds_set_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_presentation(sqos, &access_scope, &coherent_access, &ordered_access); + CU_ASSERT_EQUAL_FATAL(access_scope, DDS_PRESENTATION_GROUP); + CU_ASSERT_EQUAL_FATAL(coherent_access, true); + CU_ASSERT_EQUAL_FATAL(coherent_access, true); + /* create a reader for case 1 and check that the reader is + * disabled by trying to set an immutable qos. We use the + * history qos for that purpose.*/ + reader1 = dds_create_reader(subscriber1, topic, NULL, NULL); + CU_ASSERT_FATAL(reader1 > 0); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(reader1, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(reader1, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* try to enable the reader, this should fail because + * the subscriber is not enabled */ + ret = dds_enable(reader1); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); + + /* Case 2: create a disabled subscriber with autoenable=true */ + dds_qset_entity_factory(sqos, true); + ret = dds_set_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(sqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* check that the subscriber is still disabled by trying to set + * an immutable qos. We use the presentation qos for that purpose */ + dds_qset_presentation(sqos, DDS_PRESENTATION_INSTANCE, false, false); + ret = dds_set_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_presentation(sqos, &access_scope, &coherent_access, &ordered_access); + CU_ASSERT_EQUAL_FATAL(access_scope, DDS_PRESENTATION_INSTANCE); + CU_ASSERT_EQUAL_FATAL(coherent_access, false); + CU_ASSERT_EQUAL_FATAL(coherent_access, false); + /* create a reader for case 2 and check that the reader is + * disabled by trying to set an immutable qos. We use the + * history qos for that purpose.*/ + reader2 = dds_create_reader(subscriber1, topic, NULL, NULL); + CU_ASSERT_FATAL(reader2 > 0); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(reader2, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(reader2, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* try to enable the reader, this should fail because + * the subscriber is not enabled */ + ret = dds_enable(reader2); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); + + /* now enable the subscriber */ + ret = dds_enable(subscriber1); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that the subscriber is still disabled by trying to set + * an immutable qos. We use the presentation qos for that purpose */ + dds_qset_presentation(sqos, DDS_PRESENTATION_GROUP, true, false); + ret = dds_set_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + /* reader1 should remain disabled, check that reader1 can still + * change one of its immutable qos settings */ + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 10); + ret = dds_set_qos(reader1, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(reader1, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 10); + /* reader2 has become enabled when the subscriber was enabled. + * Check that reader 2 cannot change its immutable qos setting */ + ret = dds_set_qos(reader2, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + /* now enable reader 1 */ + ret = dds_enable(reader1); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* now check that we cannot change the immutable qos for reader1 any more */ + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 20); + ret = dds_set_qos(reader1, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + + /* check that re-enabling the subscriber, reader1 and reader2 + * return DDS_RETCODE_OK */ + ret = dds_enable(subscriber1); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_enable(reader1); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_enable(reader2); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + + /* Case 3: create an enabled subscriber with autoenable=false */ + dds_qset_entity_factory(sqos, false); + subscriber2 = dds_create_subscriber(participant, sqos, NULL); + ret = dds_set_qos(subscriber2, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(subscriber2, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(sqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + ret = dds_enable(subscriber2); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* create a reader for case 3 and check that the reader is + * disabled by trying to set an immutable qos. We use the + * history qos for that purpose.*/ + reader3 = dds_create_reader(subscriber2, topic, NULL, NULL); + CU_ASSERT_FATAL(reader3 > 0); + /* check that reader can still change one of its immutable qos settings */ + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 30); + ret = dds_set_qos(reader3, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_get_qos(reader3, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 30); + + /* Case 4: create a reader for an enabled subscriber with autoenable=true */ + ret = dds_get_qos(subscriber1, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(sqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* check that reader4 is automatically enabled by + * trying to set an immutable qos. */ + reader4 = dds_create_reader(subscriber1, topic, NULL, NULL); + CU_ASSERT_FATAL(reader4 > 0); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 40); + ret = dds_set_qos(reader4, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + + /* enable reader3 */ + ret = dds_enable(reader3); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 50); + ret = dds_set_qos(reader3, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(rqos); + dds_delete_qos(sqos); + dds_delete_qos(pqos); +} + +/* The following test case tries to delete a reader that is disabled + * by deleting the reader, its parent, and the parent of its parent */ +CU_Test(ddsc_reader, delete_disabled_reader) { + dds_entity_t participant, subscriber, reader, topic; + dds_qos_t *sqos, *rqos; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + + sqos = dds_create_qos(); + rqos = dds_create_qos(); + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_qset_entity_factory(sqos, false); + subscriber = dds_create_subscriber(participant, sqos, NULL); + CU_ASSERT_FATAL(subscriber > 0); + topic = dds_create_topic(participant, &Space_Type1_desc, "ddsc_reader_disabled", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + /* try to delete a disabled reader */ + reader = dds_create_reader(subscriber, topic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(reader, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + ret = dds_delete(reader); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* try to delete the parent of a disabled reader */ + reader = dds_create_reader(subscriber, topic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + ret = dds_delete(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* try to delete the grandparent of a disabled reader */ + subscriber = dds_create_subscriber(participant, sqos, NULL); + CU_ASSERT_FATAL(subscriber > 0); + reader = dds_create_reader(subscriber, topic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(sqos); + dds_delete_qos(rqos); +} + +/* The following test validates return codes for operations + * on a disabled reader + */ +CU_Test(ddsc_reader, not_enabled) { + dds_entity_t participant, subscriber, reader, topic; + dds_qos_t *sqos, *rqos; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + void* samples[MAX_SAMPLES]; + static dds_sample_info_t info[MAX_SAMPLES]; + uint32_t mask = DDS_ANY_SAMPLE_STATE | DDS_ANY_VIEW_STATE | DDS_ANY_INSTANCE_STATE; + struct ddsi_serdata *buf; + dds_duration_t duration = DDS_SECS(1); + + sqos = dds_create_qos(); + rqos = dds_create_qos(); + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + dds_qset_entity_factory(sqos, false); + subscriber = dds_create_subscriber(participant, sqos, NULL); + CU_ASSERT_FATAL(subscriber > 0); + topic = dds_create_topic(participant, &Space_Type1_desc, "ddsc_reader_disabled", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + /* create a disabled reader */ + reader = dds_create_reader(subscriber, topic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(reader, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* dds_read */ + ret = dds_read(reader, samples, info, MAX_SAMPLES, MAX_SAMPLES); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_read_wl */ + ret = dds_read_wl(reader, samples, info, MAX_SAMPLES); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_read_mask */ + ret = dds_read_mask(reader, samples, info, MAX_SAMPLES, MAX_SAMPLES, mask); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_read_mask_wl */ + ret = dds_read_mask_wl(reader, samples, info, MAX_SAMPLES, mask); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_readcdr */ + ret = dds_readcdr(reader, &buf, MAX_SAMPLES, info, mask); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* TODO: dds_read_instance */ + /* TODO: dds_read_instance_wl */ + /* TODO: dds_read_instance_mask */ + /* TODO: dds_read_instance_mask_wl */ + /* TODO: dds_read_next */ + ret = dds_read_next(reader, samples, info); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_read_next_wl */ + ret = dds_read_next_wl(reader, samples, info); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_take */ + ret = dds_take(reader, samples, info, MAX_SAMPLES, MAX_SAMPLES); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_take_wl */ + ret = dds_take_wl(reader, samples, info, MAX_SAMPLES); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_take_mask */ + ret = dds_take_mask(reader, samples, info, MAX_SAMPLES, MAX_SAMPLES, mask); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_take_mask_wl */ + ret = dds_read_mask_wl(reader, samples, info, MAX_SAMPLES, mask); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_takecdr */ + ret = dds_takecdr(reader, &buf, MAX_SAMPLES, info, mask); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* TODO: dds_take_instance */ + /* TODO: dds_take_instance_wl */ + /* TODO: dds_take_instance_mask */ + /* TODO: dds_take_instance_mask_wl */ + /* YODO: dds_take_next */ + ret = dds_take_next(reader, samples, info); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_take_next_wl */ + ret = dds_take_next_wl (reader, samples, info); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_return_loan */ + /* dds_reader_wait_for_historical_data */ + ret = dds_reader_wait_for_historical_data (reader, duration); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(sqos); + dds_delete_qos(rqos); +} diff --git a/src/core/ddsc/tests/subscriber.c b/src/core/ddsc/tests/subscriber.c index 46696cb7d5..8e94ab0fe9 100644 --- a/src/core/ddsc/tests/subscriber.c +++ b/src/core/ddsc/tests/subscriber.c @@ -14,6 +14,7 @@ #include #include "CUnit/Test.h" +#include "test_common.h" /* We are deliberately testing some bad arguments that SAL will complain about. * So, silence SAL regarding these issues. */ @@ -124,6 +125,228 @@ CU_Test(ddsc_subscriber, create) { dds_delete(participant); } +/* This test verifies that subscribers are enabled by default */ +CU_Test(ddsc_subscriber, enable_by_default) { + dds_entity_t participant, subscriber; + dds_return_t status, status1; + dds_qos_t *pqos, *sqos; + bool autoenable; + + /* create a default subscriber and check that autoenable=true */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + pqos = dds_create_qos(); + status = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(subscriber > 0); + sqos = dds_create_qos(); + status = dds_get_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(sqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + status1 = dds_enable (subscriber); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); + /* check that the subscriber is really enabled + * by trying to set an immutable qos */ + dds_qset_presentation(sqos, DDS_PRESENTATION_TOPIC, true, true); + status = dds_set_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_IMMUTABLE_POLICY); + status = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + dds_delete_qos(sqos); + dds_delete_qos(pqos); + + /* create a participant with autoenable=false + * check that a default subscriber is disabled and has autoenable=true */ + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + status = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(subscriber > 0); + sqos = dds_create_qos(); + status = dds_get_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(sqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* the subscriber should be disabled because the participant + * has autoenable=false. To check that the subscriber is really + * disabled we try to set an immutable qos. We use the presentation + * qos for that purpose. Setting it should succeed. */ + dds_qset_presentation(sqos, DDS_PRESENTATION_TOPIC, true, true); + status = dds_set_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + dds_delete_qos(sqos); + dds_delete_qos(pqos); +} + +/* In this test a subscriber is created in a disabled state + * In this state immutable qos settings should still be changable. + * After the subsciber has been enabled these qos settings cannot + * change anymore */ +CU_Test(ddsc_subscriber, disabled_subscriber_enable_later) { + dds_entity_t participant, subscriber; + dds_qos_t *pqos, *sqos; + bool autoenable; + bool status; + dds_return_t ret; + bool c_access, o_access; + dds_presentation_access_scope_kind_t pr_kind; + uint32_t mask; + + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant with autoenable=false */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a default subscriber that should be disabled + * and has autoenable=true */ + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(subscriber > 0); + sqos = dds_create_qos(); + ret = dds_get_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(sqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* the subscriber should be disabled because the participant + * has autoenable=false. To check that the subscriber is really + * disabled try to set an immutable qos. We use the presentation qos + * for that purpose. Setting it should succeed. */ + dds_qset_presentation(sqos, DDS_PRESENTATION_GROUP, true, true); + ret = dds_set_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that change is qos is really accepted */ + ret = dds_get_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_presentation(sqos, &pr_kind,&c_access, &o_access); + CU_ASSERT_EQUAL_FATAL(pr_kind, DDS_PRESENTATION_GROUP); + CU_ASSERT_EQUAL_FATAL(c_access, true); + CU_ASSERT_EQUAL_FATAL(o_access, true); + /* the following operations should all be available on a + * disabled entity: set_qos, get_qos, get_status_condition, + * factory operations, get_status_changes, lookup operations + * We already checked the dds_set_qos(), dds_get_qos() and + * getting/setting factory settings, so let's + * check get_status_changes() now + */ + ret = dds_get_status_changes(subscriber, &mask); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* now enable the subscriber and try again to set the + * presentation qos. This should now result in IMMUTABLE_POLICY + * because the subscriber is already enabled */ + ret = dds_enable(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qset_presentation(sqos, DDS_PRESENTATION_INSTANCE, false, false); + ret = dds_set_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + ret = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(sqos); + dds_delete_qos(pqos); +} + +CU_Test(ddsc_subscriber, delete_disabled_subscriber) { + dds_entity_t participant, subscriber; + dds_qos_t *pqos; + dds_return_t ret; + + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant with autoenable=false */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a default subscriber that should be disabled */ + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(subscriber > 0); + /* delete the participant */ + ret = dds_delete(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pqos); +} + +CU_Test(ddsc_subscriber, not_enabled) { + dds_entity_t participant, subscriber, reader, topic; + dds_qos_t *pqos, *sqos, *rqos; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + + pqos = dds_create_qos(); + sqos = dds_create_qos(); + rqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant with autoenable=false */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a default subscriber that should be disabled */ + subscriber = dds_create_subscriber(participant, NULL, NULL); + CU_ASSERT_FATAL(subscriber > 0); + /* dds_get_qos */ + ret = dds_get_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qset_presentation(sqos, DDS_PRESENTATION_GROUP, true, true); + /* dds_set_qos */ + ret = dds_set_qos(subscriber, sqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* dds_create_topic */ + topic = dds_create_topic(participant, &Space_Type1_desc, "ddsc_participant_disabled", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + /* dds_create_reader */ + reader = dds_create_reader(participant, topic, NULL, NULL); + CU_ASSERT_FATAL(reader > 0); + dds_qset_history(rqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(reader, rqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(rqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* dds_delete_reader */ + ret = dds_delete(reader); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* dds_begin_coherent --> currently not implemented, + * but should return DDS_RETCODE_NOT_ENABLED once implemented */ + ret = dds_begin_coherent(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_UNSUPPORTED); + /* dds_end_coherent --> currently not implemented, + * but should return DDS_RETCODE_NOT_ENABLED once implemented */ + ret = dds_end_coherent(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_UNSUPPORTED); + /* dds_triggered */ + ret = dds_triggered(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_NOT_ENABLED); + /* dds_notify_readers --> currently unsupported, but once + * supported DDS_RETCODE_NOT_ENABLED should be returned */ + ret = dds_notify_readers(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_UNSUPPORTED); + /* dds_enable */ + ret = dds_enable(subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* dds_delete */ + ret = dds_delete (subscriber); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pqos); + dds_delete_qos(sqos); + dds_delete_qos(rqos); +} + #ifdef _MSC_VER #pragma warning(pop) #endif diff --git a/src/core/ddsc/tests/writer.c b/src/core/ddsc/tests/writer.c index 6f63447897..45a8191787 100644 --- a/src/core/ddsc/tests/writer.c +++ b/src/core/ddsc/tests/writer.c @@ -140,3 +140,287 @@ CU_Test(ddsc_create_writer, participant_mismatch, .init = setup, .fini = teardow dds_delete(l_pub); dds_delete(l_par); } + +CU_Test(ddsc_writer, enable_by_default) { + dds_return_t status, status1; + dds_qos_t *pqos, *wqos; + bool autoenable; + + /* check that default autoenable setting of participant is true */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + pqos = dds_create_qos(); + status = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* check that default autoenable setting of publisher is true */ + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, "ddsc_writer_enable", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + writer = dds_create_writer(publisher, topic, NULL, NULL); + CU_ASSERT_FATAL(writer > 0); + wqos = dds_create_qos(); + status = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + status = dds_qget_entity_factory(wqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + + /* enabling an already enabled entity is a noop */ + status1 = dds_enable (writer); + CU_ASSERT_EQUAL_FATAL(status1, DDS_RETCODE_OK); + + /* we check that the writer is really enabled + * by trying to set a qos that cannot be changed once + * the reader is enabled. We use the history qos + * for that purpose */ + dds_qset_history(wqos, DDS_HISTORY_KEEP_ALL, 0); + status = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_IMMUTABLE_POLICY); + status = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(status, DDS_RETCODE_OK); + dds_delete_qos(pqos); + dds_delete_qos(wqos); +} + +CU_Test(ddsc_writer, disable_writer_enable_later) { + dds_qos_t *pqos, *wqos; + bool autoenable; + bool status; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant with autoenable=false */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a default publisher that should be disabled */ + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, "ddsc_writer_enable", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + writer = dds_create_writer(publisher, topic, NULL, NULL); + CU_ASSERT_FATAL(writer > 0); + /* get the autoenable value for this writer */ + wqos = dds_create_qos(); + ret = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(wqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* the autoenable is true, but the writer should + * not be enabled because the publisher was not enabled + * Because there is no explicit call to find out if an entity + * is enabled we do this by trying to set an immutable qos + * on the writer. This should succeed if the writer + * is not yet enabled, and fail if it is. We use the history + * qos for that purpose */ + dds_qset_history(wqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that qos is really changed */ + ret = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(wqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* now try to enable the writer and set the immutable + * reader qos again. We should not be able to enable the + * writer because the publisher is still disabled. + * The writer remains disabled and we should still be able + * to modify its immutable qos */ + ret = dds_enable(writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); + dds_qset_history(wqos, DDS_HISTORY_KEEP_LAST, 20); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that qos is really changed */ + ret = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(wqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_LAST); + CU_ASSERT_EQUAL_FATAL(hist_depth, 20); + /* now enable the publisher and the writer, and try + * to set an immutable qos. This then should fail */ + ret = dds_enable(publisher); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_enable(writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qset_history(wqos, DDS_HISTORY_KEEP_LAST, 30); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + /* check that qos has not changed */ + ret = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(wqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_LAST); + CU_ASSERT_EQUAL_FATAL(hist_depth, 20); + ret = dds_delete (participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(wqos); + dds_delete_qos(pqos); +} + +CU_Test(ddsc_writer, delete_disabled_writer) { + dds_qos_t *pubqos, *wqos; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + + /* create a participant */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a publisher with autoenable=false */ + pubqos = dds_create_qos(); + dds_qset_entity_factory(pubqos, false); + publisher = dds_create_publisher(participant, pubqos, NULL); + CU_ASSERT_FATAL(publisher > 0); + /* create a writer */ + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, "ddsc_writer_enable", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + writer = dds_create_writer(publisher, topic, NULL, NULL); + CU_ASSERT_FATAL(writer > 0); + /* check that the writer is disabled by + * trying to set an immutable qos. This should succeed + * First check that current value is KEEPLAST-1 */ + wqos = dds_create_qos(); + ret = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(wqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_LAST); + CU_ASSERT_EQUAL_FATAL(hist_depth, 1); + /* Now change the qos */ + dds_qset_history(wqos, DDS_HISTORY_KEEP_LAST, 10); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that qos is really changed */ + ret = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(wqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_LAST); + CU_ASSERT_EQUAL_FATAL(hist_depth, 10); + /* Now we know that the writer is disabled. + * Let's now delete the participant */ + ret = dds_delete(writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(wqos); + dds_delete_qos(pubqos); +} + +CU_Test(ddsc_writer, delete_parent_of_disabled_reader) { + dds_qos_t *pubqos; + dds_return_t ret; + + /* create a participant */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, NULL, NULL); + CU_ASSERT_FATAL(participant > 0); + /* create a publisher with autoenable=false */ + pubqos = dds_create_qos(); + dds_qset_entity_factory(pubqos, false); + publisher = dds_create_publisher(participant, pubqos, NULL); + CU_ASSERT_FATAL(publisher > 0); + /* create a writer */ + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, "ddsc_writer_disabled", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + writer = dds_create_writer(publisher, topic, NULL, NULL); + CU_ASSERT_FATAL(writer > 0); + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(pubqos); +} + +CU_Test(ddsc_writer, autoenable_disabled_writer) { + dds_qos_t *pqos, *pubqos, *wqos; + bool autoenable; + bool status; + dds_return_t ret; + dds_history_kind_t hist_kind; + int32_t hist_depth; + + pqos = dds_create_qos(); + dds_qset_entity_factory(pqos, false); + /* create a participant with autoenable=false */ + participant = dds_create_participant (DDS_DOMAIN_DEFAULT, pqos, NULL); + CU_ASSERT_FATAL(participant > 0); + ret = dds_get_qos(participant, pqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, false); + /* create a disabled publisher */ + publisher = dds_create_publisher(participant, NULL, NULL); + CU_ASSERT_FATAL(publisher > 0); + /* check that autoenable of the publisher is set to true */ + pubqos = dds_create_qos(); + ret = dds_get_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + status = dds_qget_entity_factory(pubqos, &autoenable); + CU_ASSERT_EQUAL_FATAL(status, true); + CU_ASSERT_EQUAL_FATAL(autoenable, true); + /* create topic */ + topic = dds_create_topic(participant, &RoundTripModule_DataType_desc, "ddsc_writer_disabled", NULL, NULL); + CU_ASSERT_FATAL(topic > 0); + /* create a writer */ + writer = dds_create_writer(publisher, topic, NULL, NULL); + CU_ASSERT_FATAL(writer > 0); + /* the writer should be disabled because the publisher + * is disabled. To check that the writer is really + * disabled try to set an immutable qos. We use the history + * qos for that purpose. Setting it should succeed. */ + wqos = dds_create_qos(); + dds_qset_history(wqos, DDS_HISTORY_KEEP_ALL, 0); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that qos is really changed */ + ret = dds_get_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_qget_history(wqos, &hist_kind,&hist_depth); + CU_ASSERT_EQUAL_FATAL(hist_kind, DDS_HISTORY_KEEP_ALL); + CU_ASSERT_EQUAL_FATAL(hist_depth, 0); + /* enable the writer, this should fail + * because the publisher is not yet enabled */ + ret = dds_enable(writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_PRECONDITION_NOT_MET); + /* Check that the writer is still disabled + * by trying to set an immutable qos */ + dds_qset_history(wqos, DDS_HISTORY_KEEP_ALL, 10); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* enable the publisher */ + ret = dds_enable(publisher); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* to check that the publisher is enabled + * we try to set an immutable qos, this should + * fail */ + dds_qset_presentation(pubqos, DDS_PRESENTATION_GROUP, true, true); + ret = dds_set_qos(publisher, pubqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + /* the writer must be enabled because + * the writer was created using a publisher + * with autoenabled=true and the publisher + * has been enabled. To check whether the writer + * is enabled we try setting an immutable qos, + * this should fail */ + dds_qset_history(wqos, DDS_HISTORY_KEEP_ALL, 20); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + /* now enable the writer, this should be a noop */ + ret = dds_enable(writer); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + /* check that the writer is enabled by trying to set an immutable qos */ + dds_qset_history(wqos, DDS_HISTORY_KEEP_ALL, 30); + ret = dds_set_qos(writer, wqos); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_IMMUTABLE_POLICY); + ret = dds_delete(participant); + CU_ASSERT_EQUAL_FATAL(ret, DDS_RETCODE_OK); + dds_delete_qos(wqos); + dds_delete_qos(pubqos); + dds_delete_qos(pqos); +} diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_builtin_topic_if.h b/src/core/ddsi/include/dds/ddsi/ddsi_builtin_topic_if.h index db349759d9..c89b3bf0f6 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_builtin_topic_if.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_builtin_topic_if.h @@ -29,6 +29,7 @@ struct ddsi_builtin_topic_interface { bool (*builtintopic_is_builtintopic) (const struct ddsi_sertype *type, void *arg); bool (*builtintopic_is_visible) (const struct ddsi_guid *guid, nn_vendorid_t vendorid, void *arg); struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry) (const struct ddsi_guid *guid, void *arg); + struct ddsi_tkmap_instance * (*builtintopic_get_tkmap_entry_with_iid) (const struct ddsi_guid *guid, const uint64_t iid, void *arg); void (*builtintopic_write) (const struct entity_common *e, ddsrt_wctime_t timestamp, bool alive, void *arg); }; @@ -41,6 +42,9 @@ inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interf inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid) { return btif ? btif->builtintopic_get_tkmap_entry (guid, btif->arg) : NULL; } +inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry_with_iid (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid, const uint64_t iid) { + return btif ? btif->builtintopic_get_tkmap_entry_with_iid (guid, iid, btif->arg) : NULL; +} inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, ddsrt_wctime_t timestamp, bool alive) { if (btif) btif->builtintopic_write (e, timestamp, alive, btif->arg); } diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h b/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h index e29460b1ca..86ba8e2023 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_tkmap.h @@ -36,6 +36,7 @@ DDS_EXPORT void ddsi_tkmap_free (struct ddsi_tkmap *tkmap); DDS_EXPORT void ddsi_tkmap_instance_ref (struct ddsi_tkmap_instance *tk); DDS_EXPORT uint64_t ddsi_tkmap_lookup (struct ddsi_tkmap *tkmap, const struct ddsi_serdata *serdata); DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_find(struct ddsi_tkmap *map, struct ddsi_serdata *sd, const bool create); +DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_find_with_iid(struct ddsi_tkmap *map, struct ddsi_serdata *sd, const uint64_t iid, const bool create); DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_find_by_id (struct ddsi_tkmap *map, uint64_t iid); DDS_EXPORT struct ddsi_tkmap_instance * ddsi_tkmap_lookup_instance_ref (struct ddsi_tkmap *map, struct ddsi_serdata * sd); DDS_EXPORT void ddsi_tkmap_instance_unref (struct ddsi_tkmap *map, struct ddsi_tkmap_instance *tk); diff --git a/src/core/ddsi/include/dds/ddsi/q_entity.h b/src/core/ddsi/include/dds/ddsi/q_entity.h index d058dd1157..461442ca2f 100644 --- a/src/core/ddsi/include/dds/ddsi/q_entity.h +++ b/src/core/ddsi/include/dds/ddsi/q_entity.h @@ -593,12 +593,14 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e); * @param[in] flags * Zero or more of: * - RTPS_PF_NO_BUILTIN_READERS do not create discovery readers in new ppant - * - RTPS_PF_NO_BUILTIN_WRITERS do not create discvoery writers in new ppant + * - RTPS_PF_NO_BUILTIN_WRITERS do not create discovery writers in new ppant * - RTPS_PF_PRIVILEGED_PP FIXME: figure out how to describe this ... * - RTPS_PF_IS_DDSI2_PP FIXME: OSPL holdover - there is no DDSI2E here * - RTPS_PF_ONLY_LOCAL FIXME: not used, it seems * @param[in] plist * Parameters/QoS for this participant + * @param[in] iid + * Instance id for this participant * * @returns A dds_return_t indicating success or failure. * @@ -610,7 +612,7 @@ nn_vendorid_t get_entity_vendorid (const struct entity_common *e); * @retval DDS_RETCODE_OUT_OF_RESOURCES * The configured maximum number of participants has been reached. */ -dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist); +dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist, const uint64_t iid); /** * @brief Create a new participant in the domain. See also new_participant_guid. @@ -622,6 +624,8 @@ dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv * See new_participant_guid * @param[in] plist * See new_participant_guid + * @param[in] iid + * Participant instance id * * @returns A dds_return_t indicating success or failure. * @@ -634,7 +638,7 @@ dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv * @retval DDS_RETCODE_OUT_OF_RESOURCES * The configured maximum number of participants has been reached. */ -dds_return_t new_participant (struct ddsi_guid *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist); +dds_return_t new_participant (struct ddsi_guid *ppguid, struct ddsi_domaingv *gv, unsigned flags, const struct ddsi_plist *plist, const uint64_t iid); /** * @brief Initiate the deletion of the participant: @@ -677,8 +681,8 @@ DDS_EXPORT struct writer *get_builtin_writer (const struct participant *pp, unsi GUID "ppguid". May return NULL if participant unknown or writer/reader already known. */ -dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg); -dds_return_t new_reader (struct reader **rd_out, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg); +dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg, const uint64_t iid); +dds_return_t new_reader (struct reader **rd_out, struct ddsi_guid *rdguid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, void *status_cb_arg, const uint64_t iid); void update_reader_qos (struct reader *rd, const struct dds_qos *xqos); void update_writer_qos (struct writer *wr, const struct dds_qos *xqos); diff --git a/src/core/ddsi/src/ddsi_plist.c b/src/core/ddsi/src/ddsi_plist.c index ae3ea37e98..0eb47bfe85 100644 --- a/src/core/ddsi/src/ddsi_plist.c +++ b/src/core/ddsi/src/ddsi_plist.c @@ -3165,7 +3165,7 @@ void ddsi_plist_init_default_participant (ddsi_plist_t *plist) ddsi_plist_init_empty (plist); plist->qos.present |= QP_ADLINK_ENTITY_FACTORY; - plist->qos.entity_factory.autoenable_created_entities = 0; + plist->qos.entity_factory.autoenable_created_entities = 1; plist->qos.present |= QP_USER_DATA; plist->qos.user_data.length = 0; diff --git a/src/core/ddsi/src/ddsi_tkmap.c b/src/core/ddsi/src/ddsi_tkmap.c index 45b39cee46..f8accd4623 100644 --- a/src/core/ddsi/src/ddsi_tkmap.c +++ b/src/core/ddsi/src/ddsi_tkmap.c @@ -155,7 +155,7 @@ struct ddsi_tkmap_instance *ddsi_tkmap_find_by_id (struct ddsi_tkmap *map, uint6 #define DDS_DEBUG_KEYHASH 1 #endif -struct ddsi_tkmap_instance *ddsi_tkmap_find (struct ddsi_tkmap *map, struct ddsi_serdata *sd, const bool create) +static struct ddsi_tkmap_instance *ddsi_tkmap_find_common (struct ddsi_tkmap *map, struct ddsi_serdata *sd, const uint64_t iid, const bool create) { struct ddsi_tkmap_instance dummy; struct ddsi_tkmap_instance *tk; @@ -189,7 +189,7 @@ struct ddsi_tkmap_instance *ddsi_tkmap_find (struct ddsi_tkmap *map, struct ddsi tk->m_sample = ddsi_serdata_to_untyped (sd); ddsrt_atomic_st32 (&tk->m_refc, 1); - tk->m_iid = ddsi_iid_gen (); + tk->m_iid = (iid == 0) ? ddsi_iid_gen() : iid; if (!ddsrt_chh_add (map->m_hh, tk)) { /* Lost a race from another thread, retry */ @@ -201,6 +201,20 @@ struct ddsi_tkmap_instance *ddsi_tkmap_find (struct ddsi_tkmap *map, struct ddsi return tk; } +struct ddsi_tkmap_instance *ddsi_tkmap_find (struct ddsi_tkmap *map, struct ddsi_serdata *sd, const bool create) +{ + return ddsi_tkmap_find_common (map, sd, 0, create); +} + +struct ddsi_tkmap_instance *ddsi_tkmap_find_with_iid (struct ddsi_tkmap *map, struct ddsi_serdata *sd, const uint64_t iid, const bool create) +{ + struct ddsi_tkmap_instance *tk; + + tk = ddsi_tkmap_find_common (map, sd, iid, create); + assert(!tk || (tk->m_iid == iid)); + return tk; +} + struct ddsi_tkmap_instance *ddsi_tkmap_lookup_instance_ref (struct ddsi_tkmap *map, struct ddsi_serdata *sd) { return ddsi_tkmap_find (map, sd, true); diff --git a/src/core/ddsi/src/q_entity.c b/src/core/ddsi/src/q_entity.c index 2a74e11df7..09d0daa68f 100644 --- a/src/core/ddsi/src/q_entity.c +++ b/src/core/ddsi/src/q_entity.c @@ -106,8 +106,8 @@ static const unsigned builtin_writers_besmask = #endif ; -static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg); -static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct ddsi_rhc *rhc, status_cb_t status_cb, void *status_cbarg); +static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_cbarg, const uint64_t iid); +static dds_return_t new_reader_guid (struct reader **rd_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct ddsi_rhc *rhc, status_cb_t status_cb, void *status_cbarg, const uint64_t iid); static struct participant *ref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity); static void unref_participant (struct participant *pp, const struct ddsi_guid *guid_of_refing_entity); static struct entity_common *entity_common_from_proxy_endpoint_common (const struct proxy_endpoint_common *c); @@ -127,6 +127,7 @@ static int gcreq_proxy_reader (struct proxy_reader *prd); extern inline bool builtintopic_is_visible (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid, nn_vendorid_t vendorid); extern inline bool builtintopic_is_builtintopic (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_sertype *type); extern inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid); +extern inline struct ddsi_tkmap_instance *builtintopic_get_tkmap_entry_with_iid (const struct ddsi_builtin_topic_interface *btif, const struct ddsi_guid *guid, const uint64_t iid); extern inline void builtintopic_write (const struct ddsi_builtin_topic_interface *btif, const struct entity_common *e, ddsrt_wctime_t timestamp, bool alive); extern inline seqno_t writer_read_seq_xmit (const struct writer *wr); @@ -249,7 +250,7 @@ const ddsrt_fibheap_def_t ldur_fhdef = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (st /* used in (proxy)participant for writer liveliness monitoring */ const ddsrt_fibheap_def_t lease_fhdef_pp = DDSRT_FIBHEAPDEF_INITIALIZER(offsetof (struct lease, pp_heapnode), compare_lease_tdur); -static void entity_common_init (struct entity_common *e, struct ddsi_domaingv *gv, const struct ddsi_guid *guid, const char *name, enum entity_kind kind, ddsrt_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal) +static void entity_common_init (struct entity_common *e, struct ddsi_domaingv *gv, const struct ddsi_guid *guid, const char *name, enum entity_kind kind, ddsrt_wctime_t tcreate, nn_vendorid_t vendorid, bool onlylocal, uint64_t iid) { e->guid = *guid; e->kind = kind; @@ -261,13 +262,13 @@ static void entity_common_init (struct entity_common *e, struct ddsi_domaingv *g ddsrt_mutex_init (&e->qos_lock); if (builtintopic_is_visible (gv->builtin_topic_interface, guid, vendorid)) { - e->tk = builtintopic_get_tkmap_entry (gv->builtin_topic_interface, guid); + e->tk = (iid == 0) ? builtintopic_get_tkmap_entry (gv->builtin_topic_interface, guid) : builtintopic_get_tkmap_entry_with_iid (gv->builtin_topic_interface, guid, iid); e->iid = e->tk->m_iid; } else { e->tk = NULL; - e->iid = ddsi_iid_gen (); + e->iid = (iid == 0) ? ddsi_iid_gen() : iid; } } @@ -569,7 +570,7 @@ static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t * subguid->entityid = to_entityid (NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_WRITER); wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_SECURE_NAME, gv->spdp_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_SECURE_NAME, gv->spdp_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL, 0); whc_free_wrinfo (wrinfo); /* But we need the as_disc address set for SPDP, because we need to send it to everyone regardless of the existence of readers. */ @@ -578,28 +579,28 @@ static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t * subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_WRITER); wrinfo = whc_make_wrinfo (NULL, &gv->builtin_stateless_xqos_wr); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_STATELESS_MESSAGE_NAME, gv->pgm_stateless_type, &gv->builtin_stateless_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_STATELESS_MESSAGE_NAME, gv->pgm_stateless_type, &gv->builtin_stateless_xqos_wr, whc_new(gv, wrinfo), NULL, NULL, 0); whc_free_wrinfo (wrinfo); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_WRITER); wrinfo = whc_make_wrinfo (NULL, &gv->builtin_secure_volatile_xqos_wr); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_VOLATILE_MESSAGE_SECURE_NAME, gv->pgm_volatile_type, &gv->builtin_secure_volatile_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_VOLATILE_MESSAGE_SECURE_NAME, gv->pgm_volatile_type, &gv->builtin_secure_volatile_xqos_wr, whc_new(gv, wrinfo), NULL, NULL, 0); whc_free_wrinfo (wrinfo); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_ANNOUNCER; wrinfo = whc_make_wrinfo (NULL, &gv->builtin_endpoint_xqos_wr); subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_SECURE_NAME, gv->pmd_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_SECURE_NAME, gv->pmd_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_SECURE_NAME, gv->sedp_writer_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_SECURE_NAME, gv->sedp_writer_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_SECURE_NAME, gv->sedp_reader_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_SECURE_NAME, gv->sedp_reader_secure_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo), NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_ANNOUNCER; whc_free_wrinfo (wrinfo); @@ -608,11 +609,11 @@ static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t * if (add_readers) { subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_SECURE_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_SECURE_NAME, gv->sedp_reader_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_SECURE_NAME, gv->sedp_reader_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_SUBSCRIPTION_MESSAGE_SECURE_DETECTOR; subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_SECURE_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_SECURE_NAME, gv->sedp_writer_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_SECURE_NAME, gv->sedp_writer_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PUBLICATION_MESSAGE_SECURE_DETECTOR; } @@ -621,19 +622,19 @@ static void add_security_builtin_endpoints(struct participant *pp, ddsi_guid_t * * besmode flag setting, because all participant do require authentication. */ subguid->entityid = to_entityid (NN_ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_SECURE_NAME, gv->spdp_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_SECURE_NAME, gv->spdp_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_SECURE_DETECTOR; subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_VOLATILE_SECURE_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_VOLATILE_MESSAGE_SECURE_NAME, gv->pgm_volatile_type, &gv->builtin_secure_volatile_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_VOLATILE_MESSAGE_SECURE_NAME, gv->pgm_volatile_type, &gv->builtin_secure_volatile_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_VOLATILE_SECURE_DETECTOR; subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_STATELESS_MESSAGE_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_STATELESS_MESSAGE_NAME, gv->pgm_stateless_type, &gv->builtin_stateless_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_STATELESS_MESSAGE_NAME, gv->pgm_stateless_type, &gv->builtin_stateless_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_STATELESS_MESSAGE_DETECTOR; subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_SECURE_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_SECURE_NAME, gv->pmd_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_SECURE_NAME, gv->pmd_secure_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_SECURE_DETECTOR; } #endif @@ -646,16 +647,16 @@ static void add_builtin_endpoints(struct participant *pp, ddsi_guid_t *subguid, /* SEDP writers: */ subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_NAME, gv->sedp_reader_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo_tl), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_NAME, gv->sedp_reader_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo_tl), NULL, NULL, 0); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_ANNOUNCER; subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_NAME, gv->sedp_writer_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo_tl), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_NAME, gv->sedp_writer_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo_tl), NULL, NULL, 0); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_ANNOUNCER; /* PMD writer: */ subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_NAME, gv->pmd_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo_tl), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_NAME, gv->pmd_type, &gv->builtin_endpoint_xqos_wr, whc_new(gv, wrinfo_tl), NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_WRITER; whc_free_wrinfo (wrinfo_tl); @@ -664,11 +665,11 @@ static void add_builtin_endpoints(struct participant *pp, ddsi_guid_t *subguid, /* TypeLookup writers */ struct whc_writer_info *wrinfo_vol = whc_make_wrinfo (NULL, &gv->builtin_volatile_xqos_wr); subguid->entityid = to_entityid (NN_ENTITYID_TL_SVC_BUILTIN_REQUEST_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REQUEST_NAME, gv->tl_svc_request_type, &gv->builtin_volatile_xqos_wr, whc_new(gv, wrinfo_vol), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REQUEST_NAME, gv->tl_svc_request_type, &gv->builtin_volatile_xqos_wr, whc_new(gv, wrinfo_vol), NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_TL_SVC_REQUEST_DATA_WRITER; subguid->entityid = to_entityid (NN_ENTITYID_TL_SVC_BUILTIN_REPLY_WRITER); - new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REPLY_NAME, gv->tl_svc_reply_type, &gv->builtin_volatile_xqos_wr, whc_new(gv, wrinfo_vol), NULL, NULL); + new_writer_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REPLY_NAME, gv->tl_svc_reply_type, &gv->builtin_volatile_xqos_wr, whc_new(gv, wrinfo_vol), NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_TL_SVC_REPLY_DATA_WRITER; whc_free_wrinfo (wrinfo_vol); #endif @@ -678,31 +679,30 @@ static void add_builtin_endpoints(struct participant *pp, ddsi_guid_t *subguid, { /* SPDP reader: */ subguid->entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_NAME, gv->spdp_type, &gv->spdp_endpoint_xqos, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_NAME, gv->spdp_type, &gv->spdp_endpoint_xqos, NULL, NULL, NULL, 0); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PARTICIPANT_DETECTOR; /* SEDP readers: */ subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_SUBSCRIPTIONS_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_NAME, gv->sedp_reader_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_SUBSCRIPTION_NAME, gv->sedp_reader_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_SUBSCRIPTION_DETECTOR; subguid->entityid = to_entityid (NN_ENTITYID_SEDP_BUILTIN_PUBLICATIONS_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_NAME, gv->sedp_writer_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PUBLICATION_NAME, gv->sedp_writer_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_DISC_BUILTIN_ENDPOINT_PUBLICATION_DETECTOR; - /* PMD reader: */ subguid->entityid = to_entityid (NN_ENTITYID_P2P_BUILTIN_PARTICIPANT_MESSAGE_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_NAME, gv->pmd_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_MESSAGE_NAME, gv->pmd_type, &gv->builtin_endpoint_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_PARTICIPANT_MESSAGE_DATA_READER; #ifdef DDS_HAS_TYPE_DISCOVERY /* TypeLookup readers: */ subguid->entityid = to_entityid (NN_ENTITYID_TL_SVC_BUILTIN_REQUEST_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REQUEST_NAME, gv->tl_svc_request_type, &gv->builtin_volatile_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REQUEST_NAME, gv->tl_svc_request_type, &gv->builtin_volatile_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_TL_SVC_REQUEST_DATA_READER; subguid->entityid = to_entityid (NN_ENTITYID_TL_SVC_BUILTIN_REPLY_READER); - new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REPLY_NAME, gv->tl_svc_reply_type, &gv->builtin_volatile_xqos_rd, NULL, NULL, NULL); + new_reader_guid (NULL, subguid, group_guid, pp, DDS_BUILTIN_TOPIC_TYPELOOKUP_REPLY_NAME, gv->tl_svc_reply_type, &gv->builtin_volatile_xqos_rd, NULL, NULL, NULL, 0); pp->bes |= NN_BUILTIN_ENDPOINT_TL_SVC_REPLY_DATA_READER; #endif } @@ -904,7 +904,7 @@ static dds_return_t check_and_load_security_config (struct ddsi_domaingv * const } #endif -dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist) +dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist, const uint64_t iid) { struct participant *pp; ddsi_guid_t subguid, group_guid; @@ -968,7 +968,7 @@ dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv pp = ddsrt_malloc (sizeof (*pp)); - entity_common_init (&pp->e, gv, ppguid, "", EK_PARTICIPANT, ddsrt_time_wallclock (), NN_VENDORID_ECLIPSE, ((flags & RTPS_PF_ONLY_LOCAL) != 0)); + entity_common_init (&pp->e, gv, ppguid, "", EK_PARTICIPANT, ddsrt_time_wallclock (), NN_VENDORID_ECLIPSE, ((flags & RTPS_PF_ONLY_LOCAL) != 0), iid); pp->user_refc = 1; pp->builtin_refc = 0; pp->builtins_deleted = 0; @@ -1028,7 +1028,7 @@ dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv { subguid.entityid = to_entityid (NN_ENTITYID_SPDP_BUILTIN_PARTICIPANT_WRITER); wrinfo = whc_make_wrinfo (NULL, &gv->spdp_endpoint_xqos); - new_writer_guid (NULL, &subguid, &group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_NAME, gv->spdp_type, &gv->spdp_endpoint_xqos, whc_new(gv, wrinfo), NULL, NULL); + new_writer_guid (NULL, &subguid, &group_guid, pp, DDS_BUILTIN_TOPIC_PARTICIPANT_NAME, gv->spdp_type, &gv->spdp_endpoint_xqos, whc_new(gv, wrinfo), NULL, NULL, 0); whc_free_wrinfo (wrinfo); /* But we need the as_disc address set for SPDP, because we need to send it to everyone regardless of the existence of readers. */ @@ -1129,7 +1129,7 @@ dds_return_t new_participant_guid (ddsi_guid_t *ppguid, struct ddsi_domaingv *gv return ret; } -dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist) +dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct ddsi_domaingv *gv, unsigned flags, const ddsi_plist_t *plist, const uint64_t iid) { union { uint64_t u64; uint32_t u32[2]; } u; u.u32[0] = gv->ppguid_base.prefix.u[1]; @@ -1139,7 +1139,7 @@ dds_return_t new_participant (ddsi_guid_t *p_ppguid, struct ddsi_domaingv *gv, u p_ppguid->prefix.u[1] = u.u32[0]; p_ppguid->prefix.u[2] = u.u32[1]; p_ppguid->entityid.u = NN_ENTITYID_PARTICIPANT; - return new_participant_guid (p_ppguid, gv, flags, plist); + return new_participant_guid (p_ppguid, gv, flags, plist, iid); } void update_participant_plist (struct participant *pp, const ddsi_plist_t *plist) @@ -3430,12 +3430,12 @@ static void new_reader_writer_common (const struct ddsrt_log_cfg *logcfg, const type_name); } -static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct ddsi_domaingv *gv, enum entity_kind kind, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, bool onlylocal, const struct ddsi_sertype *type) +static void endpoint_common_init (struct entity_common *e, struct endpoint_common *c, struct ddsi_domaingv *gv, enum entity_kind kind, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, bool onlylocal, const struct ddsi_sertype *type, uint64_t iid) { #ifndef DDS_HAS_TYPE_DISCOVERY DDSRT_UNUSED_ARG (type); #endif - entity_common_init (e, gv, guid, NULL, kind, ddsrt_time_wallclock (), NN_VENDORID_ECLIPSE, pp->e.onlylocal || onlylocal); + entity_common_init (e, gv, guid, NULL, kind, ddsrt_time_wallclock (), NN_VENDORID_ECLIPSE, pp->e.onlylocal || onlylocal, iid); c->pp = ref_participant (pp, &e->guid); if (group_guid) c->group_guid = *group_guid; @@ -3947,7 +3947,7 @@ static void new_writer_guid_common_init (struct writer *wr, const char *topic_na local_reader_ary_init (&wr->rdary); } -static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity) +static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_guid *guid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc *whc, status_cb_t status_cb, void *status_entity, const uint64_t iid) { struct writer *wr; ddsrt_mtime_t tnow = ddsrt_time_monotonic (); @@ -3966,7 +3966,7 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g the participant */ const bool onlylocal = builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, type); - endpoint_common_init (&wr->e, &wr->c, pp->e.gv, EK_WRITER, guid, group_guid, pp, onlylocal, type); + endpoint_common_init (&wr->e, &wr->c, pp->e.gv, EK_WRITER, guid, group_guid, pp, onlylocal, type, iid); new_writer_guid_common_init(wr, topic_name, type, xqos, whc, status_cb, status_entity); #ifdef DDS_HAS_SECURITY @@ -4027,7 +4027,7 @@ static dds_return_t new_writer_guid (struct writer **wr_out, const struct ddsi_g return 0; } -dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg) +dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const struct ddsi_guid *group_guid, struct participant *pp, const char *topic_name, const struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc * whc, status_cb_t status_cb, void *status_cb_arg, const uint64_t iid) { dds_return_t rc; uint32_t kind; @@ -4039,7 +4039,7 @@ dds_return_t new_writer (struct writer **wr_out, struct ddsi_guid *wrguid, const kind = type->typekind_no_key ? NN_ENTITYID_KIND_WRITER_NO_KEY : NN_ENTITYID_KIND_WRITER_WITH_KEY; if ((rc = pp_allocate_entityid (&wrguid->entityid, kind, pp)) < 0) return rc; - return new_writer_guid (wr_out, wrguid, group_guid, pp, topic_name, type, xqos, whc, status_cb, status_cb_arg); + return new_writer_guid (wr_out, wrguid, group_guid, pp, topic_name, type, xqos, whc, status_cb, status_cb_arg, iid); } struct local_orphan_writer *new_local_orphan_writer (struct ddsi_domaingv *gv, ddsi_entityid_t entityid, const char *topic_name, struct ddsi_sertype *type, const struct dds_qos *xqos, struct whc *whc) @@ -4055,7 +4055,7 @@ struct local_orphan_writer *new_local_orphan_writer (struct ddsi_domaingv *gv, d memset (&guid.prefix, 0, sizeof (guid.prefix)); guid.entityid = entityid; - entity_common_init (&wr->e, gv, &guid, NULL, EK_WRITER, ddsrt_time_wallclock (), NN_VENDORID_ECLIPSE, true); + entity_common_init (&wr->e, gv, &guid, NULL, EK_WRITER, ddsrt_time_wallclock (), NN_VENDORID_ECLIPSE, true, 0); wr->c.pp = NULL; memset (&wr->c.group_guid, 0, sizeof (wr->c.group_guid)); @@ -4461,10 +4461,11 @@ static dds_return_t new_reader_guid const struct dds_qos *xqos, struct ddsi_rhc *rhc, status_cb_t status_cb, - void * status_entity + void * status_entity, + const uint64_t iid ) { - /* see new_writer_guid for commenets */ + /* see new_writer_guid for comments */ struct reader *rd; ddsrt_mtime_t tnow = ddsrt_time_monotonic (); @@ -4479,7 +4480,7 @@ static dds_return_t new_reader_guid *rd_out = rd; const bool onlylocal = builtintopic_is_builtintopic (pp->e.gv->builtin_topic_interface, type); - endpoint_common_init (&rd->e, &rd->c, pp->e.gv, EK_READER, guid, group_guid, pp, onlylocal, type); + endpoint_common_init (&rd->e, &rd->c, pp->e.gv, EK_READER, guid, group_guid, pp, onlylocal, type, iid); /* Copy QoS, merging in defaults */ rd->xqos = ddsrt_malloc (sizeof (*rd->xqos)); @@ -4610,7 +4611,8 @@ dds_return_t new_reader const struct dds_qos *xqos, struct ddsi_rhc * rhc, status_cb_t status_cb, - void * status_cbarg + void * status_cbarg, + const uint64_t iid ) { dds_return_t rc; @@ -4620,7 +4622,7 @@ dds_return_t new_reader kind = type->typekind_no_key ? NN_ENTITYID_KIND_READER_NO_KEY : NN_ENTITYID_KIND_READER_WITH_KEY; if ((rc = pp_allocate_entityid (&rdguid->entityid, kind, pp)) < 0) return rc; - return new_reader_guid (rd_out, rdguid, group_guid, pp, topic_name, type, xqos, rhc, status_cb, status_cbarg); + return new_reader_guid (rd_out, rdguid, group_guid, pp, topic_name, type, xqos, rhc, status_cb, status_cbarg, iid); } static void gc_delete_reader (struct gcreq *gcreq) @@ -5121,7 +5123,7 @@ bool new_proxy_participant (struct ddsi_domaingv *gv, const struct ddsi_guid *pp proxypp = ddsrt_malloc (sizeof (*proxypp)); - entity_common_init (&proxypp->e, gv, ppguid, "", EK_PROXY_PARTICIPANT, timestamp, vendor, false); + entity_common_init (&proxypp->e, gv, ppguid, "", EK_PROXY_PARTICIPANT, timestamp, vendor, false, 0); proxypp->refc = 1; proxypp->lease_expired = 0; proxypp->deleting = 0; @@ -5579,7 +5581,7 @@ static int proxy_endpoint_common_init (struct entity_common *e, struct proxy_end assert ((plist->qos.present & (QP_TOPIC_NAME | QP_TYPE_NAME)) == (QP_TOPIC_NAME | QP_TYPE_NAME)); name = (plist->present & PP_ENTITY_NAME) ? plist->entity_name : ""; - entity_common_init (e, proxypp->e.gv, guid, name, kind, tcreate, proxypp->vendor, false); + entity_common_init (e, proxypp->e.gv, guid, name, kind, tcreate, proxypp->vendor, false, 0); c->xqos = ddsi_xqos_dup (&plist->qos); c->as = ref_addrset (as); c->vendor = proxypp->vendor; diff --git a/src/security/core/tests/common/test_utils.c b/src/security/core/tests/common/test_utils.c index 5d4839f904..d08809dd07 100644 --- a/src/security/core/tests/common/test_utils.c +++ b/src/security/core/tests/common/test_utils.c @@ -501,6 +501,9 @@ void rd_wr_init_fail( goto fail; dds_set_status_mask (*rd, DDS_SUBSCRIPTION_MATCHED_STATUS); } + dds_delete_qos (qos); + return; + fail: dds_delete_qos (qos); } diff --git a/src/security/core/tests/secure_communication.c b/src/security/core/tests/secure_communication.c index 4c98488999..1f4635c82b 100644 --- a/src/security/core/tests/secure_communication.c +++ b/src/security/core/tests/secure_communication.c @@ -448,7 +448,7 @@ CU_TheoryDataPoints(ddssec_secure_communication, multiple_readers) = { CU_DataPoints(size_t, 1, 3, 1, 3), /* number of participants per domain */ CU_DataPoints(size_t, 3, 1, 3, 3), /* number of readers per participant */ }; -CU_Theory((size_t n_dom, size_t n_pp, size_t n_rd), ddssec_secure_communication, multiple_readers, .timeout = 90, .disabled = false) +CU_Theory((size_t n_dom, size_t n_pp, size_t n_rd), ddssec_secure_communication, multiple_readers, .timeout = 120, .disabled = false) { DDS_Security_ProtectionKind metadata_pk[] = { PK_N, PK_SOA, PK_EOA }; DDS_Security_BasicProtectionKind payload_pk[] = { BPK_N, BPK_S, BPK_E };