blob: 2cc193ab45580fa6a66600642f0c555e1f7ad2ed [file] [log] [blame]
Michal Vasko7bcb48e2016-01-15 10:28:54 +01001/**
Michal Vasko95ea9ff2021-11-09 12:29:14 +01002 * @file messages_server.c
3 * @author Michal Vasko <mvasko@cesnet.cz>
4 * @brief libnetconf2 - server NETCONF messages functions
Michal Vasko7bcb48e2016-01-15 10:28:54 +01005 *
Michal Vasko95ea9ff2021-11-09 12:29:14 +01006 * @copyright
Michal Vasko7bcb48e2016-01-15 10:28:54 +01007 * Copyright (c) 2015 CESNET, z.s.p.o.
8 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +01009 * This source code is licensed under BSD 3-Clause License (the "License").
10 * You may not use this file except in compliance with the License.
11 * You may obtain a copy of the License at
Michal Vaskoafd416b2016-02-25 14:51:46 +010012 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +010013 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko7bcb48e2016-01-15 10:28:54 +010014 */
15
Michal Vaskoba9f3582023-02-22 10:26:32 +010016#define _GNU_SOURCE /* pthread_rwlock_t, strdup */
17
Michal Vasko7bcb48e2016-01-15 10:28:54 +010018#include <ctype.h>
Michal Vaskob83a3fa2021-05-26 09:53:42 +020019#include <inttypes.h>
20#include <stdarg.h>
Michal Vasko7bcb48e2016-01-15 10:28:54 +010021#include <stdlib.h>
22#include <string.h>
Michal Vasko7bcb48e2016-01-15 10:28:54 +010023
24#include <libyang/libyang.h>
25
Michal Vasko9e8ac262020-04-07 13:06:45 +020026#include "compat.h"
roman3f9b65c2023-06-05 14:26:58 +020027#include "config.h"
28#include "log_p.h"
29#include "messages_p.h"
30#include "messages_server.h"
31#include "netconf.h"
Michal Vasko1a38c862016-01-15 15:50:07 +010032
33extern struct nc_server_opts server_opts;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010034
35API struct nc_server_reply *
36nc_server_reply_ok(void)
37{
38 struct nc_server_reply *ret;
39
40 ret = malloc(sizeof *ret);
41 if (!ret) {
42 ERRMEM;
43 return NULL;
44 }
45
46 ret->type = NC_RPL_OK;
47 return ret;
48}
49
50API struct nc_server_reply *
Radek Krejci36dfdb32016-09-01 16:56:35 +020051nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtype)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010052{
53 struct nc_server_reply_data *ret;
54
roman40672412023-05-04 11:10:22 +020055 NC_CHECK_ARG_RET(NULL, data, NULL);
56
57 if (!(data->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
58 ERR(NULL, "nc_server_reply_data bad data");
Michal Vaskob08743b2016-04-13 14:23:49 +020059 return NULL;
60 }
61
Michal Vasko7bcb48e2016-01-15 10:28:54 +010062 ret = malloc(sizeof *ret);
63 if (!ret) {
64 ERRMEM;
65 return NULL;
66 }
67
68 ret->type = NC_RPL_DATA;
Radek Krejci36dfdb32016-09-01 16:56:35 +020069 ret->wd = wd;
Michal Vaskob08743b2016-04-13 14:23:49 +020070 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Michal Vasko77367452021-02-16 16:32:18 +010071 if (lyd_dup_single(data, NULL, LYD_DUP_RECURSIVE, &ret->data)) {
72 free(ret);
73 return NULL;
74 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +010075 } else {
76 ret->data = data;
77 }
78 if (paramtype != NC_PARAMTYPE_CONST) {
79 ret->free = 1;
80 } else {
81 ret->free = 0;
82 }
83 return (struct nc_server_reply *)ret;
84}
85
86API struct nc_server_reply *
Michal Vasko77367452021-02-16 16:32:18 +010087nc_server_reply_err(struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010088{
89 struct nc_server_reply_error *ret;
90
roman40672412023-05-04 11:10:22 +020091 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +010092
93 ret = malloc(sizeof *ret);
94 if (!ret) {
95 ERRMEM;
96 return NULL;
97 }
98
99 ret->type = NC_RPL_ERROR;
Michal Vasko77367452021-02-16 16:32:18 +0100100 ret->err = err;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100101 return (struct nc_server_reply *)ret;
102}
103
104API int
Michal Vasko77367452021-02-16 16:32:18 +0100105nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100106{
107 struct nc_server_reply_error *err_rpl;
108
roman40672412023-05-04 11:10:22 +0200109 NC_CHECK_ARG_RET(NULL, reply, err, -1);
110
111 if (reply->type != NC_RPL_ERROR) {
112 ERR(NULL, "nc_server_reply_add_err: bad reply type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100113 return -1;
114 }
115
116 err_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100117 lyd_insert_sibling(err_rpl->err, err, &err_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100118 return 0;
119}
120
Michal Vasko77367452021-02-16 16:32:18 +0100121API const struct lyd_node *
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100122nc_server_reply_get_last_err(const struct nc_server_reply *reply)
123{
124 struct nc_server_reply_error *err_rpl;
125
roman40672412023-05-04 11:10:22 +0200126 NC_CHECK_ARG_RET(NULL, reply, NULL);
127
128 if (reply->type != NC_RPL_ERROR) {
129 ERR(NULL, "nc_server_reply_get_last_err: bad reply type");
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100130 return NULL;
131 }
132
133 err_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100134 if (!err_rpl->err) {
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100135 return NULL;
136 }
Michal Vasko77367452021-02-16 16:32:18 +0100137 return err_rpl->err->prev;
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100138}
139
Michal Vasko77367452021-02-16 16:32:18 +0100140static const char *
141nc_err_tag2str(NC_ERR tag)
142{
143 switch (tag) {
144 case NC_ERR_IN_USE:
145 return "in-use";
146 case NC_ERR_INVALID_VALUE:
147 return "invalid-value";
148 case NC_ERR_ACCESS_DENIED:
149 return "access-denied";
150 case NC_ERR_ROLLBACK_FAILED:
151 return "rollback-failed";
152 case NC_ERR_OP_NOT_SUPPORTED:
153 return "operation-not-supported";
154 case NC_ERR_TOO_BIG:
155 return "too-big";
156 case NC_ERR_RES_DENIED:
157 return "resource-denied";
158 case NC_ERR_MISSING_ATTR:
159 return "missing-attribute";
160 case NC_ERR_BAD_ATTR:
161 return "bad-attribute";
162 case NC_ERR_UNKNOWN_ATTR:
163 return "unknown-attribute";
164 case NC_ERR_MISSING_ELEM:
165 return "missing-element";
166 case NC_ERR_BAD_ELEM:
167 return "bad-element";
168 case NC_ERR_UNKNOWN_ELEM:
169 return "unknown-element";
170 case NC_ERR_UNKNOWN_NS:
171 return "unknown-namespace";
172 case NC_ERR_LOCK_DENIED:
173 return "lock-denied";
174 case NC_ERR_DATA_EXISTS:
175 return "data-exists";
176 case NC_ERR_DATA_MISSING:
177 return "data-missing";
178 case NC_ERR_OP_FAILED:
179 return "operation-failed";
180 case NC_ERR_MALFORMED_MSG:
181 return "malformed-message";
182 default:
183 break;
184 }
185
186 return NULL;
187}
188
189static NC_ERR
190nc_err_str2tag(const char *str)
191{
192 if (!strcmp(str, "in-use")) {
193 return NC_ERR_IN_USE;
194 } else if (!strcmp(str, "invalid-value")) {
195 return NC_ERR_INVALID_VALUE;
196 } else if (!strcmp(str, "access-denied")) {
197 return NC_ERR_ACCESS_DENIED;
198 } else if (!strcmp(str, "rollback-failed")) {
199 return NC_ERR_ROLLBACK_FAILED;
200 } else if (!strcmp(str, "operation-not-supported")) {
201 return NC_ERR_OP_NOT_SUPPORTED;
202 } else if (!strcmp(str, "too-big")) {
203 return NC_ERR_TOO_BIG;
204 } else if (!strcmp(str, "resource-denied")) {
205 return NC_ERR_RES_DENIED;
206 } else if (!strcmp(str, "missing-attribute")) {
207 return NC_ERR_MISSING_ATTR;
208 } else if (!strcmp(str, "bad-attribute")) {
209 return NC_ERR_BAD_ATTR;
210 } else if (!strcmp(str, "unknown-attribute")) {
211 return NC_ERR_UNKNOWN_ATTR;
212 } else if (!strcmp(str, "missing-element")) {
213 return NC_ERR_MISSING_ELEM;
214 } else if (!strcmp(str, "bad-element")) {
215 return NC_ERR_BAD_ELEM;
216 } else if (!strcmp(str, "unknown-element")) {
217 return NC_ERR_UNKNOWN_ELEM;
218 } else if (!strcmp(str, "unknown-namespace")) {
219 return NC_ERR_UNKNOWN_NS;
220 } else if (!strcmp(str, "lock-denied")) {
221 return NC_ERR_LOCK_DENIED;
222 } else if (!strcmp(str, "data-exists")) {
223 return NC_ERR_DATA_EXISTS;
224 } else if (!strcmp(str, "data-missing")) {
225 return NC_ERR_DATA_MISSING;
226 } else if (!strcmp(str, "operation-failed")) {
227 return NC_ERR_OP_FAILED;
228 } else if (!strcmp(str, "malformed-message")) {
229 return NC_ERR_MALFORMED_MSG;
230 }
231
232 return 0;
233}
234
235static const char *
236nc_err_type2str(NC_ERR_TYPE type)
237{
238 switch (type) {
239 case NC_ERR_TYPE_TRAN:
240 return "transport";
241 case NC_ERR_TYPE_RPC:
242 return "rpc";
243 case NC_ERR_TYPE_PROT:
244 return "protocol";
245 case NC_ERR_TYPE_APP:
246 return "application";
247 default:
248 break;
249 }
250
251 return NULL;
252}
253
254static NC_ERR_TYPE
255nc_err_str2type(const char *str)
256{
257 if (!strcmp(str, "transport")) {
258 return NC_ERR_TYPE_TRAN;
259 } else if (!strcmp(str, "rpc")) {
260 return NC_ERR_TYPE_RPC;
261 } else if (!strcmp(str, "protocol")) {
262 return NC_ERR_TYPE_PROT;
263 } else if (!strcmp(str, "application")) {
264 return NC_ERR_TYPE_APP;
265 }
266
267 return 0;
268}
269
270API struct lyd_node *
271nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100272{
273 va_list ap;
Michal Vasko77367452021-02-16 16:32:18 +0100274 struct lyd_node *err = NULL;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100275 NC_ERR_TYPE type;
276 const char *arg1, *arg2;
277 uint32_t sid;
278
roman40672412023-05-04 11:10:22 +0200279 NC_CHECK_ARG_RET(NULL, tag, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100280
Michal Vasko77367452021-02-16 16:32:18 +0100281 /* rpc-error */
282 if (lyd_new_opaq2(NULL, ctx, "rpc-error", NULL, NULL, NC_NS_BASE, &err)) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100283 return NULL;
284 }
285
286 va_start(ap, tag);
287
Michal Vasko77367452021-02-16 16:32:18 +0100288 /* error-type */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100289 switch (tag) {
290 case NC_ERR_IN_USE:
291 case NC_ERR_INVALID_VALUE:
292 case NC_ERR_ACCESS_DENIED:
293 case NC_ERR_ROLLBACK_FAILED:
294 case NC_ERR_OP_NOT_SUPPORTED:
Radek Krejci127f8952016-10-12 14:57:16 +0200295 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko2f923d12016-04-05 11:33:02 +0200296 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200297 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100298 goto fail;
299 }
300 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100301 case NC_ERR_TOO_BIG:
302 case NC_ERR_RES_DENIED:
Michal Vasko77367452021-02-16 16:32:18 +0100303 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100304 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100305 case NC_ERR_MISSING_ATTR:
306 case NC_ERR_BAD_ATTR:
307 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko77367452021-02-16 16:32:18 +0100308 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100309 if (type == NC_ERR_TYPE_TRAN) {
roman40672412023-05-04 11:10:22 +0200310 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100311 goto fail;
312 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100313 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100314 case NC_ERR_MISSING_ELEM:
315 case NC_ERR_BAD_ELEM:
316 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko77367452021-02-16 16:32:18 +0100317 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100318 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200319 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100320 goto fail;
321 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100322 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100323 case NC_ERR_UNKNOWN_NS:
Michal Vasko77367452021-02-16 16:32:18 +0100324 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100325 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200326 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100327 goto fail;
328 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100329 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100330 case NC_ERR_LOCK_DENIED:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100331 type = NC_ERR_TYPE_PROT;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100332 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100333 case NC_ERR_DATA_EXISTS:
334 case NC_ERR_DATA_MISSING:
335 type = NC_ERR_TYPE_APP;
336 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100337 case NC_ERR_OP_FAILED:
Michal Vasko77367452021-02-16 16:32:18 +0100338 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100339 if (type == NC_ERR_TYPE_TRAN) {
roman40672412023-05-04 11:10:22 +0200340 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100341 goto fail;
342 }
343 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100344 case NC_ERR_MALFORMED_MSG:
345 type = NC_ERR_TYPE_RPC;
346 break;
Michal Vasko77367452021-02-16 16:32:18 +0100347 default:
roman40672412023-05-04 11:10:22 +0200348 ERRARG(NULL, "tag");
Michal Vasko77367452021-02-16 16:32:18 +0100349 goto fail;
350 }
351 if (lyd_new_opaq2(err, NULL, "error-type", nc_err_type2str(type), NULL, NC_NS_BASE, NULL)) {
352 goto fail;
353 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100354
Michal Vasko77367452021-02-16 16:32:18 +0100355 /* error-tag */
356 if (lyd_new_opaq2(err, NULL, "error-tag", nc_err_tag2str(tag), NULL, NC_NS_BASE, NULL)) {
357 goto fail;
358 }
359
360 /* error-severity */
361 if (lyd_new_opaq2(err, NULL, "error-severity", "error", NULL, NC_NS_BASE, NULL)) {
362 goto fail;
363 }
364
365 /* error-message */
366 switch (tag) {
367 case NC_ERR_IN_USE:
368 nc_err_set_msg(err, "The request requires a resource that already is in use.", "en");
369 break;
370 case NC_ERR_INVALID_VALUE:
371 nc_err_set_msg(err, "The request specifies an unacceptable value for one or more parameters.", "en");
372 break;
373 case NC_ERR_TOO_BIG:
374 nc_err_set_msg(err, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
375 break;
376 case NC_ERR_MISSING_ATTR:
377 nc_err_set_msg(err, "An expected attribute is missing.", "en");
378 break;
379 case NC_ERR_BAD_ATTR:
380 nc_err_set_msg(err, "An attribute value is not correct.", "en");
381 break;
382 case NC_ERR_UNKNOWN_ATTR:
383 nc_err_set_msg(err, "An unexpected attribute is present.", "en");
384 break;
385 case NC_ERR_MISSING_ELEM:
386 nc_err_set_msg(err, "An expected element is missing.", "en");
387 break;
388 case NC_ERR_BAD_ELEM:
389 nc_err_set_msg(err, "An element value is not correct.", "en");
390 break;
391 case NC_ERR_UNKNOWN_ELEM:
392 nc_err_set_msg(err, "An unexpected element is present.", "en");
393 break;
394 case NC_ERR_UNKNOWN_NS:
395 nc_err_set_msg(err, "An unexpected namespace is present.", "en");
396 break;
397 case NC_ERR_ACCESS_DENIED:
398 nc_err_set_msg(err, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
399 break;
400 case NC_ERR_LOCK_DENIED:
401 nc_err_set_msg(err, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
402 break;
403 case NC_ERR_RES_DENIED:
404 nc_err_set_msg(err, "Request could not be completed because of insufficient resources.", "en");
405 break;
406 case NC_ERR_ROLLBACK_FAILED:
407 nc_err_set_msg(err, "Request to roll back some configuration change was not completed for some reason.", "en");
408 break;
409 case NC_ERR_DATA_EXISTS:
410 nc_err_set_msg(err, "Request could not be completed because the relevant data model content already exists.", "en");
411 break;
412 case NC_ERR_DATA_MISSING:
413 nc_err_set_msg(err, "Request could not be completed because the relevant data model content does not exist.", "en");
414 break;
415 case NC_ERR_OP_NOT_SUPPORTED:
416 nc_err_set_msg(err, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
417 break;
418 case NC_ERR_OP_FAILED:
419 nc_err_set_msg(err, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
420 break;
421 case NC_ERR_MALFORMED_MSG:
422 nc_err_set_msg(err, "A message could not be handled because it failed to be parsed correctly.", "en");
423 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100424 default:
roman40672412023-05-04 11:10:22 +0200425 ERRARG(NULL, "tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100426 goto fail;
427 }
428
Michal Vasko77367452021-02-16 16:32:18 +0100429 /* error-info */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100430 switch (tag) {
431 case NC_ERR_IN_USE:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100432 case NC_ERR_INVALID_VALUE:
Michal Vasko77367452021-02-16 16:32:18 +0100433 case NC_ERR_ACCESS_DENIED:
434 case NC_ERR_ROLLBACK_FAILED:
435 case NC_ERR_OP_NOT_SUPPORTED:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100436 case NC_ERR_TOO_BIG:
Michal Vasko77367452021-02-16 16:32:18 +0100437 case NC_ERR_RES_DENIED:
438 case NC_ERR_DATA_EXISTS:
439 case NC_ERR_DATA_MISSING:
440 case NC_ERR_OP_FAILED:
441 case NC_ERR_MALFORMED_MSG:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100442 break;
443 case NC_ERR_MISSING_ATTR:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100444 case NC_ERR_BAD_ATTR:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100445 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko77367452021-02-16 16:32:18 +0100446 arg1 = va_arg(ap, const char *);
447 arg2 = va_arg(ap, const char *);
448
449 nc_err_add_bad_attr(err, arg1);
450 nc_err_add_bad_elem(err, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100451 break;
452 case NC_ERR_MISSING_ELEM:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100453 case NC_ERR_BAD_ELEM:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100454 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko77367452021-02-16 16:32:18 +0100455 arg1 = va_arg(ap, const char *);
456
457 nc_err_add_bad_elem(err, arg1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100458 break;
459 case NC_ERR_UNKNOWN_NS:
Michal Vasko77367452021-02-16 16:32:18 +0100460 arg1 = va_arg(ap, const char *);
461 arg2 = va_arg(ap, const char *);
462
463 nc_err_add_bad_elem(err, arg1);
464 nc_err_add_bad_ns(err, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100465 break;
466 case NC_ERR_LOCK_DENIED:
Michal Vasko77367452021-02-16 16:32:18 +0100467 sid = va_arg(ap, uint32_t);
468
469 nc_err_set_sid(err, sid);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100470 break;
471 default:
roman40672412023-05-04 11:10:22 +0200472 ERRARG(NULL, "tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100473 goto fail;
474 }
475
476 va_end(ap);
Michal Vasko77367452021-02-16 16:32:18 +0100477 return err;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100478
479fail:
Michal Vasko11d142a2016-01-19 15:58:24 +0100480 va_end(ap);
Michal Vasko77367452021-02-16 16:32:18 +0100481 lyd_free_siblings(err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100482 return NULL;
483}
484
Michal Vasko8f3198f2016-05-04 10:45:28 +0200485API NC_ERR_TYPE
Michal Vasko77367452021-02-16 16:32:18 +0100486nc_err_get_type(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200487{
Michal Vasko77367452021-02-16 16:32:18 +0100488 struct lyd_node *match;
489
roman40672412023-05-04 11:10:22 +0200490 NC_CHECK_ARG_RET(NULL, err, 0);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200491
Michal Vasko77367452021-02-16 16:32:18 +0100492 lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match);
493 if (match) {
494 return nc_err_str2type(((struct lyd_node_opaq *)match)->value);
495 }
496
497 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200498}
499
500API NC_ERR
Michal Vasko77367452021-02-16 16:32:18 +0100501nc_err_get_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200502{
Michal Vasko77367452021-02-16 16:32:18 +0100503 struct lyd_node *match;
504
roman40672412023-05-04 11:10:22 +0200505 NC_CHECK_ARG_RET(NULL, err, 0);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200506
Michal Vasko77367452021-02-16 16:32:18 +0100507 lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match);
508 if (match) {
509 return nc_err_str2tag(((struct lyd_node_opaq *)match)->value);
510 }
511
512 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200513}
514
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100515API int
Michal Vasko77367452021-02-16 16:32:18 +0100516nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100517{
Michal Vasko77367452021-02-16 16:32:18 +0100518 struct lyd_node *match;
519
roman40672412023-05-04 11:10:22 +0200520 NC_CHECK_ARG_RET(NULL, err, error_app_tag, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100521
Michal Vasko77367452021-02-16 16:32:18 +0100522 /* remove previous node */
523 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
524 if (match) {
525 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100526 }
Michal Vasko77367452021-02-16 16:32:18 +0100527
528 if (lyd_new_opaq2(err, NULL, "error-app-tag", error_app_tag, NULL, NC_NS_BASE, NULL)) {
529 return -1;
530 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100531
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100532 return 0;
533}
534
Michal Vasko8f3198f2016-05-04 10:45:28 +0200535API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100536nc_err_get_app_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200537{
Michal Vasko77367452021-02-16 16:32:18 +0100538 struct lyd_node *match;
539
roman40672412023-05-04 11:10:22 +0200540 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200541
Michal Vasko77367452021-02-16 16:32:18 +0100542 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
543 if (match) {
544 return ((struct lyd_node_opaq *)match)->value;
545 }
546
547 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200548}
549
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100550API int
Michal Vasko77367452021-02-16 16:32:18 +0100551nc_err_set_path(struct lyd_node *err, const char *error_path)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100552{
Michal Vasko77367452021-02-16 16:32:18 +0100553 struct lyd_node *match;
554
roman40672412023-05-04 11:10:22 +0200555 NC_CHECK_ARG_RET(NULL, err, error_path, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100556
Michal Vasko77367452021-02-16 16:32:18 +0100557 /* remove previous node */
558 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
559 if (match) {
560 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100561 }
Michal Vasko77367452021-02-16 16:32:18 +0100562
563 if (lyd_new_opaq2(err, NULL, "error-path", error_path, NULL, NC_NS_BASE, NULL)) {
564 return -1;
565 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100566
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100567 return 0;
568}
569
Michal Vasko8f3198f2016-05-04 10:45:28 +0200570API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100571nc_err_get_path(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200572{
Michal Vasko77367452021-02-16 16:32:18 +0100573 struct lyd_node *match;
574
roman40672412023-05-04 11:10:22 +0200575 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200576
Michal Vasko77367452021-02-16 16:32:18 +0100577 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
578 if (match) {
579 return ((struct lyd_node_opaq *)match)->value;
580 }
581
582 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200583}
584
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100585API int
Michal Vasko77367452021-02-16 16:32:18 +0100586nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100587{
Michal Vasko77367452021-02-16 16:32:18 +0100588 struct lyd_node *match;
589 struct lyd_attr *attr;
590
roman40672412023-05-04 11:10:22 +0200591 NC_CHECK_ARG_RET(NULL, err, error_message, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100592
Michal Vasko77367452021-02-16 16:32:18 +0100593 /* remove previous message */
594 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
595 if (match) {
596 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100597 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100598
Michal Vasko77367452021-02-16 16:32:18 +0100599 if (lyd_new_opaq2(err, NULL, "error-message", error_message, NULL, NC_NS_BASE, &match)) {
600 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100601 }
Michal Vasko77367452021-02-16 16:32:18 +0100602 if (lang && lyd_new_attr(match, NULL, "xml:lang", lang, &attr)) {
603 lyd_free_tree(match);
604 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100605 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100606
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100607 return 0;
608}
609
Michal Vasko8f3198f2016-05-04 10:45:28 +0200610API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100611nc_err_get_msg(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200612{
Michal Vasko77367452021-02-16 16:32:18 +0100613 struct lyd_node *match;
614
roman40672412023-05-04 11:10:22 +0200615 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200616
Michal Vasko77367452021-02-16 16:32:18 +0100617 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
618 if (match) {
619 return ((struct lyd_node_opaq *)match)->value;
620 }
621
622 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200623}
624
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100625API int
Michal Vasko77367452021-02-16 16:32:18 +0100626nc_err_set_sid(struct lyd_node *err, uint32_t session_id)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100627{
Michal Vasko77367452021-02-16 16:32:18 +0100628 struct lyd_node *match, *info;
629 char buf[22];
630
roman40672412023-05-04 11:10:22 +0200631 NC_CHECK_ARG_RET(NULL, err, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100632
Michal Vasko77367452021-02-16 16:32:18 +0100633 /* find error-info */
634 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
635 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
636 return -1;
637 }
638
639 /* remove previous node */
640 lyd_find_sibling_opaq_next(lyd_child(info), "session-id", &match);
641 if (match) {
642 lyd_free_tree(match);
643 }
644
645 sprintf(buf, "%" PRIu32, session_id);
646 if (lyd_new_opaq2(info, NULL, "session-id", buf, NULL, NC_NS_BASE, NULL)) {
647 return -1;
648 }
649
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100650 return 0;
651}
652
653API int
Michal Vasko77367452021-02-16 16:32:18 +0100654nc_err_add_bad_attr(struct lyd_node *err, const char *attr_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100655{
Michal Vasko77367452021-02-16 16:32:18 +0100656 struct lyd_node *info;
657
roman40672412023-05-04 11:10:22 +0200658 NC_CHECK_ARG_RET(NULL, err, attr_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100659
Michal Vasko77367452021-02-16 16:32:18 +0100660 /* find error-info */
661 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
662 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100663 return -1;
664 }
Michal Vasko77367452021-02-16 16:32:18 +0100665
666 if (lyd_new_opaq2(info, NULL, "bad-attribute", attr_name, NULL, NC_NS_BASE, NULL)) {
667 return -1;
668 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100669
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100670 return 0;
671}
672
673API int
Michal Vasko77367452021-02-16 16:32:18 +0100674nc_err_add_bad_elem(struct lyd_node *err, const char *elem_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100675{
Michal Vasko77367452021-02-16 16:32:18 +0100676 struct lyd_node *info;
677
roman40672412023-05-04 11:10:22 +0200678 NC_CHECK_ARG_RET(NULL, err, elem_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100679
Michal Vasko77367452021-02-16 16:32:18 +0100680 /* find error-info */
681 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
682 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100683 return -1;
684 }
Michal Vasko77367452021-02-16 16:32:18 +0100685
686 if (lyd_new_opaq2(info, NULL, "bad-element", elem_name, NULL, NC_NS_BASE, NULL)) {
687 return -1;
688 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100689
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100690 return 0;
691}
692
693API int
Michal Vasko77367452021-02-16 16:32:18 +0100694nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100695{
Michal Vasko77367452021-02-16 16:32:18 +0100696 struct lyd_node *info;
697
roman40672412023-05-04 11:10:22 +0200698 NC_CHECK_ARG_RET(NULL, err, ns_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100699
Michal Vasko77367452021-02-16 16:32:18 +0100700 /* find error-info */
701 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
702 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100703 return -1;
704 }
Michal Vasko77367452021-02-16 16:32:18 +0100705
706 if (lyd_new_opaq2(info, NULL, "bad-namespace", ns_name, NULL, NC_NS_BASE, NULL)) {
707 return -1;
708 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100709
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100710 return 0;
711}
712
713API int
Michal Vasko77367452021-02-16 16:32:18 +0100714nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100715{
Michal Vasko77367452021-02-16 16:32:18 +0100716 struct lyd_node *info;
717
roman40672412023-05-04 11:10:22 +0200718 NC_CHECK_ARG_RET(NULL, err, other, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100719
Michal Vasko77367452021-02-16 16:32:18 +0100720 /* find error-info */
721 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
722 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100723 return -1;
724 }
Michal Vasko77367452021-02-16 16:32:18 +0100725
726 lyd_insert_child(info, other);
727
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100728 return 0;
729}
730
731void
Michal Vasko77367452021-02-16 16:32:18 +0100732nc_server_rpc_free(struct nc_server_rpc *rpc)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100733{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100734 if (!rpc) {
735 return;
736 }
737
Michal Vasko77367452021-02-16 16:32:18 +0100738 lyd_free_tree(rpc->envp);
Michal Vaskod5bfc482021-10-26 10:47:54 +0200739
740 /* may be action */
741 lyd_free_all(rpc->rpc);
Michal Vasko11d142a2016-01-19 15:58:24 +0100742
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100743 free(rpc);
744}
745
746API void
747nc_server_reply_free(struct nc_server_reply *reply)
748{
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100749 struct nc_server_reply_data *data_rpl;
750 struct nc_server_reply_error *error_rpl;
751
752 if (!reply) {
753 return;
754 }
755
756 switch (reply->type) {
757 case NC_RPL_DATA:
758 data_rpl = (struct nc_server_reply_data *)reply;
759 if (data_rpl->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100760 lyd_free_siblings(data_rpl->data);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100761 }
762 break;
763 case NC_RPL_OK:
764 /* nothing to free */
765 break;
766 case NC_RPL_ERROR:
767 error_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100768 lyd_free_siblings(error_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100769 break;
770 default:
771 break;
772 }
773 free(reply);
774}
775
Radek Krejci93e80222016-10-03 13:34:25 +0200776API struct nc_server_notif *
Michal Vasko77367452021-02-16 16:32:18 +0100777nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype)
Radek Krejci93e80222016-10-03 13:34:25 +0200778{
779 struct nc_server_notif *ntf;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100780 struct lyd_node *elem;
Michal Vasko77367452021-02-16 16:32:18 +0100781 int found;
Radek Krejci93e80222016-10-03 13:34:25 +0200782
roman40672412023-05-04 11:10:22 +0200783 NC_CHECK_ARG_RET(NULL, event, eventtime, NULL);
Radek Krejci93e80222016-10-03 13:34:25 +0200784
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100785 /* check that there is a notification */
Michal Vasko77367452021-02-16 16:32:18 +0100786 found = 0;
787 LYD_TREE_DFS_BEGIN(event, elem) {
788 if (elem->schema->nodetype == LYS_NOTIF) {
789 found = 1;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100790 break;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100791 }
Michal Vasko77367452021-02-16 16:32:18 +0100792 LYD_TREE_DFS_END(event, elem);
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100793 }
Michal Vasko77367452021-02-16 16:32:18 +0100794 if (!found) {
roman40672412023-05-04 11:10:22 +0200795 ERRARG(NULL, "event");
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100796 return NULL;
797 }
798
Radek Krejci93e80222016-10-03 13:34:25 +0200799 ntf = malloc(sizeof *ntf);
Michal Vasko25e244b2022-12-14 14:19:59 +0100800 if (!ntf) {
801 ERRMEM;
802 return NULL;
803 }
804
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100805 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Radek Krejci93e80222016-10-03 13:34:25 +0200806 ntf->eventtime = strdup(eventtime);
Michal Vasko77367452021-02-16 16:32:18 +0100807 if (lyd_dup_single(event, NULL, LYD_DUP_RECURSIVE, &ntf->ntf)) {
808 free(ntf);
809 return NULL;
810 }
Radek Krejci93e80222016-10-03 13:34:25 +0200811 } else {
812 ntf->eventtime = eventtime;
Michal Vasko77367452021-02-16 16:32:18 +0100813 ntf->ntf = event;
Radek Krejci93e80222016-10-03 13:34:25 +0200814 }
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100815 ntf->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
Radek Krejci93e80222016-10-03 13:34:25 +0200816
817 return ntf;
818}
819
820API void
821nc_server_notif_free(struct nc_server_notif *notif)
822{
823 if (!notif) {
824 return;
825 }
826
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100827 if (notif->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100828 lyd_free_tree(notif->ntf);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100829 free(notif->eventtime);
830 }
Radek Krejci93e80222016-10-03 13:34:25 +0200831 free(notif);
832}
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100833
834API const char *
835nc_server_notif_get_time(const struct nc_server_notif *notif)
836{
roman40672412023-05-04 11:10:22 +0200837 NC_CHECK_ARG_RET(NULL, notif, NULL);
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100838
839 return notif->eventtime;
840}