blob: 7864ebfca3010212733507d82fe940c2395340ac [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
roman40672412023-05-04 11:10:22 +020052 NC_CHECK_ARG_RET(NULL, data, NULL);
53
54 if (!(data->schema->nodetype & (LYS_RPC | LYS_ACTION))) {
55 ERR(NULL, "nc_server_reply_data bad data");
Michal Vaskob08743b2016-04-13 14:23:49 +020056 return NULL;
57 }
58
Michal Vasko7bcb48e2016-01-15 10:28:54 +010059 ret = malloc(sizeof *ret);
60 if (!ret) {
61 ERRMEM;
62 return NULL;
63 }
64
65 ret->type = NC_RPL_DATA;
Radek Krejci36dfdb32016-09-01 16:56:35 +020066 ret->wd = wd;
Michal Vaskob08743b2016-04-13 14:23:49 +020067 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Michal Vasko77367452021-02-16 16:32:18 +010068 if (lyd_dup_single(data, NULL, LYD_DUP_RECURSIVE, &ret->data)) {
69 free(ret);
70 return NULL;
71 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +010072 } else {
73 ret->data = data;
74 }
75 if (paramtype != NC_PARAMTYPE_CONST) {
76 ret->free = 1;
77 } else {
78 ret->free = 0;
79 }
80 return (struct nc_server_reply *)ret;
81}
82
83API struct nc_server_reply *
Michal Vasko77367452021-02-16 16:32:18 +010084nc_server_reply_err(struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010085{
86 struct nc_server_reply_error *ret;
87
roman40672412023-05-04 11:10:22 +020088 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +010089
90 ret = malloc(sizeof *ret);
91 if (!ret) {
92 ERRMEM;
93 return NULL;
94 }
95
96 ret->type = NC_RPL_ERROR;
Michal Vasko77367452021-02-16 16:32:18 +010097 ret->err = err;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010098 return (struct nc_server_reply *)ret;
99}
100
101API int
Michal Vasko77367452021-02-16 16:32:18 +0100102nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100103{
104 struct nc_server_reply_error *err_rpl;
105
roman40672412023-05-04 11:10:22 +0200106 NC_CHECK_ARG_RET(NULL, reply, err, -1);
107
108 if (reply->type != NC_RPL_ERROR) {
109 ERR(NULL, "nc_server_reply_add_err: bad reply type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100110 return -1;
111 }
112
113 err_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100114 lyd_insert_sibling(err_rpl->err, err, &err_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100115 return 0;
116}
117
Michal Vasko77367452021-02-16 16:32:18 +0100118API const struct lyd_node *
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100119nc_server_reply_get_last_err(const struct nc_server_reply *reply)
120{
121 struct nc_server_reply_error *err_rpl;
122
roman40672412023-05-04 11:10:22 +0200123 NC_CHECK_ARG_RET(NULL, reply, NULL);
124
125 if (reply->type != NC_RPL_ERROR) {
126 ERR(NULL, "nc_server_reply_get_last_err: bad reply type");
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100127 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
roman40672412023-05-04 11:10:22 +0200276 NC_CHECK_ARG_RET(NULL, tag, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100277
Michal Vasko77367452021-02-16 16:32:18 +0100278 /* rpc-error */
279 if (lyd_new_opaq2(NULL, ctx, "rpc-error", NULL, NULL, NC_NS_BASE, &err)) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100280 return NULL;
281 }
282
283 va_start(ap, tag);
284
Michal Vasko77367452021-02-16 16:32:18 +0100285 /* error-type */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100286 switch (tag) {
287 case NC_ERR_IN_USE:
288 case NC_ERR_INVALID_VALUE:
289 case NC_ERR_ACCESS_DENIED:
290 case NC_ERR_ROLLBACK_FAILED:
291 case NC_ERR_OP_NOT_SUPPORTED:
Radek Krejci127f8952016-10-12 14:57:16 +0200292 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko2f923d12016-04-05 11:33:02 +0200293 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200294 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100295 goto fail;
296 }
297 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100298 case NC_ERR_TOO_BIG:
299 case NC_ERR_RES_DENIED:
Michal Vasko77367452021-02-16 16:32:18 +0100300 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100301 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100302 case NC_ERR_MISSING_ATTR:
303 case NC_ERR_BAD_ATTR:
304 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko77367452021-02-16 16:32:18 +0100305 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100306 if (type == NC_ERR_TYPE_TRAN) {
roman40672412023-05-04 11:10:22 +0200307 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100308 goto fail;
309 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100310 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100311 case NC_ERR_MISSING_ELEM:
312 case NC_ERR_BAD_ELEM:
313 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko77367452021-02-16 16:32:18 +0100314 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100315 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200316 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100317 goto fail;
318 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100319 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100320 case NC_ERR_UNKNOWN_NS:
Michal Vasko77367452021-02-16 16:32:18 +0100321 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100322 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200323 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100324 goto fail;
325 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100326 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100327 case NC_ERR_LOCK_DENIED:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100328 type = NC_ERR_TYPE_PROT;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100329 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100330 case NC_ERR_DATA_EXISTS:
331 case NC_ERR_DATA_MISSING:
332 type = NC_ERR_TYPE_APP;
333 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100334 case NC_ERR_OP_FAILED:
Michal Vasko77367452021-02-16 16:32:18 +0100335 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100336 if (type == NC_ERR_TYPE_TRAN) {
roman40672412023-05-04 11:10:22 +0200337 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100338 goto fail;
339 }
340 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100341 case NC_ERR_MALFORMED_MSG:
342 type = NC_ERR_TYPE_RPC;
343 break;
Michal Vasko77367452021-02-16 16:32:18 +0100344 default:
roman40672412023-05-04 11:10:22 +0200345 ERRARG(NULL, "tag");
Michal Vasko77367452021-02-16 16:32:18 +0100346 goto fail;
347 }
348 if (lyd_new_opaq2(err, NULL, "error-type", nc_err_type2str(type), NULL, NC_NS_BASE, NULL)) {
349 goto fail;
350 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100351
Michal Vasko77367452021-02-16 16:32:18 +0100352 /* error-tag */
353 if (lyd_new_opaq2(err, NULL, "error-tag", nc_err_tag2str(tag), NULL, NC_NS_BASE, NULL)) {
354 goto fail;
355 }
356
357 /* error-severity */
358 if (lyd_new_opaq2(err, NULL, "error-severity", "error", NULL, NC_NS_BASE, NULL)) {
359 goto fail;
360 }
361
362 /* error-message */
363 switch (tag) {
364 case NC_ERR_IN_USE:
365 nc_err_set_msg(err, "The request requires a resource that already is in use.", "en");
366 break;
367 case NC_ERR_INVALID_VALUE:
368 nc_err_set_msg(err, "The request specifies an unacceptable value for one or more parameters.", "en");
369 break;
370 case NC_ERR_TOO_BIG:
371 nc_err_set_msg(err, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
372 break;
373 case NC_ERR_MISSING_ATTR:
374 nc_err_set_msg(err, "An expected attribute is missing.", "en");
375 break;
376 case NC_ERR_BAD_ATTR:
377 nc_err_set_msg(err, "An attribute value is not correct.", "en");
378 break;
379 case NC_ERR_UNKNOWN_ATTR:
380 nc_err_set_msg(err, "An unexpected attribute is present.", "en");
381 break;
382 case NC_ERR_MISSING_ELEM:
383 nc_err_set_msg(err, "An expected element is missing.", "en");
384 break;
385 case NC_ERR_BAD_ELEM:
386 nc_err_set_msg(err, "An element value is not correct.", "en");
387 break;
388 case NC_ERR_UNKNOWN_ELEM:
389 nc_err_set_msg(err, "An unexpected element is present.", "en");
390 break;
391 case NC_ERR_UNKNOWN_NS:
392 nc_err_set_msg(err, "An unexpected namespace is present.", "en");
393 break;
394 case NC_ERR_ACCESS_DENIED:
395 nc_err_set_msg(err, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
396 break;
397 case NC_ERR_LOCK_DENIED:
398 nc_err_set_msg(err, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
399 break;
400 case NC_ERR_RES_DENIED:
401 nc_err_set_msg(err, "Request could not be completed because of insufficient resources.", "en");
402 break;
403 case NC_ERR_ROLLBACK_FAILED:
404 nc_err_set_msg(err, "Request to roll back some configuration change was not completed for some reason.", "en");
405 break;
406 case NC_ERR_DATA_EXISTS:
407 nc_err_set_msg(err, "Request could not be completed because the relevant data model content already exists.", "en");
408 break;
409 case NC_ERR_DATA_MISSING:
410 nc_err_set_msg(err, "Request could not be completed because the relevant data model content does not exist.", "en");
411 break;
412 case NC_ERR_OP_NOT_SUPPORTED:
413 nc_err_set_msg(err, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
414 break;
415 case NC_ERR_OP_FAILED:
416 nc_err_set_msg(err, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
417 break;
418 case NC_ERR_MALFORMED_MSG:
419 nc_err_set_msg(err, "A message could not be handled because it failed to be parsed correctly.", "en");
420 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100421 default:
roman40672412023-05-04 11:10:22 +0200422 ERRARG(NULL, "tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100423 goto fail;
424 }
425
Michal Vasko77367452021-02-16 16:32:18 +0100426 /* error-info */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100427 switch (tag) {
428 case NC_ERR_IN_USE:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100429 case NC_ERR_INVALID_VALUE:
Michal Vasko77367452021-02-16 16:32:18 +0100430 case NC_ERR_ACCESS_DENIED:
431 case NC_ERR_ROLLBACK_FAILED:
432 case NC_ERR_OP_NOT_SUPPORTED:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100433 case NC_ERR_TOO_BIG:
Michal Vasko77367452021-02-16 16:32:18 +0100434 case NC_ERR_RES_DENIED:
435 case NC_ERR_DATA_EXISTS:
436 case NC_ERR_DATA_MISSING:
437 case NC_ERR_OP_FAILED:
438 case NC_ERR_MALFORMED_MSG:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100439 break;
440 case NC_ERR_MISSING_ATTR:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100441 case NC_ERR_BAD_ATTR:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100442 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko77367452021-02-16 16:32:18 +0100443 arg1 = va_arg(ap, const char *);
444 arg2 = va_arg(ap, const char *);
445
446 nc_err_add_bad_attr(err, arg1);
447 nc_err_add_bad_elem(err, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100448 break;
449 case NC_ERR_MISSING_ELEM:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100450 case NC_ERR_BAD_ELEM:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100451 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko77367452021-02-16 16:32:18 +0100452 arg1 = va_arg(ap, const char *);
453
454 nc_err_add_bad_elem(err, arg1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100455 break;
456 case NC_ERR_UNKNOWN_NS:
Michal Vasko77367452021-02-16 16:32:18 +0100457 arg1 = va_arg(ap, const char *);
458 arg2 = va_arg(ap, const char *);
459
460 nc_err_add_bad_elem(err, arg1);
461 nc_err_add_bad_ns(err, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100462 break;
463 case NC_ERR_LOCK_DENIED:
Michal Vasko77367452021-02-16 16:32:18 +0100464 sid = va_arg(ap, uint32_t);
465
466 nc_err_set_sid(err, sid);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100467 break;
468 default:
roman40672412023-05-04 11:10:22 +0200469 ERRARG(NULL, "tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100470 goto fail;
471 }
472
473 va_end(ap);
Michal Vasko77367452021-02-16 16:32:18 +0100474 return err;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100475
476fail:
Michal Vasko11d142a2016-01-19 15:58:24 +0100477 va_end(ap);
Michal Vasko77367452021-02-16 16:32:18 +0100478 lyd_free_siblings(err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100479 return NULL;
480}
481
Michal Vasko8f3198f2016-05-04 10:45:28 +0200482API NC_ERR_TYPE
Michal Vasko77367452021-02-16 16:32:18 +0100483nc_err_get_type(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200484{
Michal Vasko77367452021-02-16 16:32:18 +0100485 struct lyd_node *match;
486
roman40672412023-05-04 11:10:22 +0200487 NC_CHECK_ARG_RET(NULL, err, 0);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200488
Michal Vasko77367452021-02-16 16:32:18 +0100489 lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match);
490 if (match) {
491 return nc_err_str2type(((struct lyd_node_opaq *)match)->value);
492 }
493
494 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200495}
496
497API NC_ERR
Michal Vasko77367452021-02-16 16:32:18 +0100498nc_err_get_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200499{
Michal Vasko77367452021-02-16 16:32:18 +0100500 struct lyd_node *match;
501
roman40672412023-05-04 11:10:22 +0200502 NC_CHECK_ARG_RET(NULL, err, 0);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200503
Michal Vasko77367452021-02-16 16:32:18 +0100504 lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match);
505 if (match) {
506 return nc_err_str2tag(((struct lyd_node_opaq *)match)->value);
507 }
508
509 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200510}
511
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100512API int
Michal Vasko77367452021-02-16 16:32:18 +0100513nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100514{
Michal Vasko77367452021-02-16 16:32:18 +0100515 struct lyd_node *match;
516
roman40672412023-05-04 11:10:22 +0200517 NC_CHECK_ARG_RET(NULL, err, error_app_tag, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100518
Michal Vasko77367452021-02-16 16:32:18 +0100519 /* remove previous node */
520 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
521 if (match) {
522 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100523 }
Michal Vasko77367452021-02-16 16:32:18 +0100524
525 if (lyd_new_opaq2(err, NULL, "error-app-tag", error_app_tag, NULL, NC_NS_BASE, NULL)) {
526 return -1;
527 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100528
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100529 return 0;
530}
531
Michal Vasko8f3198f2016-05-04 10:45:28 +0200532API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100533nc_err_get_app_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200534{
Michal Vasko77367452021-02-16 16:32:18 +0100535 struct lyd_node *match;
536
roman40672412023-05-04 11:10:22 +0200537 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200538
Michal Vasko77367452021-02-16 16:32:18 +0100539 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
540 if (match) {
541 return ((struct lyd_node_opaq *)match)->value;
542 }
543
544 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200545}
546
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100547API int
Michal Vasko77367452021-02-16 16:32:18 +0100548nc_err_set_path(struct lyd_node *err, const char *error_path)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100549{
Michal Vasko77367452021-02-16 16:32:18 +0100550 struct lyd_node *match;
551
roman40672412023-05-04 11:10:22 +0200552 NC_CHECK_ARG_RET(NULL, err, error_path, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100553
Michal Vasko77367452021-02-16 16:32:18 +0100554 /* remove previous node */
555 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
556 if (match) {
557 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100558 }
Michal Vasko77367452021-02-16 16:32:18 +0100559
560 if (lyd_new_opaq2(err, NULL, "error-path", error_path, NULL, NC_NS_BASE, NULL)) {
561 return -1;
562 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100563
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100564 return 0;
565}
566
Michal Vasko8f3198f2016-05-04 10:45:28 +0200567API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100568nc_err_get_path(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200569{
Michal Vasko77367452021-02-16 16:32:18 +0100570 struct lyd_node *match;
571
roman40672412023-05-04 11:10:22 +0200572 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200573
Michal Vasko77367452021-02-16 16:32:18 +0100574 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
575 if (match) {
576 return ((struct lyd_node_opaq *)match)->value;
577 }
578
579 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200580}
581
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100582API int
Michal Vasko77367452021-02-16 16:32:18 +0100583nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100584{
Michal Vasko77367452021-02-16 16:32:18 +0100585 struct lyd_node *match;
586 struct lyd_attr *attr;
587
roman40672412023-05-04 11:10:22 +0200588 NC_CHECK_ARG_RET(NULL, err, error_message, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100589
Michal Vasko77367452021-02-16 16:32:18 +0100590 /* remove previous message */
591 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
592 if (match) {
593 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100594 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100595
Michal Vasko77367452021-02-16 16:32:18 +0100596 if (lyd_new_opaq2(err, NULL, "error-message", error_message, NULL, NC_NS_BASE, &match)) {
597 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100598 }
Michal Vasko77367452021-02-16 16:32:18 +0100599 if (lang && lyd_new_attr(match, NULL, "xml:lang", lang, &attr)) {
600 lyd_free_tree(match);
601 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100602 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100603
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100604 return 0;
605}
606
Michal Vasko8f3198f2016-05-04 10:45:28 +0200607API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100608nc_err_get_msg(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200609{
Michal Vasko77367452021-02-16 16:32:18 +0100610 struct lyd_node *match;
611
roman40672412023-05-04 11:10:22 +0200612 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200613
Michal Vasko77367452021-02-16 16:32:18 +0100614 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
615 if (match) {
616 return ((struct lyd_node_opaq *)match)->value;
617 }
618
619 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200620}
621
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100622API int
Michal Vasko77367452021-02-16 16:32:18 +0100623nc_err_set_sid(struct lyd_node *err, uint32_t session_id)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100624{
Michal Vasko77367452021-02-16 16:32:18 +0100625 struct lyd_node *match, *info;
626 char buf[22];
627
roman40672412023-05-04 11:10:22 +0200628 NC_CHECK_ARG_RET(NULL, err, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100629
Michal Vasko77367452021-02-16 16:32:18 +0100630 /* find error-info */
631 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
632 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
633 return -1;
634 }
635
636 /* remove previous node */
637 lyd_find_sibling_opaq_next(lyd_child(info), "session-id", &match);
638 if (match) {
639 lyd_free_tree(match);
640 }
641
642 sprintf(buf, "%" PRIu32, session_id);
643 if (lyd_new_opaq2(info, NULL, "session-id", buf, NULL, NC_NS_BASE, NULL)) {
644 return -1;
645 }
646
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100647 return 0;
648}
649
650API int
Michal Vasko77367452021-02-16 16:32:18 +0100651nc_err_add_bad_attr(struct lyd_node *err, const char *attr_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100652{
Michal Vasko77367452021-02-16 16:32:18 +0100653 struct lyd_node *info;
654
roman40672412023-05-04 11:10:22 +0200655 NC_CHECK_ARG_RET(NULL, err, attr_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100656
Michal Vasko77367452021-02-16 16:32:18 +0100657 /* find error-info */
658 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
659 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100660 return -1;
661 }
Michal Vasko77367452021-02-16 16:32:18 +0100662
663 if (lyd_new_opaq2(info, NULL, "bad-attribute", attr_name, NULL, NC_NS_BASE, NULL)) {
664 return -1;
665 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100666
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100667 return 0;
668}
669
670API int
Michal Vasko77367452021-02-16 16:32:18 +0100671nc_err_add_bad_elem(struct lyd_node *err, const char *elem_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100672{
Michal Vasko77367452021-02-16 16:32:18 +0100673 struct lyd_node *info;
674
roman40672412023-05-04 11:10:22 +0200675 NC_CHECK_ARG_RET(NULL, err, elem_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100676
Michal Vasko77367452021-02-16 16:32:18 +0100677 /* find error-info */
678 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
679 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100680 return -1;
681 }
Michal Vasko77367452021-02-16 16:32:18 +0100682
683 if (lyd_new_opaq2(info, NULL, "bad-element", elem_name, NULL, NC_NS_BASE, NULL)) {
684 return -1;
685 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100686
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100687 return 0;
688}
689
690API int
Michal Vasko77367452021-02-16 16:32:18 +0100691nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100692{
Michal Vasko77367452021-02-16 16:32:18 +0100693 struct lyd_node *info;
694
roman40672412023-05-04 11:10:22 +0200695 NC_CHECK_ARG_RET(NULL, err, ns_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100696
Michal Vasko77367452021-02-16 16:32:18 +0100697 /* find error-info */
698 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
699 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100700 return -1;
701 }
Michal Vasko77367452021-02-16 16:32:18 +0100702
703 if (lyd_new_opaq2(info, NULL, "bad-namespace", ns_name, NULL, NC_NS_BASE, NULL)) {
704 return -1;
705 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100706
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100707 return 0;
708}
709
710API int
Michal Vasko77367452021-02-16 16:32:18 +0100711nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100712{
Michal Vasko77367452021-02-16 16:32:18 +0100713 struct lyd_node *info;
714
roman40672412023-05-04 11:10:22 +0200715 NC_CHECK_ARG_RET(NULL, err, other, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100716
Michal Vasko77367452021-02-16 16:32:18 +0100717 /* find error-info */
718 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
719 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100720 return -1;
721 }
Michal Vasko77367452021-02-16 16:32:18 +0100722
723 lyd_insert_child(info, other);
724
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100725 return 0;
726}
727
728void
Michal Vasko77367452021-02-16 16:32:18 +0100729nc_server_rpc_free(struct nc_server_rpc *rpc)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100730{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100731 if (!rpc) {
732 return;
733 }
734
Michal Vasko77367452021-02-16 16:32:18 +0100735 lyd_free_tree(rpc->envp);
Michal Vaskod5bfc482021-10-26 10:47:54 +0200736
737 /* may be action */
738 lyd_free_all(rpc->rpc);
Michal Vasko11d142a2016-01-19 15:58:24 +0100739
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100740 free(rpc);
741}
742
743API void
744nc_server_reply_free(struct nc_server_reply *reply)
745{
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100746 struct nc_server_reply_data *data_rpl;
747 struct nc_server_reply_error *error_rpl;
748
749 if (!reply) {
750 return;
751 }
752
753 switch (reply->type) {
754 case NC_RPL_DATA:
755 data_rpl = (struct nc_server_reply_data *)reply;
756 if (data_rpl->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100757 lyd_free_siblings(data_rpl->data);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100758 }
759 break;
760 case NC_RPL_OK:
761 /* nothing to free */
762 break;
763 case NC_RPL_ERROR:
764 error_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100765 lyd_free_siblings(error_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100766 break;
767 default:
768 break;
769 }
770 free(reply);
771}
772
Radek Krejci93e80222016-10-03 13:34:25 +0200773API struct nc_server_notif *
Michal Vasko77367452021-02-16 16:32:18 +0100774nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype)
Radek Krejci93e80222016-10-03 13:34:25 +0200775{
776 struct nc_server_notif *ntf;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100777 struct lyd_node *elem;
Michal Vasko77367452021-02-16 16:32:18 +0100778 int found;
Radek Krejci93e80222016-10-03 13:34:25 +0200779
roman40672412023-05-04 11:10:22 +0200780 NC_CHECK_ARG_RET(NULL, event, eventtime, NULL);
Radek Krejci93e80222016-10-03 13:34:25 +0200781
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100782 /* check that there is a notification */
Michal Vasko77367452021-02-16 16:32:18 +0100783 found = 0;
784 LYD_TREE_DFS_BEGIN(event, elem) {
785 if (elem->schema->nodetype == LYS_NOTIF) {
786 found = 1;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100787 break;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100788 }
Michal Vasko77367452021-02-16 16:32:18 +0100789 LYD_TREE_DFS_END(event, elem);
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100790 }
Michal Vasko77367452021-02-16 16:32:18 +0100791 if (!found) {
roman40672412023-05-04 11:10:22 +0200792 ERRARG(NULL, "event");
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100793 return NULL;
794 }
795
Radek Krejci93e80222016-10-03 13:34:25 +0200796 ntf = malloc(sizeof *ntf);
Michal Vasko25e244b2022-12-14 14:19:59 +0100797 if (!ntf) {
798 ERRMEM;
799 return NULL;
800 }
801
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100802 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Radek Krejci93e80222016-10-03 13:34:25 +0200803 ntf->eventtime = strdup(eventtime);
Michal Vasko77367452021-02-16 16:32:18 +0100804 if (lyd_dup_single(event, NULL, LYD_DUP_RECURSIVE, &ntf->ntf)) {
805 free(ntf);
806 return NULL;
807 }
Radek Krejci93e80222016-10-03 13:34:25 +0200808 } else {
809 ntf->eventtime = eventtime;
Michal Vasko77367452021-02-16 16:32:18 +0100810 ntf->ntf = event;
Radek Krejci93e80222016-10-03 13:34:25 +0200811 }
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100812 ntf->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
Radek Krejci93e80222016-10-03 13:34:25 +0200813
814 return ntf;
815}
816
817API void
818nc_server_notif_free(struct nc_server_notif *notif)
819{
820 if (!notif) {
821 return;
822 }
823
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100824 if (notif->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100825 lyd_free_tree(notif->ntf);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100826 free(notif->eventtime);
827 }
Radek Krejci93e80222016-10-03 13:34:25 +0200828 free(notif);
829}
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100830
831API const char *
832nc_server_notif_get_time(const struct nc_server_notif *notif)
833{
roman40672412023-05-04 11:10:22 +0200834 NC_CHECK_ARG_RET(NULL, notif, NULL);
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100835
836 return notif->eventtime;
837}