From 6161f5c44d4caa21f375276689ea426c4a00006c Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Wed, 3 Jun 2020 15:28:57 +0200 Subject: [PATCH] Add some documentation to plist/xqos functions Signed-off-by: Erik Boasson --- src/core/ddsi/include/dds/ddsi/ddsi_plist.h | 217 +++++++++++++++++++- src/core/ddsi/include/dds/ddsi/ddsi_xqos.h | 215 +++++++++++++++++++ 2 files changed, 424 insertions(+), 8 deletions(-) diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_plist.h b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h index d1deae3..635b480 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_plist.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_plist.h @@ -233,20 +233,64 @@ typedef struct ddsi_plist { /***/ typedef struct ddsi_plist_src { - nn_protocol_version_t protocol_version; - nn_vendorid_t vendorid; - int encoding; - const unsigned char *buf; - size_t bufsz; - bool strict; - ddsi_tran_factory_t factory; /* eliminate this */ - struct ddsrt_log_cfg *logconfig; + nn_protocol_version_t protocol_version; /**< input protocol version */ + nn_vendorid_t vendorid; /**< vendor code for input */ + int encoding; /**< PL_CDR_LE or PL_CDR_BE */ + const unsigned char *buf; /**< input buffer */ + size_t bufsz; /**< size of input buffer */ + bool strict; /**< whether to be strict in checking */ + ddsi_tran_factory_t factory; /**< transport; eliminate this */ + struct ddsrt_log_cfg *logconfig; /**< logging configuration */ } ddsi_plist_src_t; +/** + * @brief Initialize global parameter-list parsing indices. + * + * These indices are derived from compile-time constant tables. This only does the work + * once; ideally it would be done at compile time instead. + */ void ddsi_plist_init_tables (void); + +/** + * @brief Initialize a ddsi_plist_t as an empty object + * + * In principle, this only clears the "present" and "aliased" bitmasks. A debug build + * additionally initializes all other bytes to 0x55. + * + * @param[out] dest plist_t to be initialized. + */ DDS_EXPORT void ddsi_plist_init_empty (ddsi_plist_t *dest); + +/** + * @brief Extend "a" with selected entries present in "b" + * + * This copies into "a" any entries present in "b" that are included in "pmask" and + * "qmask" and missing in "a". It doesn't touch any entries already present in "a". + * Calling this on an empty "a" with all bits set in "pmask" and "qmask" all is equivalent + * to copying "b" into "a"; calling this with "pmask" and "qmask" both 0 copies nothing. + * + * @param[in,out] a ddsi_plist_t to be extended + * @param[in] b ddsi_plist_t from which to copy entries + * @param[in] pmask subset of non-QoS part of b (if PP_X is set, include X) + * @param[in] qmask subset of QoS part of b (if QP_X is set, include X) + */ DDS_EXPORT void ddsi_plist_mergein_missing (ddsi_plist_t *a, const ddsi_plist_t *b, uint64_t pmask, uint64_t qmask); + +/** + * @brief Copy "src" to "dst" + * + * @param[out] dst destination, any contents are overwritten + * @param[in] src source ddsi_plist_t + */ DDS_EXPORT void ddsi_plist_copy (ddsi_plist_t *dst, const ddsi_plist_t *src); + +/** + * @brief Duplicate "src" + * + * @param[in] src ddsi_plist_t to be duplicated + * + * @returns a new (allocated using ddsrt_malloc) ddsi_plist_t containing a copy of "src". + */ DDS_EXPORT ddsi_plist_t *ddsi_plist_dup (const ddsi_plist_t *src); /** @@ -296,19 +340,176 @@ DDS_EXPORT ddsi_plist_t *ddsi_plist_dup (const ddsi_plist_t *src); * flag set; dest is cleared, *nextafterplist is NULL. */ DDS_EXPORT dds_return_t ddsi_plist_init_frommsg (ddsi_plist_t *dest, char **nextafterplist, uint64_t pwanted, uint64_t qwanted, const ddsi_plist_src_t *src); + +/** + * @brief Free memory owned by "ps" + * + * A ddsi_plist_t may own other allocated blocks of memory, depending on which fields are + * set, their types and whether they are marked as "aliased". This function releases any + * such memory owned by "ps", but not "ps" itself. Afterward, the contents of "ps" is + * undefined and must not be used again without initialising it (either via + * `ddsi_plist_init_empty`, `ddsi_plist_init_frommsg` or `ddsi_plist_copy`. + * + * @param[in] ps ddsi_plist_t for which to free memory + */ DDS_EXPORT void ddsi_plist_fini (ddsi_plist_t *ps); + +/** + * @brief Free memory owned by "plist" for a subset of the entries + * + * A ddsi_plist_t may own other allocated blocks of memory, depending on which fields are + * set, their types and whether they are marked as "aliased". This function releases any + * such memory owned by "plist" for entries included in "pmask" and "qmask". The + * "present" and "aliased" bits are cleared accordingly. + * + * @param[in,out] plist ddsi_plist_t for which to free memory + * @param[in] pmask subset of non-QoS part of b (if PP_X is set, free X if present) + * @param[in] qmask subset of QoS part of b (if QP_X is set, free X if present) + */ DDS_EXPORT void ddsi_plist_fini_mask (ddsi_plist_t *plist, uint64_t pmask, uint64_t qmask); + +/** + * @brief Replace any memory "plist" aliases by copies it owns + * + * A ddsi_plist_t may can reference other memory without owning it. This functions allows + * one to replace any such aliased memory by copies, allowing one to free the original + * copy. + * + * @param[in,out] plist ddsi_plist_t for which to replace all aliased memory by owned + * copies + */ DDS_EXPORT void ddsi_plist_unalias (ddsi_plist_t *plist); + +/** + * @brief Add selected entries in "ps" to a message in native endianness. + * + * This functions appends to "m" a serialized copy of the the entries selected by + * "pwanted"/"qwanted" and present in "ps". Each copy is preceded by a 4-byte header with + * a parameter id and length (conform the PL_CDR representation). It does *not* add a + * sentinel to allow adding additional data to the parameter list. A sentinel can be + * added using `nn_xmsg_addpar_sentinel`. + * + * @param[in,out] m message to append the parameters to + * @param[in] ps source + * @param[in] pwanted subset of non-QoS part of ps (if PP_X is set, add X if present) + * @param[in] qwanted subset of QoS part of ps (if QP_X is set, add X if present) + */ DDS_EXPORT void ddsi_plist_addtomsg (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted); + +/** + * @brief Add selected entries in "ps" to a message with selected endianness. + * + * This functions appends to "m" a serialized copy of the the entries selected by + * "pwanted"/"qwanted" and present in "ps". Each copy is preceded by a 4-byte header with + * a parameter id and length (conform the PL_CDR representation). It does *not* add a + * sentinel to allow adding additional data to the parameter list. A sentinel can be + * added using `nn_xmsg_addpar_sentinel`. + * + * @param[in,out] m message to append the parameters to + * @param[in] ps source + * @param[in] pwanted subset of non-QoS part of ps (if PP_X is set, add X if present) + * @param[in] qwanted subset of QoS part of ps (if QP_X is set, add X if present) + * @param[in] be use native endianness if false, big-endian if true + */ DDS_EXPORT void ddsi_plist_addtomsg_bo (struct nn_xmsg *m, const ddsi_plist_t *ps, uint64_t pwanted, uint64_t qwanted, bool be); + +/** + * @brief Initialize plist to match default settings for a participant + * + * @param[out] plist plist to contain the default settings. + */ DDS_EXPORT void ddsi_plist_init_default_participant (ddsi_plist_t *plist); + +/** + * @brief Determine the set of entries in which "x" differs from "y" + * + * This computes the entries set in "x" but not set in "y", not set in "x" but set in "y", + * or set in both "x" and "y" but to a different value. It returns this set reduced to + * only those included in "pmask"/"qmask", that is, if bit X is clear in "pmask", bit X + * will be clear in "pdelta", etc. + * + * @param[out] pdelta non-QoS entries that are different and not masked out + * @param[out] qdelta QoS entries that are different and not masked out + * @param[in] x one of the two plists to compare + * @param[in] y other plist to compare + * @param[in] pmask subset of non-QoS part to be compared + * @param[in] qmask subset of QoS part to be compared + */ DDS_EXPORT void ddsi_plist_delta (uint64_t *pdelta, uint64_t *qdelta, const ddsi_plist_t *x, const ddsi_plist_t *y, uint64_t pmask, uint64_t qmask); + +/** + * @brief Formats plist using `ddsi_plist_print` and writes it to the trace. + * + * @param[in] cat log category to use + * @param[in] logcfg logging configuration + * @param[in] plist parameter list to be logged + */ DDS_EXPORT void ddsi_plist_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const ddsi_plist_t *plist); + +/** + * @brief Formats plist into a buffer + * + * The representation is somewhat cryptic as all enumerated types are dumped as numbers + * and timestamps are durations as nanoseconds with "infinite" represented as + * 9223372036854775807 (INT64_MAX). + * + * @param[out] buf buffer to store the formatted representation in + * @param[in] bufsize size of buffer, if > 0, there will be a terminating 0 in buf on + * return + * @param[in] plist parameter list to be formatted as a string + * + * @returns number of bytes written to buf, excluding a terminating 0. + */ DDS_EXPORT size_t ddsi_plist_print (char * __restrict buf, size_t bufsize, const ddsi_plist_t *plist); struct nn_rsample_info; +/** + * @brief Scan a PL_CDR-serialized parameter list, checking structure and copying some information to "dest". + * + * This checks that the serialized data is structured correctly (proper aligned headers, + * declared lengths within bounds, a sentinel at the end). It sets the `statusinfo` of + * `dest` to the least significant two bits (UNREGISTER and DISPOSE) of a status info + * parameter if present, else to 0. A statusinfo parameter that is too short (less than 4 + * bytes) is treated as an invalid input. + * + * It sets the `complex_qos` flag if it encounters any parameter other than a statusinfo + * limited to those two bits, keyhash or padding, and clears it otherwise. + * + * It clears the `bswap` flag in `dest` if the input is in native endianness, and sets it + * otherwise. + * + * @param[in] src input description (see `ddsi_plist_init_frommsg`) + * @param[out] dest internal sample info of which some fields will be set + * + * @return pointer to the first byte following the sentinel if the input is well-formed, a + * null pointer if it is not. +*/ DDS_EXPORT unsigned char *ddsi_plist_quickscan (struct nn_rsample_info *dest, const ddsi_plist_src_t *src); + +/** + * @brief Locate a specific parameter in a PL_CDR-serialized parameter list + * + * This scans the serialized data until it encounters the sentinel, recording whether the + * specified parameter occurs and returning the size and address of it in `buf`. + * + * If `needle` is PID_SENTINEL, it will simply check well-formedness of the input and + * `needlep` and `needlesz` must both be null pointers. If `needle` is not PID_SENTINEL, + * `needlep` and `needlesz` may not be null pointers. + * + * @param[in] buf serialized parameter list to scan + * @param[in] bufsz length of serialized form + * @param[in] encoding encoding of `buf`, either PL_CDR_LE or PL_CDR_BE + * @param[in] needle parameter id to look for + * @param[out] needlep where to store the address of the `needle` value + * @param[out] needlesz where to store the size of the `needle` value + * + * @return Whether input was valid and if so, whether it contains the needle. + * + * @retval DDS_RETCODE_BAD_PARAMETER invalid input + * @retval DDS_RETCODE_NOT_FOUND valid input, `needle` not present + * @retval DDS_RETCODE_OK valid input, `needle` is present +*/ DDS_EXPORT dds_return_t ddsi_plist_findparam_checking (const void *buf, size_t bufsz, uint16_t encoding, nn_parameterid_t needle, void **needlep, size_t *needlesz); #if defined (__cplusplus) diff --git a/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h b/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h index b7e803a..2d740bd 100644 --- a/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h +++ b/src/core/ddsi/include/dds/ddsi/ddsi_xqos.h @@ -304,25 +304,240 @@ struct dds_qos { struct nn_xmsg; +/** + * @brief Initialize a new empty dds_qos_t as an empty object + * + * In principle, this only clears the "present" and "aliased" bitmasks. A debug build + * additionally initializes all other bytes to 0x55. + * + * @param[out] xqos qos object to be initialized. + */ DDS_EXPORT void ddsi_xqos_init_empty (dds_qos_t *xqos); + +/** + * @brief Initialize xqos to match default QoS settings for a reader + * + * @param[out] xqos qos object to contain the default settings. + */ DDS_EXPORT void ddsi_xqos_init_default_reader (dds_qos_t *xqos); + +/** + * @brief Initialize xqos to match default QoS settings for a writer + * + * @param[out] xqos qos object to contain the default settings. + */ DDS_EXPORT void ddsi_xqos_init_default_writer (dds_qos_t *xqos); + +/** + * @brief Initialize xqos to match default QoS settings for a non-autodispose writer + * + * The default writer QoS has "auto dispose unregistered instances" set to true, and + * opinions differ about what the correct behaviour is, but the setting doesn't really + * make any sense if it is treated as a macro on the writing such, such that each + * "unregister" call also performs a dispose. Cyclone DDS implements the interpretation + * that matches the name (whenever no registrations are left, make it disposed), which is + * a refinement of OpenSplice's interpretation (whenever an unregister event occurs, make + * it disposed). All these differences originate in the DCPS spec not being clear enough + * and the complicating factor is that the two different interpretations existed before + * the introduction of the DDSI specification, and yet the DDSI specification doesn't + * provide a standard way of discovering the setting for remote writers. + * + * Cyclone DDS uses the same vendor-specific extension as OpenSplice for communicating it, + * and uses a different default for different implementations. So this is the default + * used for the "RTI interpretation". + * + * @param[out] xqos qos object to contain the default settings. + */ DDS_EXPORT void ddsi_xqos_init_default_writer_noautodispose (dds_qos_t *xqos); + +/** + * @brief Initialize xqos to match default QoS settings for a subscriber + * + * @param[out] xqos qos object to contain the default settings. + */ DDS_EXPORT void ddsi_xqos_init_default_subscriber (dds_qos_t *xqos); + +/** + * @brief Initialize xqos to match default QoS settings for a publisher + * + * @param[out] xqos qos object to contain the default settings. + */ DDS_EXPORT void ddsi_xqos_init_default_publisher (dds_qos_t *xqos); + +/** + * @brief Initialize xqos to match default QoS settings for a topic + * + * @param[out] xqos qos object to contain the default settings. + */ DDS_EXPORT void ddsi_xqos_init_default_topic (dds_qos_t *xqos); + +/** + * @brief Copy "src" to "dst" + * + * @param[out] dst destination, any contents are overwritten + * @param[in] src source dds_qos_t + */ DDS_EXPORT void ddsi_xqos_copy (dds_qos_t *dst, const dds_qos_t *src); + +/** + * @brief Replace any memory "xqos" aliases by copies it owns + * + * A dds_qos_t may can reference other memory without owning it. This functions allows + * one to replace any such aliased memory by copies, allowing one to free the original + * copy. + * + * @param[in,out] xqos qos object for which to replace all aliased memory by owned + * copies + */ DDS_EXPORT void ddsi_xqos_unalias (dds_qos_t *xqos); + +/** + * @brief Free memory owned by "xqos" + * + * A dds_qos_t may own other allocated blocks of memory, depending on which fields are + * set, their types and whether they are marked as "aliased". This function releases any + * such memory owned by "xqos", but not "xqos" itself. Afterward, the content of "xqos" + * is undefined and must not be used again without initialising it. + * + * @param[in] xqos dds_qos_t for which to free memory + */ DDS_EXPORT void ddsi_xqos_fini (dds_qos_t *xqos); + +/** + * @brief Free memory owned by "xqos" for a subset of the entries + * + * A dds_qos_t may own other allocated blocks of memory, depending on which fields are + * set, their types and whether they are marked as "aliased". This function releases any + * such memory owned by "xqos" for entries included in "mask". The "present" and + * "aliased" bits are cleared accordingly. + * + * @param[in,out] xqos dds_qos_t for which to free memory + * @param[in] mask entries to free (if QP_X is set, free X if present) + */ DDS_EXPORT void ddsi_xqos_fini_mask (dds_qos_t *xqos, uint64_t mask); + +/** + * @brief Check whether xqos is valid according to the validation rules in the spec + * + * The checks concern the values for the individual fields as well as a few combinations + * of fields. Only those that are set are checked (the defaults are all valid anyway), + * and where a combination of fields must be checked and some but not all fields are + * specified, it uses the defaults for the missing ones. + * + * Invalid values get logged as category "plist" according to the specified logging + * configuration. + * + * @param[in] logcfg logging configuration + * @param[in] xqos qos object to check + * + * @returns DDS_RETCODE_OK or DDS_RETCODE_BAD_PARAMETER + */ DDS_EXPORT dds_return_t ddsi_xqos_valid (const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); + +/** + * @brief Extend "a" with selected entries present in "b" + * + * This copies into "a" any entries present in "b" that are included in "mask" and missing + * in "a". It doesn't touch any entries already present in "a". Calling this on an empty + * "a" with all bits set in "mask" is equivalent to copying "b" into "a"; calling this + * with "mask" 0 copies nothing. + * + * @param[in,out] a dds_qos_t to be extended + * @param[in] b dds_qos_t from which to copy entries + * @param[in] mask which to include (if QP_X is set, include X) + */ DDS_EXPORT void ddsi_xqos_mergein_missing (dds_qos_t *a, const dds_qos_t *b, uint64_t mask); + +/** + * @brief Determine the set of entries in which "x" differs from "y" + * + * This computes the entries set in "x" but not set in "y", not set in "x" but set in "y", + * or set in both "x" and "y" but to a different value. It returns this set reduced to + * only those included in "mask", that is, if bit X is clear in "mask", bit X will be + * clear in the result. + * + * @param[in] a one of the two plists to compare + * @param[in] b other plist to compare + * @param[in] mask subset of entries to be compared + * + * @returns Bitmask of differences + */ DDS_EXPORT uint64_t ddsi_xqos_delta (const dds_qos_t *a, const dds_qos_t *b, uint64_t mask); + +/** + * @brief Add selected entries in "xqos" to a message in native endianness. + * + * This functions appends to "xqos" a serialized copy of the the entries selected by + * "wanted" and present in "xqos". Each copy is preceded by a 4-byte header with a + * parameter id and length (conform the PL_CDR representation). It does *not* add a + * sentinel to allow adding additional data to the parameter list. A sentinel can be + * added using `nn_xmsg_addpar_sentinel`. + * + * @param[in,out] m message to append the parameters to + * @param[in] xqos source + * @param[in] wanted subset to be added (if QP_X is set, add X if present) + */ DDS_EXPORT void ddsi_xqos_addtomsg (struct nn_xmsg *m, const dds_qos_t *xqos, uint64_t wanted); + +/** + * @brief Formats xqos using `ddsi_xqos_print` and writes it to the trace. + * + * @param[in] cat log category to use + * @param[in] logcfg logging configuration + * @param[in] xqos qos object to be logged + */ DDS_EXPORT void ddsi_xqos_log (uint32_t cat, const struct ddsrt_log_cfg *logcfg, const dds_qos_t *xqos); + +/** + * @brief Formats xqos into a buffer + * + * The representation is somewhat cryptic as all enumerated types are dumped as numbers + * and timestamps are durations as nanoseconds with "infinite" represented as + * 9223372036854775807 (INT64_MAX). + * + * @param[out] buf buffer to store the formatted representation in + * @param[in] bufsize size of buffer, if > 0, there will be a terminating 0 in buf on + * return + * @param[in] xqos parameter list to be formatted as a string + * + * @returns number of bytes written to buf, excluding a terminating 0. + */ DDS_EXPORT size_t ddsi_xqos_print (char * __restrict buf, size_t bufsize, const dds_qos_t *xqos); + +/** + * @brief Duplicate "src" + * + * @param[in] src dds_qos_t to be duplicated + * + * @returns a new (allocated using ddsrt_malloc) dds_qos_t containing a copy of "src". + */ DDS_EXPORT dds_qos_t *ddsi_xqos_dup (const dds_qos_t *src); + +/** + * @brief Check if "xqos" includes properties with a name starting with "nameprefix" + * + * That is, if xqos.present has QP_PROPERTY_LIST set, and at least one of them has a name + * starting with "nameprefix". + * + * @param[in] xqos qos object to check + * @param[in] nameprefix prefix to check for + * + * @returns true iff xqos contains a matching property + */ DDS_EXPORT bool ddsi_xqos_has_prop_prefix (const dds_qos_t *xqos, const char *nameprefix); + +/** + * @brief Lookup property "name" in "xqos" and return a pointer to its value + * + * The value pointer is left unchanged if the property doesn't exist. The returned + * address points into the memory owned by the QoS object and must not be freed. + * + * @param[in] xqos qos object to check + * @param[in] name name to look for + * @param[out] value pointer to set to the value of the property if it exists + * + * @returns true iff xqos contains the property + */ DDS_EXPORT bool ddsi_xqos_find_prop (const dds_qos_t *xqos, const char *name, const char **value); #ifdef DDSI_INCLUDE_SECURITY