From fac58ab1a93aeb5985272ca5f4fe08ebf252651a Mon Sep 17 00:00:00 2001 From: Erik Boasson Date: Fri, 24 Jul 2020 12:02:49 +0200 Subject: [PATCH] Minor improvements to content filter interface Content filtering is possible in current Cyclone by setting a callback function on a topic, but this is not an interface that is intended to survive. Still, it can save the day. This commit improves the interface a bit by allowing an argument to the filter function. It also adds some tests to verify that it does work. Also point out in the header file that this really is not an interface that will be around for long and that it needs to be used with care. Signed-off-by: Erik Boasson --- src/core/ddsc/include/dds/dds.h | 62 ++++- src/core/ddsc/src/dds__topic.h | 11 - src/core/ddsc/src/dds__types.h | 7 +- src/core/ddsc/src/dds_topic.c | 109 ++++---- src/core/ddsc/tests/CMakeLists.txt | 1 + src/core/ddsc/tests/filter.c | 382 +++++++++++++++++++++++++++++ 6 files changed, 505 insertions(+), 67 deletions(-) create mode 100644 src/core/ddsc/tests/filter.c diff --git a/src/core/ddsc/include/dds/dds.h b/src/core/ddsc/include/dds/dds.h index 2a63fbb..6a95cd6 100644 --- a/src/core/ddsc/include/dds/dds.h +++ b/src/core/ddsc/include/dds/dds.h @@ -1142,32 +1142,84 @@ dds_get_type_name(dds_entity_t topic, char *name, size_t size); /** Topic filter function */ typedef bool (*dds_topic_filter_fn) (const void * sample); +typedef bool (*dds_topic_filter_arg_fn) (const void * sample, void * arg); /** - * @brief Sets a filter on a topic. + * @brief Sets a filter on a topic. To be replaced by proper filtering on readers, + * no guarantee that this will be maintained for backwards compatibility. + * + * Not thread-safe with respect to data being read/written using readers/writers + * using this topic. Be sure to create a topic entity specific to the reader you + * want to filter, then set the filter function, and only then create the reader. + * And don't change it unless you know there are no concurrent writes. * * @param[in] topic The topic on which the content filter is set. * @param[in] filter The filter function used to filter topic samples. */ -DDS_EXPORT void +DDS_DEPRECATED_EXPORT void dds_set_topic_filter(dds_entity_t topic, dds_topic_filter_fn filter); DDS_DEPRECATED_EXPORT void dds_topic_set_filter(dds_entity_t topic, dds_topic_filter_fn filter); /** - * @brief Gets the filter for a topic. + * @brief Sets a filter and filter argument on a topic. To be replaced by proper + * filtering on readers, no guarantee that this will be maintained for backwards + * compatibility. + * + * Not thread-safe with respect to data being read/written using readers/writers + * using this topic. Be sure to create a topic entity specific to the reader you + * want to filter, then set the filter function, and only then create the reader. + * And don't change it unless you know there are no concurrent writes. + * + * @param[in] topic The topic on which the content filter is set. + * @param[in] filter The filter function used to filter topic samples. + * @param[in] arg Argument for the filter function. + * + * @returns A dds_return_t indicating success or failure. + * + * @retval DDS_RETCODE_OK Filter set successfully + * @retval DDS_RETCODE_BAD_PARAMETER The topic handle is invalid +*/ +DDS_EXPORT dds_return_t +dds_set_topic_filter_and_arg( + dds_entity_t topic, + dds_topic_filter_arg_fn filter, + void *arg); + +/** + * @brief Gets the filter for a topic. To be replaced by proper filtering on readers, + * no guarantee that this will be maintained for backwards compatibility. * * @param[in] topic The topic from which to get the filter. * - * @returns The topic filter. + * @returns The topic filter, or 0 when not set or set using + * dds_set_topic_filter_and_arg. */ -DDS_EXPORT dds_topic_filter_fn +DDS_DEPRECATED_EXPORT dds_topic_filter_fn dds_get_topic_filter(dds_entity_t topic); DDS_DEPRECATED_EXPORT dds_topic_filter_fn dds_topic_get_filter(dds_entity_t topic); +/** + * @brief Gets the filter for a topic. To be replaced by proper filtering on readers, + * no guarantee that this will be maintained for backwards compatibility. + * + * @param[in] topic The topic from which to get the filter. + * @param[out] fn The topic filter function (fn may be NULL). + * @param[out] arg Filter function argument (arg may be NULL). + * + * @retval DDS_RETCODE_OK Filter set successfully + * @retval DDS_RETCODE_PRECONDITION_NOT_MET Filter was set with dds_set_topic_filter + * @retval DDS_RETCODE_BAD_PARAMETER The topic handle is invalid + */ +DDS_EXPORT dds_return_t +dds_get_topic_filter_and_arg ( + dds_entity_t topic, + dds_topic_filter_arg_fn *fn, + void **arg); + /** * @brief Creates a new instance of a DDS subscriber * diff --git a/src/core/ddsc/src/dds__topic.h b/src/core/ddsc/src/dds__topic.h index 732f4e5..5e51c04 100644 --- a/src/core/ddsc/src/dds__topic.h +++ b/src/core/ddsc/src/dds__topic.h @@ -28,17 +28,6 @@ DDS_EXPORT void dds_topic_unpin (struct dds_topic *tp) ddsrt_nonnull_all; DDS_EXPORT void dds_topic_defer_set_qos (struct dds_topic *tp) ddsrt_nonnull_all; DDS_EXPORT void dds_topic_allow_set_qos (struct dds_topic *tp) ddsrt_nonnull_all; -#ifndef DDS_TOPIC_INTERN_FILTER_FN_DEFINED -#define DDS_TOPIC_INTERN_FILTER_FN_DEFINED -typedef bool (*dds_topic_intern_filter_fn) (const void * sample, void *ctx); -#endif - -DDS_EXPORT void dds_topic_set_filter_with_ctx - (dds_entity_t topic, dds_topic_intern_filter_fn filter, void *ctx); - -DDS_EXPORT dds_topic_intern_filter_fn dds_topic_get_filter_with_ctx - (dds_entity_t topic); - DDS_EXPORT dds_entity_t dds_create_topic_impl (dds_entity_t participant, struct ddsi_sertopic **sertopic, const dds_qos_t *qos, const dds_listener_t *listener, const ddsi_plist_t *sedp_plist); #if defined (__cplusplus) diff --git a/src/core/ddsc/src/dds__types.h b/src/core/ddsc/src/dds__types.h index 420ac2c..599ea23 100644 --- a/src/core/ddsc/src/dds__types.h +++ b/src/core/ddsc/src/dds__types.h @@ -306,17 +306,12 @@ typedef struct dds_writer { dds_publication_matched_status_t m_publication_matched_status; } dds_writer; -#ifndef DDS_TOPIC_INTERN_FILTER_FN_DEFINED -#define DDS_TOPIC_INTERN_FILTER_FN_DEFINED -typedef bool (*dds_topic_intern_filter_fn) (const void * sample, void *ctx); -#endif - typedef struct dds_topic { struct dds_entity m_entity; struct ddsi_sertopic *m_stopic; struct dds_ktopic *m_ktopic; /* refc'd, constant */ - dds_topic_intern_filter_fn filter_fn; + dds_topic_filter_arg_fn filter_fn; void *filter_ctx; /* Status metrics */ diff --git a/src/core/ddsc/src/dds_topic.c b/src/core/ddsc/src/dds_topic.c index e2951f7..8a58815 100644 --- a/src/core/ddsc/src/dds_topic.c +++ b/src/core/ddsc/src/dds_topic.c @@ -13,6 +13,7 @@ #include #include +#include "dds/ddsrt/misc.h" #include "dds/ddsrt/atomics.h" #include "dds/ddsrt/heap.h" #include "dds/ddsrt/string.h" @@ -500,69 +501,87 @@ dds_entity_t dds_find_topic (dds_entity_t participant, const char *name) return DDS_RETCODE_PRECONDITION_NOT_MET; } -static bool dds_topic_chaining_filter (const void *sample, void *ctx) -{ - dds_topic_filter_fn realf = (dds_topic_filter_fn) ctx; - return realf (sample); -} - -static void dds_topic_mod_filter (dds_entity_t topic, dds_topic_intern_filter_fn *filter, void **ctx, bool set) +dds_return_t dds_set_topic_filter_and_arg (dds_entity_t topic, dds_topic_filter_arg_fn filter, void *arg) { dds_topic *t; - if (dds_topic_lock (topic, &t) == DDS_RETCODE_OK) - { - if (set) { - t->filter_fn = *filter; - t->filter_ctx = *ctx; - } else { - *filter = t->filter_fn; - *ctx = t->filter_ctx; - } - dds_topic_unlock (t); - } - else - { - *filter = 0; - *ctx = NULL; - } + dds_return_t rc; + if ((rc = dds_topic_lock (topic, &t)) != DDS_RETCODE_OK) + return rc; + t->filter_fn = filter; + t->filter_ctx = arg; + dds_topic_unlock (t); + return DDS_RETCODE_OK; +} + +static bool topic_filter_no_arg_wrapper (const void *sample, void *arg) +{ + dds_topic_filter_fn f = (dds_topic_filter_fn) arg; + return f (sample); +} + +static void dds_set_topic_filter_deprecated (dds_entity_t topic, dds_topic_filter_fn filter) +{ + dds_topic *t; + if (dds_topic_lock (topic, &t)) + return; + t->filter_fn = topic_filter_no_arg_wrapper; + // function <-> data pointer conversion guaranteed to work on POSIX, Windows + // this being a deprecated interface, there's seems to be little point in + // make it fully portable + t->filter_ctx = (void *) filter; + dds_topic_unlock (t); } void dds_set_topic_filter (dds_entity_t topic, dds_topic_filter_fn filter) { - dds_topic_intern_filter_fn chaining = dds_topic_chaining_filter; - void *realf = (void *) filter; - dds_topic_mod_filter (topic, &chaining, &realf, true); + dds_set_topic_filter_deprecated (topic, filter); } void dds_topic_set_filter (dds_entity_t topic, dds_topic_filter_fn filter) { - dds_set_topic_filter (topic, filter); + dds_set_topic_filter_deprecated (topic, filter); +} + +dds_return_t dds_get_topic_filter_and_arg (dds_entity_t topic, dds_topic_filter_arg_fn *fn, void **arg) +{ + dds_return_t rc; + dds_topic *t; + if ((rc = dds_topic_lock (topic, &t)) != DDS_RETCODE_OK) + return rc; + if (t->filter_fn == topic_filter_no_arg_wrapper) + rc = DDS_RETCODE_PRECONDITION_NOT_MET; + else + { + if (fn) + *fn = t->filter_fn; + if (arg) + *arg = t->filter_ctx; + } + dds_topic_unlock (t); + return rc; +} + +static dds_topic_filter_fn dds_get_topic_filter_deprecated (dds_entity_t topic) +{ + dds_topic *t; + dds_topic_filter_fn f = 0; + if (dds_topic_lock (topic, &t) == DDS_RETCODE_OK) + { + if (t->filter_fn == topic_filter_no_arg_wrapper) + f = (dds_topic_filter_fn) t->filter_ctx; + dds_topic_unlock (t); + } + return f; } dds_topic_filter_fn dds_get_topic_filter (dds_entity_t topic) { - dds_topic_intern_filter_fn filter; - void *ctx; - dds_topic_mod_filter (topic, &filter, &ctx, false); - return (filter == dds_topic_chaining_filter) ? (dds_topic_filter_fn) ctx : 0; + return dds_get_topic_filter_deprecated (topic); } dds_topic_filter_fn dds_topic_get_filter (dds_entity_t topic) { - return dds_get_topic_filter (topic); -} - -void dds_topic_set_filter_with_ctx (dds_entity_t topic, dds_topic_intern_filter_fn filter, void *ctx) -{ - dds_topic_mod_filter (topic, &filter, &ctx, true); -} - -dds_topic_intern_filter_fn dds_topic_get_filter_with_ctx (dds_entity_t topic) -{ - dds_topic_intern_filter_fn filter; - void *ctx; - dds_topic_mod_filter (topic, &filter, &ctx, false); - return (filter == dds_topic_chaining_filter) ? 0 : filter; + return dds_get_topic_filter_deprecated (topic); } dds_return_t dds_get_name (dds_entity_t topic, char *name, size_t size) diff --git a/src/core/ddsc/tests/CMakeLists.txt b/src/core/ddsc/tests/CMakeLists.txt index eb372bb..7fb38b9 100644 --- a/src/core/ddsc/tests/CMakeLists.txt +++ b/src/core/ddsc/tests/CMakeLists.txt @@ -28,6 +28,7 @@ set(ddsc_test_sources "entity_hierarchy.c" "entity_status.c" "err.c" + "filter.c" "instance_get_key.c" "instance_handle.c" "listener.c" diff --git a/src/core/ddsc/tests/filter.c b/src/core/ddsc/tests/filter.c new file mode 100644 index 0000000..49005b2 --- /dev/null +++ b/src/core/ddsc/tests/filter.c @@ -0,0 +1,382 @@ +/* + * Copyright(c) 2020 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 + */ + +/* NOTICE + * + * The interface tested here is not part of the supported interface. It hung + * around by accident, and because it has proven to be useful escape at times, + * it is best to have tests. + * + * The (not-too-distant) future will bring content filter expressions in the + * reader QoS that get parsed at run-time and drop these per-topic filter + * functions. + */ + +#include +#include +#include +#include +#include + +#include "dds/dds.h" +#include "dds/ddsrt/misc.h" +#include "dds/ddsrt/attributes.h" + +#include "test_common.h" + +#define MAXSAMPLES 20 + +static bool filter_long1_eq (const void *vsample, void *arg) +{ + Space_Type1 const * const sample = vsample; + return (uintptr_t) sample->long_1 == (uintptr_t) arg; +} + +static bool filter_long2_eq (const void *vsample, void *arg) +{ + Space_Type1 const * const sample = vsample; + return (uintptr_t) sample->long_2 == (uintptr_t) arg; +} + +static int cmpdata (const void *va, const void *vb) +{ + const Space_Type1 *a = va; + const Space_Type1 *b = vb; + if (a->long_1 < b->long_1) + return -1; + else if (a->long_1 > b->long_1) + return 1; + else if (a->long_2 < b->long_2) + return -1; + else if (a->long_2 > b->long_2) + return 1; + else if (a->long_3 < b->long_3) + return -1; + else if (a->long_3 > b->long_3) + return 1; + else + return 0; +} + +struct exp { + int n; // number of samples expected + const Space_Type1 *xs; // expected data, must match exactly + const dds_instance_state_t *is; // expected instance state (or NULL), indexed by key value +}; + +static void checkdata (dds_entity_t rd, const struct exp *exp, const char *headerfmt, ...) + ddsrt_attribute_format((printf, 3, 4)); + +static void checkdata (dds_entity_t rd, const struct exp *exp, const char *headerfmt, ...) +{ + Space_Type1 data[MAXSAMPLES + 1]; + void *raw[MAXSAMPLES + 1]; + for (int i = 0; i < MAXSAMPLES + 1; i++) + raw[i] = &data[i]; + dds_sample_info_t si[MAXSAMPLES + 1]; + dds_return_t ret; + va_list ap; + assert (exp->n <= MAXSAMPLES); + va_start (ap, headerfmt); + vprintf (headerfmt, ap); + va_end (ap); + ret = dds_take (rd, raw, si, MAXSAMPLES + 1, MAXSAMPLES + 1); + for (int k = 0; k < ret; k++) + { + char is = '?'; + switch (si[k].instance_state) + { + case DDS_ALIVE_INSTANCE_STATE: is = 'a'; break; + case DDS_NOT_ALIVE_NO_WRITERS_INSTANCE_STATE: is = 'u'; break; + case DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE: is = 'd'; break; + } + printf (" %c{%d,%d,%d}", is, data[k].long_1, data[k].long_2, data[k].long_3); + } + printf ("\n"); + fflush (stdout); + CU_ASSERT_FATAL (ret == exp->n); + // sort because there's no ordering between instances + qsort (data, (size_t) ret, sizeof (data[0]), cmpdata); + for (int k = 0; k < exp->n; k++) + { + CU_ASSERT_FATAL (exp->xs[k].long_1 == data[k].long_1 && + exp->xs[k].long_2 == data[k].long_2 && + exp->xs[k].long_3 == data[k].long_3); + CU_ASSERT_FATAL (exp->is == NULL || + exp->is[data[k].long_1] == si[k].instance_state); + } +} + +CU_Test (ddsc_filter, basic) +{ + dds_entity_t dp[2], tp[2][2], rd[2][2], wr[2][2]; + dds_return_t ret; + char topicname[100]; + create_unique_topic_name ("ddsc_filter", topicname, sizeof (topicname)); + dds_qos_t *qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + for (int i = 0; i < 2; i++) + { + dp[i] = dds_create_participant (0, NULL, NULL); + CU_ASSERT_FATAL (dp[i] > 0); + for (int j = 0; j < 2; j++) + { + tp[i][j] = dds_create_topic (dp[i], &Space_Type1_desc, topicname, qos, NULL); + CU_ASSERT_FATAL (tp[i][j] > 0); + rd[i][j] = dds_create_reader (dp[i], tp[i][j], qos, NULL); + CU_ASSERT_FATAL (rd[i][j] > 0); + wr[i][j] = dds_create_writer (dp[i], tp[i][j], qos, NULL); + CU_ASSERT_FATAL (wr[i][j] > 0); + } + } + dds_delete_qos (qos); + + ret = dds_set_topic_filter_and_arg (tp[0][0], filter_long1_eq, (void *) 1); + CU_ASSERT_FATAL (ret == 0); + ret = dds_set_topic_filter_and_arg (tp[1][0], filter_long2_eq, (void *) 1); + CU_ASSERT_FATAL (ret == 0); + for (int i = 0; i < 2; i++) + { + for (int j = 0; j < 2; j++) + { + ret = dds_write (wr[i][j], &(Space_Type1){1,i,j}); + CU_ASSERT_FATAL (ret == 0); + ret = dds_write (wr[i][j], &(Space_Type1){2,i,j}); + CU_ASSERT_FATAL (ret == 0); + } + } + + // expectations for each reader: + // - write-like(data) using a filtered topic filters + // - write-like(key) using a filtered topic doesn't filter (attributes may be garbage) + // - RHC always filters (and is guaranteed 0's in the attributes) + struct exp exp[][2] = { + [0] = { + [0] = { + // participant 0, topic 0: reader filtered long_1 == 1 + // writer [0][0] filtering long_1 == 1, [0][1] unfiltered + // writer [1][0] filtering long_2 == 1, [1][1] unfiltered + .n = 4, .xs = (const Space_Type1[]) { + {1,0,0}, {1,0,1}, {1,1,0}, {1,1,1} + }, + }, + [1] = { + // participant 0, topic 1: reader unfiltered + // writer [0][0] filtering long_1 == 1, [0][1] unfiltered + // writer [1][0] filtering long_2 == 1, [1][1] unfiltered + .n = 7, .xs = (const Space_Type1[]) { + {1,0,0}, {1,0,1}, {1,1,0}, {1,1,1}, + {2,0,1}, {2,1,0}, {2,1,1} + } + } + }, + [1] = { + [0] = { + // participant 1, topic 0: reader filtered long_2 == 1 + // writer [0][0] filtering long_1 == 1, [0][1] unfiltered + // writer [1][0] filtering long_2 == 1, [1][1] unfiltered + .n = 4, .xs = (const Space_Type1[]) { + {1,1,0}, {1,1,1}, + {2,1,0}, {2,1,1} + } + }, + [1] = { + // participant 1, topic 1: reader unfiltered + // writer [0][0] filtering long_1 == 1, [0][1] unfiltered + // writer [1][0] filtering long_2 == 1, [1][1] unfiltered + .n = 7, .xs = (const Space_Type1[]) { + {1,0,0}, {1,0,1}, {1,1,0}, {1,1,1}, + {2,0,1}, {2,1,0}, {2,1,1} + } + } + }, + }; + + for (int i = 0; i < 2; i++) + for (int j = 0; j < 2; j++) + checkdata (rd[i][j], &exp[i][j], "rd[%d][%d]:", i, j); + for (int i = 0; i < 2; i++) + dds_delete (dp[i]); +} + +CU_Test (ddsc_filter, ownership) +{ + dds_entity_t dp, tp[2], rd, wr[2]; + dds_return_t ret; + char topicname[100]; + create_unique_topic_name ("ddsc_filter", topicname, sizeof (topicname)); + dds_qos_t *qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + dds_qset_ownership (qos, DDS_OWNERSHIP_EXCLUSIVE); + dp = dds_create_participant (0, NULL, NULL); + CU_ASSERT_FATAL (dp > 0); + for (int i = 0; i < 2; i++) + { + tp[i] = dds_create_topic (dp, &Space_Type1_desc, topicname, qos, NULL); + CU_ASSERT_FATAL (tp[i] > 0); + } + ret = dds_set_topic_filter_and_arg (tp[0], filter_long2_eq, (void *) 1); + CU_ASSERT_FATAL (ret == 0); + rd = dds_create_reader (dp, tp[0], qos, NULL); + CU_ASSERT_FATAL (rd > 0); + for (int i = 0; i < 2; i++) + { + dds_qset_ownership_strength (qos, i); + wr[i] = dds_create_writer (dp, tp[i], qos, NULL); + CU_ASSERT_FATAL (wr[i] > 0); + } + dds_delete_qos (qos); + + // lower strength writer: create instance (and own it) + ret = dds_write (wr[0], &(Space_Type1){1,1,0}); + CU_ASSERT_FATAL (ret == 0); + // higher strength writer: filtered out on attribute should not affect ownership + // instance already exists, so it still registers + ret = dds_write (wr[1], &(Space_Type1){1,0,1}); + CU_ASSERT_FATAL (ret == 0); + // and so a second write of the lower-strength writer should be visible + ret = dds_write (wr[0], &(Space_Type1){1,1,2}); + CU_ASSERT_FATAL (ret == 0); + + // higher-strength writer, filtered out on non-existent instance: no effect + ret = dds_write (wr[1], &(Space_Type1){2,0,0}); + CU_ASSERT_FATAL (ret == 0); + // lower-strength writer creates instance, sole registered writer + ret = dds_write (wr[0], &(Space_Type1){2,1,1}); + CU_ASSERT_FATAL (ret == 0); + + // sanity check: higher strength wins if it not filtered out + ret = dds_write (wr[0], &(Space_Type1){3,1,0}); + CU_ASSERT_FATAL (ret == 0); + ret = dds_write (wr[1], &(Space_Type1){3,1,1}); + CU_ASSERT_FATAL (ret == 0); + ret = dds_write (wr[0], &(Space_Type1){3,1,2}); + CU_ASSERT_FATAL (ret == 0); + + // unregister/auto-dispose lower strength writer: + // - key 1 -> alive, because the higher strength writer did register + // - key 2 -> disposed, because the higher strength writer never registered + // - key 3 -> alive, because the higher strength still owns it + ret = dds_delete (wr[0]); + CU_ASSERT_FATAL (ret == 0); + + struct exp exp = { + .n = 5, .xs = (const Space_Type1[]) { + {1,1,0}, {1,1,2}, + {2,1,1}, + {3,1,0}, {3,1,1}, + }, .is = (const dds_instance_state_t[]) { + [1] = DDS_ALIVE_INSTANCE_STATE, + [2] = DDS_NOT_ALIVE_DISPOSED_INSTANCE_STATE, + [3] = DDS_ALIVE_INSTANCE_STATE + } + }; + checkdata (rd, &exp, "rd"); + dds_delete (dp); +} + +static bool filter_long1_eq_1 (const void *vsample) +{ + Space_Type1 const * const sample = vsample; + return sample->long_1 == 1; +} + +CU_Test (ddsc_filter, compat) +{ + // check that the deprecated interface (which relies on an internal wrapper function) still works + dds_entity_t dp, tp, rd, wr; + dds_return_t ret; + char topicname[100]; + create_unique_topic_name ("ddsc_filter", topicname, sizeof (topicname)); + dds_qos_t *qos = dds_create_qos (); + dds_qset_reliability (qos, DDS_RELIABILITY_RELIABLE, DDS_INFINITY); + dds_qset_history (qos, DDS_HISTORY_KEEP_ALL, 0); + dp = dds_create_participant (0, NULL, NULL); + CU_ASSERT_FATAL (dp > 0); + tp = dds_create_topic (dp, &Space_Type1_desc, topicname, qos, NULL); + CU_ASSERT_FATAL (tp > 0); + DDSRT_WARNING_DEPRECATED_OFF; + dds_set_topic_filter (tp, filter_long1_eq_1); + DDSRT_WARNING_DEPRECATED_ON; + rd = dds_create_reader (dp, tp, qos, NULL); + CU_ASSERT_FATAL (rd > 0); + wr = dds_create_writer (dp, tp, qos, NULL); + CU_ASSERT_FATAL (wr > 0); + dds_delete_qos (qos); + + ret = dds_write (wr, &(Space_Type1){0,0,0}); + CU_ASSERT_FATAL (ret == 0); + ret = dds_write (wr, &(Space_Type1){1,0,0}); + CU_ASSERT_FATAL (ret == 0); + + struct exp exp = { + .n = 1, .xs = (const Space_Type1[]) { + {1,0,0} + }, + }; + checkdata (rd, &exp, "rd"); + dds_delete (dp); +} + +CU_Test (ddsc_filter, get) +{ + dds_entity_t dp, tp; + dds_return_t ret; + char topicname[100]; + create_unique_topic_name ("ddsc_filter", topicname, sizeof (topicname)); + dp = dds_create_participant (0, NULL, NULL); + CU_ASSERT_FATAL (dp > 0); + tp = dds_create_topic (dp, &Space_Type1_desc, topicname, NULL, NULL); + CU_ASSERT_FATAL (tp > 0); + + dds_topic_filter_arg_fn fn; + void *arg; + dds_topic_filter_fn fn_depr; + + ret = dds_get_topic_filter_and_arg (tp, NULL, NULL); + CU_ASSERT_FATAL (ret == 0); + + ret = dds_get_topic_filter_and_arg (tp, &fn, &arg); + CU_ASSERT_FATAL (ret == 0); + CU_ASSERT (fn == 0); + CU_ASSERT (arg == 0); + + ret = dds_set_topic_filter_and_arg (tp, filter_long1_eq, (void *) 1); + CU_ASSERT_FATAL (ret == 0); + + ret = dds_get_topic_filter_and_arg (tp, &fn, &arg); + CU_ASSERT_FATAL (ret == 0); + CU_ASSERT (fn == filter_long1_eq); + CU_ASSERT (arg == (void *) 1); + + DDSRT_WARNING_DEPRECATED_OFF; + fn_depr = dds_get_topic_filter (tp); + DDSRT_WARNING_DEPRECATED_ON; + CU_ASSERT_FATAL (fn_depr == 0); + + DDSRT_WARNING_DEPRECATED_OFF; + dds_set_topic_filter (tp, filter_long1_eq_1); + DDSRT_WARNING_DEPRECATED_ON; + + ret = dds_get_topic_filter_and_arg (tp, &fn, &arg); + CU_ASSERT_FATAL (ret == DDS_RETCODE_PRECONDITION_NOT_MET); + + DDSRT_WARNING_DEPRECATED_OFF; + fn_depr = dds_get_topic_filter (tp); + DDSRT_WARNING_DEPRECATED_ON; + CU_ASSERT_FATAL (fn_depr == filter_long1_eq_1); + + dds_delete (dp); +} +