From 78d49b52a0d7b390540888b0aa67e55a7552e161 Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Mon, 3 Dec 2018 17:37:16 +0100 Subject: [PATCH] add new "builtin topic" types and conversion routines Signed-off-by: Erik Boasson --- src/core/ddsc/include/ddsc/dds.h | 23 ++ src/core/ddsi/CMakeLists.txt | 3 + .../ddsi/include/ddsi/ddsi_serdata_builtin.h | 44 +++ src/core/ddsi/include/ddsi/q_ephash.h | 1 + src/core/ddsi/src/ddsi_serdata_builtin.c | 287 ++++++++++++++++++ src/core/ddsi/src/ddsi_sertopic_builtin.c | 147 +++++++++ src/core/ddsi/src/q_ephash.c | 14 +- 7 files changed, 514 insertions(+), 5 deletions(-) create mode 100644 src/core/ddsi/include/ddsi/ddsi_serdata_builtin.h create mode 100644 src/core/ddsi/src/ddsi_serdata_builtin.c create mode 100644 src/core/ddsi/src/ddsi_sertopic_builtin.c diff --git a/src/core/ddsc/include/ddsc/dds.h b/src/core/ddsc/include/ddsc/dds.h index 32e7e59..d407d95 100644 --- a/src/core/ddsc/include/ddsc/dds.h +++ b/src/core/ddsc/include/ddsc/dds.h @@ -177,6 +177,29 @@ typedef struct dds_sample_info } dds_sample_info_t; +typedef struct dds_builtintopic_guid +{ + uint8_t v[16]; +} +dds_builtintopic_guid_t; + +typedef struct dds_builtintopic_participant +{ + dds_builtintopic_guid_t key; + dds_qos_t *qos; +} +dds_builtintopic_participant_t; + +typedef struct dds_builtintopic_endpoint +{ + dds_builtintopic_guid_t key; + dds_builtintopic_guid_t participant_key; + char *topic_name; + char *type_name; + dds_qos_t *qos; +} +dds_builtintopic_endpoint_t; + /* All entities are represented by a process-private handle, with one call to enable an entity when it was created disabled. diff --git a/src/core/ddsi/CMakeLists.txt b/src/core/ddsi/CMakeLists.txt index f88393b..cf0f7b1 100644 --- a/src/core/ddsi/CMakeLists.txt +++ b/src/core/ddsi/CMakeLists.txt @@ -20,8 +20,10 @@ PREPEND(srcs_ddsi "${CMAKE_CURRENT_LIST_DIR}/src" ddsi_mcgroup.c ddsi_serdata.c ddsi_serdata_default.c + ddsi_serdata_builtin.c ddsi_sertopic.c ddsi_sertopic_default.c + ddsi_sertopic_builtin.c ddsi_rhc_plugin.c ddsi_iid.c ddsi_tkmap.c @@ -75,6 +77,7 @@ PREPEND(hdrs_private_ddsi "${CMAKE_CURRENT_LIST_DIR}/include/ddsi" ddsi_serdata.h ddsi_sertopic.h ddsi_serdata_default.h + ddsi_serdata_builtin.h ddsi_rhc_plugin.h ddsi_iid.h ddsi_tkmap.h diff --git a/src/core/ddsi/include/ddsi/ddsi_serdata_builtin.h b/src/core/ddsi/include/ddsi/ddsi_serdata_builtin.h new file mode 100644 index 0000000..3770378 --- /dev/null +++ b/src/core/ddsi/include/ddsi/ddsi_serdata_builtin.h @@ -0,0 +1,44 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#ifndef DDSI_SERDATA_BUILTIN_H +#define DDSI_SERDATA_BUILTIN_H + +#include "os/os.h" +#include "util/ut_avl.h" +#include "sysdeps.h" +#include "ddsi/ddsi_serdata.h" +#include "ddsi/ddsi_sertopic.h" +#include "ddsi/q_xqos.h" + +struct ddsi_serdata_builtin { + struct ddsi_serdata c; + nn_guid_t key; + nn_xqos_t xqos; +}; + +enum ddsi_sertopic_builtin_type { + DSBT_PARTICIPANT, + DSBT_READER, + DSBT_WRITER +}; + +struct ddsi_sertopic_builtin { + struct ddsi_sertopic c; + enum ddsi_sertopic_builtin_type type; +}; + +extern const struct ddsi_sertopic_ops ddsi_sertopic_ops_builtin; +extern const struct ddsi_serdata_ops ddsi_serdata_ops_builtin; + +struct ddsi_sertopic *new_sertopic_builtin (enum ddsi_sertopic_builtin_type type, const char *name, const char *typename); + +#endif diff --git a/src/core/ddsi/include/ddsi/q_ephash.h b/src/core/ddsi/include/ddsi/q_ephash.h index 43863ce..3779d00 100644 --- a/src/core/ddsi/include/ddsi/q_ephash.h +++ b/src/core/ddsi/include/ddsi/q_ephash.h @@ -80,6 +80,7 @@ void ephash_remove_reader_guid (struct reader *rd); void ephash_remove_proxy_writer_guid (struct proxy_writer *pwr); void ephash_remove_proxy_reader_guid (struct proxy_reader *prd); +void *ephash_lookup_guid_untyped (const struct nn_guid *guid); void *ephash_lookup_guid (const struct nn_guid *guid, enum entity_kind kind); struct participant *ephash_lookup_participant_guid (const struct nn_guid *guid); diff --git a/src/core/ddsi/src/ddsi_serdata_builtin.c b/src/core/ddsi/src/ddsi_serdata_builtin.c new file mode 100644 index 0000000..a61bffe --- /dev/null +++ b/src/core/ddsi/src/ddsi_serdata_builtin.c @@ -0,0 +1,287 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "os/os.h" +#include "ddsi/sysdeps.h" +#include "ddsi/q_md5.h" +#include "ddsi/q_bswap.h" +#include "ddsi/q_config.h" +#include "ddsi/q_freelist.h" +#include +#include +#include "os/os.h" +#include "dds__key.h" +#include "ddsi/ddsi_tkmap.h" +#include "dds__stream.h" +#include "ddsi/q_entity.h" +#include "ddsi/ddsi_serdata_builtin.h" +//#include "dds.h" /* FIXME: need the sample types of the built-in topics */ + +static const uint64_t unihashconsts[] = { + UINT64_C (16292676669999574021), + UINT64_C (10242350189706880077), + UINT64_C (12844332200329132887), + UINT64_C (16728792139623414127) +}; + +static uint32_t hash_guid (const nn_guid_t *g) +{ + return + (uint32_t) (((((uint32_t) g->prefix.u[0] + unihashconsts[0]) * + ((uint32_t) g->prefix.u[1] + unihashconsts[1])) + + (((uint32_t) g->prefix.u[2] + unihashconsts[2]) * + ((uint32_t) g->entityid.u + unihashconsts[3]))) + >> 32); +} + +static struct ddsi_serdata *fix_serdata_builtin(struct ddsi_serdata_builtin *d, uint32_t basehash) +{ + d->c.hash = hash_guid (&d->key) ^ basehash; + return &d->c; +} + +static bool serdata_builtin_eqkey(const struct ddsi_serdata *acmn, const struct ddsi_serdata *bcmn) +{ + const struct ddsi_serdata_builtin *a = (const struct ddsi_serdata_builtin *)acmn; + const struct ddsi_serdata_builtin *b = (const struct ddsi_serdata_builtin *)bcmn; + return memcmp (&a->key, &b->key, sizeof (a->key)) == 0; +} + +static void serdata_builtin_free(struct ddsi_serdata *dcmn) +{ + struct ddsi_serdata_builtin *d = (struct ddsi_serdata_builtin *)dcmn; + if (d->c.kind == SDK_DATA) + nn_xqos_fini (&d->xqos); + os_free (d); +} + +static struct ddsi_serdata_builtin *serdata_builtin_new(const struct ddsi_sertopic_builtin *tp, enum ddsi_serdata_kind kind) +{ + struct ddsi_serdata_builtin *d = os_malloc(sizeof (*d)); + ddsi_serdata_init (&d->c, &tp->c, kind); + return d; +} + +static void from_entity_pp (struct ddsi_serdata_builtin *d, const struct participant *pp) +{ + nn_xqos_copy(&d->xqos, &pp->plist->qos); +} + +static void from_entity_proxypp (struct ddsi_serdata_builtin *d, const struct proxy_participant *proxypp) +{ + nn_xqos_copy(&d->xqos, &proxypp->plist->qos); +} + +static void set_topic_type_from_sertopic (struct ddsi_serdata_builtin *d, const struct ddsi_sertopic *tp) +{ + if (!(d->xqos.present & QP_TOPIC_NAME)) + { + d->xqos.topic_name = dds_string_dup (tp->name); + d->xqos.present |= QP_TOPIC_NAME; + } + if (!(d->xqos.present & QP_TYPE_NAME)) + { + d->xqos.type_name = dds_string_dup (tp->typename); + d->xqos.present |= QP_TYPE_NAME; + } +} + +static void from_entity_rd (struct ddsi_serdata_builtin *d, const struct reader *rd) +{ + nn_xqos_copy(&d->xqos, rd->xqos); + set_topic_type_from_sertopic(d, rd->topic); +} + +static void from_entity_prd (struct ddsi_serdata_builtin *d, const struct proxy_reader *prd) +{ + nn_xqos_copy(&d->xqos, prd->c.xqos); + assert (d->xqos.present & QP_TOPIC_NAME); + assert (d->xqos.present & QP_TYPE_NAME); +} + +static void from_entity_wr (struct ddsi_serdata_builtin *d, const struct writer *wr) +{ + nn_xqos_copy(&d->xqos, wr->xqos); + set_topic_type_from_sertopic(d, wr->topic); +} + +static void from_entity_pwr (struct ddsi_serdata_builtin *d, const struct proxy_writer *pwr) +{ + nn_xqos_copy(&d->xqos, pwr->c.xqos); + assert (d->xqos.present & QP_TOPIC_NAME); + assert (d->xqos.present & QP_TYPE_NAME); +} + +struct ddsi_serdata *ddsi_serdata_builtin_from_keyhash (const struct ddsi_sertopic *tpcmn, const nn_keyhash_t *keyhash) +{ + /* FIXME: not quite elegant to manage the creation of a serdata for a built-in topic via this function, but I also find it quite unelegant to let from_sample read straight from the underlying internal entity, and to_sample convert to the external format ... I could claim the internal entity is the "serialised form", but that forces wrapping it in a fragchain in one way or another, which, though possible, is also a bit lacking in elegance. */ + const struct ddsi_sertopic_builtin *tp = (const struct ddsi_sertopic_builtin *)tpcmn; + /* keyhash must in host format (which the GUIDs always are internally) */ + const struct entity_common *entity = ephash_lookup_guid_untyped ((const nn_guid_t *) keyhash->value); + struct ddsi_serdata_builtin *d = serdata_builtin_new(tp, entity ? SDK_DATA : SDK_KEY); + memcpy (&d->key, keyhash->value, sizeof (d->key)); + if (d->c.kind == SDK_DATA) + { + switch (entity->kind) + { + case EK_PARTICIPANT: + assert (tp->type == DSBT_PARTICIPANT); + from_entity_pp (d, (const struct participant *) entity); + break; + case EK_READER: + assert (tp->type == DSBT_READER); + from_entity_rd (d, (const struct reader *) entity); + break; + case EK_WRITER: + assert (tp->type == DSBT_WRITER); + from_entity_wr (d, (const struct writer *) entity); + break; + case EK_PROXY_PARTICIPANT: + assert (tp->type == DSBT_PARTICIPANT); + from_entity_proxypp (d, (const struct proxy_participant *) entity); + break; + case EK_PROXY_READER: + assert (tp->type == DSBT_READER); + from_entity_prd (d, (const struct proxy_reader *) entity); + break; + case EK_PROXY_WRITER: + assert (tp->type == DSBT_WRITER); + from_entity_pwr (d, (const struct proxy_writer *) entity); + break; + } + } + return fix_serdata_builtin(d, tp->c.serdata_basehash); +} + +static struct ddsi_serdata *serdata_builtin_to_topicless (const struct ddsi_serdata *serdata_common) +{ + /* All built-in ones are currently topicless */ + return ddsi_serdata_ref (serdata_common); +} + +static void convkey (dds_builtintopic_guid_t *key, const nn_guid_t *guid) +{ + nn_guid_t tmp; + tmp = nn_hton_guid (*guid); + memcpy (key, &tmp, sizeof (*key)); +} + +static char *dds_string_dup_reuse (char *old, const char *src) +{ + size_t size = strlen (src) + 1; + char *new = dds_realloc(old, size); + return memcpy (new, src, size); +} + +static dds_qos_t *dds_qos_from_xqos_reuse (dds_qos_t *old, const nn_xqos_t *src) +{ + if (old == NULL) + return nn_xqos_dup (src); + else + { + nn_xqos_fini (old); + nn_xqos_mergein_missing (old, src); + return old; + } +} + +static bool to_sample_pp (const struct ddsi_serdata_builtin *d, struct dds_builtintopic_participant *sample) +{ + convkey (&sample->key, &d->key); + if (d->c.kind == SDK_DATA) + { + sample->qos = dds_qos_from_xqos_reuse (sample->qos, &d->xqos); + } + return true; +} + +static bool to_sample_endpoint (const struct ddsi_serdata_builtin *d, struct dds_builtintopic_endpoint *sample) +{ + nn_guid_t ppguid; + convkey (&sample->key, &d->key); + ppguid = d->key; + ppguid.entityid.u = NN_ENTITYID_PARTICIPANT; + convkey (&sample->participant_key, &ppguid); + if (d->c.kind == SDK_DATA) + { + assert (d->xqos.present & QP_TOPIC_NAME); + assert (d->xqos.present & QP_TYPE_NAME); + sample->topic_name = dds_string_dup_reuse (sample->topic_name, d->xqos.topic_name); + sample->type_name = dds_string_dup_reuse (sample->type_name, d->xqos.type_name); + sample->qos = dds_qos_from_xqos_reuse (sample->qos, &d->xqos); + } + return true; +} + +static bool serdata_builtin_topicless_to_sample (const struct ddsi_sertopic *topic, const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) +{ + const struct ddsi_serdata_builtin *d = (const struct ddsi_serdata_builtin *)serdata_common; + const struct ddsi_sertopic_builtin *tp = (const struct ddsi_sertopic_builtin *)topic; + if (bufptr) abort(); else { (void)buflim; } /* FIXME: haven't implemented that bit yet! */ + /* FIXME: completing builtin topic support along these lines requires subscribers, publishers and topics to also become DDSI entities - which is probably a good thing anyway */ + switch (tp->type) + { + case DSBT_PARTICIPANT: + return to_sample_pp (d, sample); + case DSBT_READER: + case DSBT_WRITER: + return to_sample_endpoint (d, sample); + } + assert (0); + return false; +} + +static bool serdata_builtin_to_sample (const struct ddsi_serdata *serdata_common, void *sample, void **bufptr, void *buflim) +{ + return serdata_builtin_topicless_to_sample (serdata_common->topic, serdata_common, sample, bufptr, buflim); +} + +static uint32_t serdata_builtin_get_size (const struct ddsi_serdata *serdata_common) +{ + (void)serdata_common; + return 0; +} + +static void serdata_builtin_to_ser (const struct ddsi_serdata *serdata_common, size_t off, size_t sz, void *buf) +{ + (void)serdata_common; (void)off; (void)sz; (void)buf; +} + +static struct ddsi_serdata *serdata_builtin_to_ser_ref (const struct ddsi_serdata *serdata_common, size_t off, size_t sz, ddsi_iovec_t *ref) +{ + (void)serdata_common; (void)off; (void)sz; (void)ref; + return NULL; +} + +static void serdata_builtin_to_ser_unref (struct ddsi_serdata *serdata_common, const ddsi_iovec_t *ref) +{ + (void)serdata_common; (void)ref; +} + +const struct ddsi_serdata_ops ddsi_serdata_ops_builtin = { + .get_size = serdata_builtin_get_size, + .eqkey = serdata_builtin_eqkey, + .free = serdata_builtin_free, + .from_ser = 0, + .from_keyhash = ddsi_serdata_builtin_from_keyhash, + .from_sample = 0, + .to_ser = serdata_builtin_to_ser, + .to_sample = serdata_builtin_to_sample, + .to_ser_ref = serdata_builtin_to_ser_ref, + .to_ser_unref = serdata_builtin_to_ser_unref, + .to_topicless = serdata_builtin_to_topicless, + .topicless_to_sample = serdata_builtin_topicless_to_sample +}; diff --git a/src/core/ddsi/src/ddsi_sertopic_builtin.c b/src/core/ddsi/src/ddsi_sertopic_builtin.c new file mode 100644 index 0000000..31d2263 --- /dev/null +++ b/src/core/ddsi/src/ddsi_sertopic_builtin.c @@ -0,0 +1,147 @@ +/* + * Copyright(c) 2006 to 2018 ADLINK Technology Limited and others + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0, or the Eclipse Distribution License + * v. 1.0 which is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause + */ +#include +#include +#include +#include + +#include "os/os.h" +#include "ddsi/sysdeps.h" +#include "ddsi/q_md5.h" +#include "ddsi/q_bswap.h" +#include "ddsi/q_config.h" +#include "ddsi/q_freelist.h" +#include "ddsi/ddsi_sertopic.h" +#include "ddsi/ddsi_serdata_builtin.h" +#include "ddsc/dds.h" + +/* FIXME: sertopic /= ddstopic so a lot of stuff needs to be moved here from dds_topic.c and the free function needs to be implemented properly */ + +struct ddsi_sertopic *new_sertopic_builtin (enum ddsi_sertopic_builtin_type type, const char *name, const char *typename) +{ + struct ddsi_sertopic_builtin *tp = os_malloc (sizeof (*tp)); + tp->c.iid = ddsi_iid_gen(); + tp->c.name = dds_string_dup (name); + tp->c.typename = dds_string_dup (typename); + const size_t name_typename_size = strlen (tp->c.name) + 1 + strlen (tp->c.typename) + 1; + tp->c.name_typename = dds_alloc (name_typename_size); + snprintf (tp->c.name_typename, name_typename_size, "%s/%s", tp->c.name, tp->c.typename); + tp->c.ops = &ddsi_sertopic_ops_builtin; + tp->c.serdata_ops = &ddsi_serdata_ops_builtin; + tp->c.serdata_basehash = ddsi_sertopic_compute_serdata_basehash (tp->c.serdata_ops); + tp->c.status_cb = 0; + tp->c.status_cb_entity = NULL; + os_atomic_st32 (&tp->c.refc, 1); + tp->type = type; + return &tp->c; +} + +static void sertopic_builtin_deinit (struct ddsi_sertopic *tp) +{ + (void)tp; +} + +static void free_pp (void *vsample) +{ + dds_builtintopic_participant_t *sample = vsample; + dds_delete_qos (sample->qos); + sample->qos = NULL; +} + +static void free_endpoint (void *vsample) +{ + dds_builtintopic_endpoint_t *sample = vsample; + dds_free (sample->topic_name); + dds_free (sample->type_name); + dds_delete_qos (sample->qos); + sample->topic_name = sample->type_name = NULL; + sample->qos = NULL; +} + +static size_t get_size (enum ddsi_sertopic_builtin_type type) +{ + switch (type) + { + case DSBT_PARTICIPANT: + return sizeof (dds_builtintopic_participant_t); + case DSBT_READER: + case DSBT_WRITER: + return sizeof (dds_builtintopic_endpoint_t); + } + assert (0); + return 0; +} + +static void sertopic_builtin_zero_samples (const struct ddsi_sertopic *sertopic_common, void *samples, size_t count) +{ + const struct ddsi_sertopic_builtin *tp = (const struct ddsi_sertopic_builtin *)sertopic_common; + size_t size = get_size (tp->type); + memset (samples, 0, size * count); +} + +static void sertopic_builtin_realloc_samples (void **ptrs, const struct ddsi_sertopic *sertopic_common, void *old, size_t oldcount, size_t count) +{ + const struct ddsi_sertopic_builtin *tp = (const struct ddsi_sertopic_builtin *)sertopic_common; + const size_t size = get_size (tp->type); + char *new = dds_realloc (old, size * count); + if (new && count > oldcount) + memset (new + size * oldcount, 0, size * (count - oldcount)); + for (size_t i = 0; i < count; i++) + { + void *ptr = (char *) new + i * size; + ptrs[i] = ptr; + } +} + +static void sertopic_builtin_free_samples (const struct ddsi_sertopic *sertopic_common, void **ptrs, size_t count, dds_free_op_t op) +{ + if (count > 0) + { + const struct ddsi_sertopic_builtin *tp = (const struct ddsi_sertopic_builtin *)sertopic_common; + const size_t size = get_size (tp->type); +#ifndef NDEBUG + for (size_t i = 0, off = 0; i < count; i++, off += size) + assert ((char *)ptrs[i] == (char *)ptrs[0] + off); +#endif + if (op & DDS_FREE_CONTENTS_BIT) + { + void (*f) (void *); + char *ptr = ptrs[0]; + switch (tp->type) + { + case DSBT_PARTICIPANT: + f = free_pp; + break; + case DSBT_READER: + case DSBT_WRITER: + f = free_endpoint; + break; + } + for (size_t i = 0; i < count; i++) + { + f (ptr); + ptr += size; + } + } + if (op & DDS_FREE_ALL_BIT) + { + dds_free (ptrs[0]); + } + } +} + +const struct ddsi_sertopic_ops ddsi_sertopic_ops_builtin = { + .deinit = sertopic_builtin_deinit, + .zero_samples = sertopic_builtin_zero_samples, + .realloc_samples = sertopic_builtin_realloc_samples, + .free_samples = sertopic_builtin_free_samples +}; diff --git a/src/core/ddsi/src/q_ephash.c b/src/core/ddsi/src/q_ephash.c index 571d933..88cb373 100644 --- a/src/core/ddsi/src/q_ephash.c +++ b/src/core/ddsi/src/q_ephash.c @@ -116,15 +116,19 @@ static void ephash_guid_remove (struct entity_common *e) assert (x); } -static void *ephash_lookup_guid_int (const struct ephash *ephash, const struct nn_guid *guid, enum entity_kind kind) +void *ephash_lookup_guid_untyped (const struct nn_guid *guid) { /* FIXME: could (now) require guid to be first in entity_common; entity_common already is first in entity */ struct entity_common e; + e.guid = *guid; + return ut_chhLookup (gv.guid_hash->hash, &e); +} + +static void *ephash_lookup_guid_int (const struct ephash *ephash, const struct nn_guid *guid, enum entity_kind kind) +{ struct entity_common *res; (void)ephash; - e.guid = *guid; - res = ut_chhLookup (gv.guid_hash->hash, &e); - if (res && res->kind == kind) + if ((res = ephash_lookup_guid_untyped (guid)) != NULL && res->kind == kind) return res; else return NULL; @@ -132,7 +136,7 @@ static void *ephash_lookup_guid_int (const struct ephash *ephash, const struct n void *ephash_lookup_guid (const struct nn_guid *guid, enum entity_kind kind) { - return ephash_lookup_guid_int (gv.guid_hash, guid, kind); + return ephash_lookup_guid_int (NULL, guid, kind); } void ephash_insert_participant_guid (struct participant *pp)