From b91721e79b644b03e7613804d10ca49eec349344 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Thu, 13 Jun 2024 16:01:56 +0200 Subject: [PATCH 01/14] feat: switch attachment to z_bytes --- include/zenoh-pico/api/primitives.h | 13 +- include/zenoh-pico/api/types.h | 125 +---------- include/zenoh-pico/net/primitives.h | 26 +-- include/zenoh-pico/net/query.h | 6 +- include/zenoh-pico/net/reply.h | 2 +- include/zenoh-pico/net/sample.h | 6 +- include/zenoh-pico/protocol/core.h | 66 ------ .../zenoh-pico/protocol/definitions/message.h | 6 +- .../zenoh-pico/protocol/definitions/network.h | 7 +- include/zenoh-pico/session/queryable.h | 2 +- include/zenoh-pico/session/subscription.h | 4 +- src/api/api.c | 201 ++---------------- src/net/primitives.c | 32 +-- src/net/query.c | 11 +- src/net/reply.c | 7 +- src/net/sample.c | 21 +- src/protocol/codec/message.c | 51 +---- src/protocol/core.c | 81 ------- src/protocol/definitions/message.c | 11 +- src/protocol/definitions/network.c | 23 +- src/session/push.c | 8 +- src/session/query.c | 8 +- src/session/queryable.c | 2 +- src/session/rx.c | 13 +- src/session/subscription.c | 6 +- 25 files changed, 104 insertions(+), 634 deletions(-) diff --git a/include/zenoh-pico/api/primitives.h b/include/zenoh-pico/api/primitives.h index d00aa8098..de9aa2bd5 100644 --- a/include/zenoh-pico/api/primitives.h +++ b/include/zenoh-pico/api/primitives.h @@ -842,7 +842,6 @@ void z_query_parameters(const z_loaned_query_t *query, z_view_string_t *paramete */ const z_loaned_value_t *z_query_value(const z_loaned_query_t *query); -#if Z_FEATURE_ATTACHMENT == 1 /** * Gets a query attachment value by aliasing it. * @@ -850,10 +849,9 @@ const z_loaned_value_t *z_query_value(const z_loaned_query_t *query); * query: Pointer to the :c:type:`z_loaned_query_t` to get the attachment from. * * Return: - * The attachment value wrapped as a :c:type:`z_attachment_t`. + * Pointer to the attachment as a :c:type:`z_loaned_bytes_t`. */ -z_attachment_t z_query_attachment(const z_loaned_query_t *query); -#endif +const z_loaned_bytes_t *z_query_attachment(const z_loaned_query_t *query); /** * Gets a query keyexpr by aliasing it. @@ -1219,7 +1217,6 @@ z_sample_kind_t z_sample_kind(const z_loaned_sample_t *sample); */ z_qos_t z_sample_qos(const z_loaned_sample_t *sample); -#if Z_FEATURE_ATTACHMENT == 1 /** * Gets the attachment of a value by aliasing it. * @@ -1227,10 +1224,10 @@ z_qos_t z_sample_qos(const z_loaned_sample_t *sample); * sample: Pointer to a :c:type:`z_loaned_sample_t` to get the attachment from. * * Return: - * The attachment wrapped as a :c:type:`z_attachment_t`. + * Pointer to the attachment as a :c:type:`z_loaned_bytes_t`. */ -z_attachment_t z_sample_attachment(const z_loaned_sample_t *sample); -#endif +const z_loaned_bytes_t *z_sample_attachment(const z_loaned_sample_t *sample); + #if Z_FEATURE_PUBLICATION == 1 /** * Builds a :c:type:`z_put_options_t` with default values. diff --git a/include/zenoh-pico/api/types.h b/include/zenoh-pico/api/types.h index 96576a0de..b5a0b617e 100644 --- a/include/zenoh-pico/api/types.h +++ b/include/zenoh-pico/api/types.h @@ -261,11 +261,11 @@ typedef struct { * * Members: * z_owned_encoding_t *encoding: The encoding of the payload. - * z_attachment_t attachment: an attachment to the response. + * z_owned_bytes_t *attachment: An optional attachment to the response. */ typedef struct { z_owned_encoding_t *encoding; - z_attachment_t attachment; + z_owned_bytes_t *attachment; } z_query_reply_options_t; /** @@ -275,14 +275,13 @@ typedef struct { * z_owned_encoding_t *encoding: The encoding of the payload. * z_congestion_control_t congestion_control: The congestion control to apply when routing this message. * z_priority_t priority: The priority of this message when routed. + * z_owned_bytes_t *attachment: An optional attachment to the publication. */ typedef struct { z_owned_encoding_t *encoding; z_congestion_control_t congestion_control; z_priority_t priority; -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t attachment; -#endif + z_owned_bytes_t *attachment; } z_put_options_t; /** @@ -303,12 +302,11 @@ typedef struct { * * Members: * z_owned_encoding_t *encoding: The encoding of the payload. + * z_owned_bytes_t *attachment: An optional attachment to the publication. */ typedef struct { z_owned_encoding_t *encoding; -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t attachment; -#endif + z_owned_bytes_t *attachment; } z_publisher_put_options_t; /** @@ -327,6 +325,7 @@ typedef struct { * z_owned_encoding_t *encoding: Payload encoding. * z_query_consolidation_t consolidation: The replies consolidation strategy to apply on replies. * z_query_target_t target: The queryables that should be targeted by this get. + * z_owned_bytes_t *attachment: An optional attachment to the query. */ typedef struct { z_owned_bytes_t *payload; @@ -334,9 +333,7 @@ typedef struct { z_query_consolidation_t consolidation; z_query_target_t target; uint32_t timeout_ms; -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t attachment; -#endif + z_owned_bytes_t *attachment; } z_get_options_t; /** @@ -633,112 +630,6 @@ typedef struct { } z_owned_closure_zid_t; void z_closure_zid_call(const z_owned_closure_zid_t *closure, const z_id_t *id); -#if Z_FEATURE_ATTACHMENT == 1 -struct _z_slice_pair_t { - _z_slice_t *key; - _z_slice_t *value; -}; - -void _z_slice_pair_clear(struct _z_slice_pair_t *this_); - -_Z_ELEM_DEFINE(_z_slice_pair, struct _z_slice_pair_t, _z_noop_size, _z_slice_pair_clear, _z_noop_copy) -_Z_LIST_DEFINE(_z_slice_pair, struct _z_slice_pair_t) - -/** - * A map of maybe-owned vector of bytes to maybe-owned vector of bytes. - */ -// TODO(sashacmc): z_owned_bytes_map_t for attachment -typedef struct z_owned_bytes_map_t { - _z_slice_pair_list_t *_inner; -} z_owned_bytes_map_t; - -/** - * Aliases `this` into a generic `z_attachment_t`, allowing it to be passed to corresponding APIs. - */ -z_attachment_t z_bytes_map_as_attachment(const z_owned_bytes_map_t *this_); - -/** - * Returns `true` if the map is not in its gravestone state - */ -bool z_bytes_map_check(const z_owned_bytes_map_t *this_); - -/** - * Deletes the map, resetting `this` to its gravestone value. - * - * This function is double-free safe, passing a pointer to the gravestone value will have no effect. - */ -void z_bytes_map_drop(z_owned_bytes_map_t *this_); - -/** - * Builds a map from the provided attachment, copying keys and values. - * - * If `this` is at gravestone value, the returned value will also be at gravestone value. - */ -z_owned_bytes_map_t z_bytes_map_from_attachment(z_attachment_t this_); - -/** - * Builds a map from the provided attachment, aliasing the attachment's keys and values. - * - * If `this` is at gravestone value, the returned value will also be at gravestone value. - */ - -z_owned_bytes_map_t z_bytes_map_from_attachment_aliasing(z_attachment_t this_); - -/** - * Returns the value associated with `key`, returning a gravestone value if: - * - `this` or `key` is in gravestone state. - * - `this` has no value associated to `key` - */ - -z_loaned_slice_t *z_bytes_map_get(const z_owned_bytes_map_t *this_, z_loaned_slice_t *key); - -/** - * Associates `value` to `key` in the map, aliasing them. - * - * Note that once `key` is aliased, reinserting at the same key may alias the previous instance, or the new instance of - * `key`. - * - * Calling this with `NULL` or the gravestone value is undefined behaviour. - */ - -void z_bytes_map_insert_by_alias(const z_owned_bytes_map_t *this_, z_loaned_slice_t *key, z_loaned_slice_t *value); - -/** - * Associates `value` to `key` in the map, copying them to obtain ownership: `key` and `value` are not aliased past the - * function's return. - * - * Calling this with `NULL` or the gravestone value is undefined behaviour. - */ - -void z_bytes_map_insert_by_copy(const z_owned_bytes_map_t *this_, z_loaned_slice_t *key, z_loaned_slice_t *value); - -/** - * Iterates over the key-value pairs in the map. - * - * `body` will be called once per pair, with `ctx` as its last argument. - * If `body` returns a non-zero value, the iteration will stop immediately and the value will be returned. - * Otherwise, this will return 0 once all pairs have been visited. - * `body` is not given ownership of the key nor value, which alias the pairs in the map. - * It is safe to keep these aliases until existing keys are modified/removed, or the map is destroyed. - * Note that this map is unordered. - * - * Calling this with `NULL` or the gravestone value is undefined behaviour. - */ - -int8_t z_bytes_map_iter(const z_owned_bytes_map_t *this_, z_attachment_iter_body_t body, void *ctx); - -/** - * Builds a new map. - */ -// TODO(sashacmc): z_bytes_map_new for attachment -z_owned_bytes_map_t z_bytes_map_new(void); - -/** - * Initializes a `z_owned_bytes_map_t` - */ -// TODO(sashacmc): z_bytes_map_null for attachment -z_owned_bytes_map_t z_bytes_map_null(void); -#endif /** * Returns a view of `str` using `strlen` (this constructor should not be used on untrusted input). diff --git a/include/zenoh-pico/net/primitives.h b/include/zenoh-pico/net/primitives.h index 09bed035d..ed9ef6989 100644 --- a/include/zenoh-pico/net/primitives.h +++ b/include/zenoh-pico/net/primitives.h @@ -115,17 +115,13 @@ int8_t _z_undeclare_publisher(_z_publisher_t *pub); * kind: The kind of the value. * cong_ctrl: The congestion control of this write. Possible values defined * in :c:type:`_z_congestion_control_t`. + * attachment: An optional attachment to this write. * Returns: * ``0`` in case of success, ``-1`` in case of failure. */ int8_t _z_write(_z_session_t *zn, const _z_keyexpr_t keyexpr, const uint8_t *payload, const size_t len, const _z_encoding_t encoding, const z_sample_kind_t kind, const z_congestion_control_t cong_ctrl, - z_priority_t priority -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_t attachment -#endif -); + z_priority_t priority, const _z_bytes_t attachment); #endif #if Z_FEATURE_SUBSCRIPTION == 1 @@ -201,10 +197,10 @@ int8_t _z_undeclare_queryable(_z_queryable_t *qle); * key: The resource key of this reply. The caller keeps the ownership. * payload: The value of this reply, the caller keeps ownership. * kind: The type of operation. - * att: The optional attachment to the sample. + * attachment: An optional attachment to the reply. */ int8_t _z_send_reply(const _z_query_t *query, const _z_keyexpr_t keyexpr, const _z_value_t payload, - const z_sample_kind_t kind, z_attachment_t att); + const z_sample_kind_t kind, const _z_bytes_t attachment); #endif #if Z_FEATURE_QUERY == 1 @@ -220,18 +216,16 @@ int8_t _z_send_reply(const _z_query_t *query, const _z_keyexpr_t keyexpr, const * consolidation: The kind of consolidation that should be applied on replies. * value: The payload of the query. * callback: The callback function that will be called on reception of replies for this query. - * arg_call: A pointer that will be passed to the **callback** on each call. * dropper: The callback function that will be called on upon completion of the callback. - * arg_drop: A pointer that will be passed to the **dropper** on each call. + * arg: A pointer that will be passed to the **callback** on each call. + * timeout_ms: The timeout value of this query. + * attachment: An optional attachment to this query. + * + * */ int8_t _z_query(_z_session_t *zn, _z_keyexpr_t keyexpr, const char *parameters, const z_query_target_t target, const z_consolidation_mode_t consolidation, const _z_value_t value, _z_reply_handler_t callback, - _z_drop_handler_t dropper, void *arg, uint32_t timeout_ms -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_t attachment -#endif -); + _z_drop_handler_t dropper, void *arg, uint32_t timeout_ms, const _z_bytes_t attachment); #endif #if Z_FEATURE_INTEREST == 1 diff --git a/include/zenoh-pico/net/query.h b/include/zenoh-pico/net/query.h index fb458f9a2..e04cc6f88 100644 --- a/include/zenoh-pico/net/query.h +++ b/include/zenoh-pico/net/query.h @@ -28,9 +28,7 @@ typedef struct _z_query_t { _z_keyexpr_t _key; uint32_t _request_id; _z_session_t *_zn; -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t attachment; -#endif + _z_bytes_t attachment; char *_parameters; _Bool _anyke; } _z_query_t; @@ -49,7 +47,7 @@ typedef struct { #if Z_FEATURE_QUERYABLE == 1 _z_query_t _z_query_create(const _z_value_t *value, const _z_keyexpr_t *key, const _z_slice_t *parameters, - _z_session_t *zn, uint32_t request_id, z_attachment_t att); + _z_session_t *zn, uint32_t request_id, const _z_bytes_t attachment); void _z_queryable_clear(_z_queryable_t *qbl); void _z_queryable_free(_z_queryable_t **qbl); #endif diff --git a/include/zenoh-pico/net/reply.h b/include/zenoh-pico/net/reply.h index c240d3841..f8ad26449 100644 --- a/include/zenoh-pico/net/reply.h +++ b/include/zenoh-pico/net/reply.h @@ -63,7 +63,7 @@ void _z_reply_free(_z_reply_t **hello); void _z_reply_copy(_z_reply_t *dst, _z_reply_t *src); _z_reply_t _z_reply_create(_z_keyexpr_t keyexpr, z_reply_tag_t tag, _z_id_t id, const _z_slice_t *payload, const _z_timestamp_t *timestamp, _z_encoding_t encoding, z_sample_kind_t kind, - z_attachment_t att); + const _z_bytes_t attachment); _Z_REFCOUNT_DEFINE(_z_reply, _z_reply) diff --git a/include/zenoh-pico/net/sample.h b/include/zenoh-pico/net/sample.h index 30e7ac97a..13b1023dd 100644 --- a/include/zenoh-pico/net/sample.h +++ b/include/zenoh-pico/net/sample.h @@ -35,9 +35,7 @@ typedef struct _z_sample_t { _z_encoding_t encoding; z_sample_kind_t kind; _z_qos_t qos; -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t attachment; -#endif + _z_bytes_t attachment; } _z_sample_t; void _z_sample_clear(_z_sample_t *sample); @@ -60,6 +58,6 @@ _z_sample_t _z_sample_duplicate(const _z_sample_t *src); _z_sample_t _z_sample_create(const _z_keyexpr_t *key, const _z_slice_t *payload, _z_timestamp_t timestamp, const _z_encoding_t encoding, const z_sample_kind_t kind, const _z_qos_t qos, - const z_attachment_t att); + const _z_bytes_t attachment); #endif /* ZENOH_PICO_SAMPLE_NETAPI_H */ diff --git a/include/zenoh-pico/protocol/core.h b/include/zenoh-pico/protocol/core.h index 5354dc2e4..99377f0e0 100644 --- a/include/zenoh-pico/protocol/core.h +++ b/include/zenoh-pico/protocol/core.h @@ -65,72 +65,6 @@ typedef struct { uint64_t time; } _z_timestamp_t; -/** - * The body of a loop over an attachment's key-value pairs. - * - * `key` and `value` are loaned to the body for the duration of a single call. - * `context` is passed transparently through the iteration driver. - * - * Returning `0` is treated as `continue`. - * Returning any other value is treated as `break`. - */ -typedef int8_t (*z_attachment_iter_body_t)(_z_slice_t key, _z_slice_t value, void *context); -/** - * The driver of a loop over an attachment's key-value pairs. - * - * This function is expected to call `loop_body` once for each key-value pair - * within `iterator`, passing `context`, and returning any non-zero value immediately (breaking iteration). - */ -typedef int8_t (*z_attachment_iter_driver_t)(const void *iterator, z_attachment_iter_body_t loop_body, void *context); -/** - * The v-table for an attachment. - */ -typedef struct z_attachment_vtable_t { - /** - * See `z_attachment_iteration_driver_t`'s documentation. - */ - z_attachment_iter_driver_t iteration_driver; -} z_attachment_vtable_t; - -/** - * A v-table based map of byte slice to byte slice. - * - * `vtable == NULL` marks the gravestone value, as this type is often optional. - * Users are encouraged to use `z_attachment_null` and `z_attachment_check` to interact. - */ -typedef struct z_attachment_t { - const void *data; - z_attachment_iter_driver_t iteration_driver; -} z_attachment_t; - -typedef struct { - union { - z_attachment_t decoded; - _z_slice_t encoded; - } body; - _Bool is_encoded; -} _z_owned_encoded_attachment_t; - -z_attachment_t z_attachment_null(void); -z_attachment_t _z_encoded_as_attachment(const _z_owned_encoded_attachment_t *att); - -#if Z_FEATURE_ATTACHMENT == 1 - -_Bool z_attachment_check(const z_attachment_t *attachment); -int8_t z_attachment_iterate(z_attachment_t this_, z_attachment_iter_body_t body, void *ctx); -_z_slice_t z_attachment_get(z_attachment_t this_, _z_slice_t key); - -/** - * Estimate the length of an attachment once encoded. - */ -size_t _z_attachment_estimate_length(z_attachment_t att); - -/** - * Drop an attachment that was decoded from a received message - */ -void _z_attachment_drop(z_attachment_t *att); -#endif - _z_timestamp_t _z_timestamp_duplicate(const _z_timestamp_t *tstamp); _z_timestamp_t _z_timestamp_null(void); void _z_timestamp_clear(_z_timestamp_t *tstamp); diff --git a/include/zenoh-pico/protocol/definitions/message.h b/include/zenoh-pico/protocol/definitions/message.h index 39d09dff8..36dd0f2bf 100644 --- a/include/zenoh-pico/protocol/definitions/message.h +++ b/include/zenoh-pico/protocol/definitions/message.h @@ -75,9 +75,7 @@ typedef struct { _z_m_push_commons_t _commons; _z_slice_t _payload; _z_encoding_t _encoding; -#if Z_FEATURE_ATTACHMENT == 1 - _z_owned_encoded_attachment_t _attachment; -#endif + _z_bytes_t _attachment; } _z_msg_put_t; void _z_msg_put_clear(_z_msg_put_t *); #define _Z_M_PUT_ID 0x01 @@ -102,7 +100,7 @@ typedef struct { _z_source_info_t _ext_info; _z_value_t _ext_value; z_consolidation_mode_t _consolidation; - _z_owned_encoded_attachment_t _ext_attachment; + _z_bytes_t _ext_attachment; } _z_msg_query_t; typedef struct { _Bool info; diff --git a/include/zenoh-pico/protocol/definitions/network.h b/include/zenoh-pico/protocol/definitions/network.h index 28e9f04b8..1940a4660 100644 --- a/include/zenoh-pico/protocol/definitions/network.h +++ b/include/zenoh-pico/protocol/definitions/network.h @@ -293,12 +293,7 @@ _Z_VEC_DEFINE(_z_network_message, _z_network_message_t) void _z_msg_fix_mapping(_z_zenoh_message_t *msg, uint16_t mapping); _z_network_message_t _z_msg_make_query(_Z_MOVE(_z_keyexpr_t) key, _Z_MOVE(_z_slice_t) parameters, _z_zint_t qid, z_consolidation_mode_t consolidation, _Z_MOVE(_z_value_t) value, - uint32_t timeout_ms -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_t attachment -#endif -); + uint32_t timeout_ms, _z_bytes_t attachment); _z_network_message_t _z_n_msg_make_reply(_z_zint_t rid, _Z_MOVE(_z_keyexpr_t) key, _Z_MOVE(_z_push_body_t) body); _z_network_message_t _z_n_msg_make_response_final(_z_zint_t rid); _z_network_message_t _z_n_msg_make_declare(_z_declaration_t declaration, _Bool has_interest_id, uint32_t interest_id); diff --git a/include/zenoh-pico/session/queryable.h b/include/zenoh-pico/session/queryable.h index dbce05646..78c5f3cad 100644 --- a/include/zenoh-pico/session/queryable.h +++ b/include/zenoh-pico/session/queryable.h @@ -29,7 +29,7 @@ _z_session_queryable_rc_list_t *_z_get_session_queryable_by_key(_z_session_t *zn _z_session_queryable_rc_t *_z_register_session_queryable(_z_session_t *zn, _z_session_queryable_t *q); int8_t _z_trigger_queryables(_z_session_t *zn, const _z_msg_query_t *query, const _z_keyexpr_t q_key, uint32_t qid, - z_attachment_t att); + const _z_bytes_t attachment); void _z_unregister_session_queryable(_z_session_t *zn, _z_session_queryable_rc_t *q); void _z_flush_session_queryable(_z_session_t *zn); #endif diff --git a/include/zenoh-pico/session/subscription.h b/include/zenoh-pico/session/subscription.h index a85dac0a7..0635a9572 100644 --- a/include/zenoh-pico/session/subscription.h +++ b/include/zenoh-pico/session/subscription.h @@ -20,7 +20,7 @@ /*------------------ Subscription ------------------*/ void _z_trigger_local_subscriptions(_z_session_t *zn, const _z_keyexpr_t keyexpr, const uint8_t *payload, - _z_zint_t payload_len, const _z_n_qos_t qos, const z_attachment_t att); + _z_zint_t payload_len, const _z_n_qos_t qos, const _z_bytes_t att); #if Z_FEATURE_SUBSCRIPTION == 1 _z_subscription_rc_t *_z_get_subscription_by_id(_z_session_t *zn, uint8_t is_local, const _z_zint_t id); @@ -29,7 +29,7 @@ _z_subscription_rc_list_t *_z_get_subscriptions_by_key(_z_session_t *zn, uint8_t _z_subscription_rc_t *_z_register_subscription(_z_session_t *zn, uint8_t is_local, _z_subscription_t *sub); int8_t _z_trigger_subscriptions(_z_session_t *zn, const _z_keyexpr_t keyexpr, const _z_slice_t payload, const _z_encoding_t encoding, const _z_zint_t kind, const _z_timestamp_t timestamp, - const _z_n_qos_t qos, const z_attachment_t att); + const _z_n_qos_t qos, const _z_bytes_t attachment); void _z_unregister_subscription(_z_session_t *zn, uint8_t is_local, _z_subscription_rc_t *sub); void _z_flush_subscriptions(_z_session_t *zn); #endif diff --git a/src/api/api.c b/src/api/api.c index 29b7d23d2..4601451e3 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -532,9 +532,7 @@ void z_query_parameters(const z_loaned_query_t *query, z_view_string_t *paramete const z_loaned_value_t *z_query_value(const z_loaned_query_t *query) { return &query->in->val._value; } -#if Z_FEATURE_ATTACHMENT == 1 -z_attachment_t z_query_attachment(const z_loaned_query_t *query) { return query->in->val.attachment; } -#endif +const z_loaned_bytes_t *z_query_attachment(const z_loaned_query_t *query) { return &query->in->val.attachment; } const z_loaned_keyexpr_t *z_query_keyexpr(const z_loaned_query_t *query) { return &query->in->val._key; } @@ -839,9 +837,9 @@ const z_loaned_bytes_t *z_sample_payload(const z_loaned_sample_t *sample) { retu z_timestamp_t z_sample_timestamp(const z_loaned_sample_t *sample) { return _Z_RC_IN_VAL(sample).timestamp; } const z_loaned_encoding_t *z_sample_encoding(const z_loaned_sample_t *sample) { return &_Z_RC_IN_VAL(sample).encoding; } z_qos_t z_sample_qos(const z_loaned_sample_t *sample) { return _Z_RC_IN_VAL(sample).qos; } -#if Z_FEATURE_ATTACHMENT == 1 -z_attachment_t z_sample_attachment(const z_loaned_sample_t *sample) { return _Z_RC_IN_VAL(sample).attachment; } -#endif +const z_loaned_bytes_t *z_sample_attachment(const z_loaned_sample_t *sample) { + return &_Z_RC_IN_VAL(sample).attachment; +} const char *z_string_data(const z_loaned_string_t *str) { return str->val; } size_t z_string_len(const z_loaned_string_t *str) { return str->len; } @@ -862,9 +860,7 @@ void z_put_options_default(z_put_options_t *options) { options->congestion_control = Z_CONGESTION_CONTROL_DEFAULT; options->priority = Z_PRIORITY_DEFAULT; options->encoding = NULL; -#if Z_FEATURE_ATTACHMENT == 1 - options->attachment = z_attachment_null(); -#endif + options->attachment = NULL; } void z_delete_options_default(z_delete_options_t *options) { @@ -882,29 +878,17 @@ int8_t z_put(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, co opt.congestion_control = options->congestion_control; opt.encoding = options->encoding; opt.priority = options->priority; -#if Z_FEATURE_ATTACHMENT == 1 opt.attachment = options->attachment; -#endif } + ret = _z_write(&_Z_RC_IN_VAL(zs), *keyexpr, (const uint8_t *)payload, payload_len, - _z_encoding_from_owned(opt.encoding), Z_SAMPLE_KIND_PUT, opt.congestion_control, opt.priority -#if Z_FEATURE_ATTACHMENT == 1 - , - opt.attachment -#endif - ); + _z_encoding_from_owned(opt.encoding), Z_SAMPLE_KIND_PUT, opt.congestion_control, opt.priority, + _z_bytes_from_owned_bytes(opt.attachment)); // Trigger local subscriptions -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t att = opt.attachment; -#else - z_attachment_t att = z_attachment_null(); -#endif _z_trigger_local_subscriptions(&_Z_RC_IN_VAL(zs), *keyexpr, payload, payload_len, _z_n_qos_make(0, opt.congestion_control == Z_CONGESTION_CONTROL_BLOCK, opt.priority), - att - - ); + _z_bytes_from_owned_bytes(opt.attachment)); // Clean-up z_encoding_drop(opt.encoding); return ret; @@ -920,12 +904,7 @@ int8_t z_delete(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, opt.priority = options->priority; } ret = _z_write(&_Z_RC_IN_VAL(zs), *keyexpr, NULL, 0, _z_encoding_null(), Z_SAMPLE_KIND_DELETE, - opt.congestion_control, opt.priority -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_null() -#endif - ); + opt.congestion_control, opt.priority, _z_bytes_null()); return ret; } @@ -981,9 +960,7 @@ int8_t z_undeclare_publisher(z_owned_publisher_t *pub) { return _z_publisher_dro void z_publisher_put_options_default(z_publisher_put_options_t *options) { options->encoding = NULL; -#if Z_FEATURE_ATTACHMENT == 1 - options->attachment = z_attachment_null(); -#endif + options->attachment = NULL; } void z_publisher_delete_options_default(z_publisher_delete_options_t *options) { options->__dummy = 0; } @@ -996,29 +973,18 @@ int8_t z_publisher_put(const z_loaned_publisher_t *pub, const uint8_t *payload, z_publisher_put_options_default(&opt); if (options != NULL) { opt.encoding = options->encoding; -#if Z_FEATURE_ATTACHMENT == 1 opt.attachment = options->attachment; -#endif } // Check if write filter is active before writing if (!_z_write_filter_active(pub)) { // Write value ret = _z_write(&pub->_zn.in->val, pub->_key, payload, len, _z_encoding_from_owned(opt.encoding), - Z_SAMPLE_KIND_PUT, pub->_congestion_control, pub->_priority -#if Z_FEATURE_ATTACHMENT == 1 - , - opt.attachment -#endif - ); + Z_SAMPLE_KIND_PUT, pub->_congestion_control, pub->_priority, + _z_bytes_from_owned_bytes(opt.attachment)); } - -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t att = opt.attachment; -#else - z_attachment_t att = z_attachment_null(); -#endif // Trigger local subscriptions - _z_trigger_local_subscriptions(&pub->_zn.in->val, pub->_key, payload, len, _Z_N_QOS_DEFAULT, att); + _z_trigger_local_subscriptions(&pub->_zn.in->val, pub->_key, payload, len, _Z_N_QOS_DEFAULT, + _z_bytes_from_owned_bytes(opt.attachment)); // Clean-up z_encoding_drop(opt.encoding); @@ -1028,12 +994,7 @@ int8_t z_publisher_put(const z_loaned_publisher_t *pub, const uint8_t *payload, int8_t z_publisher_delete(const z_loaned_publisher_t *pub, const z_publisher_delete_options_t *options) { (void)(options); return _z_write(&pub->_zn.in->val, pub->_key, NULL, 0, _z_encoding_null(), Z_SAMPLE_KIND_DELETE, - pub->_congestion_control, pub->_priority -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_null() -#endif - ); + pub->_congestion_control, pub->_priority, _z_bytes_null()); } z_owned_keyexpr_t z_publisher_keyexpr(z_loaned_publisher_t *publisher) { @@ -1053,9 +1014,7 @@ void z_get_options_default(z_get_options_t *options) { options->consolidation = z_query_consolidation_default(); options->encoding = NULL; options->payload = NULL; -#if Z_FEATURE_ATTACHMENT == 1 - options->attachment = z_attachment_null(); -#endif + options->attachment = NULL; options->timeout_ms = Z_GET_TIMEOUT_DEFAULT; } @@ -1073,9 +1032,7 @@ int8_t z_get(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, co opt.target = options->target; opt.encoding = options->encoding; opt.payload = z_bytes_move(options->payload); -#if Z_FEATURE_ATTACHMENT == 1 opt.attachment = options->attachment; -#endif } if (opt.consolidation.mode == Z_CONSOLIDATION_MODE_AUTO) { @@ -1091,12 +1048,7 @@ int8_t z_get(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, co .encoding = _z_encoding_from_owned(opt.encoding)}; ret = _z_query(&_Z_RC_IN_VAL(zs), *keyexpr, parameters, opt.target, opt.consolidation.mode, value, callback->call, - callback->drop, ctx, opt.timeout_ms -#if Z_FEATURE_ATTACHMENT == 1 - , - opt.attachment -#endif - ); + callback->drop, ctx, opt.timeout_ms, _z_bytes_from_owned_bytes(opt.attachment)); if (opt.payload != NULL) { z_bytes_drop(opt.payload); } @@ -1180,7 +1132,8 @@ int8_t z_query_reply(const z_loaned_query_t *query, const z_loaned_keyexpr_t *ke _z_value_t value = {.payload = _z_bytes_from_owned_bytes(payload), .encoding = _z_encoding_from_owned(opts.encoding)}; - int8_t ret = _z_send_reply(&query->in->val, *keyexpr, value, Z_SAMPLE_KIND_PUT, opts.attachment); + int8_t ret = + _z_send_reply(&query->in->val, *keyexpr, value, Z_SAMPLE_KIND_PUT, _z_bytes_from_owned_bytes(opts.attachment)); if (payload != NULL) { z_bytes_drop(payload); } @@ -1406,117 +1359,3 @@ int8_t zp_send_join(const z_loaned_session_t *zs, const zp_send_join_options_t * (void)(options); return _zp_send_join(&_Z_RC_IN_VAL(zs)); } -#if Z_FEATURE_ATTACHMENT == 1 -void _z_slice_pair_clear(struct _z_slice_pair_t *this_) { - _z_slice_clear(&this_->key); - _z_slice_clear(&this_->value); -} - -z_attachment_t z_bytes_map_as_attachment(const z_owned_bytes_map_t *this_) { - if (!z_bytes_map_check(this_)) { - return z_attachment_null(); - } - return (z_attachment_t){.data = this_, .iteration_driver = (z_attachment_iter_driver_t)z_bytes_map_iter}; -} -bool z_bytes_map_check(const z_owned_bytes_map_t *this_) { return this_->_inner != NULL; } -void z_bytes_map_drop(z_owned_bytes_map_t *this_) { _z_slice_pair_list_free(&this_->_inner); } - -int8_t _z_slice_map_insert_by_alias(z_loaned_slice_t *key, z_loaned_slice_t *value, void *this_) { - z_bytes_map_insert_by_alias((z_owned_bytes_map_t *)this_, key, value); - return 0; -} -int8_t _z_slice_map_insert_by_copy(z_loaned_slice_t *key, z_loaned_slice_t *value, void *this_) { - z_bytes_map_insert_by_copy((z_owned_bytes_map_t *)this_, key, value); - return 0; -} -z_owned_bytes_map_t z_bytes_map_from_attachment(z_attachment_t this_) { - if (!z_attachment_check(&this_)) { - return z_bytes_map_null(); - } - z_owned_bytes_map_t map = z_bytes_map_new(); - z_attachment_iterate(this_, _z_slice_map_insert_by_copy, &map); - return map; -} -z_owned_bytes_map_t z_bytes_map_from_attachment_aliasing(z_attachment_t this_) { - if (!z_attachment_check(&this_)) { - return z_bytes_map_null(); - } - z_owned_bytes_map_t map = z_bytes_map_new(); - z_attachment_iterate(this_, _z_slice_map_insert_by_alias, &map); - return map; -} -z_loaned_slice_t *z_bytes_map_get(const z_owned_bytes_map_t *this_, z_loaned_slice_t *key) { - _z_slice_pair_list_t *current = this_->_inner; - while (current) { - struct _z_slice_pair_t *head = _z_slice_pair_list_head(current); - if (_z_slice_eq(&key, &head->key)) { - return _z_slice_wrap(head->value.start, head->value.len); - } - } - return z_slice_null(); -} -void z_bytes_map_insert_by_alias(const z_owned_bytes_map_t *this_, z_loaned_slice_t *key, z_loaned_slice_t *value) { - _z_slice_pair_list_t *current = this_->_inner; - while (current) { - struct _z_slice_pair_t *head = _z_slice_pair_list_head(current); - if (_z_slice_eq(&key, &head->key)) { - break; - } - current = _z_slice_pair_list_tail(current); - } - if (current) { - struct _z_slice_pair_t *head = _z_slice_pair_list_head(current); - _z_slice_clear(&head->value); - head->value = _z_slice_wrap(value.start, value.len); - } else { - struct _z_slice_pair_t *insert = z_malloc(sizeof(struct _z_slice_pair_t)); - memset(insert, 0, sizeof(struct _z_slice_pair_t)); - insert->key = _z_slice_wrap(key.start, key.len); - insert->value = _z_slice_wrap(value.start, value.len); - ((z_owned_bytes_map_t *)this_)->_inner = _z_slice_pair_list_push(this_->_inner, insert); - } -} -void z_bytes_map_insert_by_copy(const z_owned_bytes_map_t *this_, z_loaned_slice_t *key, z_loaned_slice_t *value) { - _z_slice_pair_list_t *current = this_->_inner; - while (current) { - struct _z_slice_pair_t *head = _z_slice_pair_list_head(current); - if (_z_slice_eq(&key, &head->key)) { - break; - } - current = _z_slice_pair_list_tail(current); - } - if (current) { - struct _z_slice_pair_t *head = _z_slice_pair_list_head(current); - _z_slice_clear(&head->value); - _z_slice_copy(&head->value, &value); - if (!head->key._is_alloc) { - _z_slice_copy(&head->key, &key); - } - } else { - struct _z_slice_pair_t *insert = z_malloc(sizeof(struct _z_slice_pair_t)); - memset(insert, 0, sizeof(struct _z_slice_pair_t)); - _z_slice_copy(&insert->key, &key); - _z_slice_copy(&insert->value, &value); - ((z_owned_bytes_map_t *)this_)->_inner = _z_slice_pair_list_push(this_->_inner, insert); - } -} -int8_t z_bytes_map_iter(const z_owned_bytes_map_t *this_, z_attachment_iter_body_t body, void *ctx) { - _z_slice_pair_list_t *current = this_->_inner; - while (current) { - struct _z_slice_pair_t *head = _z_slice_pair_list_head(current); - int8_t ret = body(head->key, head->value, ctx); - if (ret) { - return ret; - } - current = _z_slice_pair_list_tail(current); - } - return 0; -} -z_owned_bytes_map_t z_bytes_map_new(void) { return (z_owned_bytes_map_t){._inner = _z_slice_pair_list_new()}; } -z_owned_bytes_map_t z_bytes_map_null(void) { return (z_owned_bytes_map_t){._inner = NULL}; } - -int8_t z_bytes_from_str(z_owned_slice_t *bytes const char *str) { - bytes->_val = _z_slice_wrap((const uint8_t *)str, strlen(str)); - return _Z_RES_OK; -} -#endif diff --git a/src/net/primitives.c b/src/net/primitives.c index c19ae7824..c0392e806 100644 --- a/src/net/primitives.c +++ b/src/net/primitives.c @@ -131,12 +131,7 @@ int8_t _z_undeclare_publisher(_z_publisher_t *pub) { /*------------------ Write ------------------*/ int8_t _z_write(_z_session_t *zn, const _z_keyexpr_t keyexpr, const uint8_t *payload, const size_t len, const _z_encoding_t encoding, const z_sample_kind_t kind, const z_congestion_control_t cong_ctrl, - z_priority_t priority -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_t attachment -#endif -) { + z_priority_t priority, const _z_bytes_t attachment) { int8_t ret = _Z_RES_OK; _z_network_message_t msg; switch (kind) { @@ -154,9 +149,7 @@ int8_t _z_write(_z_session_t *zn, const _z_keyexpr_t keyexpr, const uint8_t *pay ._commons = {._timestamp = _z_timestamp_null(), ._source_info = _z_source_info_null()}, ._payload = _z_slice_wrap(payload, len), ._encoding = encoding, -#if Z_FEATURE_ATTACHMENT == 1 - ._attachment = {.is_encoded = false, .body.decoded = attachment}, -#endif + ._attachment = attachment, }, }, }; @@ -324,7 +317,7 @@ int8_t _z_undeclare_queryable(_z_queryable_t *qle) { } int8_t _z_send_reply(const _z_query_t *query, _z_keyexpr_t keyexpr, const _z_value_t payload, - const z_sample_kind_t kind, z_attachment_t att) { + const z_sample_kind_t kind, const _z_bytes_t att) { int8_t ret = _Z_RES_OK; _z_keyexpr_t q_ke; @@ -363,10 +356,7 @@ int8_t _z_send_reply(const _z_query_t *query, _z_keyexpr_t keyexpr, const _z_val z_msg._body._response._body._reply._body._body._put._encoding = payload.encoding; z_msg._body._response._body._reply._body._body._put._commons._timestamp = _z_timestamp_null(); z_msg._body._response._body._reply._body._body._put._commons._source_info = _z_source_info_null(); -#if Z_FEATURE_ATTACHMENT == 1 - z_msg._body._response._body._reply._body._body._put._attachment.body.decoded = att; - z_msg._body._response._body._reply._body._body._put._attachment.is_encoded = false; -#endif + z_msg._body._response._body._reply._body._body._put._attachment = att; break; } if (_z_send_n_msg(query->_zn, &z_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK) != _Z_RES_OK) { @@ -384,12 +374,7 @@ int8_t _z_send_reply(const _z_query_t *query, _z_keyexpr_t keyexpr, const _z_val /*------------------ Query ------------------*/ int8_t _z_query(_z_session_t *zn, _z_keyexpr_t keyexpr, const char *parameters, const z_query_target_t target, const z_consolidation_mode_t consolidation, _z_value_t value, _z_reply_handler_t callback, - _z_drop_handler_t dropper, void *arg, uint32_t timeout_ms -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_t attachment -#endif -) { + _z_drop_handler_t dropper, void *arg, uint32_t timeout_ms, const _z_bytes_t attachment) { int8_t ret = _Z_RES_OK; // Create the pending query object @@ -410,12 +395,7 @@ int8_t _z_query(_z_session_t *zn, _z_keyexpr_t keyexpr, const char *parameters, if (ret == _Z_RES_OK) { _z_slice_t params = _z_slice_wrap((uint8_t *)pq->_parameters, strlen(pq->_parameters)); _z_zenoh_message_t z_msg = - _z_msg_make_query(&keyexpr, ¶ms, pq->_id, pq->_consolidation, &value, timeout_ms -#if Z_FEATURE_ATTACHMENT == 1 - , - attachment -#endif - ); + _z_msg_make_query(&keyexpr, ¶ms, pq->_id, pq->_consolidation, &value, timeout_ms, attachment); if (_z_send_n_msg(zn, &z_msg, Z_RELIABILITY_RELIABLE, Z_CONGESTION_CONTROL_BLOCK) != _Z_RES_OK) { _z_unregister_pending_query(zn, pq); diff --git a/src/net/query.c b/src/net/query.c index cb58f8f84..081524f8e 100644 --- a/src/net/query.c +++ b/src/net/query.c @@ -38,14 +38,12 @@ void _z_query_clear(_z_query_t *q) { z_free(q->_parameters); _z_keyexpr_clear(&q->_key); _z_value_clear(&q->_value); -#if Z_FEATURE_ATTACHMENT == 1 - _z_attachment_drop(&q->attachment); -#endif + _z_bytes_clear(&q->attachment); } #if Z_FEATURE_QUERYABLE == 1 _z_query_t _z_query_create(const _z_value_t *value, const _z_keyexpr_t *key, const _z_slice_t *parameters, - _z_session_t *zn, uint32_t request_id, z_attachment_t att) { + _z_session_t *zn, uint32_t request_id, const _z_bytes_t att) { _z_query_t q = _z_query_null(); q._request_id = request_id; q._zn = zn; // Ideally would have been an rc @@ -53,11 +51,8 @@ _z_query_t _z_query_create(const _z_value_t *value, const _z_keyexpr_t *key, con memcpy(q._parameters, parameters->start, parameters->len); q._parameters[parameters->len] = 0; q._anyke = (strstr(q._parameters, Z_SELECTOR_QUERY_MATCH) == NULL) ? false : true; -#if Z_FEATURE_ATTACHMENT == 1 q.attachment = att; -#else - _ZP_UNUSED(att); -#endif + _z_keyexpr_copy(&q._key, key); _z_value_copy(&q._value, value); return q; diff --git a/src/net/reply.c b/src/net/reply.c index 36866ff90..8c42833b9 100644 --- a/src/net/reply.c +++ b/src/net/reply.c @@ -86,7 +86,7 @@ void _z_pending_reply_clear(_z_pending_reply_t *pr) { _z_reply_t _z_reply_create(_z_keyexpr_t keyexpr, z_reply_tag_t tag, _z_id_t id, const _z_slice_t *payload, const _z_timestamp_t *timestamp, _z_encoding_t encoding, z_sample_kind_t kind, - z_attachment_t att) { + const _z_bytes_t att) { _z_reply_t reply = _z_reply_null(); reply._tag = tag; if (tag == Z_REPLY_TAG_DATA) { @@ -98,9 +98,8 @@ _z_reply_t _z_reply_create(_z_keyexpr_t keyexpr, z_reply_tag_t tag, _z_id_t id, _z_slice_copy(&sample.payload._slice, payload); sample.kind = kind; sample.timestamp = _z_timestamp_duplicate(timestamp); -#if Z_FEATURE_ATTACHMENT == 1 sample.attachment = att; // FIXME: call z_attachment_move or copy -#endif + // Create sample rc from value reply.data.sample = _z_sample_rc_new_from_val(sample); } @@ -109,7 +108,7 @@ _z_reply_t _z_reply_create(_z_keyexpr_t keyexpr, z_reply_tag_t tag, _z_id_t id, #else _z_reply_t _z_reply_create(_z_keyexpr_t keyexpr, z_reply_tag_t tag, _z_id_t id, const _z_slice_t *payload, const _z_timestamp_t *timestamp, _z_encoding_t encoding, z_sample_kind_t kind, - z_attachment_t att) { + const _z_bytes_t att) { _ZP_UNUSED(keyexpr); _ZP_UNUSED(tag); _ZP_UNUSED(id); diff --git a/src/net/sample.c b/src/net/sample.c index 7d8ec345f..f71744358 100644 --- a/src/net/sample.c +++ b/src/net/sample.c @@ -24,9 +24,7 @@ _z_sample_t _z_sample_null(void) { .timestamp = _z_timestamp_null(), .kind = 0, .qos = {0}, -#if Z_FEATURE_ATTACHMENT == 1 - .attachment = z_attachment_null(), -#endif + .attachment = _z_bytes_null(), }; return s; } @@ -52,9 +50,7 @@ void _z_sample_clear(_z_sample_t *sample) { _z_bytes_clear(&sample->payload); _z_encoding_clear(&sample->encoding); _z_timestamp_clear(&sample->timestamp); -#if Z_FEATURE_ATTACHMENT == 1 - _z_attachment_drop(&sample->attachment); -#endif + _z_bytes_clear(&sample->attachment); } void _z_sample_free(_z_sample_t **sample) { @@ -71,11 +67,8 @@ void _z_sample_copy(_z_sample_t *dst, const _z_sample_t *src) { dst->payload = _z_bytes_duplicate(&src->payload); dst->timestamp = _z_timestamp_duplicate(&src->timestamp); _z_encoding_copy(&dst->encoding, &src->encoding); - dst->kind = src->kind; -#if Z_FEATURE_ATTACHMENT == 1 - dst->attachment = src->attachment; -#endif + dst->attachment = _z_bytes_duplicate(&src->attachment); } _z_sample_t _z_sample_duplicate(const _z_sample_t *src) { @@ -87,7 +80,7 @@ _z_sample_t _z_sample_duplicate(const _z_sample_t *src) { #if Z_FEATURE_SUBSCRIPTION == 1 _z_sample_t _z_sample_create(const _z_keyexpr_t *key, const _z_slice_t *payload, const _z_timestamp_t timestamp, const _z_encoding_t encoding, const z_sample_kind_t kind, const _z_qos_t qos, - const z_attachment_t att) { + const _z_bytes_t att) { _z_sample_t s = _z_sample_null(); _z_keyexpr_copy(&s.keyexpr, key); _z_slice_copy(&s.payload._slice, payload); @@ -95,17 +88,13 @@ _z_sample_t _z_sample_create(const _z_keyexpr_t *key, const _z_slice_t *payload, s.kind = kind; s.timestamp = timestamp; s.qos = qos; -#if Z_FEATURE_ATTACHMENT == 1 s.attachment = att; // FIXME: call z_attachment_move or copy -#else - _ZP_UNUSED(att); -#endif return s; } #else _z_sample_t _z_sample_create(const _z_keyexpr_t *key, const _z_slice_t *payload, const _z_timestamp_t timestamp, const _z_encoding_t encoding, const z_sample_kind_t kind, const _z_qos_t qos, - const z_attachment_t att) { + const _z_bytes_t att) { _ZP_UNUSED(key); _ZP_UNUSED(payload); _ZP_UNUSED(timestamp); diff --git a/src/protocol/codec/message.c b/src/protocol/codec/message.c index f52362677..3ba5e3216 100644 --- a/src/protocol/codec/message.c +++ b/src/protocol/codec/message.c @@ -242,20 +242,7 @@ int8_t _z_source_info_encode_ext(_z_wbuf_t *wbf, const _z_source_info_t *info) { _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, info->_source_sn)); return ret; } -#if Z_FEATURE_ATTACHMENT == 1 -int8_t _z_attachment_encode_ext_kv(_z_slice_t key, _z_slice_t value, void *ctx) { - _z_wbuf_t *wbf = (_z_wbuf_t *)ctx; - _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &key)); - _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &value)); - return 0; -} -int8_t _z_attachment_encode_ext(_z_wbuf_t *wbf, z_attachment_t att) { - size_t len = _z_attachment_estimate_length(att); - _Z_RETURN_IF_ERR(_z_zsize_encode(wbf, len)); - _Z_RETURN_IF_ERR(z_attachment_iterate(att, _z_attachment_encode_ext_kv, wbf)); - return 0; -} -#endif + /*------------------ Push Body Field ------------------*/ int8_t _z_push_body_encode(_z_wbuf_t *wbf, const _z_push_body_t *pshb) { (void)(wbf); @@ -264,12 +251,8 @@ int8_t _z_push_body_encode(_z_wbuf_t *wbf, const _z_push_body_t *pshb) { _Bool has_source_info = _z_id_check(pshb->_body._put._commons._source_info._id) || pshb->_body._put._commons._source_info._source_sn != 0 || pshb->_body._put._commons._source_info._entity_id != 0; -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t att = _z_encoded_as_attachment(&pshb->_body._put._attachment); - _Bool has_attachment = pshb->_is_put && z_attachment_check(&att); -#else - _Bool has_attachment = false; -#endif + + _Bool has_attachment = pshb->_is_put && _z_bytes_check(pshb->_body._put._attachment); _Bool has_timestamp = _z_timestamp_check(&pshb->_body._put._commons._timestamp); _Bool has_encoding = false; if (has_source_info || has_attachment) { @@ -301,12 +284,10 @@ int8_t _z_push_body_encode(_z_wbuf_t *wbf, const _z_push_body_t *pshb) { _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZBUF | 0x01 | (has_attachment ? _Z_FLAG_Z_Z : 0))); _Z_RETURN_IF_ERR(_z_source_info_encode_ext(wbf, &pshb->_body._put._commons._source_info)); } -#if Z_FEATURE_ATTACHMENT == 1 if (has_attachment) { _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZBUF | 0x03)); - _Z_RETURN_IF_ERR(_z_attachment_encode_ext(wbf, att)); + _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &pshb->_body._put._attachment._slice)); } -#endif if (pshb->_is_put) { _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &pshb->_body._put._payload)); } @@ -322,15 +303,12 @@ int8_t _z_push_body_decode_extensions(_z_msg_ext_t *extension, void *ctx) { ret = _z_source_info_decode(&pshb->_body._put._commons._source_info, &zbf); break; } -#if Z_FEATURE_ATTACHMENT == 1 case _Z_MSG_EXT_ENC_ZBUF | 0x03: { - pshb->_body._put._attachment.is_encoded = true; - pshb->_body._put._attachment.body.encoded = extension->_body._zbuf._val._is_alloc - ? _z_slice_steal(&extension->_body._zbuf._val) - : _z_slice_duplicate(&extension->_body._zbuf._val); + pshb->_body._put._attachment._slice = extension->_body._zbuf._val._is_alloc + ? _z_slice_steal(&extension->_body._zbuf._val) + : _z_slice_duplicate(&extension->_body._zbuf._val); break; } -#endif default: if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) { ret = _z_msg_ext_unknown_error(extension, 0x08); @@ -447,14 +425,10 @@ int8_t _z_query_encode(_z_wbuf_t *wbf, const _z_msg_query_t *msg) { _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, extheader)); _Z_RETURN_IF_ERR(_z_source_info_encode_ext(wbf, &msg->_ext_info)); } -#if Z_FEATURE_ATTACHMENT == 1 if (required_exts.attachment) { _Z_RETURN_IF_ERR(_z_uint8_encode(wbf, _Z_MSG_EXT_ENC_ZBUF | 0x05)); - z_attachment_t att = _z_encoded_as_attachment(&msg->_ext_attachment); - _Z_RETURN_IF_ERR(_z_attachment_encode_ext(wbf, att)); + _Z_RETURN_IF_ERR(_z_slice_encode(wbf, &msg->_ext_attachment._slice)); } -#endif - return ret; } @@ -474,15 +448,12 @@ int8_t _z_query_decode_extensions(_z_msg_ext_t *extension, void *ctx) { _z_slice_copy(&msg->_ext_value.payload._slice, &bytes); break; } -#if Z_FEATURE_ATTACHMENT == 1 case _Z_MSG_EXT_ENC_ZBUF | 0x05: { - msg->_ext_attachment.is_encoded = true; - msg->_ext_attachment.body.encoded = extension->_body._zbuf._val._is_alloc - ? _z_slice_steal(&extension->_body._zbuf._val) - : _z_slice_duplicate(&extension->_body._zbuf._val); + msg->_ext_attachment._slice = extension->_body._zbuf._val._is_alloc + ? _z_slice_steal(&extension->_body._zbuf._val) + : _z_slice_duplicate(&extension->_body._zbuf._val); break; } -#endif default: if (_Z_HAS_FLAG(extension->_header, _Z_MSG_EXT_FLAG_M)) { ret = _z_msg_ext_unknown_error(extension, 0x09); diff --git a/src/protocol/core.c b/src/protocol/core.c index cb1617481..81e27b5a4 100644 --- a/src/protocol/core.c +++ b/src/protocol/core.c @@ -76,84 +76,3 @@ void _z_value_copy(_z_value_t *dst, const _z_value_t *src) { _z_encoding_copy(&dst->encoding, &src->encoding); _z_bytes_copy(&dst->payload, &src->payload); } - -z_attachment_t z_attachment_null(void) { return (z_attachment_t){.data = NULL, .iteration_driver = NULL}; } - -#if Z_FEATURE_ATTACHMENT == 1 -struct _z_seeker_t { - _z_slice_t key; - _z_slice_t value; -}; -int8_t _z_attachment_get_seeker(_z_slice_t key, _z_slice_t value, void *ctx) { - struct _z_seeker_t *seeker = (struct _z_seeker_t *)ctx; - _z_slice_t seeked = seeker->key; - if (key.len == seeked.len && memcmp(key.start, seeked.start, seeked.len)) { - seeker->value = (_z_slice_t){.start = value.start, .len = value.len, ._is_alloc = false}; - return 1; - } - return 0; -} -_z_slice_t z_attachment_get(z_attachment_t this_, _z_slice_t key) { - struct _z_seeker_t seeker = {.value = {0}, .key = key}; - z_attachment_iterate(this_, _z_attachment_get_seeker, (void *)&seeker); - return seeker.value; -} -int8_t _z_attachment_estimate_length_body(_z_slice_t key, _z_slice_t value, void *ctx) { - size_t *len = (size_t *)ctx; - *len += _z_zint_len(key.len) + key.len + _z_zint_len(value.len) + value.len; - return 0; -} -size_t _z_attachment_estimate_length(z_attachment_t att) { - size_t len = 0; - z_attachment_iterate(att, _z_attachment_estimate_length_body, &len); - return len; -} - -int8_t _z_encoded_attachment_iteration_driver(const void *this_, z_attachment_iter_body_t body, void *ctx) { - _z_zbuf_t data = _z_slice_as_zbuf(*(_z_slice_t *)this_); - while (_z_zbuf_can_read(&data)) { - _z_slice_t key = _z_slice_empty(); - _z_slice_t value = _z_slice_empty(); - _z_slice_decode(&key, &data); - _z_slice_decode(&value, &data); - int8_t ret = body(key, value, ctx); - if (ret != 0) { - return ret; - } - } - return 0; -} - -z_attachment_t _z_encoded_as_attachment(const _z_owned_encoded_attachment_t *att) { - if (att->is_encoded) { - // Recopy z_bytes data in allocated memory to avoid it going out of scope - z_bytes_t *att_data = (_z_slice_t *)z_malloc(sizeof(_z_slice_t)); - if (att_data == NULL) { - return att->body.decoded; - } - *att_data = att->body.encoded; - return (z_attachment_t){.data = att_data, .iteration_driver = _z_encoded_attachment_iteration_driver}; - } else { - return att->body.decoded; - } -} - -_Bool z_attachment_check(const z_attachment_t *attachment) { return attachment->iteration_driver != NULL; } - -int8_t z_attachment_iterate(z_attachment_t this_, z_attachment_iter_body_t body, void *ctx) { - return this_.iteration_driver(this_.data, body, ctx); -} - -void _z_attachment_drop(z_attachment_t *att) { - if (att->iteration_driver == _z_encoded_attachment_iteration_driver) { - _z_slice_clear((z_bytes_t *)att->data); - z_free((z_bytes_t *)att->data); - } -} - -#else // Z_FEATURE_ATTACHMENT == 1 -z_attachment_t _z_encoded_as_attachment(const _z_owned_encoded_attachment_t *att) { - _ZP_UNUSED(att); - return z_attachment_null(); -} -#endif diff --git a/src/protocol/definitions/message.c b/src/protocol/definitions/message.c index b9bb3ecb1..1f448562c 100644 --- a/src/protocol/definitions/message.c +++ b/src/protocol/definitions/message.c @@ -29,17 +29,10 @@ void _z_msg_put_clear(_z_msg_put_t *msg) { } _z_msg_query_reqexts_t _z_msg_query_required_extensions(const _z_msg_query_t *msg) { -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t att = _z_encoded_as_attachment(&msg->_ext_attachment); -#endif - return (_z_msg_query_reqexts_t) { + return (_z_msg_query_reqexts_t){ .body = msg->_ext_value.payload._slice.start != NULL || _z_encoding_check(&msg->_ext_value.encoding), .info = _z_id_check(msg->_ext_info._id) || msg->_ext_info._entity_id != 0 || msg->_ext_info._source_sn != 0, -#if Z_FEATURE_ATTACHMENT == 1 - .attachment = z_attachment_check(&att) -#else - .attachment = false -#endif + .attachment = _z_bytes_check(msg->_ext_attachment), }; } diff --git a/src/protocol/definitions/network.c b/src/protocol/definitions/network.c index 57322e339..63341b68e 100644 --- a/src/protocol/definitions/network.c +++ b/src/protocol/definitions/network.c @@ -138,12 +138,7 @@ void _z_n_msg_free(_z_network_message_t **msg) { _z_zenoh_message_t _z_msg_make_query(_Z_MOVE(_z_keyexpr_t) key, _Z_MOVE(_z_slice_t) parameters, _z_zint_t qid, z_consolidation_mode_t consolidation, _Z_MOVE(_z_value_t) value, - uint32_t timeout_ms -#if Z_FEATURE_ATTACHMENT == 1 - , - z_attachment_t attachment -#endif -) { + uint32_t timeout_ms, _z_bytes_t attachment) { return (_z_zenoh_message_t){ ._tag = _Z_N_REQUEST, ._body._request = @@ -151,14 +146,14 @@ _z_zenoh_message_t _z_msg_make_query(_Z_MOVE(_z_keyexpr_t) key, _Z_MOVE(_z_slice ._rid = qid, ._key = _z_keyexpr_steal(key), ._tag = _Z_REQUEST_QUERY, - ._body._query = {._parameters = _z_slice_steal(parameters), - ._consolidation = consolidation, - ._ext_value = _z_value_steal(value), - ._ext_info = _z_source_info_null(), -#if Z_FEATURE_ATTACHMENT == 1 - ._ext_attachment = {.body.decoded = attachment, .is_encoded = false} -#endif - }, + ._body._query = + { + ._parameters = _z_slice_steal(parameters), + ._consolidation = consolidation, + ._ext_value = _z_value_steal(value), + ._ext_info = _z_source_info_null(), + ._ext_attachment = attachment, + }, ._ext_budget = 0, ._ext_qos = _Z_N_QOS_DEFAULT, ._ext_target = Z_QUERY_TARGET_BEST_MATCHING, diff --git a/src/session/push.c b/src/session/push.c index df197244c..0763d0bd4 100644 --- a/src/session/push.c +++ b/src/session/push.c @@ -29,12 +29,8 @@ int8_t _z_trigger_push(_z_session_t *zn, _z_n_msg_push_t *push) { _z_encoding_t encoding = push->_body._is_put ? push->_body._body._put._encoding : _z_encoding_null(); int kind = push->_body._is_put ? Z_SAMPLE_KIND_PUT : Z_SAMPLE_KIND_DELETE; #if Z_FEATURE_SUBSCRIPTION == 1 -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t att = _z_encoded_as_attachment(&push->_body._body._put._attachment); -#else - z_attachment_t att = z_attachment_null(); -#endif - ret = _z_trigger_subscriptions(zn, push->_key, payload, encoding, kind, push->_timestamp, push->_qos, att); + ret = _z_trigger_subscriptions(zn, push->_key, payload, encoding, kind, push->_timestamp, push->_qos, + push->_body._body._put._attachment); #endif return ret; } diff --git a/src/session/query.c b/src/session/query.c index 17f909788..e8dabd71c 100644 --- a/src/session/query.c +++ b/src/session/query.c @@ -113,15 +113,9 @@ int8_t _z_trigger_query_reply_partial(_z_session_t *zn, const _z_zint_t id, cons ret = _Z_ERR_QUERY_NOT_MATCH; } - // Retrieve attachment -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t att = _z_encoded_as_attachment(&msg->_attachment); -#else - z_attachment_t att = z_attachment_null(); -#endif // Build the reply _z_reply_t reply = _z_reply_create(expanded_ke, Z_REPLY_TAG_DATA, zn->_local_zid, &msg->_payload, - &msg->_commons._timestamp, msg->_encoding, Z_SAMPLE_KIND_PUT, att); + &msg->_commons._timestamp, msg->_encoding, Z_SAMPLE_KIND_PUT, msg->_attachment); // Verify if this is a newer reply, free the old one in case it is if ((ret == _Z_RES_OK) && ((pen_qry->_consolidation == Z_CONSOLIDATION_MODE_LATEST) || diff --git a/src/session/queryable.c b/src/session/queryable.c index 0e5b207ca..a09afd6ab 100644 --- a/src/session/queryable.c +++ b/src/session/queryable.c @@ -133,7 +133,7 @@ _z_session_queryable_rc_t *_z_register_session_queryable(_z_session_t *zn, _z_se } int8_t _z_trigger_queryables(_z_session_t *zn, const _z_msg_query_t *msgq, const _z_keyexpr_t q_key, uint32_t qid, - z_attachment_t att) { + const _z_bytes_t att) { int8_t ret = _Z_RES_OK; _zp_session_lock_mutex(zn); diff --git a/src/session/rx.c b/src/session/rx.c index d5d5d8e33..c1a53ce1c 100644 --- a/src/session/rx.c +++ b/src/session/rx.c @@ -91,8 +91,8 @@ int8_t _z_handle_network_message(_z_session_t *zn, _z_zenoh_message_t *msg, uint case _Z_REQUEST_QUERY: { #if Z_FEATURE_QUERYABLE == 1 _z_msg_query_t *query = &req._body._query; - z_attachment_t att = _z_encoded_as_attachment(&req._body._query._ext_attachment); - ret = _z_trigger_queryables(zn, query, req._key, (uint32_t)req._rid, att); + ret = _z_trigger_queryables(zn, query, req._key, (uint32_t)req._rid, + req._body._query._ext_attachment); #else _Z_DEBUG("_Z_REQUEST_QUERY dropped, queryables not supported"); #endif @@ -100,13 +100,8 @@ int8_t _z_handle_network_message(_z_session_t *zn, _z_zenoh_message_t *msg, uint case _Z_REQUEST_PUT: { _z_msg_put_t put = req._body._put; #if Z_FEATURE_SUBSCRIPTION == 1 -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t att = _z_encoded_as_attachment(&put._attachment); -#else - z_attachment_t att = z_attachment_null(); -#endif ret = _z_trigger_subscriptions(zn, req._key, put._payload, put._encoding, Z_SAMPLE_KIND_PUT, - put._commons._timestamp, req._ext_qos, att); + put._commons._timestamp, req._ext_qos, put._attachment); #endif if (ret == _Z_RES_OK) { _z_network_message_t final = _z_n_msg_make_response_final(req._rid); @@ -118,7 +113,7 @@ int8_t _z_handle_network_message(_z_session_t *zn, _z_zenoh_message_t *msg, uint #if Z_FEATURE_SUBSCRIPTION == 1 ret = _z_trigger_subscriptions(zn, req._key, _z_slice_empty(), _z_encoding_null(), Z_SAMPLE_KIND_DELETE, del._commons._timestamp, req._ext_qos, - z_attachment_null()); + _z_bytes_null()); #endif if (ret == _Z_RES_OK) { _z_network_message_t final = _z_n_msg_make_response_final(req._rid); diff --git a/src/session/subscription.c b/src/session/subscription.c index 7444719ac..66c8510a8 100644 --- a/src/session/subscription.c +++ b/src/session/subscription.c @@ -139,7 +139,7 @@ _z_subscription_rc_t *_z_register_subscription(_z_session_t *zn, uint8_t is_loca } void _z_trigger_local_subscriptions(_z_session_t *zn, const _z_keyexpr_t keyexpr, const uint8_t *payload, - _z_zint_t payload_len, const _z_n_qos_t qos, const z_attachment_t att) { + _z_zint_t payload_len, const _z_n_qos_t qos, const _z_bytes_t att) { _z_encoding_t encoding = _z_encoding_null(); int8_t ret = _z_trigger_subscriptions(zn, keyexpr, _z_slice_wrap(payload, payload_len), encoding, Z_SAMPLE_KIND_PUT, _z_timestamp_null(), qos, att); @@ -148,7 +148,7 @@ void _z_trigger_local_subscriptions(_z_session_t *zn, const _z_keyexpr_t keyexpr int8_t _z_trigger_subscriptions(_z_session_t *zn, const _z_keyexpr_t keyexpr, const _z_slice_t payload, const _z_encoding_t encoding, const _z_zint_t kind, const _z_timestamp_t timestamp, - const _z_n_qos_t qos, const z_attachment_t att) { + const _z_n_qos_t qos, const _z_bytes_t att) { int8_t ret = _Z_RES_OK; _zp_session_lock_mutex(zn); @@ -209,7 +209,7 @@ void _z_flush_subscriptions(_z_session_t *zn) { #else // Z_FEATURE_SUBSCRIPTION == 0 void _z_trigger_local_subscriptions(_z_session_t *zn, const _z_keyexpr_t keyexpr, const uint8_t *payload, - _z_zint_t payload_len, _z_n_qos_t qos, z_attachment_t att) { + _z_zint_t payload_len, _z_n_qos_t qos, const _z_bytes_t att) { _ZP_UNUSED(zn); _ZP_UNUSED(keyexpr); _ZP_UNUSED(payload); From 6fc6f5adfafaef58b9decab5c57e2f7fab8fa7bc Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Thu, 13 Jun 2024 16:02:31 +0200 Subject: [PATCH 02/14] fix: remove attachment from build and example --- .github/workflows/build-check.yaml | 35 ------------------------------ examples/unix/c11/z_get.c | 24 -------------------- examples/unix/c11/z_put.c | 10 --------- examples/unix/c11/z_queryable.c | 27 ----------------------- examples/unix/c11/z_sub.c | 21 +----------------- 5 files changed, 1 insertion(+), 116 deletions(-) diff --git a/.github/workflows/build-check.yaml b/.github/workflows/build-check.yaml index 88ec7dc3b..854c65e35 100644 --- a/.github/workflows/build-check.yaml +++ b/.github/workflows/build-check.yaml @@ -195,38 +195,3 @@ jobs: - name: Kill Zenoh router if: always() run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }} - - no_attachment_test: - needs: zenoh_build - name: Build and test without attachment on ubuntu-latest - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Download Zenoh artifacts - uses: actions/download-artifact@v4 - with: - name: ${{ needs.zenoh_build.outputs.artifact-name }} - - - name: Unzip Zenoh artifacts - run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone - - - id: run-zenoh - name: Run Zenoh router - run: | - RUST_LOG=debug ./zenoh-standalone/zenohd & - echo "zenohd-pid=$!" >> $GITHUB_OUTPUT - - - name: Build project and run test - run: | - sudo apt install -y ninja-build - CMAKE_GENERATOR=Ninja make - python3 ./build/tests/modularity.py --pub 1 --sub 1 --queryable 1 --query 1 --attachment 0 - timeout-minutes: 5 - env: - Z_FEATURE_ATTACHMENT: 0 - - - name: Kill Zenoh router - if: always() - run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }} diff --git a/examples/unix/c11/z_get.c b/examples/unix/c11/z_get.c index 61c7df1ed..f026674f0 100644 --- a/examples/unix/c11/z_get.c +++ b/examples/unix/c11/z_get.c @@ -29,14 +29,6 @@ void reply_dropper(void *ctx) { z_condvar_free(&cond); } -#if Z_FEATURE_ATTACHMENT == 1 -int8_t attachment_handler(z_bytes_t key, z_bytes_t att_value, void *ctx) { - (void)ctx; - printf(">>> %.*s: %.*s\n", (int)key.len, key.start, (int)att_value.len, att_value.start); - return 0; -} -#endif - void reply_handler(const z_loaned_reply_t *reply, void *ctx) { (void)(ctx); if (z_reply_is_ok(reply)) { @@ -47,12 +39,6 @@ void reply_handler(const z_loaned_reply_t *reply, void *ctx) { z_bytes_decode_into_string(z_sample_payload(sample), &replystr); printf(">> Received ('%s': '%s')\n", z_string_data(z_loan(keystr)), z_string_data(z_loan(replystr))); -#if Z_FEATURE_ATTACHMENT == 1 - if (z_attachment_check(&sample.attachment)) { - printf("Attachement found\n"); - z_attachment_iterate(sample.attachment, attachment_handler, NULL); - } -#endif z_drop(z_move(keystr)); z_drop(z_move(replystr)); } else { @@ -140,11 +126,6 @@ int main(int argc, char **argv) { z_bytes_encode_from_string(&payload, value); opts.payload = &payload; } -#if Z_FEATURE_ATTACHMENT == 1 - z_owned_bytes_map_t map = z_bytes_map_new(); - z_bytes_map_insert_by_alias(&map, z_bytes_from_str("hi"), z_bytes_from_str("there")); - opts.attachment = z_bytes_map_as_attachment(&map); -#endif z_owned_closure_reply_t callback; z_closure(&callback, reply_handler, reply_dropper); @@ -160,11 +141,6 @@ int main(int argc, char **argv) { zp_stop_lease_task(z_loan_mut(s)); z_close(z_move(s)); - -#if Z_FEATURE_ATTACHMENT == 1 - z_bytes_map_drop(&map); -#endif - return 0; } #else diff --git a/examples/unix/c11/z_put.c b/examples/unix/c11/z_put.c index d6ac6cc87..de8b39176 100644 --- a/examples/unix/c11/z_put.c +++ b/examples/unix/c11/z_put.c @@ -105,19 +105,9 @@ int main(int argc, char **argv) { z_put_options_t options; z_put_options_default(&options); options.encoding = z_move(encoding); -#if Z_FEATURE_ATTACHMENT == 1 - z_owned_bytes_map_t map = z_bytes_map_new(); - z_bytes_map_insert_by_alias(&map, z_bytes_from_str("hi"), z_bytes_from_str("there")); - options.attachment = z_bytes_map_as_attachment(&map); -#endif if (z_put(z_loan(s), z_loan(ke), (const uint8_t *)value, strlen(value), &options) < 0) { printf("Oh no! Put has failed...\n"); } - -#if Z_FEATURE_ATTACHMENT == 1 - z_bytes_map_drop(&map); -#endif - // Clean up z_undeclare_keyexpr(z_loan(s), z_move(ke)); zp_stop_read_task(z_loan_mut(s)); diff --git a/examples/unix/c11/z_queryable.c b/examples/unix/c11/z_queryable.c index cc65c3956..acf3681bc 100644 --- a/examples/unix/c11/z_queryable.c +++ b/examples/unix/c11/z_queryable.c @@ -23,14 +23,6 @@ const char *keyexpr = "demo/example/zenoh-pico-queryable"; const char *value = "Queryable from Pico!"; static int msg_nb = 0; -#if Z_FEATURE_ATTACHMENT == 1 -int8_t attachment_handler(z_bytes_t key, z_bytes_t att_value, void *ctx) { - (void)ctx; - printf(">>> %.*s: %.*s\n", (int)key.len, key.start, (int)att_value.len, att_value.start); - return 0; -} -#endif - void query_handler(const z_loaned_query_t *query, void *ctx) { (void)(ctx); z_owned_string_t keystr; @@ -47,14 +39,6 @@ void query_handler(const z_loaned_query_t *query, void *ctx) { } z_drop(z_move(payload_string)); -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t attachment = z_query_attachment(query); - if (z_attachment_check(&attachment)) { - printf("Attachement found\n"); - z_attachment_iterate(attachment, attachment_handler, NULL); - } -#endif - // Create encoding z_owned_encoding_t encoding; zp_encoding_make(&encoding, Z_ENCODING_ID_TEXT_PLAIN, NULL); @@ -63,13 +47,6 @@ void query_handler(const z_loaned_query_t *query, void *ctx) { z_query_reply_options_default(&options); options.encoding = z_move(encoding); -#if Z_FEATURE_ATTACHMENT == 1 - // Add attachment - z_owned_bytes_map_t map = z_bytes_map_new(); - z_bytes_map_insert_by_alias(&map, z_bytes_from_str("hello"), z_bytes_from_str("world")); - options.attachment = z_bytes_map_as_attachment(&map); -#endif - // Reply value encoding z_owned_bytes_t reply_payload; z_bytes_encode_from_string(&reply_payload, value); @@ -77,10 +54,6 @@ void query_handler(const z_loaned_query_t *query, void *ctx) { z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), &options); z_drop(z_move(keystr)); msg_nb++; - -#if Z_FEATURE_ATTACHMENT == 1 - z_bytes_map_drop(&map); -#endif } int main(int argc, char **argv) { diff --git a/examples/unix/c11/z_sub.c b/examples/unix/c11/z_sub.c index 3f245eefb..a307117d1 100644 --- a/examples/unix/c11/z_sub.c +++ b/examples/unix/c11/z_sub.c @@ -24,14 +24,6 @@ static int msg_nb = 0; -#if Z_FEATURE_ATTACHMENT == 1 -int8_t attachment_handler(z_bytes_t key, z_bytes_t value, void *ctx) { - (void)ctx; - printf(">>> %.*s: %.*s\n", (int)key.len, key.start, (int)value.len, value.start); - return 0; -} -#endif - void data_handler(const z_loaned_sample_t *sample, void *ctx) { (void)(ctx); z_owned_string_t keystr; @@ -39,13 +31,6 @@ void data_handler(const z_loaned_sample_t *sample, void *ctx) { z_owned_string_t value; z_bytes_decode_into_string(z_sample_payload(sample), &value); printf(">> [Subscriber] Received ('%s': '%s')\n", z_string_data(z_loan(keystr)), z_string_data(z_loan(value))); -#if Z_FEATURE_ATTACHMENT == 1 - z_attachment_t attachment = z_sample_attachment(sample); - if (z_attachment_check(&attachment)) { - printf("Attachement found\n"); - z_attachment_iterate(attachment, attachment_handler, NULL); - } -#endif z_drop(z_move(keystr)); z_drop(z_move(value)); msg_nb++; @@ -130,15 +115,11 @@ int main(int argc, char **argv) { } sleep(1); } - + // Clean up z_undeclare_subscriber(z_move(sub)); - - // Stop read and lease tasks for zenoh-pico zp_stop_read_task(z_loan_mut(s)); zp_stop_lease_task(z_loan_mut(s)); - z_close(z_move(s)); - return 0; } #else From 367d66ab1e3381c5f7157021fcfd9f84305d7444 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Thu, 13 Jun 2024 16:03:28 +0200 Subject: [PATCH 03/14] feat: remove attachment feature token --- CMakeLists.txt | 3 --- GNUmakefile | 3 +-- docs/conf.py | 1 - include/zenoh-pico/config.h | 7 ------- tests/modularity.py | 2 +- 5 files changed, 2 insertions(+), 14 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 80c468f2e..dd644085f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -132,7 +132,6 @@ set(Z_FEATURE_SUBSCRIPTION 1 CACHE STRING "Toggle subscription feature") set(Z_FEATURE_QUERY 1 CACHE STRING "Toggle query feature") set(Z_FEATURE_QUERYABLE 1 CACHE STRING "Toggle queryable feature") set(Z_FEATURE_RAWETH_TRANSPORT 0 CACHE STRING "Toggle raw ethernet transport feature") -set(Z_FEATURE_ATTACHMENT 0 CACHE STRING "Toggle attachment feature") set(Z_FEATURE_INTEREST 0 CACHE STRING "Toggle interest feature") # Toggle to 1 when protocol changes are merged add_definition(Z_FEATURE_MULTI_THREAD=${Z_FEATURE_MULTI_THREAD}) add_definition(Z_FEATURE_PUBLICATION=${Z_FEATURE_PUBLICATION}) @@ -140,7 +139,6 @@ add_definition(Z_FEATURE_SUBSCRIPTION=${Z_FEATURE_SUBSCRIPTION}) add_definition(Z_FEATURE_QUERY=${Z_FEATURE_QUERY}) add_definition(Z_FEATURE_QUERYABLE=${Z_FEATURE_QUERYABLE}) add_definition(Z_FEATURE_RAWETH_TRANSPORT=${Z_FEATURE_RAWETH_TRANSPORT}) -add_definition(Z_FEATURE_ATTACHMENT=${Z_FEATURE_ATTACHMENT}) add_definition(Z_FEATURE_INTEREST=${Z_FEATURE_INTEREST}) add_compile_definitions("Z_BUILD_DEBUG=$") message(STATUS "Building with feature confing:\n\ @@ -149,7 +147,6 @@ message(STATUS "Building with feature confing:\n\ * SUBSCRIPTION: ${Z_FEATURE_SUBSCRIPTION}\n\ * QUERY: ${Z_FEATURE_QUERY}\n\ * QUERYABLE: ${Z_FEATURE_QUERYABLE}\n\ -* ATTACHMENT: ${Z_FEATURE_ATTACHMENT}\n\ * INTEREST: ${Z_FEATURE_INTEREST}\n\ * RAWETH: ${Z_FEATURE_RAWETH_TRANSPORT}") diff --git a/GNUmakefile b/GNUmakefile index 48cf3c329..465c8abad 100644 --- a/GNUmakefile +++ b/GNUmakefile @@ -56,7 +56,6 @@ Z_FEATURE_PUBLICATION?=1 Z_FEATURE_SUBSCRIPTION?=1 Z_FEATURE_QUERY?=1 Z_FEATURE_QUERYABLE?=1 -Z_FEATURE_ATTACHMENT?=0 Z_FEATURE_INTEREST?=1 Z_FEATURE_RAWETH_TRANSPORT?=0 @@ -76,7 +75,7 @@ CROSSIMG_PREFIX=zenoh-pico_ CMAKE_OPT=-DZENOH_DEBUG=$(ZENOH_DEBUG) -DBUILD_EXAMPLES=$(BUILD_EXAMPLES) -DCMAKE_BUILD_TYPE=$(BUILD_TYPE) -DBUILD_TESTING=$(BUILD_TESTING) -DBUILD_MULTICAST=$(BUILD_MULTICAST)\ -DZ_FEATURE_MULTI_THREAD=$(Z_FEATURE_MULTI_THREAD) -DZ_FEATURE_INTEREST=$(Z_FEATURE_INTEREST) \ -DZ_FEATURE_PUBLICATION=$(Z_FEATURE_PUBLICATION) -DZ_FEATURE_SUBSCRIPTION=$(Z_FEATURE_SUBSCRIPTION) -DZ_FEATURE_QUERY=$(Z_FEATURE_QUERY) -DZ_FEATURE_QUERYABLE=$(Z_FEATURE_QUERYABLE)\ - -DZ_FEATURE_RAWETH_TRANSPORT=$(Z_FEATURE_RAWETH_TRANSPORT) -DZ_FEATURE_ATTACHMENT=$(Z_FEATURE_ATTACHMENT) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H. + -DZ_FEATURE_RAWETH_TRANSPORT=$(Z_FEATURE_RAWETH_TRANSPORT) -DBUILD_INTEGRATION=$(BUILD_INTEGRATION) -DBUILD_TOOLS=$(BUILD_TOOLS) -DBUILD_SHARED_LIBS=$(BUILD_SHARED_LIBS) -H. ifeq ($(FORCE_C99), ON) CMAKE_OPT += -DCMAKE_C_STANDARD=99 diff --git a/docs/conf.py b/docs/conf.py index a55ae85c5..37caaf948 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -33,7 +33,6 @@ "-DZ_FEATURE_SUBSCRIPTION=1", "-DZ_FEATURE_QUERY=1", "-DZ_FEATURE_QUERYABLE=1", - "-DZ_FEATURE_ATTACHMENT=1", ] # -- Options for HTML output ------------------------------------------------- diff --git a/include/zenoh-pico/config.h b/include/zenoh-pico/config.h index 8b5788e23..08d8933b6 100644 --- a/include/zenoh-pico/config.h +++ b/include/zenoh-pico/config.h @@ -232,13 +232,6 @@ #define Z_FEATURE_FRAGMENTATION 1 #endif -/** - * Enable attachments. - */ -#ifndef Z_FEATURE_ATTACHMENT -#define Z_FEATURE_ATTACHMENT 0 -#endif - /** * Enable interests. */ diff --git a/tests/modularity.py b/tests/modularity.py index c7603c412..226a04290 100644 --- a/tests/modularity.py +++ b/tests/modularity.py @@ -297,7 +297,7 @@ def query_and_queryable(args): parser.add_argument("--sub", type=int, choices=[0, 1], help="Z_FEATURE_SUBSCRIPTION (0 or 1)") parser.add_argument("--queryable", type=int, choices=[0, 1], help="Z_FEATURE_QUERYABLE (0 or 1)") parser.add_argument("--query", type=int, choices=[0, 1], help="Z_FEATURE_QUERY (0 or 1)") - parser.add_argument("--attachment", type=int, choices=[0, 1], help="Z_FEATURE_ATTACHMENT (0 or 1)") + parser.add_argument("--attachment", type=int, choices=[0, 1], help="testing with attachment (0 or 1)") EXIT_STATUS = 0 prog_args = parser.parse_args() print( From a6047977bcfebb7da1cdb7f719b2f5bdea8efdcd Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Thu, 13 Jun 2024 16:19:01 +0200 Subject: [PATCH 04/14] fix: init missing query reply attachment option --- src/api/api.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/api.c b/src/api/api.c index 4601451e3..7ab6ce292 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -1118,7 +1118,10 @@ int8_t z_declare_queryable(z_owned_queryable_t *queryable, const z_loaned_sessio int8_t z_undeclare_queryable(z_owned_queryable_t *queryable) { return _z_queryable_drop(&queryable->_val); } -void z_query_reply_options_default(z_query_reply_options_t *options) { options->encoding = NULL; } +void z_query_reply_options_default(z_query_reply_options_t *options) { + options->encoding = NULL; + options->attachment = NULL; +} int8_t z_query_reply(const z_loaned_query_t *query, const z_loaned_keyexpr_t *keyexpr, z_owned_bytes_t *payload, const z_query_reply_options_t *options) { From e6debb2308862eb70611bd873e4c154edc7eae12 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 15:47:04 +0200 Subject: [PATCH 05/14] feat: add api functions for attachments --- CMakeLists.txt | 1 + include/zenoh-pico/api/primitives.h | 45 +++++++++++++++ src/api/api.c | 87 ++++++++++++++++++++++++++++- src/collections/slice.c | 1 + 4 files changed, 133 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dd644085f..2c7af19fe 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -177,6 +177,7 @@ endif() if(CMAKE_BUILD_TYPE MATCHES "DEBUG") if(UNIX) + # FIXME: seems to not apply to library files, Issue #422 add_compile_options(-c -Wall -Wextra -Werror -Wshadow -Wpedantic -Wunused -Wstrict-prototypes -pipe -g -O0) # add_compile_options(-Wconversion) # add_link_options(-fsanitize=address) diff --git a/include/zenoh-pico/api/primitives.h b/include/zenoh-pico/api/primitives.h index de9aa2bd5..bdf754c92 100644 --- a/include/zenoh-pico/api/primitives.h +++ b/include/zenoh-pico/api/primitives.h @@ -584,6 +584,21 @@ int8_t z_bytes_decode_into_slice(const z_loaned_bytes_t *bytes, z_owned_slice_t */ int8_t z_bytes_decode_into_string(const z_loaned_bytes_t *bytes, z_owned_string_t *str); +/** + * Decodes data into a pair of :c:type:`z_owned_bytes_t` + * + * Parameters: + * bytes: Pointer to a :c:type:`z_loaned_bytes_t` to decode. + * first: Pointer to an uninitialized :c:type:`z_owned_bytes_t` to contain the first element. + * second: Pointer to an uninitialized :c:type:`z_owned_bytes_t` to contain the second element. + * curr_idx: Pointer to the current decoding index. + * + * Return: + * ``0`` if decode successful, or a ``negative value`` otherwise. + */ +int8_t zp_bytes_decode_into_pair(const z_loaned_bytes_t *bytes, z_owned_bytes_t *first, z_owned_bytes_t *second, + size_t *curr_idx); + /** * Encodes a signed integer into a :c:type:`z_owned_bytes_t` * @@ -752,6 +767,36 @@ int8_t z_bytes_encode_from_string(z_owned_bytes_t *bytes, const char *s); */ int8_t z_bytes_encode_from_string_copy(z_owned_bytes_t *bytes, const char *s); +/** + * Constructs payload from an iterator to `z_owned_bytes_t`. + * Parameters: + * bytes: An uninitialized :c:type:`z_owned_bytes_t` to contain the encoded payload. + * iterator_body: Iterator body function, providing data items. Returning false is treated as iteration end. + * context: Arbitrary context that will be passed to iterator_body. + * total_len: The length of all the items to encode. + * + * Return: + * ``0`` if encode successful, ``negative value`` otherwise. + */ +int8_t zp_bytes_encode_from_iter(z_owned_bytes_t *bytes, + _Bool (*iterator_body)(z_owned_bytes_t *data, void *context, size_t *curr_idx), + void *context, size_t total_len); + +/** + * Append a pair of `z_owned_bytes` objects which are consumed in the process. + * + * Parameters: + * bytes: An pre-initialized :c:type:`z_owned_bytes_t` to contain the encoded pair. + * first: Pointer to the first `z_owned_bytes` to encode. + * second: Pointer to the second `z_owned_bytes` to encode. + * curr_idx: Pointer to the current encoding index value. + * + * Return: + * ``0`` if encode successful, ``negative value`` otherwise. + */ +int8_t zp_bytes_encode_from_pair(z_owned_bytes_t *bytes, z_owned_bytes_t *first, z_owned_bytes_t *second, + size_t *curr_idx); + /** * Checks validity of a timestamp * diff --git a/src/api/api.c b/src/api/api.c index 7ab6ce292..9bea1c9d8 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -337,6 +337,49 @@ int8_t z_bytes_decode_into_string(const z_loaned_bytes_t *bytes, z_owned_string_ return _Z_RES_OK; } +int8_t zp_bytes_decode_into_pair(const z_loaned_bytes_t *bytes, z_owned_bytes_t *first, z_owned_bytes_t *second, + size_t *curr_idx) { + // Check bound size + if (*curr_idx >= bytes->_slice.len) { + return _Z_ERR_GENERIC; + } + // Init pair of owned bytes + z_bytes_null(first); + z_bytes_null(second); + first->_val = (_z_bytes_t *)z_malloc(sizeof(_z_bytes_t)); + second->_val = (_z_bytes_t *)z_malloc(sizeof(_z_bytes_t)); + if ((first->_val == NULL) || (second->_val == NULL)) { + return _Z_ERR_SYSTEM_OUT_OF_MEMORY; + } + // Extract first item size + size_t first_len = 0; + // FIXME: size endianness, Issue #420 + memcpy(&first_len, &bytes->_slice.start[*curr_idx], sizeof(uint32_t)); + *curr_idx += sizeof(uint32_t); + // Allocate first item bytes + *first->_val = _z_bytes_make(first_len); + if (!_z_bytes_check(*first->_val)) { + return _Z_ERR_SYSTEM_OUT_OF_MEMORY; + } + // Extract first item data + memcpy((uint8_t *)first->_val->_slice.start, &bytes->_slice.start[*curr_idx], first_len); + *curr_idx += first_len; + + // Extract second item size + size_t second_len = 0; + memcpy(&second_len, &bytes->_slice.start[*curr_idx], sizeof(uint32_t)); + *curr_idx += sizeof(uint32_t); + // Allocate second item bytes + *second->_val = _z_bytes_make(second_len); + if (!_z_bytes_check(*second->_val)) { + return _Z_ERR_SYSTEM_OUT_OF_MEMORY; + } + // Extract second item data + memcpy((uint8_t *)second->_val->_slice.start, &bytes->_slice.start[*curr_idx], second_len); + *curr_idx += second_len; + return _Z_RES_OK; +} + int8_t z_bytes_encode_from_int8(z_owned_bytes_t *bytes, int8_t val) { return z_bytes_encode_from_uint8(bytes, (uint8_t)val); } @@ -503,6 +546,48 @@ int8_t z_bytes_encode_from_string_copy(z_owned_bytes_t *bytes, const char *s) { return _Z_RES_OK; } +int8_t zp_bytes_encode_from_iter(z_owned_bytes_t *bytes, + _Bool (*iterator_body)(z_owned_bytes_t *data, void *context, size_t *curr_idx), + void *context, size_t total_len) { + // Init owned bytes + z_bytes_null(bytes); + bytes->_val = (_z_bytes_t *)z_malloc(sizeof(_z_bytes_t)); + if (bytes->_val == NULL) { + return _Z_ERR_SYSTEM_OUT_OF_MEMORY; + } + // Allocate bytes + *bytes->_val = _z_bytes_make(total_len); + if (!_z_bytes_check(*bytes->_val)) { + return _Z_ERR_SYSTEM_OUT_OF_MEMORY; + } + size_t curr_idx = 0; + while (iterator_body(bytes, context, &curr_idx)) + ; + return _Z_RES_OK; +} + +int8_t zp_bytes_encode_from_pair(z_owned_bytes_t *bytes, z_owned_bytes_t *first, z_owned_bytes_t *second, + size_t *curr_idx) { + // Calculate pair size + size_t first_len = z_slice_len(&first->_val->_slice); + size_t second_len = z_slice_len(&second->_val->_slice); + size_t len = 2 * sizeof(uint32_t) + first_len + second_len; + // Copy data + // FIXME: size endianness, Issue #420 + memcpy((uint8_t *)&bytes->_val->_slice.start[*curr_idx], &first_len, sizeof(uint32_t)); + *curr_idx += sizeof(uint32_t); + memcpy((uint8_t *)&bytes->_val->_slice.start[*curr_idx], z_slice_data(&first->_val->_slice), first_len); + *curr_idx += first_len; + memcpy((uint8_t *)&bytes->_val->_slice.start[*curr_idx], &second_len, sizeof(uint32_t)); + *curr_idx += sizeof(uint32_t); + memcpy((uint8_t *)&bytes->_val->_slice.start[*curr_idx], z_slice_data(&second->_val->_slice), second_len); + *curr_idx += second_len; + // Clean up + z_bytes_drop(first); + z_bytes_drop(second); + return _Z_RES_OK; +} + _Bool z_timestamp_check(z_timestamp_t ts) { return _z_timestamp_check(&ts); } z_query_target_t z_query_target_default(void) { return Z_QUERY_TARGET_DEFAULT; } @@ -985,9 +1070,9 @@ int8_t z_publisher_put(const z_loaned_publisher_t *pub, const uint8_t *payload, // Trigger local subscriptions _z_trigger_local_subscriptions(&pub->_zn.in->val, pub->_key, payload, len, _Z_N_QOS_DEFAULT, _z_bytes_from_owned_bytes(opt.attachment)); - // Clean-up z_encoding_drop(opt.encoding); + z_bytes_drop(opt.attachment); return ret; } diff --git a/src/collections/slice.c b/src/collections/slice.c index e9e24dbc2..59668747e 100644 --- a/src/collections/slice.c +++ b/src/collections/slice.c @@ -162,6 +162,7 @@ uint8_t _z_bytes_to_uint8(const _z_bytes_t *bs) { return val; } +// FIXME: int16+ endianness, Issue #420 uint16_t _z_bytes_to_uint16(const _z_bytes_t *bs) { uint16_t val = 0; memcpy(&val, bs->_slice.start, sizeof(val)); From 25e19867080ff47d879ba48e860612c1527cec68 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 15:47:18 +0200 Subject: [PATCH 06/14] fix: conversion issue --- tests/z_msgcodec_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/z_msgcodec_test.c b/tests/z_msgcodec_test.c index 0937f42ac..ab7a421e7 100644 --- a/tests/z_msgcodec_test.c +++ b/tests/z_msgcodec_test.c @@ -785,7 +785,7 @@ void subscriber_declaration(void) { _z_decl_queryable_t gen_queryable_declaration(void) { _z_decl_queryable_t e_qd = {._keyexpr = gen_keyexpr(), ._id = (uint32_t)gen_uint64(), - ._ext_queryable_info = {._complete = gen_uint8(), ._distance = (uint32_t)gen_zint()}}; + ._ext_queryable_info = {._complete = gen_uint8(), ._distance = gen_uint16()}}; return e_qd; } From 8a1db828d9d36a82defbd4d6af2d1af4653b6d5d Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 15:48:37 +0200 Subject: [PATCH 07/14] feat: add attachment examples --- examples/CMakeLists.txt | 2 + examples/unix/c11/z_pub_attachment.c | 184 +++++++++++++++++++++++++++ examples/unix/c11/z_sub_attachment.c | 178 ++++++++++++++++++++++++++ include/zenoh-pico/api/primitives.h | 2 +- 4 files changed, 365 insertions(+), 1 deletion(-) create mode 100644 examples/unix/c11/z_pub_attachment.c create mode 100644 examples/unix/c11/z_sub_attachment.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 7650b6cfa..b072b9283 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -36,9 +36,11 @@ if(UNIX) add_example(z_put unix/c11/z_put.c) add_example(z_pub unix/c11/z_pub.c) add_example(z_pub_st unix/c11/z_pub_st.c) + add_example(z_pub_attachment unix/c11/z_pub_attachment.c) add_example(z_sub unix/c11/z_sub.c) add_example(z_sub_channel unix/c11/z_sub_channel.c) add_example(z_sub_st unix/c11/z_sub_st.c) + add_example(z_sub_attachment unix/c11/z_sub_attachment.c) add_example(z_pull unix/c11/z_pull.c) add_example(z_get unix/c11/z_get.c) add_example(z_get_channel unix/c11/z_get_channel.c) diff --git a/examples/unix/c11/z_pub_attachment.c b/examples/unix/c11/z_pub_attachment.c new file mode 100644 index 000000000..50bc1c106 --- /dev/null +++ b/examples/unix/c11/z_pub_attachment.c @@ -0,0 +1,184 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +#include +#include +#include +#include +#include +#include +#include + +#include "zenoh-pico/system/platform.h" + +typedef struct kv_pair_t { + const char *key; + const char *value; +} kv_pair_t; + +typedef struct kv_pairs_t { + const kv_pair_t *data; + uint32_t len; + uint32_t current_idx; +} kv_pairs_t; + +#if Z_FEATURE_PUBLICATION == 1 + +size_t kv_pairs_length(kv_pairs_t *kvp) { + size_t ret = 0; + for (size_t i = 0; i < kvp->len; i++) { + // Size fields + ret += 2 * sizeof(uint32_t); + // Data size + ret += strlen(kvp->data[i].key) + strlen(kvp->data[i].value); + } + return ret; +} + +_Bool create_attachment_iter(z_owned_bytes_t *kv_pair, void *context, size_t *curr_idx) { + kv_pairs_t *kvs = (kv_pairs_t *)(context); + z_owned_bytes_t k, v; + if (kvs->current_idx >= kvs->len) { + return false; + } else { + z_bytes_encode_from_string(&k, kvs->data[kvs->current_idx].key); + z_bytes_encode_from_string(&v, kvs->data[kvs->current_idx].value); + zp_bytes_encode_from_pair(kv_pair, z_move(k), z_move(v), curr_idx); + kvs->current_idx++; + return true; + } +} + +int main(int argc, char **argv) { + const char *keyexpr = "demo/example/zenoh-pico-pub"; + char *const default_value = "Pub from Pico!"; + char *value = default_value; + const char *mode = "client"; + char *clocator = NULL; + char *llocator = NULL; + int n = 2147483647; // max int value by default + + int opt; + while ((opt = getopt(argc, argv, "k:v:e:m:l:n:")) != -1) { + switch (opt) { + case 'k': + keyexpr = optarg; + break; + case 'v': + value = optarg; + break; + case 'e': + clocator = optarg; + break; + case 'm': + mode = optarg; + break; + case 'l': + llocator = optarg; + break; + case 'n': + n = atoi(optarg); + break; + case '?': + if (optopt == 'k' || optopt == 'v' || optopt == 'e' || optopt == 'm' || optopt == 'l' || + optopt == 'n') { + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + } else { + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + } + return 1; + default: + return -1; + } + } + + z_owned_config_t config; + z_config_default(&config); + zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode); + if (clocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator); + } + if (llocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator); + } + + printf("Opening session...\n"); + z_owned_session_t s; + if (z_open(&s, z_move(config)) < 0) { + printf("Unable to open session!\n"); + return -1; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan_mut(s), NULL) < 0 || zp_start_lease_task(z_loan_mut(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + z_close(z_move(s)); + return -1; + } + // Wait for joins in peer mode + if (strcmp(mode, "peer") == 0) { + printf("Waiting for joins...\n"); + sleep(3); + } + // Declare publisher + printf("Declaring publisher for '%s'...\n", keyexpr); + z_view_keyexpr_t ke; + z_view_keyexpr_from_string(&ke, keyexpr); + z_owned_publisher_t pub; + if (z_declare_publisher(&pub, z_loan(s), z_loan(ke), NULL) < 0) { + printf("Unable to declare publisher for key expression!\n"); + return -1; + } + + z_publisher_put_options_t options; + z_publisher_put_options_default(&options); + + // Allocate attachment + kv_pair_t kvs[2]; + kvs[0] = (kv_pair_t){.key = "source", .value = "C"}; + z_owned_bytes_t attachment; + + // Allocate buffer + char buf[256]; + char buf_ind[16]; + + // Publish data + printf("Press CTRL-C to quit...\n"); + for (int idx = 0; idx < n; ++idx) { + z_sleep_s(1); + + // Add attachment value + sprintf(buf_ind, "%d", idx); + kvs[1] = (kv_pair_t){.key = "index", .value = buf_ind}; + kv_pairs_t ctx = (kv_pairs_t){.data = kvs, .current_idx = 0, .len = 2}; + zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&ctx, kv_pairs_length(&ctx)); + options.attachment = z_move(attachment); + + sprintf(buf, "[%4d] %s", idx, value); + printf("Putting Data ('%s': '%s')...\n", keyexpr, buf); + z_publisher_put(z_loan(pub), (const uint8_t *)buf, strlen(buf), &options); + } + // Clean up + z_undeclare_publisher(z_move(pub)); + zp_stop_read_task(z_loan_mut(s)); + zp_stop_lease_task(z_loan_mut(s)); + z_close(z_move(s)); + return 0; +} +#else +int main(void) { + printf("ERROR: Zenoh pico was compiled without Z_FEATURE_PUBLICATION but this example requires it.\n"); + return -2; +} +#endif diff --git a/examples/unix/c11/z_sub_attachment.c b/examples/unix/c11/z_sub_attachment.c new file mode 100644 index 000000000..7c0a0cfef --- /dev/null +++ b/examples/unix/c11/z_sub_attachment.c @@ -0,0 +1,178 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +#include +#include +#include +#include +#include +#include +#include + +typedef struct kv_pair_t { + z_owned_string_t key; + z_owned_string_t value; +} kv_pair_t; + +typedef struct kv_pairs_t { + kv_pair_t *data; + uint32_t len; + uint32_t current_idx; +} kv_pairs_t; + +#define KVP_LEN 16 + +#if Z_FEATURE_SUBSCRIPTION == 1 + +static int msg_nb = 0; + +void parse_attachment(kv_pairs_t *kvp, const z_loaned_bytes_t *attachment) { + size_t curr_idx = 0; + z_owned_bytes_t first, second; + while ((kvp->current_idx < kvp->len) && (zp_bytes_decode_into_pair(attachment, &first, &second, &curr_idx) == 0)) { + z_bytes_decode_into_string(z_loan(first), &kvp->data[kvp->current_idx].key); + z_bytes_decode_into_string(z_loan(second), &kvp->data[kvp->current_idx].value); + z_bytes_drop(&first); + z_bytes_drop(&second); + kvp->current_idx++; + } +} + +void print_attachment(kv_pairs_t *kvp) { + printf(" with attachment:\n"); + for (uint32_t i = 0; i < kvp->current_idx; i++) { + printf(" %d: %s, %s\n", i, z_string_data(z_loan(kvp->data[i].key)), + z_string_data(z_loan(kvp->data[i].value))); + } +} + +void drop_attachment(kv_pairs_t *kvp) { + for (size_t i = 0; i < kvp->current_idx; i++) { + z_string_drop(&kvp->data[i].key); + z_string_drop(&kvp->data[i].value); + } + z_free(kvp->data); +} + +void data_handler(const z_loaned_sample_t *sample, void *ctx) { + (void)(ctx); + z_owned_string_t keystr; + z_keyexpr_to_string(z_sample_keyexpr(sample), &keystr); + z_owned_string_t value; + z_bytes_decode_into_string(z_sample_payload(sample), &value); + printf(">> [Subscriber] Received ('%s': '%s')\n", z_string_data(z_loan(keystr)), z_string_data(z_loan(value))); + // Check attachment + kv_pairs_t kvp = {.current_idx = 0, .len = KVP_LEN, .data = (kv_pair_t *)malloc(KVP_LEN * sizeof(kv_pair_t))}; + parse_attachment(&kvp, z_sample_attachment(sample)); + if (kvp.current_idx > 0) { + print_attachment(&kvp); + } + drop_attachment(&kvp); + z_drop(z_move(keystr)); + z_drop(z_move(value)); + msg_nb++; +} + +int main(int argc, char **argv) { + const char *keyexpr = "demo/example/**"; + const char *mode = "client"; + char *clocator = NULL; + char *llocator = NULL; + int n = 0; + + int opt; + while ((opt = getopt(argc, argv, "k:e:m:l:n:")) != -1) { + switch (opt) { + case 'k': + keyexpr = optarg; + break; + case 'e': + clocator = optarg; + break; + case 'm': + mode = optarg; + break; + case 'l': + llocator = optarg; + break; + case 'n': + n = atoi(optarg); + break; + case '?': + if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'l' || optopt == 'n') { + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + } else { + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + } + return 1; + default: + return -1; + } + } + + z_owned_config_t config; + z_config_default(&config); + zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode); + if (clocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator); + } + if (llocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator); + } + + printf("Opening session...\n"); + z_owned_session_t s; + if (z_open(&s, z_move(config)) < 0) { + printf("Unable to open session!\n"); + return -1; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan_mut(s), NULL) < 0 || zp_start_lease_task(z_loan_mut(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + z_close(z_session_move(&s)); + return -1; + } + + z_owned_closure_sample_t callback; + z_closure(&callback, data_handler); + printf("Declaring Subscriber on '%s'...\n", keyexpr); + z_owned_subscriber_t sub; + z_view_keyexpr_t ke; + z_view_keyexpr_from_string(&ke, keyexpr); + if (z_declare_subscriber(&sub, z_loan(s), z_loan(ke), z_move(callback), NULL) < 0) { + printf("Unable to declare subscriber.\n"); + return -1; + } + + printf("Press CTRL-C to quit...\n"); + while (1) { + if ((n != 0) && (msg_nb >= n)) { + break; + } + sleep(1); + } + // Clean up + z_undeclare_subscriber(z_move(sub)); + zp_stop_read_task(z_loan_mut(s)); + zp_stop_lease_task(z_loan_mut(s)); + z_close(z_move(s)); + return 0; +} +#else +int main(void) { + printf("ERROR: Zenoh pico was compiled without Z_FEATURE_SUBSCRIPTION but this example requires it.\n"); + return -2; +} +#endif diff --git a/include/zenoh-pico/api/primitives.h b/include/zenoh-pico/api/primitives.h index bdf754c92..5ea4f2557 100644 --- a/include/zenoh-pico/api/primitives.h +++ b/include/zenoh-pico/api/primitives.h @@ -795,7 +795,7 @@ int8_t zp_bytes_encode_from_iter(z_owned_bytes_t *bytes, * ``0`` if encode successful, ``negative value`` otherwise. */ int8_t zp_bytes_encode_from_pair(z_owned_bytes_t *bytes, z_owned_bytes_t *first, z_owned_bytes_t *second, - size_t *curr_idx); + size_t *curr_idx); /** * Checks validity of a timestamp From e8c4e2958c3aa0bf5db41f5f2db5f6c5a5905fa5 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 15:56:03 +0200 Subject: [PATCH 08/14] fix: check for null value before in drop function --- src/api/api.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/api.c b/src/api/api.c index 9bea1c9d8..b3ae48245 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -686,7 +686,7 @@ void z_closure_zid_call(const z_owned_closure_zid_t *closure, const z_id_t *id) return ret; \ } \ void z_##name##_drop(z_owned_##name##_t *obj) { \ - if (obj->_val != NULL) { \ + if ((obj != NULL) && (obj->_val != NULL)) { \ f_free(&obj->_val); \ } \ } From 6e455e0f9936dcfe053b39cd945710f8e9353318 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 15:56:17 +0200 Subject: [PATCH 09/14] fix: copy attachment --- src/net/reply.c | 2 +- src/net/sample.c | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/net/reply.c b/src/net/reply.c index 8c42833b9..9dfc5c4fb 100644 --- a/src/net/reply.c +++ b/src/net/reply.c @@ -98,7 +98,7 @@ _z_reply_t _z_reply_create(_z_keyexpr_t keyexpr, z_reply_tag_t tag, _z_id_t id, _z_slice_copy(&sample.payload._slice, payload); sample.kind = kind; sample.timestamp = _z_timestamp_duplicate(timestamp); - sample.attachment = att; // FIXME: call z_attachment_move or copy + sample.attachment = _z_bytes_duplicate(&att); // Create sample rc from value reply.data.sample = _z_sample_rc_new_from_val(sample); diff --git a/src/net/sample.c b/src/net/sample.c index f71744358..7ceca0f2f 100644 --- a/src/net/sample.c +++ b/src/net/sample.c @@ -88,7 +88,7 @@ _z_sample_t _z_sample_create(const _z_keyexpr_t *key, const _z_slice_t *payload, s.kind = kind; s.timestamp = timestamp; s.qos = qos; - s.attachment = att; // FIXME: call z_attachment_move or copy + s.attachment = _z_bytes_duplicate(&att); return s; } #else From 4f4b952ef9e9f5e1fec2e0f282ae08614562c886 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 16:25:28 +0200 Subject: [PATCH 10/14] ci: add attachment test --- .github/workflows/build-check.yaml | 35 ++++++- CMakeLists.txt | 1 + tests/attachment.py | 157 +++++++++++++++++++++++++++++ tests/modularity.py | 27 +---- 4 files changed, 195 insertions(+), 25 deletions(-) create mode 100644 tests/attachment.py diff --git a/.github/workflows/build-check.yaml b/.github/workflows/build-check.yaml index 854c65e35..3e1f3d69d 100644 --- a/.github/workflows/build-check.yaml +++ b/.github/workflows/build-check.yaml @@ -115,7 +115,7 @@ jobs: run: | sudo apt install -y ninja-build CMAKE_GENERATOR=Ninja make - python3 ./build/tests/modularity.py --pub $Z_FEATURE_PUBLICATION --sub $Z_FEATURE_SUBSCRIPTION --queryable $Z_FEATURE_QUERYABLE --query $Z_FEATURE_QUERY --attachment 0 + python3 ./build/tests/modularity.py --pub $Z_FEATURE_PUBLICATION --sub $Z_FEATURE_SUBSCRIPTION --queryable $Z_FEATURE_QUERYABLE --query $Z_FEATURE_QUERY timeout-minutes: 5 env: Z_FEATURE_PUBLICATION: ${{ matrix.feature_publication }} @@ -195,3 +195,36 @@ jobs: - name: Kill Zenoh router if: always() run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }} + + attachment_test: + needs: zenoh_build + name: Test attachments + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + + - name: Download Zenoh artifacts + uses: actions/download-artifact@v4 + with: + name: ${{ needs.zenoh_build.outputs.artifact-name }} + + - name: Unzip Zenoh artifacts + run: unzip ${{ needs.zenoh_build.outputs.artifact-name }} -d zenoh-standalone + + - id: run-zenoh + name: Run Zenoh router + run: | + RUST_LOG=debug ./zenoh-standalone/zenohd & + echo "zenohd-pid=$!" >> $GITHUB_OUTPUT + + - name: Build project and run test + run: | + sudo apt install -y ninja-build + CMAKE_GENERATOR=Ninja make + python3 ./build/tests/attachment.py + timeout-minutes: 5 + + - name: Kill Zenoh router + if: always() + run: kill ${{ steps.run-zenoh.outputs.zenohd-pid }} diff --git a/CMakeLists.txt b/CMakeLists.txt index 2c7af19fe..cf15dadea 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -361,6 +361,7 @@ if(UNIX OR MSVC) configure_file(${PROJECT_SOURCE_DIR}/tests/raweth.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/raweth.py COPYONLY) configure_file(${PROJECT_SOURCE_DIR}/tests/fragment.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/fragment.py COPYONLY) configure_file(${PROJECT_SOURCE_DIR}/tests/single_thread.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/single_thread.py COPYONLY) + configure_file(${PROJECT_SOURCE_DIR}/tests/attachment.py ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/attachment.py COPYONLY) enable_testing() add_test(z_data_struct_test ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/z_data_struct_test) diff --git a/tests/attachment.py b/tests/attachment.py new file mode 100644 index 000000000..2c85490af --- /dev/null +++ b/tests/attachment.py @@ -0,0 +1,157 @@ +import argparse +import os +from signal import SIGINT +import subprocess +import sys +import time + +# Specify the directory for the binaries +DIR_EXAMPLES = "build/examples" + + +def pub_and_sub(): + print("*** Pub & sub test ***") + test_status = 0 + + # Expected z_pub output & status + z_pub_expected_status = 0 + z_pub_expected_output = '''Opening session... +Declaring publisher for 'demo/example/zenoh-pico-pub'... +Press CTRL-C to quit... +Putting Data ('demo/example/zenoh-pico-pub': '[ 0] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 1] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 2] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 3] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 4] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 5] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 6] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 7] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 8] Pub from Pico!')... +Putting Data ('demo/example/zenoh-pico-pub': '[ 9] Pub from Pico!')...''' + + # Expected z_sub output & status + z_sub_expected_status = 0 + z_sub_expected_output = '''Opening session... +Declaring Subscriber on 'demo/example/**'... +Press CTRL-C to quit... +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 0] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 0 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 1] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 1 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 2] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 2 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 3] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 3 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 4] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 4 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 5] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 5 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 6] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 6 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 7] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 7 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 8] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 8 +>> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 9] Pub from Pico!') + with attachment: + 0: source, C + 1: index, 9''' + + print("Start subscriber") + # Start z_sub in the background + z_sub_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_sub_attachment -n 10" + + z_sub_process = subprocess.Popen( + z_sub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True + ) + + # Introduce a delay to ensure z_sub starts + time.sleep(2) + + print("Start publisher") + # Start z_pub + z_pub_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_pub_attachment -n 10" + z_pub_process = subprocess.Popen( + z_pub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True + ) + + # Wait for z_pub to finish + z_pub_process.wait() + + print("Stop subscriber") + time.sleep(2) + if z_sub_process.poll() is None: + # send SIGINT to group + z_sub_process_gid = os.getpgid(z_sub_process.pid) + os.killpg(z_sub_process_gid, SIGINT) + + # Wait for z_sub to finish + z_sub_process.wait() + + print("Check publisher status & output") + # Check the exit status of z_pub + z_pub_status = z_pub_process.returncode + if z_pub_status == z_pub_expected_status: + print("z_pub status valid") + else: + print(f"z_pub status invalid, expected: {z_pub_expected_status}, received: {z_pub_status}") + test_status = 1 + + # Check output of z_pub + z_pub_output = z_pub_process.stdout.read() + if z_pub_expected_output in z_pub_output: + print("z_pub output valid") + else: + print("z_pub output invalid:") + print(f"Expected: \"{z_pub_expected_output}\"") + print(f"Received: \"{z_pub_output}\"") + test_status = 1 + + print("Check subscriber status & output") + # Check the exit status of z_sub + z_sub_status = z_sub_process.returncode + if z_sub_status == z_sub_expected_status: + print("z_sub status valid") + else: + print(f"z_sub status invalid, expected: {z_sub_expected_status}, received: {z_sub_status}") + test_status = 1 + + # Check output of z_sub + z_sub_output = z_sub_process.stdout.read() + if z_sub_expected_output in z_sub_output: + print("z_sub output valid") + else: + print("z_sub output invalid:") + print(f"Expected: \"{z_sub_expected_output}\"") + print(f"Received: \"{z_sub_output}\"") + test_status = 1 + # Return value + return test_status + + +if __name__ == "__main__": + EXIT_STATUS = 0 + + # Test pub and sub examples + if pub_and_sub() == 1: + EXIT_STATUS = 1 + # Exit + sys.exit(EXIT_STATUS) diff --git a/tests/modularity.py b/tests/modularity.py index 226a04290..499ab817c 100644 --- a/tests/modularity.py +++ b/tests/modularity.py @@ -159,15 +159,7 @@ def query_and_queryable(args): if args.query == 1: z_query_expected_status = 0 if args.queryable == 1: - if args.attachment == 1: - z_query_expected_output = """Opening session... -Sending Query 'demo/example/**'... ->> Received ('demo/example/**': 'Queryable from Pico!') -Attachement found ->>> hello: world ->> Received query final notification""" - else: - z_query_expected_output = """Opening session... + z_query_expected_output = """Opening session... Sending Query 'demo/example/**'... >> Received ('demo/example/**': 'Queryable from Pico!') >> Received query final notification""" @@ -185,16 +177,7 @@ def query_and_queryable(args): if args.queryable == 1: z_queryable_expected_status = -2 if args.query == 1: - if args.attachment == 1: - z_queryable_expected_output = """Opening session... -Creating Queryable on 'demo/example/zenoh-pico-queryable'... -Press CTRL-C to quit... - >> [Queryable handler] Received Query 'demo/example/**' -Attachement found ->>> hi: there -""" - else: - z_queryable_expected_output = """Opening session... + z_queryable_expected_output = """Opening session... Creating Queryable on 'demo/example/zenoh-pico-queryable'... Press CTRL-C to quit... >> [Queryable handler] Received Query 'demo/example/**' @@ -297,13 +280,9 @@ def query_and_queryable(args): parser.add_argument("--sub", type=int, choices=[0, 1], help="Z_FEATURE_SUBSCRIPTION (0 or 1)") parser.add_argument("--queryable", type=int, choices=[0, 1], help="Z_FEATURE_QUERYABLE (0 or 1)") parser.add_argument("--query", type=int, choices=[0, 1], help="Z_FEATURE_QUERY (0 or 1)") - parser.add_argument("--attachment", type=int, choices=[0, 1], help="testing with attachment (0 or 1)") EXIT_STATUS = 0 prog_args = parser.parse_args() - print( - f"Args value, pub:{prog_args.pub}, sub:{prog_args.sub}, " - f"queryable:{prog_args.queryable}, query:{prog_args.query}, attachment:{prog_args.attachment}" - ) + print(f"Args value, pub:{prog_args.pub}, sub:{prog_args.sub}, " f"queryable:{prog_args.queryable}, query:{prog_args.query}") # Test pub and sub examples if pub_and_sub(prog_args) == 1: From ef610ea2a95b130fd39349357791f51cce1f8ae1 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 17:22:23 +0200 Subject: [PATCH 11/14] fix: query/reply memory leaks --- src/api/api.c | 3 +++ src/net/query.c | 2 +- src/net/reply.c | 2 +- src/protocol/codec/message.c | 4 ++-- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/api/api.c b/src/api/api.c index b3ae48245..c1baf064b 100644 --- a/src/api/api.c +++ b/src/api/api.c @@ -976,6 +976,7 @@ int8_t z_put(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, co _z_bytes_from_owned_bytes(opt.attachment)); // Clean-up z_encoding_drop(opt.encoding); + z_bytes_drop(opt.attachment); return ret; } @@ -1139,6 +1140,7 @@ int8_t z_get(const z_loaned_session_t *zs, const z_loaned_keyexpr_t *keyexpr, co } // Clean-up z_encoding_drop(opt.encoding); + z_bytes_drop(opt.attachment); return ret; } @@ -1227,6 +1229,7 @@ int8_t z_query_reply(const z_loaned_query_t *query, const z_loaned_keyexpr_t *ke } // Clean-up z_encoding_drop(opts.encoding); + z_bytes_drop(opts.attachment); return ret; } #endif diff --git a/src/net/query.c b/src/net/query.c index 081524f8e..798dbd2a1 100644 --- a/src/net/query.c +++ b/src/net/query.c @@ -51,7 +51,7 @@ _z_query_t _z_query_create(const _z_value_t *value, const _z_keyexpr_t *key, con memcpy(q._parameters, parameters->start, parameters->len); q._parameters[parameters->len] = 0; q._anyke = (strstr(q._parameters, Z_SELECTOR_QUERY_MATCH) == NULL) ? false : true; - q.attachment = att; + q.attachment._slice = _z_slice_steal((_z_slice_t *)&att._slice); _z_keyexpr_copy(&q._key, key); _z_value_copy(&q._value, value); diff --git a/src/net/reply.c b/src/net/reply.c index 9dfc5c4fb..2dff090e2 100644 --- a/src/net/reply.c +++ b/src/net/reply.c @@ -98,7 +98,7 @@ _z_reply_t _z_reply_create(_z_keyexpr_t keyexpr, z_reply_tag_t tag, _z_id_t id, _z_slice_copy(&sample.payload._slice, payload); sample.kind = kind; sample.timestamp = _z_timestamp_duplicate(timestamp); - sample.attachment = _z_bytes_duplicate(&att); + sample.attachment._slice = _z_slice_steal((_z_slice_t *)&att._slice); // Create sample rc from value reply.data.sample = _z_sample_rc_new_from_val(sample); diff --git a/src/protocol/codec/message.c b/src/protocol/codec/message.c index 3ba5e3216..592323756 100644 --- a/src/protocol/codec/message.c +++ b/src/protocol/codec/message.c @@ -303,7 +303,7 @@ int8_t _z_push_body_decode_extensions(_z_msg_ext_t *extension, void *ctx) { ret = _z_source_info_decode(&pshb->_body._put._commons._source_info, &zbf); break; } - case _Z_MSG_EXT_ENC_ZBUF | 0x03: { + case _Z_MSG_EXT_ENC_ZBUF | 0x03: { // Attachment pshb->_body._put._attachment._slice = extension->_body._zbuf._val._is_alloc ? _z_slice_steal(&extension->_body._zbuf._val) : _z_slice_duplicate(&extension->_body._zbuf._val); @@ -448,7 +448,7 @@ int8_t _z_query_decode_extensions(_z_msg_ext_t *extension, void *ctx) { _z_slice_copy(&msg->_ext_value.payload._slice, &bytes); break; } - case _Z_MSG_EXT_ENC_ZBUF | 0x05: { + case _Z_MSG_EXT_ENC_ZBUF | 0x05: { // Attachment msg->_ext_attachment._slice = extension->_body._zbuf._val._is_alloc ? _z_slice_steal(&extension->_body._zbuf._val) : _z_slice_duplicate(&extension->_body._zbuf._val); From e71a74c3efe2ced19231130f5c2d67e177fd5632 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 17:23:08 +0200 Subject: [PATCH 12/14] feat: add get/queryable attachment example --- examples/CMakeLists.txt | 2 + examples/unix/c11/z_get_attachment.c | 248 ++++++++++++++++++++ examples/unix/c11/z_queryable_attachment.c | 254 +++++++++++++++++++++ 3 files changed, 504 insertions(+) create mode 100644 examples/unix/c11/z_get_attachment.c create mode 100644 examples/unix/c11/z_queryable_attachment.c diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b072b9283..ba3dd8139 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -44,8 +44,10 @@ if(UNIX) add_example(z_pull unix/c11/z_pull.c) add_example(z_get unix/c11/z_get.c) add_example(z_get_channel unix/c11/z_get_channel.c) + add_example(z_get_attachment unix/c11/z_get_attachment.c) add_example(z_queryable unix/c11/z_queryable.c) add_example(z_queryable_channel unix/c11/z_queryable_channel.c) + add_example(z_queryable_attachment unix/c11/z_queryable_attachment.c) add_example(z_info unix/c11/z_info.c) add_example(z_scout unix/c11/z_scout.c) add_example(z_ping unix/c11/z_ping.c) diff --git a/examples/unix/c11/z_get_attachment.c b/examples/unix/c11/z_get_attachment.c new file mode 100644 index 000000000..da158e7f9 --- /dev/null +++ b/examples/unix/c11/z_get_attachment.c @@ -0,0 +1,248 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, + +#include +#include +#include +#include +#include +#include + +typedef struct kv_pair_t { + const char *key; + const char *value; +} kv_pair_t; + +typedef struct kv_pairs_tx_t { + const kv_pair_t *data; + uint32_t len; + uint32_t current_idx; +} kv_pairs_tx_t; + +typedef struct kv_pair_decoded_t { + z_owned_string_t key; + z_owned_string_t value; +} kv_pair_decoded_t; + +typedef struct kv_pairs_rx_t { + kv_pair_decoded_t *data; + uint32_t len; + uint32_t current_idx; +} kv_pairs_rx_t; + +#define KVP_LEN 16 + +#if Z_FEATURE_QUERY == 1 && Z_FEATURE_MULTI_THREAD == 1 +static z_condvar_t cond; +static z_mutex_t mutex; + +size_t kv_pairs_length(kv_pairs_tx_t *kvp) { + size_t ret = 0; + for (size_t i = 0; i < kvp->len; i++) { + // Size fields + ret += 2 * sizeof(uint32_t); + // Data size + ret += strlen(kvp->data[i].key) + strlen(kvp->data[i].value); + } + return ret; +} + +_Bool create_attachment_iter(z_owned_bytes_t *kv_pair, void *context, size_t *curr_idx) { + kv_pairs_tx_t *kvs = (kv_pairs_tx_t *)(context); + z_owned_bytes_t k, v; + if (kvs->current_idx >= kvs->len) { + return false; + } else { + z_bytes_encode_from_string(&k, kvs->data[kvs->current_idx].key); + z_bytes_encode_from_string(&v, kvs->data[kvs->current_idx].value); + zp_bytes_encode_from_pair(kv_pair, z_move(k), z_move(v), curr_idx); + kvs->current_idx++; + return true; + } +} + +void parse_attachment(kv_pairs_rx_t *kvp, const z_loaned_bytes_t *attachment) { + size_t curr_idx = 0; + z_owned_bytes_t first, second; + while ((kvp->current_idx < kvp->len) && (zp_bytes_decode_into_pair(attachment, &first, &second, &curr_idx) == 0)) { + z_bytes_decode_into_string(z_loan(first), &kvp->data[kvp->current_idx].key); + z_bytes_decode_into_string(z_loan(second), &kvp->data[kvp->current_idx].value); + z_bytes_drop(&first); + z_bytes_drop(&second); + kvp->current_idx++; + } +} + +void print_attachment(kv_pairs_rx_t *kvp) { + printf(" with attachment:\n"); + for (uint32_t i = 0; i < kvp->current_idx; i++) { + printf(" %d: %s, %s\n", i, z_string_data(z_loan(kvp->data[i].key)), + z_string_data(z_loan(kvp->data[i].value))); + } +} + +void drop_attachment(kv_pairs_rx_t *kvp) { + for (size_t i = 0; i < kvp->current_idx; i++) { + z_string_drop(&kvp->data[i].key); + z_string_drop(&kvp->data[i].value); + } + z_free(kvp->data); +} + +void reply_dropper(void *ctx) { + (void)(ctx); + printf(">> Received query final notification\n"); + z_condvar_signal(&cond); + z_condvar_free(&cond); +} + +void reply_handler(const z_loaned_reply_t *reply, void *ctx) { + (void)(ctx); + if (z_reply_is_ok(reply)) { + const z_loaned_sample_t *sample = z_reply_ok(reply); + z_owned_string_t keystr; + z_keyexpr_to_string(z_sample_keyexpr(sample), &keystr); + z_owned_string_t replystr; + z_bytes_decode_into_string(z_sample_payload(sample), &replystr); + + printf(">> Received ('%s': '%s')\n", z_string_data(z_loan(keystr)), z_string_data(z_loan(replystr))); + + // Check attachment + kv_pairs_rx_t kvp = { + .current_idx = 0, .len = KVP_LEN, .data = (kv_pair_decoded_t *)malloc(KVP_LEN * sizeof(kv_pair_decoded_t))}; + parse_attachment(&kvp, z_sample_attachment(sample)); + if (kvp.current_idx > 0) { + print_attachment(&kvp); + } + drop_attachment(&kvp); + + z_drop(z_move(keystr)); + z_drop(z_move(replystr)); + } else { + printf(">> Received an error\n"); + } +} + +int main(int argc, char **argv) { + const char *keyexpr = "demo/example/**"; + const char *mode = "client"; + const char *clocator = NULL; + const char *llocator = NULL; + const char *value = NULL; + + int opt; + while ((opt = getopt(argc, argv, "k:e:m:v:l:")) != -1) { + switch (opt) { + case 'k': + keyexpr = optarg; + break; + case 'e': + clocator = optarg; + break; + case 'm': + mode = optarg; + break; + case 'l': + llocator = optarg; + break; + case 'v': + value = optarg; + break; + case '?': + if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'v' || optopt == 'l') { + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + } else { + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + } + return 1; + default: + return -1; + } + } + + z_mutex_init(&mutex); + z_condvar_init(&cond); + + z_owned_config_t config; + z_config_default(&config); + zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode); + if (clocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator); + } + if (llocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator); + } + + printf("Opening session...\n"); + z_owned_session_t s; + if (z_open(&s, z_move(config)) < 0) { + printf("Unable to open session!\n"); + return -1; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan_mut(s), NULL) < 0 || zp_start_lease_task(z_loan_mut(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + z_close(z_session_move(&s)); + return -1; + } + + z_view_keyexpr_t ke; + if (z_view_keyexpr_from_string(&ke, keyexpr) < 0) { + printf("%s is not a valid key expression", keyexpr); + return -1; + } + + z_mutex_lock(&mutex); + printf("Sending Query '%s'...\n", keyexpr); + z_get_options_t opts; + z_get_options_default(&opts); + // Value encoding + z_owned_bytes_t payload; + if (value != NULL) { + z_bytes_encode_from_string(&payload, value); + opts.payload = &payload; + } + + // Add attachment value + kv_pair_t kvs[1]; + kvs[0] = (kv_pair_t){.key = "test_key", .value = "test_value"}; + kv_pairs_tx_t ctx = (kv_pairs_tx_t){.data = kvs, .current_idx = 0, .len = 1}; + z_owned_bytes_t attachment; + zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&ctx, kv_pairs_length(&ctx)); + opts.attachment = z_move(attachment); + + z_owned_closure_reply_t callback; + z_closure(&callback, reply_handler, reply_dropper); + if (z_get(z_loan(s), z_loan(ke), "", z_move(callback), &opts) < 0) { + printf("Unable to send query.\n"); + return -1; + } + z_condvar_wait(&cond, &mutex); + z_mutex_unlock(&mutex); + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan_mut(s)); + zp_stop_lease_task(z_loan_mut(s)); + + z_close(z_move(s)); + return 0; +} +#else +int main(void) { + printf( + "ERROR: Zenoh pico was compiled without Z_FEATURE_QUERY or Z_FEATURE_MULTI_THREAD but this example requires " + "them.\n"); + return -2; +} +#endif diff --git a/examples/unix/c11/z_queryable_attachment.c b/examples/unix/c11/z_queryable_attachment.c new file mode 100644 index 000000000..d6b41fac2 --- /dev/null +++ b/examples/unix/c11/z_queryable_attachment.c @@ -0,0 +1,254 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, + +#include +#include +#include +#include +#include +#include + +typedef struct kv_pair_t { + const char *key; + const char *value; +} kv_pair_t; + +typedef struct kv_pairs_tx_t { + const kv_pair_t *data; + uint32_t len; + uint32_t current_idx; +} kv_pairs_tx_t; + +typedef struct kv_pair_decoded_t { + z_owned_string_t key; + z_owned_string_t value; +} kv_pair_decoded_t; + +typedef struct kv_pairs_rx_t { + kv_pair_decoded_t *data; + uint32_t len; + uint32_t current_idx; +} kv_pairs_rx_t; + +#define KVP_LEN 16 + +#if Z_FEATURE_QUERYABLE == 1 +const char *keyexpr = "demo/example/zenoh-pico-queryable"; +const char *value = "Queryable from Pico!"; +static int msg_nb = 0; + +size_t kv_pairs_length(kv_pairs_tx_t *kvp) { + size_t ret = 0; + for (size_t i = 0; i < kvp->len; i++) { + // Size fields + ret += 2 * sizeof(uint32_t); + // Data size + ret += strlen(kvp->data[i].key) + strlen(kvp->data[i].value); + } + return ret; +} + +_Bool create_attachment_iter(z_owned_bytes_t *kv_pair, void *context, size_t *curr_idx) { + kv_pairs_tx_t *kvs = (kv_pairs_tx_t *)(context); + z_owned_bytes_t k, v; + if (kvs->current_idx >= kvs->len) { + return false; + } else { + z_bytes_encode_from_string(&k, kvs->data[kvs->current_idx].key); + z_bytes_encode_from_string(&v, kvs->data[kvs->current_idx].value); + zp_bytes_encode_from_pair(kv_pair, z_move(k), z_move(v), curr_idx); + kvs->current_idx++; + return true; + } +} + +void parse_attachment(kv_pairs_rx_t *kvp, const z_loaned_bytes_t *attachment) { + size_t curr_idx = 0; + z_owned_bytes_t first, second; + while ((kvp->current_idx < kvp->len) && (zp_bytes_decode_into_pair(attachment, &first, &second, &curr_idx) == 0)) { + z_bytes_decode_into_string(z_loan(first), &kvp->data[kvp->current_idx].key); + z_bytes_decode_into_string(z_loan(second), &kvp->data[kvp->current_idx].value); + z_bytes_drop(&first); + z_bytes_drop(&second); + kvp->current_idx++; + } +} + +void print_attachment(kv_pairs_rx_t *kvp) { + printf(" with attachment:\n"); + for (uint32_t i = 0; i < kvp->current_idx; i++) { + printf(" %d: %s, %s\n", i, z_string_data(z_loan(kvp->data[i].key)), + z_string_data(z_loan(kvp->data[i].value))); + } +} + +void drop_attachment(kv_pairs_rx_t *kvp) { + for (size_t i = 0; i < kvp->current_idx; i++) { + z_string_drop(&kvp->data[i].key); + z_string_drop(&kvp->data[i].value); + } + z_free(kvp->data); +} + +void query_handler(const z_loaned_query_t *query, void *ctx) { + (void)(ctx); + z_owned_string_t keystr; + z_keyexpr_to_string(z_query_keyexpr(query), &keystr); + z_view_string_t params; + z_query_parameters(query, ¶ms); + printf(" >> [Queryable handler] Received Query '%s%.*s'\n", z_string_data(z_loan(keystr)), (int)z_loan(params)->len, + z_loan(params)->val); + // Process value + z_owned_string_t payload_string; + z_bytes_decode_into_string(z_value_payload(z_query_value(query)), &payload_string); + if (z_string_len(z_loan(payload_string)) > 1) { + printf(" with value '%s'\n", z_string_data(z_loan(payload_string))); + } + // Check attachment + kv_pairs_rx_t kvp = { + .current_idx = 0, .len = KVP_LEN, .data = (kv_pair_decoded_t *)malloc(KVP_LEN * sizeof(kv_pair_decoded_t))}; + parse_attachment(&kvp, z_query_attachment(query)); + if (kvp.current_idx > 0) { + print_attachment(&kvp); + } + drop_attachment(&kvp); + z_drop(z_move(payload_string)); + + // Create encoding + z_owned_encoding_t encoding; + zp_encoding_make(&encoding, Z_ENCODING_ID_TEXT_PLAIN, NULL); + + z_query_reply_options_t options; + z_query_reply_options_default(&options); + options.encoding = z_move(encoding); + + // Reply value encoding + z_owned_bytes_t reply_payload; + z_bytes_encode_from_string(&reply_payload, value); + + // Reply attachment + kv_pair_t kvs[1]; + kvs[0] = (kv_pair_t){.key = "reply_key", .value = "reply_value"}; + kv_pairs_tx_t kv_ctx = (kv_pairs_tx_t){.data = kvs, .current_idx = 0, .len = 1}; + z_owned_bytes_t attachment; + zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&kv_ctx, kv_pairs_length(&kv_ctx)); + options.attachment = z_move(attachment); + + z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), &options); + z_drop(z_move(keystr)); + msg_nb++; +} + +int main(int argc, char **argv) { + const char *mode = "client"; + char *clocator = NULL; + char *llocator = NULL; + int n = 0; + + int opt; + while ((opt = getopt(argc, argv, "k:e:m:v:l:n:")) != -1) { + switch (opt) { + case 'k': + keyexpr = optarg; + break; + case 'e': + clocator = optarg; + break; + case 'm': + mode = optarg; + break; + case 'l': + llocator = optarg; + break; + case 'v': + value = optarg; + break; + case 'n': + n = atoi(optarg); + break; + case '?': + if (optopt == 'k' || optopt == 'e' || optopt == 'm' || optopt == 'v' || optopt == 'l' || + optopt == 'n') { + fprintf(stderr, "Option -%c requires an argument.\n", optopt); + } else { + fprintf(stderr, "Unknown option `-%c'.\n", optopt); + } + return 1; + default: + return -1; + } + } + + z_owned_config_t config; + z_config_default(&config); + zp_config_insert(z_loan_mut(config), Z_CONFIG_MODE_KEY, mode); + if (clocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_CONNECT_KEY, clocator); + } + if (llocator != NULL) { + zp_config_insert(z_loan_mut(config), Z_CONFIG_LISTEN_KEY, llocator); + } + + printf("Opening session...\n"); + z_owned_session_t s; + if (z_open(&s, z_move(config)) < 0) { + printf("Unable to open session!\n"); + return -1; + } + + // Start read and lease tasks for zenoh-pico + if (zp_start_read_task(z_loan_mut(s), NULL) < 0 || zp_start_lease_task(z_loan_mut(s), NULL) < 0) { + printf("Unable to start read and lease tasks\n"); + z_close(z_session_move(&s)); + return -1; + } + + z_view_keyexpr_t ke; + if (z_view_keyexpr_from_string(&ke, keyexpr) < 0) { + printf("%s is not a valid key expression", keyexpr); + return -1; + } + + printf("Creating Queryable on '%s'...\n", keyexpr); + z_owned_closure_query_t callback; + z_closure(&callback, query_handler); + z_owned_queryable_t qable; + if (z_declare_queryable(&qable, z_loan(s), z_loan(ke), z_move(callback), NULL) < 0) { + printf("Unable to create queryable.\n"); + return -1; + } + + printf("Press CTRL-C to quit...\n"); + while (1) { + if ((n != 0) && (msg_nb >= n)) { + break; + } + sleep(1); + } + + z_undeclare_queryable(z_move(qable)); + + // Stop read and lease tasks for zenoh-pico + zp_stop_read_task(z_loan_mut(s)); + zp_stop_lease_task(z_loan_mut(s)); + + z_close(z_move(s)); + + return 0; +} +#else +int main(void) { + printf("ERROR: Zenoh pico was compiled without Z_FEATURE_QUERYABLE but this example requires it.\n"); + return -2; +} +#endif From a4885582e12703773ba223f28a0dac2873612946 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Fri, 14 Jun 2024 17:32:44 +0200 Subject: [PATCH 13/14] tests: add query/queryable attachment test --- tests/attachment.py | 140 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 111 insertions(+), 29 deletions(-) diff --git a/tests/attachment.py b/tests/attachment.py index 2c85490af..b4f477541 100644 --- a/tests/attachment.py +++ b/tests/attachment.py @@ -22,12 +22,7 @@ def pub_and_sub(): Putting Data ('demo/example/zenoh-pico-pub': '[ 1] Pub from Pico!')... Putting Data ('demo/example/zenoh-pico-pub': '[ 2] Pub from Pico!')... Putting Data ('demo/example/zenoh-pico-pub': '[ 3] Pub from Pico!')... -Putting Data ('demo/example/zenoh-pico-pub': '[ 4] Pub from Pico!')... -Putting Data ('demo/example/zenoh-pico-pub': '[ 5] Pub from Pico!')... -Putting Data ('demo/example/zenoh-pico-pub': '[ 6] Pub from Pico!')... -Putting Data ('demo/example/zenoh-pico-pub': '[ 7] Pub from Pico!')... -Putting Data ('demo/example/zenoh-pico-pub': '[ 8] Pub from Pico!')... -Putting Data ('demo/example/zenoh-pico-pub': '[ 9] Pub from Pico!')...''' +Putting Data ('demo/example/zenoh-pico-pub': '[ 4] Pub from Pico!')...''' # Expected z_sub output & status z_sub_expected_status = 0 @@ -53,31 +48,11 @@ def pub_and_sub(): >> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 4] Pub from Pico!') with attachment: 0: source, C - 1: index, 4 ->> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 5] Pub from Pico!') - with attachment: - 0: source, C - 1: index, 5 ->> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 6] Pub from Pico!') - with attachment: - 0: source, C - 1: index, 6 ->> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 7] Pub from Pico!') - with attachment: - 0: source, C - 1: index, 7 ->> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 8] Pub from Pico!') - with attachment: - 0: source, C - 1: index, 8 ->> [Subscriber] Received ('demo/example/zenoh-pico-pub': '[ 9] Pub from Pico!') - with attachment: - 0: source, C - 1: index, 9''' + 1: index, 4''' print("Start subscriber") # Start z_sub in the background - z_sub_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_sub_attachment -n 10" + z_sub_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_sub_attachment -n 5" z_sub_process = subprocess.Popen( z_sub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True @@ -88,7 +63,7 @@ def pub_and_sub(): print("Start publisher") # Start z_pub - z_pub_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_pub_attachment -n 10" + z_pub_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_pub_attachment -n 5" z_pub_process = subprocess.Popen( z_pub_command, shell=True, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE, text=True ) @@ -147,11 +122,118 @@ def pub_and_sub(): return test_status +def query_and_queryable(): + print("*** Query & queryable test ***") + test_status = 0 + + # Expected z_query output & status + + z_query_expected_status = 0 + z_query_expected_output = """Opening session... +Sending Query 'demo/example/**'... +>> Received ('demo/example/**': 'Queryable from Pico!') + with attachment: + 0: reply_key, reply_value +>> Received query final notification""" + + # Expected z_queryable output & status + z_queryable_expected_status = 0 + z_queryable_expected_output = """Opening session... +Creating Queryable on 'demo/example/zenoh-pico-queryable'... +Press CTRL-C to quit... + >> [Queryable handler] Received Query 'demo/example/**' + with attachment: + 0: test_key, test_value""" + + print("Start queryable") + # Start z_queryable in the background + z_queryable_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_queryable_attachment -n 1" + z_queryable_process = subprocess.Popen( + z_queryable_command, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + + # Introduce a delay to ensure z_queryable starts + time.sleep(2) + + print("Start query") + # Start z_query + z_query_command = f"stdbuf -oL -eL ./{DIR_EXAMPLES}/z_get_attachment" + z_query_process = subprocess.Popen( + z_query_command, + shell=True, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + text=True, + ) + + # Wait for z_query to finish + z_query_process.wait() + + print("Stop queryable") + time.sleep(2) + if z_queryable_process.poll() is None: + # send SIGINT to group + z_quaryable_process_gid = os.getpgid(z_queryable_process.pid) + os.killpg(z_quaryable_process_gid, SIGINT) + + # Wait for z_queryable to finish + z_queryable_process.wait() + + print("Check query status & output") + # Check the exit status of z_query + z_query_status = z_query_process.returncode + if z_query_status == z_query_expected_status: + print("z_query status valid") + else: + print(f"z_query status invalid, expected: {z_query_expected_status}," f" received: {z_query_status}") + test_status = 1 + + # Check output of z_query + z_query_output = z_query_process.stdout.read() + if z_query_expected_output in z_query_output: + print("z_query output valid") + else: + print("z_query output invalid:") + print(f'Expected: "{z_query_expected_output}"') + print(f'Received: "{z_query_output}"') + test_status = 1 + + print("Check queryable status & output") + # Check the exit status of z_queryable + z_queryable_status = z_queryable_process.returncode + if z_queryable_status == z_queryable_expected_status: + print("z_queryable status valid") + else: + print(f"z_queryable status invalid, expected: {z_queryable_expected_status}," f" received: {z_queryable_status}") + test_status = 1 + + # Check output of z_queryable + z_queryable_output = z_queryable_process.stdout.read() + if z_queryable_expected_output in z_queryable_output: + print("z_queryable output valid") + else: + print("z_queryable output invalid:") + print(f'Expected: "{z_queryable_expected_output}"') + print(f'Received: "{z_queryable_output}"') + test_status = 1 + # Return status + return test_status + + if __name__ == "__main__": EXIT_STATUS = 0 # Test pub and sub examples if pub_and_sub() == 1: EXIT_STATUS = 1 + # Test query and queryable examples + if query_and_queryable() == 1: + EXIT_STATUS = 1 # Exit sys.exit(EXIT_STATUS) From dbd71b66c5336c63b3448f229d8aa7b5997300b6 Mon Sep 17 00:00:00 2001 From: Jean-Roland Date: Mon, 17 Jun 2024 11:36:11 +0200 Subject: [PATCH 14/14] fix: rename kv_pairs_length --- examples/unix/c11/z_get_attachment.c | 4 ++-- examples/unix/c11/z_pub_attachment.c | 5 +++-- examples/unix/c11/z_queryable_attachment.c | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/examples/unix/c11/z_get_attachment.c b/examples/unix/c11/z_get_attachment.c index da158e7f9..ca549a9e1 100644 --- a/examples/unix/c11/z_get_attachment.c +++ b/examples/unix/c11/z_get_attachment.c @@ -46,7 +46,7 @@ typedef struct kv_pairs_rx_t { static z_condvar_t cond; static z_mutex_t mutex; -size_t kv_pairs_length(kv_pairs_tx_t *kvp) { +size_t kv_pairs_size(kv_pairs_tx_t *kvp) { size_t ret = 0; for (size_t i = 0; i < kvp->len; i++) { // Size fields @@ -219,7 +219,7 @@ int main(int argc, char **argv) { kvs[0] = (kv_pair_t){.key = "test_key", .value = "test_value"}; kv_pairs_tx_t ctx = (kv_pairs_tx_t){.data = kvs, .current_idx = 0, .len = 1}; z_owned_bytes_t attachment; - zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&ctx, kv_pairs_length(&ctx)); + zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&ctx, kv_pairs_size(&ctx)); opts.attachment = z_move(attachment); z_owned_closure_reply_t callback; diff --git a/examples/unix/c11/z_pub_attachment.c b/examples/unix/c11/z_pub_attachment.c index 50bc1c106..4f7f30168 100644 --- a/examples/unix/c11/z_pub_attachment.c +++ b/examples/unix/c11/z_pub_attachment.c @@ -35,7 +35,8 @@ typedef struct kv_pairs_t { #if Z_FEATURE_PUBLICATION == 1 -size_t kv_pairs_length(kv_pairs_t *kvp) { +// Return the total serialized size of the key value pairs +size_t kv_pairs_size(kv_pairs_t *kvp) { size_t ret = 0; for (size_t i = 0; i < kvp->len; i++) { // Size fields @@ -162,7 +163,7 @@ int main(int argc, char **argv) { sprintf(buf_ind, "%d", idx); kvs[1] = (kv_pair_t){.key = "index", .value = buf_ind}; kv_pairs_t ctx = (kv_pairs_t){.data = kvs, .current_idx = 0, .len = 2}; - zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&ctx, kv_pairs_length(&ctx)); + zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&ctx, kv_pairs_size(&ctx)); options.attachment = z_move(attachment); sprintf(buf, "[%4d] %s", idx, value); diff --git a/examples/unix/c11/z_queryable_attachment.c b/examples/unix/c11/z_queryable_attachment.c index d6b41fac2..6c6ecc1ef 100644 --- a/examples/unix/c11/z_queryable_attachment.c +++ b/examples/unix/c11/z_queryable_attachment.c @@ -47,7 +47,7 @@ const char *keyexpr = "demo/example/zenoh-pico-queryable"; const char *value = "Queryable from Pico!"; static int msg_nb = 0; -size_t kv_pairs_length(kv_pairs_tx_t *kvp) { +size_t kv_pairs_size(kv_pairs_tx_t *kvp) { size_t ret = 0; for (size_t i = 0; i < kvp->len; i++) { // Size fields @@ -141,7 +141,7 @@ void query_handler(const z_loaned_query_t *query, void *ctx) { kvs[0] = (kv_pair_t){.key = "reply_key", .value = "reply_value"}; kv_pairs_tx_t kv_ctx = (kv_pairs_tx_t){.data = kvs, .current_idx = 0, .len = 1}; z_owned_bytes_t attachment; - zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&kv_ctx, kv_pairs_length(&kv_ctx)); + zp_bytes_encode_from_iter(&attachment, create_attachment_iter, (void *)&kv_ctx, kv_pairs_size(&kv_ctx)); options.attachment = z_move(attachment); z_query_reply(query, z_query_keyexpr(query), z_move(reply_payload), &options);