blob: b02f5a1ec180920098ccf4987f81e0408a89a126 [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);
roman3a95bb22023-10-26 11:07:17 +020041 NC_CHECK_ERRMEM_RET(!ret, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +010042
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);
roman3a95bb22023-10-26 11:07:17 +020060 NC_CHECK_ERRMEM_RET(!ret, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +010061
62 ret->type = NC_RPL_DATA;
Radek Krejci36dfdb32016-09-01 16:56:35 +020063 ret->wd = wd;
Michal Vaskob08743b2016-04-13 14:23:49 +020064 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Michal Vasko77367452021-02-16 16:32:18 +010065 if (lyd_dup_single(data, NULL, LYD_DUP_RECURSIVE, &ret->data)) {
66 free(ret);
67 return NULL;
68 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +010069 } else {
70 ret->data = data;
71 }
72 if (paramtype != NC_PARAMTYPE_CONST) {
73 ret->free = 1;
74 } else {
75 ret->free = 0;
76 }
77 return (struct nc_server_reply *)ret;
78}
79
80API struct nc_server_reply *
Michal Vasko77367452021-02-16 16:32:18 +010081nc_server_reply_err(struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010082{
83 struct nc_server_reply_error *ret;
84
roman40672412023-05-04 11:10:22 +020085 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +010086
87 ret = malloc(sizeof *ret);
roman3a95bb22023-10-26 11:07:17 +020088 NC_CHECK_ERRMEM_RET(!ret, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +010089
90 ret->type = NC_RPL_ERROR;
Michal Vasko77367452021-02-16 16:32:18 +010091 ret->err = err;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010092 return (struct nc_server_reply *)ret;
93}
94
95API int
Michal Vasko77367452021-02-16 16:32:18 +010096nc_server_reply_add_err(struct nc_server_reply *reply, struct lyd_node *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010097{
98 struct nc_server_reply_error *err_rpl;
99
roman40672412023-05-04 11:10:22 +0200100 NC_CHECK_ARG_RET(NULL, reply, err, -1);
101
102 if (reply->type != NC_RPL_ERROR) {
roman3adc7c02023-10-25 11:10:58 +0200103 ERR(NULL, "nc_server_reply_add_err() bad reply type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100104 return -1;
105 }
106
107 err_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100108 lyd_insert_sibling(err_rpl->err, err, &err_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100109 return 0;
110}
111
Michal Vasko77367452021-02-16 16:32:18 +0100112API const struct lyd_node *
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100113nc_server_reply_get_last_err(const struct nc_server_reply *reply)
114{
115 struct nc_server_reply_error *err_rpl;
116
roman40672412023-05-04 11:10:22 +0200117 NC_CHECK_ARG_RET(NULL, reply, NULL);
118
119 if (reply->type != NC_RPL_ERROR) {
roman3adc7c02023-10-25 11:10:58 +0200120 ERR(NULL, "nc_server_reply_get_last_err() bad reply type");
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100121 return NULL;
122 }
123
124 err_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100125 if (!err_rpl->err) {
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100126 return NULL;
127 }
Michal Vasko77367452021-02-16 16:32:18 +0100128 return err_rpl->err->prev;
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100129}
130
Michal Vasko77367452021-02-16 16:32:18 +0100131static const char *
132nc_err_tag2str(NC_ERR tag)
133{
134 switch (tag) {
135 case NC_ERR_IN_USE:
136 return "in-use";
137 case NC_ERR_INVALID_VALUE:
138 return "invalid-value";
139 case NC_ERR_ACCESS_DENIED:
140 return "access-denied";
141 case NC_ERR_ROLLBACK_FAILED:
142 return "rollback-failed";
143 case NC_ERR_OP_NOT_SUPPORTED:
144 return "operation-not-supported";
145 case NC_ERR_TOO_BIG:
146 return "too-big";
147 case NC_ERR_RES_DENIED:
148 return "resource-denied";
149 case NC_ERR_MISSING_ATTR:
150 return "missing-attribute";
151 case NC_ERR_BAD_ATTR:
152 return "bad-attribute";
153 case NC_ERR_UNKNOWN_ATTR:
154 return "unknown-attribute";
155 case NC_ERR_MISSING_ELEM:
156 return "missing-element";
157 case NC_ERR_BAD_ELEM:
158 return "bad-element";
159 case NC_ERR_UNKNOWN_ELEM:
160 return "unknown-element";
161 case NC_ERR_UNKNOWN_NS:
162 return "unknown-namespace";
163 case NC_ERR_LOCK_DENIED:
164 return "lock-denied";
165 case NC_ERR_DATA_EXISTS:
166 return "data-exists";
167 case NC_ERR_DATA_MISSING:
168 return "data-missing";
169 case NC_ERR_OP_FAILED:
170 return "operation-failed";
171 case NC_ERR_MALFORMED_MSG:
172 return "malformed-message";
173 default:
174 break;
175 }
176
177 return NULL;
178}
179
180static NC_ERR
181nc_err_str2tag(const char *str)
182{
183 if (!strcmp(str, "in-use")) {
184 return NC_ERR_IN_USE;
185 } else if (!strcmp(str, "invalid-value")) {
186 return NC_ERR_INVALID_VALUE;
187 } else if (!strcmp(str, "access-denied")) {
188 return NC_ERR_ACCESS_DENIED;
189 } else if (!strcmp(str, "rollback-failed")) {
190 return NC_ERR_ROLLBACK_FAILED;
191 } else if (!strcmp(str, "operation-not-supported")) {
192 return NC_ERR_OP_NOT_SUPPORTED;
193 } else if (!strcmp(str, "too-big")) {
194 return NC_ERR_TOO_BIG;
195 } else if (!strcmp(str, "resource-denied")) {
196 return NC_ERR_RES_DENIED;
197 } else if (!strcmp(str, "missing-attribute")) {
198 return NC_ERR_MISSING_ATTR;
199 } else if (!strcmp(str, "bad-attribute")) {
200 return NC_ERR_BAD_ATTR;
201 } else if (!strcmp(str, "unknown-attribute")) {
202 return NC_ERR_UNKNOWN_ATTR;
203 } else if (!strcmp(str, "missing-element")) {
204 return NC_ERR_MISSING_ELEM;
205 } else if (!strcmp(str, "bad-element")) {
206 return NC_ERR_BAD_ELEM;
207 } else if (!strcmp(str, "unknown-element")) {
208 return NC_ERR_UNKNOWN_ELEM;
209 } else if (!strcmp(str, "unknown-namespace")) {
210 return NC_ERR_UNKNOWN_NS;
211 } else if (!strcmp(str, "lock-denied")) {
212 return NC_ERR_LOCK_DENIED;
213 } else if (!strcmp(str, "data-exists")) {
214 return NC_ERR_DATA_EXISTS;
215 } else if (!strcmp(str, "data-missing")) {
216 return NC_ERR_DATA_MISSING;
217 } else if (!strcmp(str, "operation-failed")) {
218 return NC_ERR_OP_FAILED;
219 } else if (!strcmp(str, "malformed-message")) {
220 return NC_ERR_MALFORMED_MSG;
221 }
222
223 return 0;
224}
225
226static const char *
227nc_err_type2str(NC_ERR_TYPE type)
228{
229 switch (type) {
230 case NC_ERR_TYPE_TRAN:
231 return "transport";
232 case NC_ERR_TYPE_RPC:
233 return "rpc";
234 case NC_ERR_TYPE_PROT:
235 return "protocol";
236 case NC_ERR_TYPE_APP:
237 return "application";
238 default:
239 break;
240 }
241
242 return NULL;
243}
244
245static NC_ERR_TYPE
246nc_err_str2type(const char *str)
247{
248 if (!strcmp(str, "transport")) {
249 return NC_ERR_TYPE_TRAN;
250 } else if (!strcmp(str, "rpc")) {
251 return NC_ERR_TYPE_RPC;
252 } else if (!strcmp(str, "protocol")) {
253 return NC_ERR_TYPE_PROT;
254 } else if (!strcmp(str, "application")) {
255 return NC_ERR_TYPE_APP;
256 }
257
258 return 0;
259}
260
261API struct lyd_node *
262nc_err(const struct ly_ctx *ctx, NC_ERR tag, ...)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100263{
264 va_list ap;
Michal Vasko77367452021-02-16 16:32:18 +0100265 struct lyd_node *err = NULL;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100266 NC_ERR_TYPE type;
267 const char *arg1, *arg2;
268 uint32_t sid;
269
roman40672412023-05-04 11:10:22 +0200270 NC_CHECK_ARG_RET(NULL, tag, NULL);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100271
Michal Vasko77367452021-02-16 16:32:18 +0100272 /* rpc-error */
273 if (lyd_new_opaq2(NULL, ctx, "rpc-error", NULL, NULL, NC_NS_BASE, &err)) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100274 return NULL;
275 }
276
277 va_start(ap, tag);
278
Michal Vasko77367452021-02-16 16:32:18 +0100279 /* error-type */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100280 switch (tag) {
281 case NC_ERR_IN_USE:
282 case NC_ERR_INVALID_VALUE:
283 case NC_ERR_ACCESS_DENIED:
284 case NC_ERR_ROLLBACK_FAILED:
285 case NC_ERR_OP_NOT_SUPPORTED:
Radek Krejci127f8952016-10-12 14:57:16 +0200286 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko2f923d12016-04-05 11:33:02 +0200287 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200288 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100289 goto fail;
290 }
291 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100292 case NC_ERR_TOO_BIG:
293 case NC_ERR_RES_DENIED:
Michal Vasko77367452021-02-16 16:32:18 +0100294 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100295 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100296 case NC_ERR_MISSING_ATTR:
297 case NC_ERR_BAD_ATTR:
298 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko77367452021-02-16 16:32:18 +0100299 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100300 if (type == NC_ERR_TYPE_TRAN) {
roman40672412023-05-04 11:10:22 +0200301 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100302 goto fail;
303 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100304 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100305 case NC_ERR_MISSING_ELEM:
306 case NC_ERR_BAD_ELEM:
307 case NC_ERR_UNKNOWN_ELEM:
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_PROT) && (type != NC_ERR_TYPE_APP)) {
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_UNKNOWN_NS:
Michal Vasko77367452021-02-16 16:32:18 +0100315 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100316 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
roman40672412023-05-04 11:10:22 +0200317 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100318 goto fail;
319 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100320 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100321 case NC_ERR_LOCK_DENIED:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100322 type = NC_ERR_TYPE_PROT;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100323 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100324 case NC_ERR_DATA_EXISTS:
325 case NC_ERR_DATA_MISSING:
326 type = NC_ERR_TYPE_APP;
327 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100328 case NC_ERR_OP_FAILED:
Michal Vasko77367452021-02-16 16:32:18 +0100329 type = (NC_ERR_TYPE)va_arg(ap, int);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100330 if (type == NC_ERR_TYPE_TRAN) {
roman40672412023-05-04 11:10:22 +0200331 ERRARG(NULL, "type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100332 goto fail;
333 }
334 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100335 case NC_ERR_MALFORMED_MSG:
336 type = NC_ERR_TYPE_RPC;
337 break;
Michal Vasko77367452021-02-16 16:32:18 +0100338 default:
roman40672412023-05-04 11:10:22 +0200339 ERRARG(NULL, "tag");
Michal Vasko77367452021-02-16 16:32:18 +0100340 goto fail;
341 }
342 if (lyd_new_opaq2(err, NULL, "error-type", nc_err_type2str(type), NULL, NC_NS_BASE, NULL)) {
343 goto fail;
344 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100345
Michal Vasko77367452021-02-16 16:32:18 +0100346 /* error-tag */
347 if (lyd_new_opaq2(err, NULL, "error-tag", nc_err_tag2str(tag), NULL, NC_NS_BASE, NULL)) {
348 goto fail;
349 }
350
351 /* error-severity */
352 if (lyd_new_opaq2(err, NULL, "error-severity", "error", NULL, NC_NS_BASE, NULL)) {
353 goto fail;
354 }
355
356 /* error-message */
357 switch (tag) {
358 case NC_ERR_IN_USE:
359 nc_err_set_msg(err, "The request requires a resource that already is in use.", "en");
360 break;
361 case NC_ERR_INVALID_VALUE:
362 nc_err_set_msg(err, "The request specifies an unacceptable value for one or more parameters.", "en");
363 break;
364 case NC_ERR_TOO_BIG:
365 nc_err_set_msg(err, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
366 break;
367 case NC_ERR_MISSING_ATTR:
368 nc_err_set_msg(err, "An expected attribute is missing.", "en");
369 break;
370 case NC_ERR_BAD_ATTR:
371 nc_err_set_msg(err, "An attribute value is not correct.", "en");
372 break;
373 case NC_ERR_UNKNOWN_ATTR:
374 nc_err_set_msg(err, "An unexpected attribute is present.", "en");
375 break;
376 case NC_ERR_MISSING_ELEM:
377 nc_err_set_msg(err, "An expected element is missing.", "en");
378 break;
379 case NC_ERR_BAD_ELEM:
380 nc_err_set_msg(err, "An element value is not correct.", "en");
381 break;
382 case NC_ERR_UNKNOWN_ELEM:
383 nc_err_set_msg(err, "An unexpected element is present.", "en");
384 break;
385 case NC_ERR_UNKNOWN_NS:
386 nc_err_set_msg(err, "An unexpected namespace is present.", "en");
387 break;
388 case NC_ERR_ACCESS_DENIED:
389 nc_err_set_msg(err, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
390 break;
391 case NC_ERR_LOCK_DENIED:
392 nc_err_set_msg(err, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
393 break;
394 case NC_ERR_RES_DENIED:
395 nc_err_set_msg(err, "Request could not be completed because of insufficient resources.", "en");
396 break;
397 case NC_ERR_ROLLBACK_FAILED:
398 nc_err_set_msg(err, "Request to roll back some configuration change was not completed for some reason.", "en");
399 break;
400 case NC_ERR_DATA_EXISTS:
401 nc_err_set_msg(err, "Request could not be completed because the relevant data model content already exists.", "en");
402 break;
403 case NC_ERR_DATA_MISSING:
404 nc_err_set_msg(err, "Request could not be completed because the relevant data model content does not exist.", "en");
405 break;
406 case NC_ERR_OP_NOT_SUPPORTED:
407 nc_err_set_msg(err, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
408 break;
409 case NC_ERR_OP_FAILED:
410 nc_err_set_msg(err, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
411 break;
412 case NC_ERR_MALFORMED_MSG:
413 nc_err_set_msg(err, "A message could not be handled because it failed to be parsed correctly.", "en");
414 break;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100415 default:
roman40672412023-05-04 11:10:22 +0200416 ERRARG(NULL, "tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100417 goto fail;
418 }
419
Michal Vasko77367452021-02-16 16:32:18 +0100420 /* error-info */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100421 switch (tag) {
422 case NC_ERR_IN_USE:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100423 case NC_ERR_INVALID_VALUE:
Michal Vasko77367452021-02-16 16:32:18 +0100424 case NC_ERR_ACCESS_DENIED:
425 case NC_ERR_ROLLBACK_FAILED:
426 case NC_ERR_OP_NOT_SUPPORTED:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100427 case NC_ERR_TOO_BIG:
Michal Vasko77367452021-02-16 16:32:18 +0100428 case NC_ERR_RES_DENIED:
429 case NC_ERR_DATA_EXISTS:
430 case NC_ERR_DATA_MISSING:
431 case NC_ERR_OP_FAILED:
432 case NC_ERR_MALFORMED_MSG:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100433 break;
434 case NC_ERR_MISSING_ATTR:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100435 case NC_ERR_BAD_ATTR:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100436 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko77367452021-02-16 16:32:18 +0100437 arg1 = va_arg(ap, const char *);
438 arg2 = va_arg(ap, const char *);
439
440 nc_err_add_bad_attr(err, arg1);
441 nc_err_add_bad_elem(err, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100442 break;
443 case NC_ERR_MISSING_ELEM:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100444 case NC_ERR_BAD_ELEM:
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100445 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko77367452021-02-16 16:32:18 +0100446 arg1 = va_arg(ap, const char *);
447
448 nc_err_add_bad_elem(err, arg1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100449 break;
450 case NC_ERR_UNKNOWN_NS:
Michal Vasko77367452021-02-16 16:32:18 +0100451 arg1 = va_arg(ap, const char *);
452 arg2 = va_arg(ap, const char *);
453
454 nc_err_add_bad_elem(err, arg1);
455 nc_err_add_bad_ns(err, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100456 break;
457 case NC_ERR_LOCK_DENIED:
Michal Vasko77367452021-02-16 16:32:18 +0100458 sid = va_arg(ap, uint32_t);
459
460 nc_err_set_sid(err, sid);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100461 break;
462 default:
roman40672412023-05-04 11:10:22 +0200463 ERRARG(NULL, "tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100464 goto fail;
465 }
466
467 va_end(ap);
Michal Vasko77367452021-02-16 16:32:18 +0100468 return err;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100469
470fail:
Michal Vasko11d142a2016-01-19 15:58:24 +0100471 va_end(ap);
Michal Vasko77367452021-02-16 16:32:18 +0100472 lyd_free_siblings(err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100473 return NULL;
474}
475
Michal Vasko8f3198f2016-05-04 10:45:28 +0200476API NC_ERR_TYPE
Michal Vasko77367452021-02-16 16:32:18 +0100477nc_err_get_type(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200478{
Michal Vasko77367452021-02-16 16:32:18 +0100479 struct lyd_node *match;
480
roman40672412023-05-04 11:10:22 +0200481 NC_CHECK_ARG_RET(NULL, err, 0);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200482
Michal Vasko77367452021-02-16 16:32:18 +0100483 lyd_find_sibling_opaq_next(lyd_child(err), "error-type", &match);
484 if (match) {
485 return nc_err_str2type(((struct lyd_node_opaq *)match)->value);
486 }
487
488 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200489}
490
491API NC_ERR
Michal Vasko77367452021-02-16 16:32:18 +0100492nc_err_get_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200493{
Michal Vasko77367452021-02-16 16:32:18 +0100494 struct lyd_node *match;
495
roman40672412023-05-04 11:10:22 +0200496 NC_CHECK_ARG_RET(NULL, err, 0);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200497
Michal Vasko77367452021-02-16 16:32:18 +0100498 lyd_find_sibling_opaq_next(lyd_child(err), "error-tag", &match);
499 if (match) {
500 return nc_err_str2tag(((struct lyd_node_opaq *)match)->value);
501 }
502
503 return 0;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200504}
505
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100506API int
Michal Vasko77367452021-02-16 16:32:18 +0100507nc_err_set_app_tag(struct lyd_node *err, const char *error_app_tag)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100508{
Michal Vasko77367452021-02-16 16:32:18 +0100509 struct lyd_node *match;
510
roman40672412023-05-04 11:10:22 +0200511 NC_CHECK_ARG_RET(NULL, err, error_app_tag, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100512
Michal Vasko77367452021-02-16 16:32:18 +0100513 /* remove previous node */
514 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
515 if (match) {
516 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100517 }
Michal Vasko77367452021-02-16 16:32:18 +0100518
519 if (lyd_new_opaq2(err, NULL, "error-app-tag", error_app_tag, NULL, NC_NS_BASE, NULL)) {
520 return -1;
521 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100522
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100523 return 0;
524}
525
Michal Vasko8f3198f2016-05-04 10:45:28 +0200526API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100527nc_err_get_app_tag(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200528{
Michal Vasko77367452021-02-16 16:32:18 +0100529 struct lyd_node *match;
530
roman40672412023-05-04 11:10:22 +0200531 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200532
Michal Vasko77367452021-02-16 16:32:18 +0100533 lyd_find_sibling_opaq_next(lyd_child(err), "error-app-tag", &match);
534 if (match) {
535 return ((struct lyd_node_opaq *)match)->value;
536 }
537
538 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200539}
540
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100541API int
Michal Vasko77367452021-02-16 16:32:18 +0100542nc_err_set_path(struct lyd_node *err, const char *error_path)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100543{
Michal Vasko77367452021-02-16 16:32:18 +0100544 struct lyd_node *match;
545
roman40672412023-05-04 11:10:22 +0200546 NC_CHECK_ARG_RET(NULL, err, error_path, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100547
Michal Vasko77367452021-02-16 16:32:18 +0100548 /* remove previous node */
549 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
550 if (match) {
551 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100552 }
Michal Vasko77367452021-02-16 16:32:18 +0100553
554 if (lyd_new_opaq2(err, NULL, "error-path", error_path, NULL, NC_NS_BASE, NULL)) {
555 return -1;
556 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100557
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100558 return 0;
559}
560
Michal Vasko8f3198f2016-05-04 10:45:28 +0200561API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100562nc_err_get_path(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200563{
Michal Vasko77367452021-02-16 16:32:18 +0100564 struct lyd_node *match;
565
roman40672412023-05-04 11:10:22 +0200566 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200567
Michal Vasko77367452021-02-16 16:32:18 +0100568 lyd_find_sibling_opaq_next(lyd_child(err), "error-path", &match);
569 if (match) {
570 return ((struct lyd_node_opaq *)match)->value;
571 }
572
573 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200574}
575
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100576API int
Michal Vasko77367452021-02-16 16:32:18 +0100577nc_err_set_msg(struct lyd_node *err, const char *error_message, const char *lang)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100578{
Michal Vasko77367452021-02-16 16:32:18 +0100579 struct lyd_node *match;
580 struct lyd_attr *attr;
581
roman40672412023-05-04 11:10:22 +0200582 NC_CHECK_ARG_RET(NULL, err, error_message, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100583
Michal Vasko77367452021-02-16 16:32:18 +0100584 /* remove previous message */
585 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
586 if (match) {
587 lyd_free_tree(match);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100588 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100589
Michal Vasko77367452021-02-16 16:32:18 +0100590 if (lyd_new_opaq2(err, NULL, "error-message", error_message, NULL, NC_NS_BASE, &match)) {
591 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100592 }
Michal Vasko77367452021-02-16 16:32:18 +0100593 if (lang && lyd_new_attr(match, NULL, "xml:lang", lang, &attr)) {
594 lyd_free_tree(match);
595 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100596 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100597
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100598 return 0;
599}
600
Michal Vasko8f3198f2016-05-04 10:45:28 +0200601API const char *
Michal Vasko77367452021-02-16 16:32:18 +0100602nc_err_get_msg(const struct lyd_node *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200603{
Michal Vasko77367452021-02-16 16:32:18 +0100604 struct lyd_node *match;
605
roman40672412023-05-04 11:10:22 +0200606 NC_CHECK_ARG_RET(NULL, err, NULL);
Michal Vasko8f3198f2016-05-04 10:45:28 +0200607
Michal Vasko77367452021-02-16 16:32:18 +0100608 lyd_find_sibling_opaq_next(lyd_child(err), "error-message", &match);
609 if (match) {
610 return ((struct lyd_node_opaq *)match)->value;
611 }
612
613 return NULL;
Michal Vasko8f3198f2016-05-04 10:45:28 +0200614}
615
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100616API int
Michal Vasko77367452021-02-16 16:32:18 +0100617nc_err_set_sid(struct lyd_node *err, uint32_t session_id)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100618{
Michal Vasko77367452021-02-16 16:32:18 +0100619 struct lyd_node *match, *info;
620 char buf[22];
621
roman40672412023-05-04 11:10:22 +0200622 NC_CHECK_ARG_RET(NULL, err, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100623
Michal Vasko77367452021-02-16 16:32:18 +0100624 /* find error-info */
625 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
626 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
627 return -1;
628 }
629
630 /* remove previous node */
631 lyd_find_sibling_opaq_next(lyd_child(info), "session-id", &match);
632 if (match) {
633 lyd_free_tree(match);
634 }
635
636 sprintf(buf, "%" PRIu32, session_id);
637 if (lyd_new_opaq2(info, NULL, "session-id", buf, NULL, NC_NS_BASE, NULL)) {
638 return -1;
639 }
640
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100641 return 0;
642}
643
644API int
Michal Vasko77367452021-02-16 16:32:18 +0100645nc_err_add_bad_attr(struct lyd_node *err, const char *attr_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100646{
Michal Vasko77367452021-02-16 16:32:18 +0100647 struct lyd_node *info;
648
roman40672412023-05-04 11:10:22 +0200649 NC_CHECK_ARG_RET(NULL, err, attr_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100650
Michal Vasko77367452021-02-16 16:32:18 +0100651 /* find error-info */
652 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
653 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100654 return -1;
655 }
Michal Vasko77367452021-02-16 16:32:18 +0100656
657 if (lyd_new_opaq2(info, NULL, "bad-attribute", attr_name, NULL, NC_NS_BASE, NULL)) {
658 return -1;
659 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100660
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100661 return 0;
662}
663
664API int
Michal Vasko77367452021-02-16 16:32:18 +0100665nc_err_add_bad_elem(struct lyd_node *err, const char *elem_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100666{
Michal Vasko77367452021-02-16 16:32:18 +0100667 struct lyd_node *info;
668
roman40672412023-05-04 11:10:22 +0200669 NC_CHECK_ARG_RET(NULL, err, elem_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100670
Michal Vasko77367452021-02-16 16:32:18 +0100671 /* find error-info */
672 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
673 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100674 return -1;
675 }
Michal Vasko77367452021-02-16 16:32:18 +0100676
677 if (lyd_new_opaq2(info, NULL, "bad-element", elem_name, NULL, NC_NS_BASE, NULL)) {
678 return -1;
679 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100680
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100681 return 0;
682}
683
684API int
Michal Vasko77367452021-02-16 16:32:18 +0100685nc_err_add_bad_ns(struct lyd_node *err, const char *ns_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100686{
Michal Vasko77367452021-02-16 16:32:18 +0100687 struct lyd_node *info;
688
roman40672412023-05-04 11:10:22 +0200689 NC_CHECK_ARG_RET(NULL, err, ns_name, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100690
Michal Vasko77367452021-02-16 16:32:18 +0100691 /* find error-info */
692 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
693 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100694 return -1;
695 }
Michal Vasko77367452021-02-16 16:32:18 +0100696
697 if (lyd_new_opaq2(info, NULL, "bad-namespace", ns_name, NULL, NC_NS_BASE, NULL)) {
698 return -1;
699 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100700
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100701 return 0;
702}
703
704API int
Michal Vasko77367452021-02-16 16:32:18 +0100705nc_err_add_info_other(struct lyd_node *err, struct lyd_node *other)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100706{
Michal Vasko77367452021-02-16 16:32:18 +0100707 struct lyd_node *info;
708
roman40672412023-05-04 11:10:22 +0200709 NC_CHECK_ARG_RET(NULL, err, other, -1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100710
Michal Vasko77367452021-02-16 16:32:18 +0100711 /* find error-info */
712 lyd_find_sibling_opaq_next(lyd_child(err), "error-info", &info);
713 if (!info && lyd_new_opaq2(err, NULL, "error-info", NULL, NULL, NC_NS_BASE, &info)) {
Michal Vasko4eb3c312016-03-01 14:09:37 +0100714 return -1;
715 }
Michal Vasko77367452021-02-16 16:32:18 +0100716
717 lyd_insert_child(info, other);
718
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100719 return 0;
720}
721
722void
Michal Vasko77367452021-02-16 16:32:18 +0100723nc_server_rpc_free(struct nc_server_rpc *rpc)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100724{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100725 if (!rpc) {
726 return;
727 }
728
Michal Vasko77367452021-02-16 16:32:18 +0100729 lyd_free_tree(rpc->envp);
Michal Vaskod5bfc482021-10-26 10:47:54 +0200730
731 /* may be action */
732 lyd_free_all(rpc->rpc);
Michal Vasko11d142a2016-01-19 15:58:24 +0100733
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100734 free(rpc);
735}
736
737API void
738nc_server_reply_free(struct nc_server_reply *reply)
739{
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100740 struct nc_server_reply_data *data_rpl;
741 struct nc_server_reply_error *error_rpl;
742
743 if (!reply) {
744 return;
745 }
746
747 switch (reply->type) {
748 case NC_RPL_DATA:
749 data_rpl = (struct nc_server_reply_data *)reply;
750 if (data_rpl->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100751 lyd_free_siblings(data_rpl->data);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100752 }
753 break;
754 case NC_RPL_OK:
755 /* nothing to free */
756 break;
757 case NC_RPL_ERROR:
758 error_rpl = (struct nc_server_reply_error *)reply;
Michal Vasko77367452021-02-16 16:32:18 +0100759 lyd_free_siblings(error_rpl->err);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100760 break;
761 default:
762 break;
763 }
764 free(reply);
765}
766
Radek Krejci93e80222016-10-03 13:34:25 +0200767API struct nc_server_notif *
Michal Vasko77367452021-02-16 16:32:18 +0100768nc_server_notif_new(struct lyd_node *event, char *eventtime, NC_PARAMTYPE paramtype)
Radek Krejci93e80222016-10-03 13:34:25 +0200769{
770 struct nc_server_notif *ntf;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100771 struct lyd_node *elem;
Michal Vasko77367452021-02-16 16:32:18 +0100772 int found;
Radek Krejci93e80222016-10-03 13:34:25 +0200773
roman40672412023-05-04 11:10:22 +0200774 NC_CHECK_ARG_RET(NULL, event, eventtime, NULL);
Radek Krejci93e80222016-10-03 13:34:25 +0200775
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100776 /* check that there is a notification */
Michal Vasko77367452021-02-16 16:32:18 +0100777 found = 0;
778 LYD_TREE_DFS_BEGIN(event, elem) {
779 if (elem->schema->nodetype == LYS_NOTIF) {
780 found = 1;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100781 break;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100782 }
Michal Vasko77367452021-02-16 16:32:18 +0100783 LYD_TREE_DFS_END(event, elem);
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100784 }
Michal Vasko77367452021-02-16 16:32:18 +0100785 if (!found) {
roman40672412023-05-04 11:10:22 +0200786 ERRARG(NULL, "event");
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100787 return NULL;
788 }
789
Radek Krejci93e80222016-10-03 13:34:25 +0200790 ntf = malloc(sizeof *ntf);
roman3a95bb22023-10-26 11:07:17 +0200791 NC_CHECK_ERRMEM_RET(!ntf, NULL);
Michal Vasko25e244b2022-12-14 14:19:59 +0100792
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100793 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Radek Krejci93e80222016-10-03 13:34:25 +0200794 ntf->eventtime = strdup(eventtime);
Michal Vasko77367452021-02-16 16:32:18 +0100795 if (lyd_dup_single(event, NULL, LYD_DUP_RECURSIVE, &ntf->ntf)) {
796 free(ntf);
797 return NULL;
798 }
Radek Krejci93e80222016-10-03 13:34:25 +0200799 } else {
800 ntf->eventtime = eventtime;
Michal Vasko77367452021-02-16 16:32:18 +0100801 ntf->ntf = event;
Radek Krejci93e80222016-10-03 13:34:25 +0200802 }
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100803 ntf->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
Radek Krejci93e80222016-10-03 13:34:25 +0200804
805 return ntf;
806}
807
808API void
809nc_server_notif_free(struct nc_server_notif *notif)
810{
811 if (!notif) {
812 return;
813 }
814
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100815 if (notif->free) {
Michal Vasko77367452021-02-16 16:32:18 +0100816 lyd_free_tree(notif->ntf);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100817 free(notif->eventtime);
818 }
Radek Krejci93e80222016-10-03 13:34:25 +0200819 free(notif);
820}
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100821
822API const char *
823nc_server_notif_get_time(const struct nc_server_notif *notif)
824{
roman40672412023-05-04 11:10:22 +0200825 NC_CHECK_ARG_RET(NULL, notif, NULL);
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100826
827 return notif->eventtime;
828}