blob: 98d917ac1fab47186c71d531d40a1cd4dccde331 [file] [log] [blame]
Michal Vasko7bcb48e2016-01-15 10:28:54 +01001/**
2 * \file messages_server.c
3 * \author Michal Vasko <mvasko@cesnet.cz>
4 * \brief libnetconf2 - server NETCONF messages functions
5 *
6 * Copyright (c) 2015 CESNET, z.s.p.o.
7 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +01008 * This source code is licensed under BSD 3-Clause License (the "License").
9 * You may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
Michal Vaskoafd416b2016-02-25 14:51:46 +010011 *
Radek Krejci9b81f5b2016-02-24 13:14:49 +010012 * https://opensource.org/licenses/BSD-3-Clause
Michal Vasko7bcb48e2016-01-15 10:28:54 +010013 */
14
15#include <ctype.h>
16#include <stdlib.h>
17#include <string.h>
18#include <stdarg.h>
Andrew Langefeldbbab76f2018-08-10 15:54:59 -050019#include <stdbool.h>
Michal Vasko7bcb48e2016-01-15 10:28:54 +010020
21#include <libyang/libyang.h>
22
23#include "libnetconf.h"
Radek Krejci93e80222016-10-03 13:34:25 +020024#include "session_server.h"
Michal Vasko1a38c862016-01-15 15:50:07 +010025
26extern struct nc_server_opts server_opts;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010027
28API struct nc_server_reply *
29nc_server_reply_ok(void)
30{
31 struct nc_server_reply *ret;
32
33 ret = malloc(sizeof *ret);
34 if (!ret) {
35 ERRMEM;
36 return NULL;
37 }
38
39 ret->type = NC_RPL_OK;
40 return ret;
41}
42
43API struct nc_server_reply *
Radek Krejci36dfdb32016-09-01 16:56:35 +020044nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtype)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010045{
46 struct nc_server_reply_data *ret;
47
Michal Vaskob08743b2016-04-13 14:23:49 +020048 if (!data) {
49 ERRARG("data");
50 return NULL;
51 }
52
Michal Vasko7bcb48e2016-01-15 10:28:54 +010053 ret = malloc(sizeof *ret);
54 if (!ret) {
55 ERRMEM;
56 return NULL;
57 }
58
59 ret->type = NC_RPL_DATA;
Radek Krejci36dfdb32016-09-01 16:56:35 +020060 ret->wd = wd;
Michal Vaskob08743b2016-04-13 14:23:49 +020061 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +010062 ret->data = lyd_dup(data, 1);
63 } else {
64 ret->data = data;
65 }
66 if (paramtype != NC_PARAMTYPE_CONST) {
67 ret->free = 1;
68 } else {
69 ret->free = 0;
70 }
71 return (struct nc_server_reply *)ret;
72}
73
74API struct nc_server_reply *
Michal Vasko1a38c862016-01-15 15:50:07 +010075nc_server_reply_err(struct nc_server_error *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010076{
77 struct nc_server_reply_error *ret;
78
Michal Vasko1a38c862016-01-15 15:50:07 +010079 if (!err) {
Michal Vasko45e53ae2016-04-07 11:46:03 +020080 ERRARG("err");
Michal Vasko7bcb48e2016-01-15 10:28:54 +010081 return NULL;
82 }
83
84 ret = malloc(sizeof *ret);
85 if (!ret) {
86 ERRMEM;
87 return NULL;
88 }
89
90 ret->type = NC_RPL_ERROR;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010091 ret->err = malloc(sizeof *ret->err);
Michal Vasko4eb3c312016-03-01 14:09:37 +010092 if (!ret->err) {
93 ERRMEM;
94 free(ret);
95 return NULL;
96 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +010097 ret->err[0] = err;
98 ret->count = 1;
99 return (struct nc_server_reply *)ret;
100}
101
102API int
103nc_server_reply_add_err(struct nc_server_reply *reply, struct nc_server_error *err)
104{
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;
116 ++err_rpl->count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100117 err_rpl->err = nc_realloc(err_rpl->err, err_rpl->count * sizeof *err_rpl->err);
118 if (!err_rpl->err) {
119 ERRMEM;
120 return -1;
121 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100122 err_rpl->err[err_rpl->count - 1] = err;
123 return 0;
124}
125
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100126API const struct nc_server_error *
127nc_server_reply_get_last_err(const struct nc_server_reply *reply)
128{
129 struct nc_server_reply_error *err_rpl;
130
131 if (!reply || (reply->type != NC_RPL_ERROR)) {
132 ERRARG("reply");
133 return NULL;
134 }
135
136 err_rpl = (struct nc_server_reply_error *)reply;
137 if (!err_rpl->count) {
138 return NULL;
139 }
140 return err_rpl->err[err_rpl->count - 1];
141}
142
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100143API struct nc_server_error *
Radek Krejci127f8952016-10-12 14:57:16 +0200144nc_err(int tag, ...)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100145{
146 va_list ap;
147 struct nc_server_error *ret;
148 NC_ERR_TYPE type;
149 const char *arg1, *arg2;
150 uint32_t sid;
151
Michal Vasko1a38c862016-01-15 15:50:07 +0100152 if (!tag) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200153 ERRARG("tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100154 return NULL;
155 }
156
157 ret = calloc(1, sizeof *ret);
158 if (!ret) {
159 ERRMEM;
160 return NULL;
161 }
Michal Vasko90920b02016-05-20 14:07:00 +0200162 ret->sid = -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100163
164 va_start(ap, tag);
165
166 switch (tag) {
167 case NC_ERR_IN_USE:
168 case NC_ERR_INVALID_VALUE:
169 case NC_ERR_ACCESS_DENIED:
170 case NC_ERR_ROLLBACK_FAILED:
171 case NC_ERR_OP_NOT_SUPPORTED:
Radek Krejci127f8952016-10-12 14:57:16 +0200172 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko2f923d12016-04-05 11:33:02 +0200173 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200174 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100175 goto fail;
176 }
177 break;
178
179 case NC_ERR_TOO_BIG:
180 case NC_ERR_RES_DENIED:
Radek Krejci127f8952016-10-12 14:57:16 +0200181 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100182 /* nothing to check */
183 break;
184
185 case NC_ERR_MISSING_ATTR:
186 case NC_ERR_BAD_ATTR:
187 case NC_ERR_UNKNOWN_ATTR:
Radek Krejci127f8952016-10-12 14:57:16 +0200188 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100189 arg1 = va_arg(ap, const char *);
190 arg2 = va_arg(ap, const char *);
191
192 if (type == NC_ERR_TYPE_TRAN) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200193 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100194 goto fail;
195 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100196 nc_err_add_bad_attr(ret, arg1);
197 nc_err_add_bad_elem(ret, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100198 break;
199
200 case NC_ERR_MISSING_ELEM:
201 case NC_ERR_BAD_ELEM:
202 case NC_ERR_UNKNOWN_ELEM:
Radek Krejci127f8952016-10-12 14:57:16 +0200203 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100204 arg1 = va_arg(ap, const char *);
205
206 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200207 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100208 goto fail;
209 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100210 nc_err_add_bad_elem(ret, arg1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100211 break;
212
213 case NC_ERR_UNKNOWN_NS:
Radek Krejci127f8952016-10-12 14:57:16 +0200214 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100215 arg1 = va_arg(ap, const char *);
216 arg2 = va_arg(ap, const char *);
217
218 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200219 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100220 goto fail;
221 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100222 nc_err_add_bad_elem(ret, arg1);
223 nc_err_add_bad_ns(ret, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100224 break;
225
226 case NC_ERR_LOCK_DENIED:
227 sid = va_arg(ap, uint32_t);
228
229 type = NC_ERR_TYPE_PROT;
230 nc_err_set_sid(ret, sid);
231 break;
232
233 case NC_ERR_DATA_EXISTS:
234 case NC_ERR_DATA_MISSING:
235 type = NC_ERR_TYPE_APP;
236 break;
237
238 case NC_ERR_OP_FAILED:
Radek Krejci127f8952016-10-12 14:57:16 +0200239 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100240
241 if (type == NC_ERR_TYPE_TRAN) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200242 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100243 goto fail;
244 }
245 break;
246
247 case NC_ERR_MALFORMED_MSG:
248 type = NC_ERR_TYPE_RPC;
249 break;
250
251 default:
Michal Vasko45e53ae2016-04-07 11:46:03 +0200252 ERRARG("tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100253 goto fail;
254 }
255
256 switch (tag) {
257 case NC_ERR_IN_USE:
Michal Vasko1a38c862016-01-15 15:50:07 +0100258 nc_err_set_msg(ret, "The request requires a resource that already is in use.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100259 break;
260 case NC_ERR_INVALID_VALUE:
Michal Vasko1a38c862016-01-15 15:50:07 +0100261 nc_err_set_msg(ret, "The request specifies an unacceptable value for one or more parameters.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100262 break;
263 case NC_ERR_TOO_BIG:
Michal Vasko1a38c862016-01-15 15:50:07 +0100264 nc_err_set_msg(ret, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100265 break;
266 case NC_ERR_MISSING_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100267 nc_err_set_msg(ret, "An expected attribute is missing.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100268 break;
269 case NC_ERR_BAD_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100270 nc_err_set_msg(ret, "An attribute value is not correct.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100271 break;
272 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100273 nc_err_set_msg(ret, "An unexpected attribute is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100274 break;
275 case NC_ERR_MISSING_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100276 nc_err_set_msg(ret, "An expected element is missing.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100277 break;
278 case NC_ERR_BAD_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100279 nc_err_set_msg(ret, "An element value is not correct.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100280 break;
281 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100282 nc_err_set_msg(ret, "An unexpected element is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100283 break;
284 case NC_ERR_UNKNOWN_NS:
Michal Vasko1a38c862016-01-15 15:50:07 +0100285 nc_err_set_msg(ret, "An unexpected namespace is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100286 break;
287 case NC_ERR_ACCESS_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100288 nc_err_set_msg(ret, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100289 break;
290 case NC_ERR_LOCK_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100291 nc_err_set_msg(ret, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100292 break;
293 case NC_ERR_RES_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100294 nc_err_set_msg(ret, "Request could not be completed because of insufficient resources.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100295 break;
296 case NC_ERR_ROLLBACK_FAILED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100297 nc_err_set_msg(ret, "Request to roll back some configuration change was not completed for some reason.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100298 break;
299 case NC_ERR_DATA_EXISTS:
Michal Vasko1a38c862016-01-15 15:50:07 +0100300 nc_err_set_msg(ret, "Request could not be completed because the relevant data model content already exists.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100301 break;
302 case NC_ERR_DATA_MISSING:
Michal Vasko1a38c862016-01-15 15:50:07 +0100303 nc_err_set_msg(ret, "Request could not be completed because the relevant data model content does not exist.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100304 break;
305 case NC_ERR_OP_NOT_SUPPORTED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100306 nc_err_set_msg(ret, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100307 break;
308 case NC_ERR_OP_FAILED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100309 nc_err_set_msg(ret, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100310 break;
311 case NC_ERR_MALFORMED_MSG:
Michal Vasko1a38c862016-01-15 15:50:07 +0100312 nc_err_set_msg(ret, "A message could not be handled because it failed to be parsed correctly.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100313 break;
314 default:
Michal Vasko45e53ae2016-04-07 11:46:03 +0200315 ERRARG("tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100316 goto fail;
317 }
318
319 va_end(ap);
320
321 ret->type = type;
322 ret->tag = tag;
323 return ret;
324
325fail:
Michal Vasko11d142a2016-01-19 15:58:24 +0100326 va_end(ap);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100327 free(ret);
328 return NULL;
329}
330
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200331static struct lyxml_elem *
332nc_err_libyang_other_elem(const char *name, const char *content, int cont_len)
333{
334 struct lyxml_elem *root = NULL;
335 struct lyxml_ns *ns;
336
337 root = calloc(1, sizeof *root);
338 if (!root) {
339 ERRMEM;
340 goto error;
341 }
342 root->prev = root;
343 root->name = lydict_insert(server_opts.ctx, name, 0);
344 root->content = lydict_insert(server_opts.ctx, content, cont_len);
345
346 ns = calloc(1, sizeof *root->ns);
347 if (!ns) {
348 ERRMEM;
349 goto error;
350 }
351 root->attr = (struct lyxml_attr *)ns;
352 ns->type = LYXML_ATTR_NS;
353 ns->parent = root;
354 ns->value = lydict_insert(server_opts.ctx, "urn:ietf:params:xml:ns:yang:1", 0);
355 root->ns = ns;
356
357 return root;
358
359error:
360 lyxml_free(server_opts.ctx, root);
361 return NULL;
362}
363
Radek Krejci877e1822016-04-06 16:37:43 +0200364API struct nc_server_error *
Michal Vaskoc9970242018-02-14 16:03:35 +0100365nc_err_libyang(struct ly_ctx *ctx)
Radek Krejci877e1822016-04-06 16:37:43 +0200366{
367 struct nc_server_error *e;
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200368 struct lyxml_elem *elem;
369 const char *str, *stri, *strj, *strk, *strl, *uniqi, *uniqj;
370 char *attr, *path;
371 int len;
Radek Krejci877e1822016-04-06 16:37:43 +0200372
373 if (!ly_errno) {
374 /* LY_SUCCESS */
375 return NULL;
376 } else if (ly_errno == LY_EVALID) {
Michal Vaskoc9970242018-02-14 16:03:35 +0100377 switch (ly_vecode(ctx)) {
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200378 /* RFC 6020 section 13 errors */
379 case LYVE_NOUNIQ:
380 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
381 nc_err_set_app_tag(e, "data-not-unique");
Michal Vaskoc9970242018-02-14 16:03:35 +0100382 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200383
384 /* parse the message and get all the information we need */
Michal Vaskoc9970242018-02-14 16:03:35 +0100385 str = ly_errmsg(ctx);
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200386 uniqi = strchr(str, '"');
387 uniqi++;
388 uniqj = strchr(uniqi, '"');
389
390 stri = strchr(uniqj + 1, '"');
391 stri++;
392 strj = strchr(stri, '"');
393
394 strk = strchr(strj + 1, '"');
395 ++strk;
396 strl = strchr(strk, '"');
397
398 /* maximum length is the whole unique string with the longer list instance identifier */
399 len = (uniqj - uniqi) + (strj - stri > strl - strk ? strj - stri : strl - strk);
400 path = malloc(len + 1);
401 if (!path) {
402 ERRMEM;
403 return e;
404 }
405
406 /* create non-unique elements, one in 1st list, one in 2nd list, for each unique list */
407 while (1) {
408 uniqj = strpbrk(uniqi, " \"");
409
410 len = sprintf(path, "%.*s/%.*s", (int)(strj - stri), stri, (int)(uniqj - uniqi), uniqi);
411 elem = nc_err_libyang_other_elem("non-unique", path, len);
412 if (!elem) {
413 free(path);
414 return e;
415 }
416 nc_err_add_info_other(e, elem);
417
418 len = sprintf(path, "%.*s/%.*s", (int)(strl - strk), strk, (int)(uniqj - uniqi), uniqi);
419 elem = nc_err_libyang_other_elem("non-unique", path, len);
420 if (!elem) {
421 return e;
422 }
423 nc_err_add_info_other(e, elem);
424
425 if (uniqj[0] == '"') {
426 break;
427 }
428 uniqi = uniqj + 1;
429 }
430 free(path);
431 break;
432 case LYVE_NOMAX:
433 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
434 nc_err_set_app_tag(e, "too-many-elements");
Michal Vaskoc9970242018-02-14 16:03:35 +0100435 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200436 break;
437 case LYVE_NOMIN:
438 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
439 nc_err_set_app_tag(e, "too-few-elements");
Michal Vaskoc9970242018-02-14 16:03:35 +0100440 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200441 break;
442 case LYVE_NOMUST:
443 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
Michal Vaskoc9970242018-02-14 16:03:35 +0100444 if (ly_errapptag(ctx)) {
445 nc_err_set_app_tag(e, ly_errapptag(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200446 } else {
447 nc_err_set_app_tag(e, "must-violation");
448 }
Michal Vasko591db0d2019-03-26 08:39:48 +0100449 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200450 break;
451 case LYVE_NOREQINS:
452 case LYVE_NOLEAFREF:
453 e = nc_err(NC_ERR_DATA_MISSING);
454 nc_err_set_app_tag(e, "instance-required");
Michal Vaskoc9970242018-02-14 16:03:35 +0100455 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200456 break;
457 case LYVE_NOMANDCHOICE:
458 e = nc_err(NC_ERR_DATA_MISSING);
459 nc_err_set_app_tag(e, "missing-choice");
Michal Vaskoc9970242018-02-14 16:03:35 +0100460 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200461
Michal Vaskoc9970242018-02-14 16:03:35 +0100462 str = ly_errmsg(ctx);
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200463 stri = strchr(str, '"');
464 stri++;
465 strj = strchr(stri, '"');
466 elem = nc_err_libyang_other_elem("missing-choice", stri, strj - stri);
467 if (elem) {
468 nc_err_add_info_other(e, elem);
469 }
470 break;
Radek Krejci877e1822016-04-06 16:37:43 +0200471 case LYVE_INELEM:
Michal Vaskoc9970242018-02-14 16:03:35 +0100472 str = ly_errpath(ctx);
Michal Vasko6d8a9722020-02-10 14:56:40 +0100473 if (!str || !strcmp(str, "/")) {
Radek Krejci877e1822016-04-06 16:37:43 +0200474 e = nc_err(NC_ERR_OP_NOT_SUPPORTED, NC_ERR_TYPE_APP);
475 /* keep default message */
476 return e;
477 } else {
Michal Vaskoc9970242018-02-14 16:03:35 +0100478 e = nc_err(NC_ERR_UNKNOWN_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200479 }
480 break;
481 case LYVE_MISSELEM:
482 case LYVE_INORDER:
Michal Vaskoc9970242018-02-14 16:03:35 +0100483 e = nc_err(NC_ERR_MISSING_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200484 break;
485 case LYVE_INVAL:
Michal Vaskoc9970242018-02-14 16:03:35 +0100486 e = nc_err(NC_ERR_BAD_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200487 break;
488 case LYVE_INATTR:
489 case LYVE_MISSATTR:
Michal Vasko37fdad52017-03-02 11:40:22 +0100490 case LYVE_INMETA:
Michal Vaskoc9970242018-02-14 16:03:35 +0100491 str = ly_errmsg(ctx);
Radek Krejci877e1822016-04-06 16:37:43 +0200492 stri = strchr(str, '"');
493 stri++;
Michal Vasko11a0c4f2018-01-03 14:29:06 +0100494 if (!strncmp(stri, "<none>:", 7)) {
495 stri += 7;
496 }
Radek Krejci877e1822016-04-06 16:37:43 +0200497 strj = strchr(stri, '"');
498 strj--;
Michal Vasko630485f2018-01-03 14:28:32 +0100499 attr = strndup(stri, (strj - stri) + 1);
Michal Vaskoc9970242018-02-14 16:03:35 +0100500 if (ly_vecode(ctx) == LYVE_INATTR) {
501 e = nc_err(NC_ERR_UNKNOWN_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
502 } else if (ly_vecode(ctx) == LYVE_MISSATTR) {
503 e = nc_err(NC_ERR_MISSING_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
Michal Vasko37fdad52017-03-02 11:40:22 +0100504 } else { /* LYVE_INMETA */
Michal Vaskoc9970242018-02-14 16:03:35 +0100505 e = nc_err(NC_ERR_BAD_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
Radek Krejci537fb522016-04-07 16:36:25 +0200506 }
Radek Krejci877e1822016-04-06 16:37:43 +0200507 free(attr);
508 break;
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200509 case LYVE_NOCONSTR:
510 case LYVE_NOWHEN:
Radek Krejci877e1822016-04-06 16:37:43 +0200511 e = nc_err(NC_ERR_INVALID_VALUE, NC_ERR_TYPE_PROT);
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200512 /* LYVE_NOCONSTR (length, range, pattern) can have a specific error-app-tag */
Michal Vaskoc9970242018-02-14 16:03:35 +0100513 if (ly_errapptag(ctx)) {
514 nc_err_set_app_tag(e, ly_errapptag(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200515 }
Michal Vasko591db0d2019-03-26 08:39:48 +0100516 nc_err_set_path(e, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200517 break;
518 default:
519 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
520 break;
521 }
522 } else {
523 /* non-validation (internal) error */
524 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
525 }
Michal Vaskoc9970242018-02-14 16:03:35 +0100526 nc_err_set_msg(e, ly_errmsg(ctx), "en");
Radek Krejci877e1822016-04-06 16:37:43 +0200527 return e;
528}
529
Michal Vasko8f3198f2016-05-04 10:45:28 +0200530API NC_ERR_TYPE
Michal Vaskoea201782017-03-16 09:49:54 +0100531nc_err_get_type(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200532{
533 if (!err) {
534 ERRARG("err");
535 return 0;
536 }
537
538 return err->type;
539}
540
541API NC_ERR
Michal Vaskoea201782017-03-16 09:49:54 +0100542nc_err_get_tag(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200543{
544 if (!err) {
545 ERRARG("err");
546 return 0;
547 }
548
549 return err->tag;
550}
551
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100552API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100553nc_err_set_app_tag(struct nc_server_error *err, const char *error_app_tag)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100554{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200555 if (!err) {
556 ERRARG("err");
557 return -1;
558 } else if (!error_app_tag) {
559 ERRARG("error_app_tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100560 return -1;
561 }
562
563 if (err->apptag) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100564 lydict_remove(server_opts.ctx, err->apptag);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100565 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100566 err->apptag = lydict_insert(server_opts.ctx, error_app_tag, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100567
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100568 return 0;
569}
570
Michal Vasko8f3198f2016-05-04 10:45:28 +0200571API const char *
Michal Vaskoea201782017-03-16 09:49:54 +0100572nc_err_get_app_tag(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200573{
574 if (!err) {
575 ERRARG("err");
576 return NULL;
577 }
578
579 return err->apptag;
580}
581
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100582API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100583nc_err_set_path(struct nc_server_error *err, const char *error_path)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100584{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200585 if (!err) {
586 ERRARG("err");
587 return -1;
588 } else if (!error_path) {
589 ERRARG("error_path");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100590 return -1;
591 }
592
593 if (err->path) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100594 lydict_remove(server_opts.ctx, err->path);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100595 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100596 err->path = lydict_insert(server_opts.ctx, error_path, 0);
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 Vaskoea201782017-03-16 09:49:54 +0100602nc_err_get_path(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200603{
604 if (!err) {
605 ERRARG("err");
606 return 0;
607 }
608
609 return err->path;
610}
611
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100612API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100613nc_err_set_msg(struct nc_server_error *err, const char *error_message, const char *lang)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100614{
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
623 if (err->message) {
Michal Vasko092ea742016-04-12 15:08:59 +0200624 lydict_remove(server_opts.ctx, err->message);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100625 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100626 err->message = lydict_insert(server_opts.ctx, error_message, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100627
628 if (err->message_lang) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100629 lydict_remove(server_opts.ctx, err->message_lang);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100630 }
631 if (lang) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100632 err->message_lang = lydict_insert(server_opts.ctx, lang, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100633 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100634
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100635 return 0;
636}
637
Michal Vasko8f3198f2016-05-04 10:45:28 +0200638API const char *
Michal Vaskoea201782017-03-16 09:49:54 +0100639nc_err_get_msg(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200640{
641 if (!err) {
642 ERRARG("err");
643 return 0;
644 }
645
646 return err->message;
647}
648
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100649API int
650nc_err_set_sid(struct nc_server_error *err, uint32_t session_id)
651{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200652 if (!err) {
653 ERRARG("err");
654 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100655 }
656
657 err->sid = session_id;
658 return 0;
659}
660
661API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100662nc_err_add_bad_attr(struct nc_server_error *err, const char *attr_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100663{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200664 if (!err) {
665 ERRARG("err");
666 return -1;
667 } else if (!attr_name) {
668 ERRARG("attr_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100669 return -1;
670 }
671
672 ++err->attr_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100673 err->attr = nc_realloc(err->attr, err->attr_count * sizeof *err->attr);
674 if (!err->attr) {
675 ERRMEM;
676 return -1;
677 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100678 err->attr[err->attr_count - 1] = lydict_insert(server_opts.ctx, attr_name, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100679
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100680 return 0;
681}
682
683API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100684nc_err_add_bad_elem(struct nc_server_error *err, const char *elem_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100685{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200686 if (!err) {
687 ERRARG("err");
688 return -1;
689 } else if (!elem_name) {
690 ERRARG("elem_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100691 return -1;
692 }
693
694 ++err->elem_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100695 err->elem = nc_realloc(err->elem, err->elem_count * sizeof *err->elem);
696 if (!err->elem) {
697 ERRMEM;
698 return -1;
699 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100700 err->elem[err->elem_count - 1] = lydict_insert(server_opts.ctx, elem_name, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100701
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100702 return 0;
703}
704
705API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100706nc_err_add_bad_ns(struct nc_server_error *err, const char *ns_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100707{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200708 if (!err) {
709 ERRARG("err");
710 return -1;
711 } else if (!ns_name) {
712 ERRARG("ns_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100713 return -1;
714 }
715
716 ++err->ns_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100717 err->ns = nc_realloc(err->ns, err->ns_count * sizeof *err->ns);
718 if (!err->ns) {
719 ERRMEM;
720 return -1;
721 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100722 err->ns[err->ns_count - 1] = lydict_insert(server_opts.ctx, ns_name, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100723
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100724 return 0;
725}
726
727API int
728nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other)
729{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200730 if (!err) {
731 ERRARG("err");
732 return -1;
733 } else if (!other) {
734 ERRARG("other");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100735 return -1;
736 }
737
738 ++err->other_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100739 err->other = nc_realloc(err->other, err->other_count * sizeof *err->other);
740 if (!err->other) {
741 ERRMEM;
742 return -1;
743 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100744 err->other[err->other_count - 1] = other;
745 return 0;
746}
747
748void
Michal Vaskoca4a2422016-02-02 12:17:14 +0100749nc_server_rpc_free(struct nc_server_rpc *rpc, struct ly_ctx *ctx)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100750{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100751 if (!rpc) {
752 return;
753 }
754
Michal Vaskoca4a2422016-02-02 12:17:14 +0100755 lyxml_free(ctx, rpc->root);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100756 lyd_free(rpc->tree);
Michal Vasko11d142a2016-01-19 15:58:24 +0100757
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100758 free(rpc);
759}
760
761API void
762nc_server_reply_free(struct nc_server_reply *reply)
763{
764 uint32_t i;
765 struct nc_server_reply_data *data_rpl;
766 struct nc_server_reply_error *error_rpl;
767
768 if (!reply) {
769 return;
770 }
771
772 switch (reply->type) {
773 case NC_RPL_DATA:
774 data_rpl = (struct nc_server_reply_data *)reply;
775 if (data_rpl->free) {
776 lyd_free_withsiblings(data_rpl->data);
777 }
778 break;
779 case NC_RPL_OK:
780 /* nothing to free */
781 break;
782 case NC_RPL_ERROR:
783 error_rpl = (struct nc_server_reply_error *)reply;
784 for (i = 0; i < error_rpl->count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100785 nc_err_free(error_rpl->err[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100786 }
787 free(error_rpl->err);
788 break;
789 default:
790 break;
791 }
792 free(reply);
793}
794
795API void
Michal Vasko1a38c862016-01-15 15:50:07 +0100796nc_err_free(struct nc_server_error *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100797{
798 uint32_t i;
799
800 if (!err) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100801 return;
802 }
803
Michal Vasko1a38c862016-01-15 15:50:07 +0100804 lydict_remove(server_opts.ctx, err->apptag);
805 lydict_remove(server_opts.ctx, err->path);
806 lydict_remove(server_opts.ctx, err->message);
807 lydict_remove(server_opts.ctx, err->message_lang);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100808 for (i = 0; i < err->attr_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100809 lydict_remove(server_opts.ctx, err->attr[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100810 }
811 free(err->attr);
812 for (i = 0; i < err->elem_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100813 lydict_remove(server_opts.ctx, err->elem[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100814 }
815 free(err->elem);
816 for (i = 0; i < err->ns_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100817 lydict_remove(server_opts.ctx, err->ns[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100818 }
819 free(err->ns);
820 for (i = 0; i < err->other_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100821 lyxml_free(server_opts.ctx, err->other[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100822 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100823 free(err->other);
824 free(err);
825}
Radek Krejci93e80222016-10-03 13:34:25 +0200826
827API struct nc_server_notif *
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100828nc_server_notif_new(struct lyd_node* event, char *eventtime, NC_PARAMTYPE paramtype)
Radek Krejci93e80222016-10-03 13:34:25 +0200829{
830 struct nc_server_notif *ntf;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100831 struct lyd_node *elem;
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500832 bool found_notif = false;
Radek Krejci93e80222016-10-03 13:34:25 +0200833
Michal Vasko3106b7b2018-01-04 10:32:42 +0100834 if (!event) {
Radek Krejci93e80222016-10-03 13:34:25 +0200835 ERRARG("event");
836 return NULL;
837 } else if (!eventtime) {
838 ERRARG("eventtime");
839 return NULL;
840 }
841
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100842 /* check that there is a notification */
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500843 for (elem = event; elem && !found_notif; elem = elem->child) {
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100844next_node:
845 switch (elem->schema->nodetype) {
846 case LYS_LEAF:
847 /* key, skip it */
848 elem = elem->next;
849 if (!elem) {
850 /* error */
Michal Vasko93ab6172018-02-16 15:58:12 +0100851 ERRARG("event");
852 return NULL;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100853 }
854 goto next_node;
855 case LYS_CONTAINER:
856 case LYS_LIST:
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100857 /* ok */
858 break;
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500859 case LYS_NOTIF:
860 found_notif = true;
861 break;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100862 default:
863 /* error */
Michal Vasko93ab6172018-02-16 15:58:12 +0100864 ERRARG("event");
865 return NULL;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100866 }
867 }
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500868 if (!found_notif) {
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100869 ERRARG("event");
870 return NULL;
871 }
872
Radek Krejci93e80222016-10-03 13:34:25 +0200873 ntf = malloc(sizeof *ntf);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100874 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Radek Krejci93e80222016-10-03 13:34:25 +0200875 ntf->eventtime = strdup(eventtime);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100876 ntf->tree = lyd_dup(event, 1);
Radek Krejci93e80222016-10-03 13:34:25 +0200877 } else {
878 ntf->eventtime = eventtime;
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100879 ntf->tree = 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) {
894 lyd_free(notif->tree);
895 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}