Initializing domain with configuration as a string

For targets that do not support ddsrt_setenv and ddsrt_getenv, an alternative
method is needed to supply an application specific configuration. One way to
implement this, is to add a function for creating a domain with a string
arguments, which needs to be called before any call to dds_create_participant
for given domain identifier.

The function dds_create_domain has been added, which has as arguments a domain
identifier and a configuration string. The string is treated in the same way
as the string that is retrieved from the environment variable, in that it may
containt a comma separated list of file names and/or XML fragments for the
configuration.

Two tests have been added. One limits the number of participants to two and
verifies that creating a third participant fails. The other tests checks
incorrect calls to dds_create_domain.

An assert in dds_handle_delete has been weakened.

Signed-off-by: Frans Faase <frans.faase@adlinktech.com>
This commit is contained in:
Frans Faase 2019-09-13 11:45:14 +02:00 committed by eboasson
parent 67f7f56a62
commit f48bbd3d1c
8 changed files with 173 additions and 75 deletions

View file

@ -726,7 +726,7 @@ dds_set_listener(dds_entity_t entity, const dds_listener_t * listener);
* If no configuration file exists, the default domain is configured as 0.
*
*
* @param[in] domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). Valid values for domain id are between 0 and 230. DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
* @param[in] domain The domain in which to create the participant (can be DDS_DOMAIN_DEFAULT). DDS_DOMAIN_DEFAULT is for using the domain in the configuration.
* @param[in] qos The QoS to set on the new participant (can be NULL).
* @param[in] listener Any listener functions associated with the new participant (can be NULL).
@ -743,6 +743,33 @@ dds_create_participant(
const dds_qos_t *qos,
const dds_listener_t *listener);
/**
* @brief Creates a domain with a given configuration
*
* To explicitly create a domain based on a configuration passed as a string.
* Normally, the domain is created implicitly on the first call to
* dds_create_particiant based on the configuration specified throught
* the environment. This function allows to by-pass this behaviour.
*
*
* @param[in] domain The domain to be created. DEFAULT_DOMAIN is not allowed.
* @param[in] config A configuration string containing file names and/or XML fragments representing the configuration.
*
* @returns A return code
*
* @retval DDS_RETCODE_OK
* The domain with the domain identifier has been created from
* given configuration string.
* @retval DDS_RETCODE_BAD_PARAMETER
* Illegal value for domain id or the configfile parameter is NULL.
* @retval DDS_PRECONDITION_NOT_MET
* The domain already existed and cannot be created again.
* @retval DDS_RETCODE_ERROR
* An internal error has occurred.
*/
DDS_EXPORT dds_return_t
dds_create_domain(const dds_domainid_t domain, const char *config);
/**
* @brief Get entity parent.
*

View file

@ -18,7 +18,7 @@
extern "C" {
#endif
DDS_EXPORT dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id);
DDS_EXPORT dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config) ddsrt_nonnull((1,4));
DDS_EXPORT dds_domain *dds_domain_find_locked (dds_domainid_t id);
#if defined (__cplusplus)

View file

@ -11,7 +11,6 @@
*/
#include <string.h>
#include "dds/ddsrt/environ.h"
#include "dds/ddsrt/process.h"
#include "dds/ddsrt/heap.h"
#include "dds__init.h"
@ -28,7 +27,6 @@
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_gc.h"
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
static dds_return_t dds_domain_free (dds_entity *vdomain);
@ -50,7 +48,7 @@ static int dds_domain_compare (const void *va, const void *vb)
static const ddsrt_avl_treedef_t dds_domaintree_def = DDSRT_AVL_TREEDEF_INITIALIZER (
offsetof (dds_domain, m_node), offsetof (dds_domain, m_id), dds_domain_compare, 0);
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id)
static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_id, const char *config)
{
dds_return_t ret = DDS_RETCODE_OK;
char * uri = NULL;
@ -89,8 +87,7 @@ static dds_return_t dds_domain_init (dds_domain *domain, dds_domainid_t domain_i
a value (if nothing has been set previously, it a warning is good
enough) */
(void) ddsrt_getenv ("CYCLONEDDS_URI", &uri);
domain->cfgst = config_init (uri, &domain->gv.config, domain_id);
domain->cfgst = config_init (config, &domain->gv.config, domain_id);
if (domain->cfgst == NULL)
{
DDS_ILOG (DDS_LC_CONFIG, domain_id, "Failed to parse configuration XML file %s\n", uri);
@ -197,7 +194,7 @@ dds_domain *dds_domain_find_locked (dds_domainid_t id)
return ddsrt_avl_lookup (&dds_domaintree_def, &dds_global.m_domains, &id);
}
dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
dds_return_t dds_domain_create_internal (dds_domain **domain_out, dds_domainid_t id, bool use_existing, const char *config)
{
struct dds_domain *dom;
dds_return_t ret;
@ -223,6 +220,11 @@ dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
switch (ret)
{
case DDS_RETCODE_OK:
if (!use_existing)
{
ret = DDS_RETCODE_PRECONDITION_NOT_MET;
break;
}
ddsrt_mutex_lock (&dom->m_entity.m_mutex);
if (dds_handle_is_closed (&dom->m_entity.m_hdllink))
{
@ -239,7 +241,7 @@ dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
break;
case DDS_RETCODE_NOT_FOUND:
dom = dds_alloc (sizeof (*dom));
if ((ret = dds_domain_init (dom, id)) < 0)
if ((ret = dds_domain_init (dom, id, config)) < 0)
dds_free (dom);
else
{
@ -256,6 +258,29 @@ dds_return_t dds_domain_create (dds_domain **domain_out, dds_domainid_t id)
return ret;
}
dds_return_t dds_create_domain(const dds_domainid_t domain, const char *config)
{
dds_domain *dom;
dds_entity_t ret;
if (domain == DDS_DOMAIN_DEFAULT || config == NULL)
return DDS_RETCODE_BAD_PARAMETER;
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
goto err_dds_init;
if ((ret = dds_domain_create_internal (&dom, domain, false, config)) < 0)
goto err_domain_create;
return DDS_RETCODE_OK;
err_domain_create:
dds_delete_impl_pinned (&dds_global.m_entity, DIS_EXPLICIT);
err_dds_init:
return ret;
}
static dds_return_t dds_domain_free (dds_entity *vdomain)
{
struct dds_domain *domain = (struct dds_domain *) vdomain;

View file

@ -172,8 +172,8 @@ int32_t dds_handle_delete (struct dds_handle_link *link)
{
assert (cf & HDL_FLAG_CLOSING);
assert (cf & HDL_FLAG_CLOSED);
}
assert ((cf & HDL_REFCOUNT_MASK) == 0u);
}
assert ((cf & HDL_PINCOUNT_MASK) == 1u);
#endif
ddsrt_mutex_lock (&handles.lock);

View file

@ -12,11 +12,13 @@
#include <assert.h>
#include "dds/ddsrt/cdtors.h"
#include "dds/ddsrt/environ.h"
#include "dds/ddsi/q_entity.h"
#include "dds/ddsi/q_thread.h"
#include "dds/ddsi/q_config.h"
#include "dds/ddsi/q_plist.h"
#include "dds/ddsi/q_globals.h"
#include "dds/version.h"
#include "dds__init.h"
#include "dds__domain.h"
#include "dds__participant.h"
@ -82,12 +84,15 @@ dds_entity_t dds_create_participant (const dds_domainid_t domain, const dds_qos_
dds_participant * pp;
nn_plist_t plist;
dds_qos_t *new_qos = NULL;
char *config = "";
/* Make sure DDS instance is initialized. */
if ((ret = dds_init ()) < 0)
goto err_dds_init;
if ((ret = dds_domain_create (&dom, domain)) < 0)
(void) ddsrt_getenv (DDS_PROJECT_NAME_NOSPACE_CAPS"_URI", &config);
if ((ret = dds_domain_create_internal (&dom, domain, true, config)) < 0)
goto err_domain_create;
new_qos = dds_create_qos ();

View file

@ -75,3 +75,46 @@ CU_Test(ddsc_config, simple_udp, .init = ddsrt_init, .fini = ddsrt_fini) {
dds_delete(participant);
}
CU_Test(ddsc_config, user_config, .init = ddsrt_init, .fini = ddsrt_fini) {
CU_ASSERT_FATAL(dds_create_domain(1,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
dds_entity_t participant_1;
dds_entity_t participant_2;
dds_entity_t participant_3;
participant_1 = dds_create_participant(1, NULL, NULL);
CU_ASSERT_FATAL(participant_1 > 0);
participant_2 = dds_create_participant(1, NULL, NULL);
CU_ASSERT_FATAL(participant_2 > 0);
participant_3 = dds_create_participant(1, NULL, NULL);
CU_ASSERT(participant_3 <= 0);
dds_delete(participant_3);
dds_delete(participant_2);
dds_delete(participant_1);
}
CU_Test(ddsc_config, incorrect_config, .init = ddsrt_init, .fini = ddsrt_fini) {
CU_ASSERT_FATAL(dds_create_domain(1, NULL) == DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT_FATAL(dds_create_domain(1, "<CycloneDDS incorrect XML") != DDS_RETCODE_OK);
CU_ASSERT_FATAL(dds_create_domain(DDS_DOMAIN_DEFAULT,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_BAD_PARAMETER);
CU_ASSERT_FATAL(dds_create_domain(2,
"<"DDS_PROJECT_NAME"><Domain><Id>any</Id></Domain>"
"<DDSI2E><Internal><MaxParticipants>2</MaxParticipants></Internal></DDSI2E>"
"</"DDS_PROJECT_NAME">") == DDS_RETCODE_OK);
CU_ASSERT_FATAL(dds_create_domain(2, "") == DDS_RETCODE_PRECONDITION_NOT_MET);
}

View file

@ -393,7 +393,7 @@ struct config
struct cfgst;
struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid);
struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domid) ddsrt_nonnull((1,2));
void config_print_cfgst (struct cfgst *cfgst, const struct ddsrt_log_cfg *logcfg);
void config_free_source_info (struct cfgst *cfgst);
void config_fini (struct cfgst *cfgst);

View file

@ -2696,10 +2696,13 @@ static FILE *config_open_file (char *tok, char **cursor, uint32_t domid)
return fp;
}
struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t domid)
struct cfgst *config_init (const char *config, struct config *cfg, uint32_t domid)
{
int ok = 1;
struct cfgst *cfgst;
char env_input[32];
char *copy, *cursor;
struct ddsrt_xmlp_callbacks cb;
memset (cfg, 0, sizeof (*cfg));
@ -2720,18 +2723,14 @@ struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t
ends up on the right value */
cfgst->cfg->domainId = domid;
/* configfile == NULL will get you the default configuration */
if (configfile) {
char env_input[32];
char *copy = ddsrt_strdup (configfile), *cursor = copy;
struct ddsrt_xmlp_callbacks cb;
cb.attr = proc_attr;
cb.elem_close = proc_elem_close;
cb.elem_data = proc_elem_data;
cb.elem_open = proc_elem_open;
cb.error = proc_error;
copy = ddsrt_strdup (config);
cursor = copy;
while (*cursor && (isspace ((unsigned char) *cursor) || *cursor == ','))
cursor++;
while (ok && cursor && cursor[0])
@ -2785,7 +2784,6 @@ struct cfgst *config_init (const char *configfile, struct config *cfg, uint32_t
}
}
ddsrt_free (copy);
}
/* Set defaults for everything not set that we have a default value
for, signal errors for things unset but without a default. */