blob: 078d041996e6f40028fbb5c39844c37fe2f850f8 [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"
Michal Vasko7bcb48e2016-01-15 10:28:54 +010027#include "libnetconf.h"
Radek Krejci93e80222016-10-03 13:34:25 +020028#include "session_server.h"
Michal Vasko1a38c862016-01-15 15:50:07 +010029
30extern struct nc_server_opts server_opts;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010031
32API struct nc_server_reply *
33nc_server_reply_ok(void)
34{
35 struct nc_server_reply *ret;
36
37 ret = malloc(sizeof *ret);
38 if (!ret) {
39 ERRMEM;
40 return NULL;
41 }
42
43 ret->type = NC_RPL_OK;
44 return ret;
45}
46
47API struct nc_server_reply *
Radek Krejci36dfdb32016-09-01 16:56:35 +020048nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtype)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010049{
50 struct nc_server_reply_data *ret;
51
Michal Vaskoed9457d2022-06-06 11:50:19 +020052 if (!data || !(data->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
Michal Vaskob08743b2016-04-13 14:23:49 +020053 ERRARG("data");
54 return NULL;
55 }
56
Michal Vasko7bcb48e2016-01-15 10:28:54 +010057 ret = malloc(sizeof *ret);
58 if (!ret) {
59 ERRMEM;
60 return NULL;
61 }
62
63 ret->type = NC_RPL_DATA;
Radek Krejci36dfdb32016-09-01 16:56:35 +020064 ret->wd = wd;
Michal Vaskob08743b2016-04-13 14:23:49 +020065 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Michal Vasko77367452021-02-16 16:32:18 +010066 if (lyd_dup_single(data, NULL, LYD_DUP_RECURSIVE, &ret->data)) {
67 free(ret);
68 return NULL;
69 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +010070 } else {
71 ret->data = data;
72 }
73 if (paramtype != NC_PARAMTYPE_CONST) {
74 ret->free = 1;
75 } else {
76 ret->free = 0;
77 }
78 return (struct nc_server_reply *)ret;
79}
80
81API struct nc_server_reply *
Michal Vasko77367452021-02-16 16:32:18 +010082nc_server_reply_err(struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010083{
84 struct nc_server_reply_error *ret;
85
Michal Vasko1a38c862016-01-15 15:50:07 +010086 if (!err) {
Michal Vasko45e53ae2016-04-07 11:46:03 +020087 ERRARG("err");
Michal Vasko7bcb48e2016-01-15 10:28:54 +010088 return NULL;
89 }
90
91 ret = malloc(sizeof *ret);
92 if (!ret) {
93 ERRMEM;
94 return NULL;
95 }
96
97 ret->type = NC_RPL_ERROR;
Michal Vasko77367452021-02-16 16:32:18 +010098 ret->err = err;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010099 return (struct nc_server_reply *)ret;
100}
101
102API int
Michal Vasko77367452021-02-16 16:32:18 +0100103nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100104{
105 struct nc_server_reply_error *err_rpl;
106
Michal Vasko45e53ae2016-04-07 11:46:03 +0200107 if (!reply || (reply->type != NC_RPL_ERROR)) {
108 ERRARG("reply");
109 return -1;
110 } else if (!err) {
111 ERRARG("err");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100112 return -1;
113 }
114
115 err_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100116 lyd_insert_sibling(err_rpl->err, err, &err_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100117 return 0;
118}
119
Michal Vasko77367452021-02-16 16:32:18 +0100120API const struct lyd_node *
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100121nc_server_reply_get_last_err(const struct nc_server_reply *reply)
122{
123 struct nc_server_reply_error *err_rpl;
124
125 if (!reply || (reply->type != NC_RPL_ERROR)) {
126 ERRARG("reply");
127 return NULL;
128 }
129
130 err_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100131 if (!err_rpl->err) {
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100132 return NULL;
133 }
Michal Vasko77367452021-02-16 16:32:18 +0100134 return err_rpl->err->prev;
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100135}
136
Michal Vasko77367452021-02-16 16:32:18 +0100137static const char *
138nc_err_tag2str(NC_ERR tag)
139{
140 switch (tag) {
141 case NC_ERR_IN_USE:
142 return "in-use";
143 case NC_ERR_INVALID_VALUE:
144 return "invalid-value";
145 case NC_ERR_ACCESS_DENIED:
146 return "access-denied";
147 case NC_ERR_ROLLBACK_FAILED:
148 return "rollback-failed";
149 case NC_ERR_OP_NOT_SUPPORTED:
150 return "operation-not-supported";
151 case NC_ERR_TOO_BIG:
152 return "too-big";
153 case NC_ERR_RES_DENIED:
154 return "resource-denied";
155 case NC_ERR_MISSING_ATTR:
156 return "missing-attribute";
157 case NC_ERR_BAD_ATTR:
158 return "bad-attribute";
159 case NC_ERR_UNKNOWN_ATTR:
160 return "unknown-attribute";
161 case NC_ERR_MISSING_ELEM:
162 return "missing-element";
163 case NC_ERR_BAD_ELEM:
164 return "bad-element";
165 case NC_ERR_UNKNOWN_ELEM:
166 return "unknown-element";
167 case NC_ERR_UNKNOWN_NS:
168 return "unknown-namespace";
169 case NC_ERR_LOCK_DENIED:
170 return "lock-denied";
171 case NC_ERR_DATA_EXISTS:
172 return "data-exists";
173 case NC_ERR_DATA_MISSING:
174 return "data-missing";
175 case NC_ERR_OP_FAILED:
176 return "operation-failed";
177 case NC_ERR_MALFORMED_MSG:
178 return "malformed-message";
179 default:
180 break;
181 }
182
183 return NULL;
184}
185
186static NC_ERR
187nc_err_str2tag(const char *str)
188{
189 if (!strcmp(str, "in-use")) {
190 return NC_ERR_IN_USE;
191 } else if (!strcmp(str, "invalid-value")) {
192 return NC_ERR_INVALID_VALUE;
193 } else if (!strcmp(str, "access-denied")) {
194 return NC_ERR_ACCESS_DENIED;
195 } else if (!strcmp(str, "rollback-failed")) {
196 return NC_ERR_ROLLBACK_FAILED;
197 } else if (!strcmp(str, "operation-not-supported")) {
198 return NC_ERR_OP_NOT_SUPPORTED;
199 } else if (!strcmp(str, "too-big")) {
200 return NC_ERR_TOO_BIG;
201 } else if (!strcmp(str, "resource-denied")) {
202 return NC_ERR_RES_DENIED;
203 } else if (!strcmp(str, "missing-attribute")) {
204 return NC_ERR_MISSING_ATTR;
205 } else if (!strcmp(str, "bad-attribute")) {
206 return NC_ERR_BAD_ATTR;
207 } else if (!strcmp(str, "unknown-attribute")) {
208 return NC_ERR_UNKNOWN_ATTR;
209 } else if (!strcmp(str, "missing-element")) {
210 return NC_ERR_MISSING_ELEM;
211 } else if (!strcmp(str, "bad-element")) {
212 return NC_ERR_BAD_ELEM;
213 } else if (!strcmp(str, "unknown-element")) {
214 return NC_ERR_UNKNOWN_ELEM;
215 } else if (!strcmp(str, "unknown-namespace")) {
216 return NC_ERR_UNKNOWN_NS;
217 } else if (!strcmp(str, "lock-denied")) {
218 return NC_ERR_LOCK_DENIED;
219 } else if (!strcmp(str, "data-exists")) {
220 return NC_ERR_DATA_EXISTS;
221 } else if (!strcmp(str, "data-missing")) {
222 return NC_ERR_DATA_MISSING;
223 } else if (!strcmp(str, "operation-failed")) {
224 return NC_ERR_OP_FAILED;
225 } else if (!strcmp(str, "malformed-message")) {
226 return NC_ERR_MALFORMED_MSG;
227 }
228
229 return 0;
230}
231
232static const char *
233nc_err_type2str(NC_ERR_TYPE type)
234{
235 switch (type) {
236 case NC_ERR_TYPE_TRAN:
237 return "transport";
238 case NC_ERR_TYPE_RPC:
239 return "rpc";
240 case NC_ERR_TYPE_PROT:
241 return "protocol";
242 case NC_ERR_TYPE_APP:
243 return "application";
244 default:
245 break;
246 }
247
248 return NULL;
249}
250
251static NC_ERR_TYPE
252nc_err_str2type(const char *str)
253{
254 if (!strcmp(str, "transport")) {
255 return NC_ERR_TYPE_TRAN;
256 } else if (!strcmp(str, "rpc")) {
257 return NC_ERR_TYPE_RPC;
258 } else if (!strcmp(str, "protocol")) {
259 return NC_ERR_TYPE_PROT;
260 } else if (!strcmp(str, "application")) {
261 return NC_ERR_TYPE_APP;
262 }
263
264 return 0;
265}
266
267API struct lyd_node *
268nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100269{
270 va_list ap;
Michal Vasko77367452021-02-16 16:32:18 +0100271 struct lyd_node *err = NULL;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100272 NC_ERR_TYPE type;
273 const char *arg1, *arg2;
274 uint32_t sid;
275
Michal Vasko1a38c862016-01-15 15:50:07 +0100276 if (!tag) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200277 ERRARG("tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100278 return NULL;
279 }
280
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)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200297 ERRARG("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) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200310 ERRARG("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)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200319 ERRARG("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)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200326 ERRARG("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) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200340 ERRARG("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:
348 ERRARG("tag");
349 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:
Michal Vasko45e53ae2016-04-07 11:46:03 +0200425 ERRARG("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:
Michal Vasko45e53ae2016-04-07 11:46:03 +0200472 ERRARG("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
Michal Vasko8f3198f2016-05-04 10:45:28 +0200490 if (!err) {
491 ERRARG("err");
492 return 0;
493 }
494
Michal Vasko77367452021-02-16 16:32:18 +0100495 lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match);
496 if (match) {
497 return nc_err_str2type(((struct lyd_node_opaq *)match)->value);
498 }
499
500 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200501}
502
503API NC_ERR
Michal Vasko77367452021-02-16 16:32:18 +0100504nc_err_get_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200505{
Michal Vasko77367452021-02-16 16:32:18 +0100506 struct lyd_node *match;
507
Michal Vasko8f3198f2016-05-04 10:45:28 +0200508 if (!err) {
509 ERRARG("err");
510 return 0;
511 }
512
Michal Vasko77367452021-02-16 16:32:18 +0100513 lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match);
514 if (match) {
515 return nc_err_str2tag(((struct lyd_node_opaq *)match)->value);
516 }
517
518 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200519}
520
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100521API int
Michal Vasko77367452021-02-16 16:32:18 +0100522nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100523{
Michal Vasko77367452021-02-16 16:32:18 +0100524 struct lyd_node *match;
525
Michal Vasko45e53ae2016-04-07 11:46:03 +0200526 if (!err) {
527 ERRARG("err");
528 return -1;
529 } else if (!error_app_tag) {
530 ERRARG("error_app_tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100531 return -1;
532 }
533
Michal Vasko77367452021-02-16 16:32:18 +0100534 /* remove previous node */
535 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
536 if (match) {
537 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100538 }
Michal Vasko77367452021-02-16 16:32:18 +0100539
540 if (lyd_new_opaq2(err, NULL, "error-app-tag", error_app_tag, NULL, NC_NS_BASE, NULL)) {
541 return -1;
542 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100543
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100544 return 0;
545}
546
Michal Vasko8f3198f2016-05-04 10:45:28 +0200547API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100548nc_err_get_app_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200549{
Michal Vasko77367452021-02-16 16:32:18 +0100550 struct lyd_node *match;
551
Michal Vasko8f3198f2016-05-04 10:45:28 +0200552 if (!err) {
553 ERRARG("err");
554 return NULL;
555 }
556
Michal Vasko77367452021-02-16 16:32:18 +0100557 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
558 if (match) {
559 return ((struct lyd_node_opaq *)match)->value;
560 }
561
562 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200563}
564
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100565API int
Michal Vasko77367452021-02-16 16:32:18 +0100566nc_err_set_path(struct lyd_node *err, const char *error_path)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100567{
Michal Vasko77367452021-02-16 16:32:18 +0100568 struct lyd_node *match;
569
Michal Vasko45e53ae2016-04-07 11:46:03 +0200570 if (!err) {
571 ERRARG("err");
572 return -1;
573 } else if (!error_path) {
574 ERRARG("error_path");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100575 return -1;
576 }
577
Michal Vasko77367452021-02-16 16:32:18 +0100578 /* remove previous node */
579 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
580 if (match) {
581 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100582 }
Michal Vasko77367452021-02-16 16:32:18 +0100583
584 if (lyd_new_opaq2(err, NULL, "error-path", error_path, NULL, NC_NS_BASE, NULL)) {
585 return -1;
586 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100587
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100588 return 0;
589}
590
Michal Vasko8f3198f2016-05-04 10:45:28 +0200591API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100592nc_err_get_path(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200593{
Michal Vasko77367452021-02-16 16:32:18 +0100594 struct lyd_node *match;
595
Michal Vasko8f3198f2016-05-04 10:45:28 +0200596 if (!err) {
597 ERRARG("err");
598 return 0;
599 }
600
Michal Vasko77367452021-02-16 16:32:18 +0100601 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
602 if (match) {
603 return ((struct lyd_node_opaq *)match)->value;
604 }
605
606 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200607}
608
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100609API int
Michal Vasko77367452021-02-16 16:32:18 +0100610nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100611{
Michal Vasko77367452021-02-16 16:32:18 +0100612 struct lyd_node *match;
613 struct lyd_attr *attr;
614
Michal Vasko45e53ae2016-04-07 11:46:03 +0200615 if (!err) {
616 ERRARG("err");
617 return -1;
618 } else if (!error_message) {
619 ERRARG("error_message");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100620 return -1;
621 }
622
Michal Vasko77367452021-02-16 16:32:18 +0100623 /* remove previous message */
624 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
625 if (match) {
626 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100627 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100628
Michal Vasko77367452021-02-16 16:32:18 +0100629 if (lyd_new_opaq2(err, NULL, "error-message", error_message, NULL, NC_NS_BASE, &match)) {
630 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100631 }
Michal Vasko77367452021-02-16 16:32:18 +0100632 if (lang && lyd_new_attr(match, NULL, "xml:lang", lang, &attr)) {
633 lyd_free_tree(match);
634 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100635 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100636
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100637 return 0;
638}
639
Michal Vasko8f3198f2016-05-04 10:45:28 +0200640API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100641nc_err_get_msg(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200642{
Michal Vasko77367452021-02-16 16:32:18 +0100643 struct lyd_node *match;
644
Michal Vasko8f3198f2016-05-04 10:45:28 +0200645 if (!err) {
646 ERRARG("err");
Michal Vasko77367452021-02-16 16:32:18 +0100647 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200648 }
649
Michal Vasko77367452021-02-16 16:32:18 +0100650 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
651 if (match) {
652 return ((struct lyd_node_opaq *)match)->value;
653 }
654
655 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200656}
657
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100658API int
Michal Vasko77367452021-02-16 16:32:18 +0100659nc_err_set_sid(struct lyd_node *err, uint32_t session_id)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100660{
Michal Vasko77367452021-02-16 16:32:18 +0100661 struct lyd_node *match, *info;
662 char buf[22];
663
Michal Vasko45e53ae2016-04-07 11:46:03 +0200664 if (!err) {
665 ERRARG("err");
666 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100667 }
668
Michal Vasko77367452021-02-16 16:32:18 +0100669 /* find error-info */
670 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
671 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
672 return -1;
673 }
674
675 /* remove previous node */
676 lyd_find_sibling_opaq_next(lyd_child(info), "session-id", &match);
677 if (match) {
678 lyd_free_tree(match);
679 }
680
681 sprintf(buf, "%" PRIu32, session_id);
682 if (lyd_new_opaq2(info, NULL, "session-id", buf, NULL, NC_NS_BASE, NULL)) {
683 return -1;
684 }
685
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100686 return 0;
687}
688
689API int
Michal Vasko77367452021-02-16 16:32:18 +0100690nc_err_add_bad_attr(struct lyd_node *err, const char *attr_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100691{
Michal Vasko77367452021-02-16 16:32:18 +0100692 struct lyd_node *info;
693
Michal Vasko45e53ae2016-04-07 11:46:03 +0200694 if (!err) {
695 ERRARG("err");
696 return -1;
697 } else if (!attr_name) {
698 ERRARG("attr_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100699 return -1;
700 }
701
Michal Vasko77367452021-02-16 16:32:18 +0100702 /* find error-info */
703 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
704 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100705 return -1;
706 }
Michal Vasko77367452021-02-16 16:32:18 +0100707
708 if (lyd_new_opaq2(info, NULL, "bad-attribute", attr_name, NULL, NC_NS_BASE, NULL)) {
709 return -1;
710 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100711
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100712 return 0;
713}
714
715API int
Michal Vasko77367452021-02-16 16:32:18 +0100716nc_err_add_bad_elem(struct lyd_node *err, const char *elem_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100717{
Michal Vasko77367452021-02-16 16:32:18 +0100718 struct lyd_node *info;
719
Michal Vasko45e53ae2016-04-07 11:46:03 +0200720 if (!err) {
721 ERRARG("err");
722 return -1;
723 } else if (!elem_name) {
724 ERRARG("elem_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100725 return -1;
726 }
727
Michal Vasko77367452021-02-16 16:32:18 +0100728 /* find error-info */
729 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
730 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100731 return -1;
732 }
Michal Vasko77367452021-02-16 16:32:18 +0100733
734 if (lyd_new_opaq2(info, NULL, "bad-element", elem_name, NULL, NC_NS_BASE, NULL)) {
735 return -1;
736 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100737
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100738 return 0;
739}
740
741API int
Michal Vasko77367452021-02-16 16:32:18 +0100742nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100743{
Michal Vasko77367452021-02-16 16:32:18 +0100744 struct lyd_node *info;
745
Michal Vasko45e53ae2016-04-07 11:46:03 +0200746 if (!err) {
747 ERRARG("err");
748 return -1;
749 } else if (!ns_name) {
750 ERRARG("ns_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100751 return -1;
752 }
753
Michal Vasko77367452021-02-16 16:32:18 +0100754 /* find error-info */
755 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
756 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100757 return -1;
758 }
Michal Vasko77367452021-02-16 16:32:18 +0100759
760 if (lyd_new_opaq2(info, NULL, "bad-namespace", ns_name, NULL, NC_NS_BASE, NULL)) {
761 return -1;
762 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100763
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100764 return 0;
765}
766
767API int
Michal Vasko77367452021-02-16 16:32:18 +0100768nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100769{
Michal Vasko77367452021-02-16 16:32:18 +0100770 struct lyd_node *info;
771
Michal Vasko45e53ae2016-04-07 11:46:03 +0200772 if (!err) {
773 ERRARG("err");
774 return -1;
775 } else if (!other) {
776 ERRARG("other");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100777 return -1;
778 }
779
Michal Vasko77367452021-02-16 16:32:18 +0100780 /* find error-info */
781 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
782 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100783 return -1;
784 }
Michal Vasko77367452021-02-16 16:32:18 +0100785
786 lyd_insert_child(info, other);
787
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100788 return 0;
789}
790
791void
Michal Vasko77367452021-02-16 16:32:18 +0100792nc_server_rpc_free(struct nc_server_rpc *rpc)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100793{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100794 if (!rpc) {
795 return;
796 }
797
Michal Vasko77367452021-02-16 16:32:18 +0100798 lyd_free_tree(rpc->envp);
Michal Vaskod5bfc482021-10-26 10:47:54 +0200799
800 /* may be action */
801 lyd_free_all(rpc->rpc);
Michal Vasko11d142a2016-01-19 15:58:24 +0100802
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100803 free(rpc);
804}
805
806API void
807nc_server_reply_free(struct nc_server_reply *reply)
808{
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100809 struct nc_server_reply_data *data_rpl;
810 struct nc_server_reply_error *error_rpl;
811
812 if (!reply) {
813 return;
814 }
815
816 switch (reply->type) {
817 case NC_RPL_DATA:
818 data_rpl = (struct nc_server_reply_data *)reply;
819 if (data_rpl->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100820 lyd_free_siblings(data_rpl->data);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100821 }
822 break;
823 case NC_RPL_OK:
824 /* nothing to free */
825 break;
826 case NC_RPL_ERROR:
827 error_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100828 lyd_free_siblings(error_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100829 break;
830 default:
831 break;
832 }
833 free(reply);
834}
835
Radek Krejci93e80222016-10-03 13:34:25 +0200836API struct nc_server_notif *
Michal Vasko77367452021-02-16 16:32:18 +0100837nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype)
Radek Krejci93e80222016-10-03 13:34:25 +0200838{
839 struct nc_server_notif *ntf;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100840 struct lyd_node *elem;
Michal Vasko77367452021-02-16 16:32:18 +0100841 int found;
Radek Krejci93e80222016-10-03 13:34:25 +0200842
Michal Vasko3106b7b2018-01-04 10:32:42 +0100843 if (!event) {
Radek Krejci93e80222016-10-03 13:34:25 +0200844 ERRARG("event");
845 return NULL;
846 } else if (!eventtime) {
847 ERRARG("eventtime");
848 return NULL;
849 }
850
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100851 /* check that there is a notification */
Michal Vasko77367452021-02-16 16:32:18 +0100852 found = 0;
853 LYD_TREE_DFS_BEGIN(event, elem) {
854 if (elem->schema->nodetype == LYS_NOTIF) {
855 found = 1;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100856 break;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100857 }
Michal Vasko77367452021-02-16 16:32:18 +0100858 LYD_TREE_DFS_END(event, elem);
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100859 }
Michal Vasko77367452021-02-16 16:32:18 +0100860 if (!found) {
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100861 ERRARG("event");
862 return NULL;
863 }
864
Radek Krejci93e80222016-10-03 13:34:25 +0200865 ntf = malloc(sizeof *ntf);
Michal Vasko25e244b2022-12-14 14:19:59 +0100866 if (!ntf) {
867 ERRMEM;
868 return NULL;
869 }
870
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100871 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Radek Krejci93e80222016-10-03 13:34:25 +0200872 ntf->eventtime = strdup(eventtime);
Michal Vasko77367452021-02-16 16:32:18 +0100873 if (lyd_dup_single(event, NULL, LYD_DUP_RECURSIVE, &ntf->ntf)) {
874 free(ntf);
875 return NULL;
876 }
Radek Krejci93e80222016-10-03 13:34:25 +0200877 } else {
878 ntf->eventtime = eventtime;
Michal Vasko77367452021-02-16 16:32:18 +0100879 ntf->ntf = event;
Radek Krejci93e80222016-10-03 13:34:25 +0200880 }
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100881 ntf->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
Radek Krejci93e80222016-10-03 13:34:25 +0200882
883 return ntf;
884}
885
886API void
887nc_server_notif_free(struct nc_server_notif *notif)
888{
889 if (!notif) {
890 return;
891 }
892
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100893 if (notif->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100894 lyd_free_tree(notif->ntf);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100895 free(notif->eventtime);
896 }
Radek Krejci93e80222016-10-03 13:34:25 +0200897 free(notif);
898}
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100899
900API const char *
901nc_server_notif_get_time(const struct nc_server_notif *notif)
902{
903 if (!notif) {
904 ERRARG("notif");
905 return NULL;
906 }
907
908 return notif->eventtime;
909}