Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,13 @@ set (CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR})
# set version of the project
set(LIBYANG_MAJOR_VERSION 6)
set(LIBYANG_MINOR_VERSION 4)
set(LIBYANG_MICRO_VERSION 25)
set(LIBYANG_MICRO_VERSION 26)
set(LIBYANG_VERSION ${LIBYANG_MAJOR_VERSION}.${LIBYANG_MINOR_VERSION}.${LIBYANG_MICRO_VERSION})

# set version of the library
set(LIBYANG_MAJOR_SOVERSION 5)
set(LIBYANG_MINOR_SOVERSION 12)
set(LIBYANG_MICRO_SOVERSION 1)
set(LIBYANG_MINOR_SOVERSION 13)
set(LIBYANG_MICRO_SOVERSION 0)
set(LIBYANG_SOVERSION_FULL ${LIBYANG_MAJOR_SOVERSION}.${LIBYANG_MINOR_SOVERSION}.${LIBYANG_MICRO_SOVERSION})
set(LIBYANG_SOVERSION ${LIBYANG_MAJOR_SOVERSION})

Expand Down
2 changes: 2 additions & 0 deletions src/json.c
Original file line number Diff line number Diff line change
Expand Up @@ -1067,6 +1067,7 @@ lyjson_ctx_backup(struct lyjson_ctx *jsonctx)
jsonctx->backup.value = jsonctx->value;
jsonctx->backup.value_len = jsonctx->value_len;
jsonctx->backup.input = jsonctx->in->current;
jsonctx->backup.line = jsonctx->in->line;
jsonctx->backup.dynamic = jsonctx->dynamic;
jsonctx->dynamic = 0;
}
Expand All @@ -1082,6 +1083,7 @@ lyjson_ctx_restore(struct lyjson_ctx *jsonctx)
jsonctx->value = jsonctx->backup.value;
jsonctx->value_len = jsonctx->backup.value_len;
jsonctx->in->current = jsonctx->backup.input;
jsonctx->in->line = jsonctx->backup.line;
jsonctx->dynamic = jsonctx->backup.dynamic;
jsonctx->backup.dynamic = 0;
}
Expand Down
1 change: 1 addition & 0 deletions src/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ struct lyjson_ctx {
uint32_t value_len;
ly_bool dynamic;
const char *input;
uint64_t line;
} backup;
};

Expand Down
96 changes: 77 additions & 19 deletions src/parser_cbor.c
Original file line number Diff line number Diff line change
Expand Up @@ -1213,7 +1213,7 @@ lydcbor_parse_any(struct lyd_cbor_ctx *lydctx, const struct lysc_node *snode, st
if (lydctx->parse_opts & LYD_PARSE_ANYDATA_STRICT) {
/* explicit strict data parsing */
lydctx->parse_opts |= LYD_PARSE_STRICT;
} else if ((lydctx->int_opts & LYD_INTOPT_ENVELOPE) && !(lydctx->int_opts & LYD_INTOPT_ANY)) {
} else if ((lydctx->int_opts & LYD_INTOPT_YP_ENVELOPE) && !(lydctx->int_opts & LYD_INTOPT_ANY)) {
/* the notification in the envelope contents, parsed as data like any other notification */
} else {
/* make the parser process data as opaq nodes */
Expand Down Expand Up @@ -1752,29 +1752,28 @@ lyd_parse_cbor(const struct ly_ctx *ctx, const struct lysc_ext_instance *ext, st
return rc;
}

LY_ERR
lyd_parse_cbor_restconf(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
struct lyd_node **first_p, struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p)
/**
* @brief Parse the RESTCONF notification envelope with eventTime.
*
* @param[in] ctx libyang context.
* @param[in] root Root CBOR map of the input.
* @param[out] envp Parsed envelope with eventTime, may be returned possibly even on an error.
* @param[out] notif CBOR map with the notification.
* @return LY_ERR value.
*/
static LY_ERR
lydcbor_env_restconf_notif(const struct ly_ctx *ctx, const cbor_item_t *root, struct lyd_node **envp,
const cbor_item_t **notif)
{
LY_ERR r, rc = LY_SUCCESS;
struct lyd_cbor_ctx *lydctx = NULL;
const cbor_item_t *root, *notif, *event_time = NULL;
LY_ERR rc = LY_SUCCESS;
const cbor_item_t *event_time = NULL;
struct cbor_pair *pairs;
struct lyd_node *node;
char *str = NULL;
size_t str_len;
uint32_t i;

assert(ctx && in && first_p && envp && lydctx_p);

*envp = NULL;

rc = lyd_parse_cbor_init(ctx, in, parse_opts, val_opts, &lydctx);
LY_CHECK_GOTO(rc, cleanup);
lydctx->int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_NOTIF | LYD_INTOPT_EVENTTIME;

/* parse "notification" */
root = lydctx->cborctx->cbor_data;
pairs = cbor_map_handle(root);
if ((cbor_map_size(root) != 1) || !cbor_isa_string(pairs[0].key)) {
LOGVAL(ctx, NULL, LYVE_DATA, "Expected a single CBOR map member \"ietf-restconf:notification\".");
Expand All @@ -1793,15 +1792,15 @@ lyd_parse_cbor_restconf(const struct ly_ctx *ctx, struct ly_in *in, uint32_t par
rc = LY_EVALID;
goto cleanup;
}
notif = pairs[0].value;
*notif = pairs[0].value;

rc = lyd_create_opaq(ctx, "notification", 12, "ietf-restconf", 13, "ietf-restconf", 13, NULL, 0, NULL,
LY_VALUE_CBOR, NULL, LYD_VALHINT_STRING, envp);
LY_CHECK_GOTO(rc, cleanup);

/* find eventTime, it can be anywhere in the map */
pairs = cbor_map_handle(notif);
for (i = 0; i < cbor_map_size(notif); ++i) {
pairs = cbor_map_handle(*notif);
for (i = 0; i < cbor_map_size(*notif); ++i) {
if (!cbor_isa_string(pairs[i].key)) {
continue;
}
Expand Down Expand Up @@ -1839,10 +1838,69 @@ lyd_parse_cbor_restconf(const struct ly_ctx *ctx, struct ly_in *in, uint32_t par
lyd_insert_child(*envp, node);
LY_CHECK_GOTO(rc = lyd_parser_notif_eventtime_validate(node), cleanup);

cleanup:
free(str);
return rc;
}

LY_ERR
lyd_parse_cbor_restconf(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
enum lyd_type data_type, struct lyd_node **first_p, struct lyd_node **envp, struct ly_set *parsed,
struct lyd_ctx **lydctx_p)
{
LY_ERR r, rc = LY_SUCCESS;
struct lyd_cbor_ctx *lydctx = NULL;
const cbor_item_t *root, *notif;
struct cbor_pair *pairs;
char *str = NULL;
size_t str_len;
ly_bool yp_envelope = 0;

assert(ctx && in && first_p && envp && lydctx_p);
assert((data_type == LYD_TYPE_NOTIF_RESTCONF) || (data_type == LYD_TYPE_NOTIF_ENVELOPE) ||
(data_type == LYD_TYPE_NOTIF_AUTO));

rc = lyd_parse_cbor_init(ctx, in, parse_opts, val_opts, &lydctx);
LY_CHECK_GOTO(rc, cleanup);
root = lydctx->cborctx->cbor_data;

if (data_type == LYD_TYPE_NOTIF_ENVELOPE) {
yp_envelope = 1;
} else if (data_type == LYD_TYPE_NOTIF_AUTO) {
/* peek at the name of the first member */
pairs = cbor_map_handle(root);
if (cbor_map_size(root) && pairs && cbor_isa_string(pairs[0].key)) {
LY_CHECK_GOTO(rc = lydcbor_item_to_string(ctx, pairs[0].key, &str, &str_len), cleanup);
yp_envelope = !ly_strncmp("ietf-yp-notification:envelope", str, str_len);
if (!yp_envelope && ly_strncmp("ietf-restconf:notification", str, str_len)) {
LOGVAL(ctx, NULL, LYVE_DATA, "Unexpected object \"%.*s\" instead of \"ietf-restconf:notification\" "
"or \"ietf-yp-notification:envelope\".", (int)str_len, str);
rc = LY_EVALID;
goto cleanup;
}
}
}

if (yp_envelope) {
/* YANG-Push notification envelope */
LY_CHECK_GOTO(rc = lyd_parser_yp_envelope_check(ctx), cleanup);
lydctx->int_opts = LYD_INTOPT_NOTIF | LYD_INTOPT_NO_SIBLINGS | LYD_INTOPT_YP_ENVELOPE;
notif = root;
} else {
/* RESTCONF notification envelope */
lydctx->int_opts = LYD_INTOPT_WITH_SIBLINGS | LYD_INTOPT_NOTIF | LYD_INTOPT_EVENTTIME;
LY_CHECK_GOTO(rc = lydcbor_env_restconf_notif(ctx, root, envp, &notif), cleanup);
}

/* parse the notification */
r = lydcbor_subtree_r(lydctx, NULL, first_p, parsed, notif);
LY_DPARSER_ERR_GOTO(r, rc = r, lydctx, cleanup);

if ((lydctx->int_opts & LYD_INTOPT_NO_SIBLINGS) && *first_p && (*first_p)->next) {
LOGVAL(ctx, NULL, LYVE_SYNTAX, "Unexpected sibling node.");
rc = LY_EVALID;
goto cleanup;
}
if (!lydctx->op_node) {
LOGVAL(ctx, NULL, LYVE_DATA, "Missing the operation node.");
r = LY_EVALID;
Expand Down
15 changes: 13 additions & 2 deletions src/parser_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,17 @@ lyd_parser_notif_eventtime_validate(const struct lyd_node *node)
return LY_SUCCESS;
}

LY_ERR
lyd_parser_yp_envelope_check(const struct ly_ctx *ctx)
{
if (!ly_ctx_get_module_implemented(ctx, "ietf-yp-notification")) {
LOGERR(ctx, LY_EINVAL, "Module \"ietf-yp-notification\" is not implemented.");
return LY_EINVAL;
}

return LY_SUCCESS;
}

LY_ERR
lyd_parser_find_operation(const struct lyd_node *parent, uint32_t int_opts, struct lyd_node **op)
{
Expand Down Expand Up @@ -140,7 +151,7 @@ lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
LY_ERR rc = LY_SUCCESS;

if (lydctx->int_opts & LYD_INTOPT_ANY) {
if ((lydctx->int_opts & LYD_INTOPT_ENVELOPE) && (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
if ((lydctx->int_opts & LYD_INTOPT_YP_ENVELOPE) && (snode->nodetype & (LYS_RPC | LYS_ACTION | LYS_NOTIF))) {
/* only one notification and no RPC/action in the envelope */
if (snode->nodetype != LYS_NOTIF) {
goto error_node_inval;
Expand All @@ -154,7 +165,7 @@ lyd_parser_check_schema(struct lyd_ctx *lydctx, const struct lysc_node *snode)
goto cleanup;
}

if ((lydctx->int_opts & LYD_INTOPT_ENVELOPE) && !snode->parent && (strcmp(snode->name, "envelope") ||
if ((lydctx->int_opts & LYD_INTOPT_YP_ENVELOPE) && !snode->parent && (strcmp(snode->name, "envelope") ||
strcmp(snode->module->name, "ietf-yp-notification"))) {
/* the root must be the envelope */
goto error_node_inval;
Expand Down
16 changes: 14 additions & 2 deletions src/parser_data.h
Original file line number Diff line number Diff line change
Expand Up @@ -373,9 +373,12 @@ enum lyd_type {
LYD_TYPE_REPLY_RESTCONF, /**< message-body of a RESTCONF operation output parameters
([ref](https://www.rfc-editor.org/rfc/rfc8040.html#section-3.6.2)) */

LYD_TYPE_NOTIF_ENVELOPE /**< YANG-Push notification envelope, the 'envelope' structure of the
LYD_TYPE_NOTIF_ENVELOPE, /**< YANG-Push notification envelope, the 'envelope' structure of the
'ietf-yp-notification' module
([ref](https://datatracker.ietf.org/doc/draft-ietf-netconf-notif-envelope/)) */
LYD_TYPE_NOTIF_AUTO /**< notification in the YANG-Push envelope (::LYD_TYPE_NOTIF_ENVELOPE) or in the
NETCONF/RESTCONF one (::LYD_TYPE_NOTIF_NETCONF, ::LYD_TYPE_NOTIF_RESTCONF),
detected from the input */
};
/** @} datatype */

Expand Down Expand Up @@ -440,6 +443,14 @@ enum lyd_type {
* - @p op - must be provided, the notification data tree separated from the envelope 'contents' will be returned
* here, pointing to the operation;
*
* - ::LYD_TYPE_NOTIF_AUTO:
* - @p ctx - must have the 'ietf-yp-notification' module implemented to parse the YANG-Push envelope;
* - @p parent - must be NULL, the whole notification is expected;
* - @p format - can be ::LYD_XML, ::LYD_JSON, or ::LYD_CBOR;
* - @p tree - must be provided, see ::LYD_TYPE_NOTIF_ENVELOPE, ::LYD_TYPE_NOTIF_NETCONF, and
* ::LYD_TYPE_NOTIF_RESTCONF, only the YANG-Push envelope has a schema;
* - @p op - must be provided, the notification data tree itself will be returned here, pointing to the operation;
*
* - ::LYD_TYPE_RPC_YANG:
* - ::LYD_TYPE_NOTIF_YANG:
* - ::LYD_TYPE_REPLY_YANG:
Expand All @@ -458,7 +469,8 @@ enum lyd_type {
* @param[out] tree Optional full parsed data tree. If @p parent is set, set to NULL.
* @param[out] op Optional pointer to the operation (action/RPC/notification) node.
* @return LY_ERR value.
* @return LY_ENOT if @p data_type is a NETCONF message and the root XML element is not the expected one.
* @return LY_ENOT if @p data_type is a NETCONF message or ::LYD_TYPE_NOTIF_AUTO in XML and the root XML element is
* not the expected one.
*/
LIBYANG_API_DECL LY_ERR lyd_parse_op(const struct ly_ctx *ctx, struct lyd_node *parent, struct ly_in *in, LYD_FORMAT format,
enum lyd_type data_type, uint32_t parse_options, struct lyd_node **tree, struct lyd_node **op);
Expand Down
19 changes: 15 additions & 4 deletions src/parser_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ typedef void (*lyd_ctx_free_clb)(struct lyd_ctx *ctx);
#define LYD_INTOPT_SKIP_SIBLINGS 0x40 /**< Perform the validation task only for the specfic subtree, skip other siblings. */
#define LYD_INTOPT_NO_SIBLINGS 0x80 /**< If there are any siblings, return an error. */
#define LYD_INTOPT_EVENTTIME 0x0100 /**< Parse notification eventTime node. */
#define LYD_INTOPT_ENVELOPE 0x0200 /**< YANG-Push notification envelope is being parsed. */
#define LYD_INTOPT_YP_ENVELOPE 0x0200 /**< YANG-Push notification envelope is being parsed. */

/**
* @brief Internal (common) context for YANG data parsers.
Expand Down Expand Up @@ -288,7 +288,7 @@ LY_ERR lyd_parse_xml(const struct ly_ctx *ctx, struct lyd_node *parent, struct l
* @param[in] in Input structure.
* @param[in] parse_opts Options for parser, see @ref dataparseroptions.
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
* @param[in] data_type Expected NETCONF data type of the data.
* @param[in] data_type Expected NETCONF data type of the data, ::LYD_TYPE_NOTIF_ENVELOPE, or ::LYD_TYPE_NOTIF_AUTO.
* @param[out] envp Individual parsed envelopes tree, may be returned possibly even on an error.
* @param[out] parsed Set to add all the parsed siblings into.
* @param[out] lydctx_p Data parser context to finish validation.
Expand Down Expand Up @@ -326,7 +326,7 @@ LY_ERR lyd_parse_json(const struct ly_ctx *ctx, struct lyd_node *parent, const s
* @param[in] in Input structure.
* @param[in] parse_opts Options for parser, see @ref dataparseroptions.
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
* @param[in] data_type Expected RESTCONF data type of the data.
* @param[in] data_type Expected RESTCONF data type of the data, ::LYD_TYPE_NOTIF_ENVELOPE, or ::LYD_TYPE_NOTIF_AUTO.
* @param[out] envp Individual parsed envelopes tree, may be returned possibly even on an error.
* @param[out] parsed Set to add all the parsed siblings into.
* @param[out] lydctx_p Data parser context to finish validation.
Expand Down Expand Up @@ -383,14 +383,16 @@ LY_ERR lyd_parse_cbor(const struct ly_ctx *ctx, const struct lysc_ext_instance *
* @param[in] in Input structure.
* @param[in] parse_opts Options for parser, see @ref dataparseroptions.
* @param[in] val_opts Options for the validation phase, see @ref datavalidationoptions.
* @param[in] data_type Expected RESTCONF data type of the data, ::LYD_TYPE_NOTIF_ENVELOPE, or ::LYD_TYPE_NOTIF_AUTO.
* @param[in,out] first_p Pointer to the first top-level parsed node.
* @param[out] envp Parsed envelope with eventTime, may be returned possibly even on an error.
* @param[out] parsed Set to add all the parsed siblings into.
* @param[out] lydctx_p Data parser context to finish validation.
* @return LY_ERR value.
*/
LY_ERR lyd_parse_cbor_restconf(const struct ly_ctx *ctx, struct ly_in *in, uint32_t parse_opts, uint32_t val_opts,
struct lyd_node **first_p, struct lyd_node **envp, struct ly_set *parsed, struct lyd_ctx **lydctx_p);
enum lyd_type data_type, struct lyd_node **first_p, struct lyd_node **envp, struct ly_set *parsed,
struct lyd_ctx **lydctx_p);

/**
* @brief Validate eventTime date-and-time value.
Expand All @@ -401,6 +403,15 @@ LY_ERR lyd_parse_cbor_restconf(const struct ly_ctx *ctx, struct ly_in *in, uint3
*/
LY_ERR lyd_parser_notif_eventtime_validate(const struct lyd_node *node);

/**
* @brief Check that a YANG-Push notification envelope can be parsed.
*
* @param[in] ctx libyang context.
* @return LY_SUCCESS on success.
* @return LY_EINVAL if the 'ietf-yp-notification' module is not implemented.
*/
LY_ERR lyd_parser_yp_envelope_check(const struct ly_ctx *ctx);

/**
* @brief Search all the parents for an operation node, check validity based on internal parser flags.
*
Expand Down
Loading
Loading