blob: 33cbba6bb83ba761dba56c35ccbc50f1b1085bdf [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
Michal Vasko9e8ac262020-04-07 13:06:45 +020023#include "compat.h"
Michal Vasko7bcb48e2016-01-15 10:28:54 +010024#include "libnetconf.h"
Radek Krejci93e80222016-10-03 13:34:25 +020025#include "session_server.h"
Michal Vasko1a38c862016-01-15 15:50:07 +010026
27extern struct nc_server_opts server_opts;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010028
29API struct nc_server_reply *
30nc_server_reply_ok(void)
31{
32 struct nc_server_reply *ret;
33
34 ret = malloc(sizeof *ret);
35 if (!ret) {
36 ERRMEM;
37 return NULL;
38 }
39
40 ret->type = NC_RPL_OK;
41 return ret;
42}
43
44API struct nc_server_reply *
Radek Krejci36dfdb32016-09-01 16:56:35 +020045nc_server_reply_data(struct lyd_node *data, NC_WD_MODE wd, NC_PARAMTYPE paramtype)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010046{
47 struct nc_server_reply_data *ret;
48
Michal Vaskob08743b2016-04-13 14:23:49 +020049 if (!data) {
50 ERRARG("data");
51 return NULL;
52 }
53
Michal Vasko7bcb48e2016-01-15 10:28:54 +010054 ret = malloc(sizeof *ret);
55 if (!ret) {
56 ERRMEM;
57 return NULL;
58 }
59
60 ret->type = NC_RPL_DATA;
Radek Krejci36dfdb32016-09-01 16:56:35 +020061 ret->wd = wd;
Michal Vaskob08743b2016-04-13 14:23:49 +020062 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +010063 ret->data = lyd_dup(data, 1);
64 } else {
65 ret->data = data;
66 }
67 if (paramtype != NC_PARAMTYPE_CONST) {
68 ret->free = 1;
69 } else {
70 ret->free = 0;
71 }
72 return (struct nc_server_reply *)ret;
73}
74
75API struct nc_server_reply *
Michal Vasko1a38c862016-01-15 15:50:07 +010076nc_server_reply_err(struct nc_server_error *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010077{
78 struct nc_server_reply_error *ret;
79
Michal Vasko1a38c862016-01-15 15:50:07 +010080 if (!err) {
Michal Vasko45e53ae2016-04-07 11:46:03 +020081 ERRARG("err");
Michal Vasko7bcb48e2016-01-15 10:28:54 +010082 return NULL;
83 }
84
85 ret = malloc(sizeof *ret);
86 if (!ret) {
87 ERRMEM;
88 return NULL;
89 }
90
91 ret->type = NC_RPL_ERROR;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010092 ret->err = malloc(sizeof *ret->err);
Michal Vasko4eb3c312016-03-01 14:09:37 +010093 if (!ret->err) {
94 ERRMEM;
95 free(ret);
96 return NULL;
97 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +010098 ret->err[0] = err;
99 ret->count = 1;
100 return (struct nc_server_reply *)ret;
101}
102
103API int
104nc_server_reply_add_err(struct nc_server_reply *reply, struct nc_server_error *err)
105{
106 struct nc_server_reply_error *err_rpl;
107
Michal Vasko45e53ae2016-04-07 11:46:03 +0200108 if (!reply || (reply->type != NC_RPL_ERROR)) {
109 ERRARG("reply");
110 return -1;
111 } else if (!err) {
112 ERRARG("err");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100113 return -1;
114 }
115
116 err_rpl = (struct nc_server_reply_error *)reply;
117 ++err_rpl->count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100118 err_rpl->err = nc_realloc(err_rpl->err, err_rpl->count * sizeof *err_rpl->err);
119 if (!err_rpl->err) {
120 ERRMEM;
121 return -1;
122 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100123 err_rpl->err[err_rpl->count - 1] = err;
124 return 0;
125}
126
Michal Vaskoaa2e5a72017-03-16 09:48:44 +0100127API const struct nc_server_error *
128nc_server_reply_get_last_err(const struct nc_server_reply *reply)
129{
130 struct nc_server_reply_error *err_rpl;
131
132 if (!reply || (reply->type != NC_RPL_ERROR)) {
133 ERRARG("reply");
134 return NULL;
135 }
136
137 err_rpl = (struct nc_server_reply_error *)reply;
138 if (!err_rpl->count) {
139 return NULL;
140 }
141 return err_rpl->err[err_rpl->count - 1];
142}
143
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100144API struct nc_server_error *
Radek Krejci127f8952016-10-12 14:57:16 +0200145nc_err(int tag, ...)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100146{
147 va_list ap;
148 struct nc_server_error *ret;
149 NC_ERR_TYPE type;
150 const char *arg1, *arg2;
151 uint32_t sid;
152
Michal Vasko1a38c862016-01-15 15:50:07 +0100153 if (!tag) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200154 ERRARG("tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100155 return NULL;
156 }
157
158 ret = calloc(1, sizeof *ret);
159 if (!ret) {
160 ERRMEM;
161 return NULL;
162 }
Michal Vasko90920b02016-05-20 14:07:00 +0200163 ret->sid = -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100164
165 va_start(ap, tag);
166
167 switch (tag) {
168 case NC_ERR_IN_USE:
169 case NC_ERR_INVALID_VALUE:
170 case NC_ERR_ACCESS_DENIED:
171 case NC_ERR_ROLLBACK_FAILED:
172 case NC_ERR_OP_NOT_SUPPORTED:
Radek Krejci127f8952016-10-12 14:57:16 +0200173 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko2f923d12016-04-05 11:33:02 +0200174 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200175 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100176 goto fail;
177 }
178 break;
179
180 case NC_ERR_TOO_BIG:
181 case NC_ERR_RES_DENIED:
Radek Krejci127f8952016-10-12 14:57:16 +0200182 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100183 /* nothing to check */
184 break;
185
186 case NC_ERR_MISSING_ATTR:
187 case NC_ERR_BAD_ATTR:
188 case NC_ERR_UNKNOWN_ATTR:
Radek Krejci127f8952016-10-12 14:57:16 +0200189 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100190 arg1 = va_arg(ap, const char *);
191 arg2 = va_arg(ap, const char *);
192
193 if (type == NC_ERR_TYPE_TRAN) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200194 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100195 goto fail;
196 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100197 nc_err_add_bad_attr(ret, arg1);
198 nc_err_add_bad_elem(ret, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100199 break;
200
201 case NC_ERR_MISSING_ELEM:
202 case NC_ERR_BAD_ELEM:
203 case NC_ERR_UNKNOWN_ELEM:
Radek Krejci127f8952016-10-12 14:57:16 +0200204 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100205 arg1 = va_arg(ap, const char *);
206
207 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200208 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100209 goto fail;
210 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100211 nc_err_add_bad_elem(ret, arg1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100212 break;
213
214 case NC_ERR_UNKNOWN_NS:
Radek Krejci127f8952016-10-12 14:57:16 +0200215 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100216 arg1 = va_arg(ap, const char *);
217 arg2 = va_arg(ap, const char *);
218
219 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200220 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100221 goto fail;
222 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100223 nc_err_add_bad_elem(ret, arg1);
224 nc_err_add_bad_ns(ret, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100225 break;
226
227 case NC_ERR_LOCK_DENIED:
228 sid = va_arg(ap, uint32_t);
229
230 type = NC_ERR_TYPE_PROT;
231 nc_err_set_sid(ret, sid);
232 break;
233
234 case NC_ERR_DATA_EXISTS:
235 case NC_ERR_DATA_MISSING:
236 type = NC_ERR_TYPE_APP;
237 break;
238
239 case NC_ERR_OP_FAILED:
Radek Krejci127f8952016-10-12 14:57:16 +0200240 type = (NC_ERR_TYPE)va_arg(ap, int); /* NC_ERR_TYPE enum is automatically promoted to int */
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100241
242 if (type == NC_ERR_TYPE_TRAN) {
Michal Vasko45e53ae2016-04-07 11:46:03 +0200243 ERRARG("type");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100244 goto fail;
245 }
246 break;
247
248 case NC_ERR_MALFORMED_MSG:
249 type = NC_ERR_TYPE_RPC;
250 break;
251
252 default:
Michal Vasko45e53ae2016-04-07 11:46:03 +0200253 ERRARG("tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100254 goto fail;
255 }
256
257 switch (tag) {
258 case NC_ERR_IN_USE:
Michal Vasko1a38c862016-01-15 15:50:07 +0100259 nc_err_set_msg(ret, "The request requires a resource that already is in use.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100260 break;
261 case NC_ERR_INVALID_VALUE:
Michal Vasko1a38c862016-01-15 15:50:07 +0100262 nc_err_set_msg(ret, "The request specifies an unacceptable value for one or more parameters.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100263 break;
264 case NC_ERR_TOO_BIG:
Michal Vasko1a38c862016-01-15 15:50:07 +0100265 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 +0100266 break;
267 case NC_ERR_MISSING_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100268 nc_err_set_msg(ret, "An expected attribute is missing.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100269 break;
270 case NC_ERR_BAD_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100271 nc_err_set_msg(ret, "An attribute value is not correct.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100272 break;
273 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100274 nc_err_set_msg(ret, "An unexpected attribute is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100275 break;
276 case NC_ERR_MISSING_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100277 nc_err_set_msg(ret, "An expected element is missing.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100278 break;
279 case NC_ERR_BAD_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100280 nc_err_set_msg(ret, "An element value is not correct.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100281 break;
282 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100283 nc_err_set_msg(ret, "An unexpected element is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100284 break;
285 case NC_ERR_UNKNOWN_NS:
Michal Vasko1a38c862016-01-15 15:50:07 +0100286 nc_err_set_msg(ret, "An unexpected namespace is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100287 break;
288 case NC_ERR_ACCESS_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100289 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 +0100290 break;
291 case NC_ERR_LOCK_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100292 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 +0100293 break;
294 case NC_ERR_RES_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100295 nc_err_set_msg(ret, "Request could not be completed because of insufficient resources.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100296 break;
297 case NC_ERR_ROLLBACK_FAILED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100298 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 +0100299 break;
300 case NC_ERR_DATA_EXISTS:
Michal Vasko1a38c862016-01-15 15:50:07 +0100301 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 +0100302 break;
303 case NC_ERR_DATA_MISSING:
Michal Vasko1a38c862016-01-15 15:50:07 +0100304 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 +0100305 break;
306 case NC_ERR_OP_NOT_SUPPORTED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100307 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 +0100308 break;
309 case NC_ERR_OP_FAILED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100310 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 +0100311 break;
312 case NC_ERR_MALFORMED_MSG:
Michal Vasko1a38c862016-01-15 15:50:07 +0100313 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 +0100314 break;
315 default:
Michal Vasko45e53ae2016-04-07 11:46:03 +0200316 ERRARG("tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100317 goto fail;
318 }
319
320 va_end(ap);
321
322 ret->type = type;
323 ret->tag = tag;
324 return ret;
325
326fail:
Michal Vasko11d142a2016-01-19 15:58:24 +0100327 va_end(ap);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100328 free(ret);
329 return NULL;
330}
331
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200332static struct lyxml_elem *
333nc_err_libyang_other_elem(const char *name, const char *content, int cont_len)
334{
335 struct lyxml_elem *root = NULL;
336 struct lyxml_ns *ns;
337
338 root = calloc(1, sizeof *root);
339 if (!root) {
340 ERRMEM;
341 goto error;
342 }
343 root->prev = root;
344 root->name = lydict_insert(server_opts.ctx, name, 0);
345 root->content = lydict_insert(server_opts.ctx, content, cont_len);
346
347 ns = calloc(1, sizeof *root->ns);
348 if (!ns) {
349 ERRMEM;
350 goto error;
351 }
352 root->attr = (struct lyxml_attr *)ns;
353 ns->type = LYXML_ATTR_NS;
354 ns->parent = root;
355 ns->value = lydict_insert(server_opts.ctx, "urn:ietf:params:xml:ns:yang:1", 0);
356 root->ns = ns;
357
358 return root;
359
360error:
361 lyxml_free(server_opts.ctx, root);
362 return NULL;
363}
364
Radek Krejci877e1822016-04-06 16:37:43 +0200365API struct nc_server_error *
Michal Vaskoc9970242018-02-14 16:03:35 +0100366nc_err_libyang(struct ly_ctx *ctx)
Radek Krejci877e1822016-04-06 16:37:43 +0200367{
368 struct nc_server_error *e;
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200369 struct lyxml_elem *elem;
370 const char *str, *stri, *strj, *strk, *strl, *uniqi, *uniqj;
371 char *attr, *path;
372 int len;
Radek Krejci877e1822016-04-06 16:37:43 +0200373
374 if (!ly_errno) {
375 /* LY_SUCCESS */
376 return NULL;
377 } else if (ly_errno == LY_EVALID) {
Michal Vaskoc9970242018-02-14 16:03:35 +0100378 switch (ly_vecode(ctx)) {
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200379 /* RFC 6020 section 13 errors */
380 case LYVE_NOUNIQ:
381 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
382 nc_err_set_app_tag(e, "data-not-unique");
Michal Vaskoc9970242018-02-14 16:03:35 +0100383 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200384
385 /* parse the message and get all the information we need */
Michal Vaskoc9970242018-02-14 16:03:35 +0100386 str = ly_errmsg(ctx);
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200387 uniqi = strchr(str, '"');
388 uniqi++;
389 uniqj = strchr(uniqi, '"');
390
391 stri = strchr(uniqj + 1, '"');
392 stri++;
393 strj = strchr(stri, '"');
394
395 strk = strchr(strj + 1, '"');
396 ++strk;
397 strl = strchr(strk, '"');
398
399 /* maximum length is the whole unique string with the longer list instance identifier */
400 len = (uniqj - uniqi) + (strj - stri > strl - strk ? strj - stri : strl - strk);
401 path = malloc(len + 1);
402 if (!path) {
403 ERRMEM;
404 return e;
405 }
406
407 /* create non-unique elements, one in 1st list, one in 2nd list, for each unique list */
408 while (1) {
409 uniqj = strpbrk(uniqi, " \"");
410
411 len = sprintf(path, "%.*s/%.*s", (int)(strj - stri), stri, (int)(uniqj - uniqi), uniqi);
412 elem = nc_err_libyang_other_elem("non-unique", path, len);
413 if (!elem) {
414 free(path);
415 return e;
416 }
417 nc_err_add_info_other(e, elem);
418
419 len = sprintf(path, "%.*s/%.*s", (int)(strl - strk), strk, (int)(uniqj - uniqi), uniqi);
420 elem = nc_err_libyang_other_elem("non-unique", path, len);
421 if (!elem) {
422 return e;
423 }
424 nc_err_add_info_other(e, elem);
425
426 if (uniqj[0] == '"') {
427 break;
428 }
429 uniqi = uniqj + 1;
430 }
431 free(path);
432 break;
433 case LYVE_NOMAX:
434 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
435 nc_err_set_app_tag(e, "too-many-elements");
Michal Vaskoc9970242018-02-14 16:03:35 +0100436 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200437 break;
438 case LYVE_NOMIN:
439 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
440 nc_err_set_app_tag(e, "too-few-elements");
Michal Vaskoc9970242018-02-14 16:03:35 +0100441 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200442 break;
443 case LYVE_NOMUST:
444 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
Michal Vaskoc9970242018-02-14 16:03:35 +0100445 if (ly_errapptag(ctx)) {
446 nc_err_set_app_tag(e, ly_errapptag(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200447 } else {
448 nc_err_set_app_tag(e, "must-violation");
449 }
Michal Vasko591db0d2019-03-26 08:39:48 +0100450 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200451 break;
452 case LYVE_NOREQINS:
453 case LYVE_NOLEAFREF:
454 e = nc_err(NC_ERR_DATA_MISSING);
455 nc_err_set_app_tag(e, "instance-required");
Michal Vaskoc9970242018-02-14 16:03:35 +0100456 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200457 break;
458 case LYVE_NOMANDCHOICE:
459 e = nc_err(NC_ERR_DATA_MISSING);
460 nc_err_set_app_tag(e, "missing-choice");
Michal Vaskoc9970242018-02-14 16:03:35 +0100461 nc_err_set_path(e, ly_errpath(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200462
Michal Vaskoc9970242018-02-14 16:03:35 +0100463 str = ly_errmsg(ctx);
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200464 stri = strchr(str, '"');
465 stri++;
466 strj = strchr(stri, '"');
467 elem = nc_err_libyang_other_elem("missing-choice", stri, strj - stri);
468 if (elem) {
469 nc_err_add_info_other(e, elem);
470 }
471 break;
Radek Krejci877e1822016-04-06 16:37:43 +0200472 case LYVE_INELEM:
Michal Vaskoc9970242018-02-14 16:03:35 +0100473 str = ly_errpath(ctx);
Michal Vasko6d8a9722020-02-10 14:56:40 +0100474 if (!str || !strcmp(str, "/")) {
Radek Krejci877e1822016-04-06 16:37:43 +0200475 e = nc_err(NC_ERR_OP_NOT_SUPPORTED, NC_ERR_TYPE_APP);
476 /* keep default message */
477 return e;
478 } else {
Michal Vaskoc9970242018-02-14 16:03:35 +0100479 e = nc_err(NC_ERR_UNKNOWN_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200480 }
481 break;
482 case LYVE_MISSELEM:
483 case LYVE_INORDER:
Michal Vaskoc9970242018-02-14 16:03:35 +0100484 e = nc_err(NC_ERR_MISSING_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200485 break;
486 case LYVE_INVAL:
Michal Vaskoc9970242018-02-14 16:03:35 +0100487 e = nc_err(NC_ERR_BAD_ELEM, NC_ERR_TYPE_PROT, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200488 break;
489 case LYVE_INATTR:
490 case LYVE_MISSATTR:
Michal Vasko37fdad52017-03-02 11:40:22 +0100491 case LYVE_INMETA:
Michal Vaskoc9970242018-02-14 16:03:35 +0100492 str = ly_errmsg(ctx);
Radek Krejci877e1822016-04-06 16:37:43 +0200493 stri = strchr(str, '"');
494 stri++;
Michal Vasko11a0c4f2018-01-03 14:29:06 +0100495 if (!strncmp(stri, "<none>:", 7)) {
496 stri += 7;
497 }
Radek Krejci877e1822016-04-06 16:37:43 +0200498 strj = strchr(stri, '"');
499 strj--;
Michal Vasko630485f2018-01-03 14:28:32 +0100500 attr = strndup(stri, (strj - stri) + 1);
Michal Vaskoc9970242018-02-14 16:03:35 +0100501 if (ly_vecode(ctx) == LYVE_INATTR) {
502 e = nc_err(NC_ERR_UNKNOWN_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
503 } else if (ly_vecode(ctx) == LYVE_MISSATTR) {
504 e = nc_err(NC_ERR_MISSING_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
Michal Vasko37fdad52017-03-02 11:40:22 +0100505 } else { /* LYVE_INMETA */
Michal Vaskoc9970242018-02-14 16:03:35 +0100506 e = nc_err(NC_ERR_BAD_ATTR, NC_ERR_TYPE_PROT, attr, ly_errpath(ctx));
Radek Krejci537fb522016-04-07 16:36:25 +0200507 }
Radek Krejci877e1822016-04-06 16:37:43 +0200508 free(attr);
509 break;
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200510 case LYVE_NOCONSTR:
511 case LYVE_NOWHEN:
Radek Krejci877e1822016-04-06 16:37:43 +0200512 e = nc_err(NC_ERR_INVALID_VALUE, NC_ERR_TYPE_PROT);
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200513 /* LYVE_NOCONSTR (length, range, pattern) can have a specific error-app-tag */
Michal Vaskoc9970242018-02-14 16:03:35 +0100514 if (ly_errapptag(ctx)) {
515 nc_err_set_app_tag(e, ly_errapptag(ctx));
Michal Vaskoa08e5c02016-04-12 15:12:04 +0200516 }
Michal Vasko591db0d2019-03-26 08:39:48 +0100517 nc_err_set_path(e, ly_errpath(ctx));
Radek Krejci877e1822016-04-06 16:37:43 +0200518 break;
519 default:
520 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
521 break;
522 }
523 } else {
524 /* non-validation (internal) error */
525 e = nc_err(NC_ERR_OP_FAILED, NC_ERR_TYPE_APP);
526 }
Michal Vaskoc9970242018-02-14 16:03:35 +0100527 nc_err_set_msg(e, ly_errmsg(ctx), "en");
Radek Krejci877e1822016-04-06 16:37:43 +0200528 return e;
529}
530
Michal Vasko8f3198f2016-05-04 10:45:28 +0200531API NC_ERR_TYPE
Michal Vaskoea201782017-03-16 09:49:54 +0100532nc_err_get_type(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200533{
534 if (!err) {
535 ERRARG("err");
536 return 0;
537 }
538
539 return err->type;
540}
541
542API NC_ERR
Michal Vaskoea201782017-03-16 09:49:54 +0100543nc_err_get_tag(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200544{
545 if (!err) {
546 ERRARG("err");
547 return 0;
548 }
549
550 return err->tag;
551}
552
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100553API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100554nc_err_set_app_tag(struct nc_server_error *err, const char *error_app_tag)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100555{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200556 if (!err) {
557 ERRARG("err");
558 return -1;
559 } else if (!error_app_tag) {
560 ERRARG("error_app_tag");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100561 return -1;
562 }
563
564 if (err->apptag) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100565 lydict_remove(server_opts.ctx, err->apptag);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100566 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100567 err->apptag = lydict_insert(server_opts.ctx, error_app_tag, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100568
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100569 return 0;
570}
571
Michal Vasko8f3198f2016-05-04 10:45:28 +0200572API const char *
Michal Vaskoea201782017-03-16 09:49:54 +0100573nc_err_get_app_tag(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200574{
575 if (!err) {
576 ERRARG("err");
577 return NULL;
578 }
579
580 return err->apptag;
581}
582
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100583API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100584nc_err_set_path(struct nc_server_error *err, const char *error_path)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100585{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200586 if (!err) {
587 ERRARG("err");
588 return -1;
589 } else if (!error_path) {
590 ERRARG("error_path");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100591 return -1;
592 }
593
594 if (err->path) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100595 lydict_remove(server_opts.ctx, err->path);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100596 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100597 err->path = lydict_insert(server_opts.ctx, error_path, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100598
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100599 return 0;
600}
601
Michal Vasko8f3198f2016-05-04 10:45:28 +0200602API const char *
Michal Vaskoea201782017-03-16 09:49:54 +0100603nc_err_get_path(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200604{
605 if (!err) {
606 ERRARG("err");
607 return 0;
608 }
609
610 return err->path;
611}
612
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100613API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100614nc_err_set_msg(struct nc_server_error *err, const char *error_message, const char *lang)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100615{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200616 if (!err) {
617 ERRARG("err");
618 return -1;
619 } else if (!error_message) {
620 ERRARG("error_message");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100621 return -1;
622 }
623
624 if (err->message) {
Michal Vasko092ea742016-04-12 15:08:59 +0200625 lydict_remove(server_opts.ctx, err->message);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100626 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100627 err->message = lydict_insert(server_opts.ctx, error_message, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100628
629 if (err->message_lang) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100630 lydict_remove(server_opts.ctx, err->message_lang);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100631 }
632 if (lang) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100633 err->message_lang = lydict_insert(server_opts.ctx, lang, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100634 }
Michal Vasko11d142a2016-01-19 15:58:24 +0100635
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100636 return 0;
637}
638
Michal Vasko8f3198f2016-05-04 10:45:28 +0200639API const char *
Michal Vaskoea201782017-03-16 09:49:54 +0100640nc_err_get_msg(const struct nc_server_error *err)
Michal Vasko8f3198f2016-05-04 10:45:28 +0200641{
642 if (!err) {
643 ERRARG("err");
644 return 0;
645 }
646
647 return err->message;
648}
649
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100650API int
651nc_err_set_sid(struct nc_server_error *err, uint32_t session_id)
652{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200653 if (!err) {
654 ERRARG("err");
655 return -1;
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100656 }
657
658 err->sid = session_id;
659 return 0;
660}
661
662API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100663nc_err_add_bad_attr(struct nc_server_error *err, const char *attr_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100664{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200665 if (!err) {
666 ERRARG("err");
667 return -1;
668 } else if (!attr_name) {
669 ERRARG("attr_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100670 return -1;
671 }
672
673 ++err->attr_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100674 err->attr = nc_realloc(err->attr, err->attr_count * sizeof *err->attr);
675 if (!err->attr) {
676 ERRMEM;
677 return -1;
678 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100679 err->attr[err->attr_count - 1] = lydict_insert(server_opts.ctx, attr_name, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100680
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100681 return 0;
682}
683
684API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100685nc_err_add_bad_elem(struct nc_server_error *err, const char *elem_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100686{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200687 if (!err) {
688 ERRARG("err");
689 return -1;
690 } else if (!elem_name) {
691 ERRARG("elem_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100692 return -1;
693 }
694
695 ++err->elem_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100696 err->elem = nc_realloc(err->elem, err->elem_count * sizeof *err->elem);
697 if (!err->elem) {
698 ERRMEM;
699 return -1;
700 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100701 err->elem[err->elem_count - 1] = lydict_insert(server_opts.ctx, elem_name, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100702
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100703 return 0;
704}
705
706API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100707nc_err_add_bad_ns(struct nc_server_error *err, const char *ns_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100708{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200709 if (!err) {
710 ERRARG("err");
711 return -1;
712 } else if (!ns_name) {
713 ERRARG("ns_name");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100714 return -1;
715 }
716
717 ++err->ns_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100718 err->ns = nc_realloc(err->ns, err->ns_count * sizeof *err->ns);
719 if (!err->ns) {
720 ERRMEM;
721 return -1;
722 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100723 err->ns[err->ns_count - 1] = lydict_insert(server_opts.ctx, ns_name, 0);
Michal Vasko11d142a2016-01-19 15:58:24 +0100724
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100725 return 0;
726}
727
728API int
729nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other)
730{
Michal Vasko45e53ae2016-04-07 11:46:03 +0200731 if (!err) {
732 ERRARG("err");
733 return -1;
734 } else if (!other) {
735 ERRARG("other");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100736 return -1;
737 }
738
739 ++err->other_count;
Michal Vasko4eb3c312016-03-01 14:09:37 +0100740 err->other = nc_realloc(err->other, err->other_count * sizeof *err->other);
741 if (!err->other) {
742 ERRMEM;
743 return -1;
744 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100745 err->other[err->other_count - 1] = other;
746 return 0;
747}
748
749void
Michal Vaskoca4a2422016-02-02 12:17:14 +0100750nc_server_rpc_free(struct nc_server_rpc *rpc, struct ly_ctx *ctx)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100751{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100752 if (!rpc) {
753 return;
754 }
755
Michal Vaskoca4a2422016-02-02 12:17:14 +0100756 lyxml_free(ctx, rpc->root);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100757 lyd_free(rpc->tree);
Michal Vasko11d142a2016-01-19 15:58:24 +0100758
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100759 free(rpc);
760}
761
762API void
763nc_server_reply_free(struct nc_server_reply *reply)
764{
765 uint32_t i;
766 struct nc_server_reply_data *data_rpl;
767 struct nc_server_reply_error *error_rpl;
768
769 if (!reply) {
770 return;
771 }
772
773 switch (reply->type) {
774 case NC_RPL_DATA:
775 data_rpl = (struct nc_server_reply_data *)reply;
776 if (data_rpl->free) {
777 lyd_free_withsiblings(data_rpl->data);
778 }
779 break;
780 case NC_RPL_OK:
781 /* nothing to free */
782 break;
783 case NC_RPL_ERROR:
784 error_rpl = (struct nc_server_reply_error *)reply;
785 for (i = 0; i < error_rpl->count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100786 nc_err_free(error_rpl->err[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100787 }
788 free(error_rpl->err);
789 break;
790 default:
791 break;
792 }
793 free(reply);
794}
795
796API void
Michal Vasko1a38c862016-01-15 15:50:07 +0100797nc_err_free(struct nc_server_error *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100798{
799 uint32_t i;
800
801 if (!err) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100802 return;
803 }
804
Michal Vasko1a38c862016-01-15 15:50:07 +0100805 lydict_remove(server_opts.ctx, err->apptag);
806 lydict_remove(server_opts.ctx, err->path);
807 lydict_remove(server_opts.ctx, err->message);
808 lydict_remove(server_opts.ctx, err->message_lang);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100809 for (i = 0; i < err->attr_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100810 lydict_remove(server_opts.ctx, err->attr[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100811 }
812 free(err->attr);
813 for (i = 0; i < err->elem_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100814 lydict_remove(server_opts.ctx, err->elem[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100815 }
816 free(err->elem);
817 for (i = 0; i < err->ns_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100818 lydict_remove(server_opts.ctx, err->ns[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100819 }
820 free(err->ns);
821 for (i = 0; i < err->other_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100822 lyxml_free(server_opts.ctx, err->other[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100823 }
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100824 free(err->other);
825 free(err);
826}
Radek Krejci93e80222016-10-03 13:34:25 +0200827
828API struct nc_server_notif *
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100829nc_server_notif_new(struct lyd_node* event, char *eventtime, NC_PARAMTYPE paramtype)
Radek Krejci93e80222016-10-03 13:34:25 +0200830{
831 struct nc_server_notif *ntf;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100832 struct lyd_node *elem;
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500833 bool found_notif = false;
Radek Krejci93e80222016-10-03 13:34:25 +0200834
Michal Vasko3106b7b2018-01-04 10:32:42 +0100835 if (!event) {
Radek Krejci93e80222016-10-03 13:34:25 +0200836 ERRARG("event");
837 return NULL;
838 } else if (!eventtime) {
839 ERRARG("eventtime");
840 return NULL;
841 }
842
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100843 /* check that there is a notification */
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500844 for (elem = event; elem && !found_notif; elem = elem->child) {
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100845next_node:
846 switch (elem->schema->nodetype) {
847 case LYS_LEAF:
848 /* key, skip it */
849 elem = elem->next;
850 if (!elem) {
851 /* error */
Michal Vasko93ab6172018-02-16 15:58:12 +0100852 ERRARG("event");
853 return NULL;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100854 }
855 goto next_node;
856 case LYS_CONTAINER:
857 case LYS_LIST:
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100858 /* ok */
859 break;
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500860 case LYS_NOTIF:
861 found_notif = true;
862 break;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100863 default:
864 /* error */
Michal Vasko93ab6172018-02-16 15:58:12 +0100865 ERRARG("event");
866 return NULL;
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100867 }
868 }
Andrew Langefeldbbab76f2018-08-10 15:54:59 -0500869 if (!found_notif) {
Michal Vasko0b89f3d2018-01-04 10:57:03 +0100870 ERRARG("event");
871 return NULL;
872 }
873
Radek Krejci93e80222016-10-03 13:34:25 +0200874 ntf = malloc(sizeof *ntf);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100875 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
Radek Krejci93e80222016-10-03 13:34:25 +0200876 ntf->eventtime = strdup(eventtime);
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100877 ntf->tree = lyd_dup(event, 1);
Radek Krejci93e80222016-10-03 13:34:25 +0200878 } else {
879 ntf->eventtime = eventtime;
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100880 ntf->tree = event;
Radek Krejci93e80222016-10-03 13:34:25 +0200881 }
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100882 ntf->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
Radek Krejci93e80222016-10-03 13:34:25 +0200883
884 return ntf;
885}
886
887API void
888nc_server_notif_free(struct nc_server_notif *notif)
889{
890 if (!notif) {
891 return;
892 }
893
Michal Vaskofc9dbdd2017-03-17 09:27:57 +0100894 if (notif->free) {
895 lyd_free(notif->tree);
896 free(notif->eventtime);
897 }
Radek Krejci93e80222016-10-03 13:34:25 +0200898 free(notif);
899}
Michal Vasko9a2e4d22017-03-17 09:44:49 +0100900
901API const char *
902nc_server_notif_get_time(const struct nc_server_notif *notif)
903{
904 if (!notif) {
905 ERRARG("notif");
906 return NULL;
907 }
908
909 return notif->eventtime;
910}