blob: 39b3876a318725c4ca91130ef415ec9dddf09d69 [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 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in
15 * the documentation and/or other materials provided with the
16 * distribution.
17 * 3. Neither the name of the Company nor the names of its contributors
18 * may be used to endorse or promote products derived from this
19 * software without specific prior written permission.
20 *
21 */
22
23#include <ctype.h>
24#include <stdlib.h>
25#include <string.h>
26#include <stdarg.h>
27
28#include <libyang/libyang.h>
29
30#include "libnetconf.h"
Michal Vasko1a38c862016-01-15 15:50:07 +010031
32extern struct nc_server_opts server_opts;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010033
34API struct nc_server_reply *
35nc_server_reply_ok(void)
36{
37 struct nc_server_reply *ret;
38
39 ret = malloc(sizeof *ret);
40 if (!ret) {
41 ERRMEM;
42 return NULL;
43 }
44
45 ret->type = NC_RPL_OK;
46 return ret;
47}
48
49API struct nc_server_reply *
50nc_server_reply_data(struct lyd_node *data, NC_PARAMTYPE paramtype)
51{
52 struct nc_server_reply_data *ret;
53
54 if (!data) {
55 ERRARG;
56 return NULL;
57 }
58
59 ret = malloc(sizeof *ret);
60 if (!ret) {
61 ERRMEM;
62 return NULL;
63 }
64
65 ret->type = NC_RPL_DATA;
66 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
67 ret->data = lyd_dup(data, 1);
68 } else {
69 ret->data = data;
70 }
71 if (paramtype != NC_PARAMTYPE_CONST) {
72 ret->free = 1;
73 } else {
74 ret->free = 0;
75 }
76 return (struct nc_server_reply *)ret;
77}
78
79API struct nc_server_reply *
Michal Vasko1a38c862016-01-15 15:50:07 +010080nc_server_reply_err(struct nc_server_error *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +010081{
82 struct nc_server_reply_error *ret;
83
Michal Vasko1a38c862016-01-15 15:50:07 +010084 if (!err) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +010085 ERRARG;
86 return NULL;
87 }
88
89 ret = malloc(sizeof *ret);
90 if (!ret) {
91 ERRMEM;
92 return NULL;
93 }
94
95 ret->type = NC_RPL_ERROR;
Michal Vasko7bcb48e2016-01-15 10:28:54 +010096 ret->err = malloc(sizeof *ret->err);
97 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
107 if (!reply || (reply->type != NC_RPL_ERROR) || !err) {
108 ERRARG;
109 return -1;
110 }
111
112 err_rpl = (struct nc_server_reply_error *)reply;
113 ++err_rpl->count;
114 err_rpl->err = realloc(err_rpl->err, err_rpl->count * sizeof *err_rpl->err);
115 err_rpl->err[err_rpl->count - 1] = err;
116 return 0;
117}
118
119API struct nc_server_error *
Michal Vasko1a38c862016-01-15 15:50:07 +0100120nc_err(NC_ERR tag, ...)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100121{
122 va_list ap;
123 struct nc_server_error *ret;
124 NC_ERR_TYPE type;
125 const char *arg1, *arg2;
126 uint32_t sid;
127
Michal Vasko1a38c862016-01-15 15:50:07 +0100128 if (!tag) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100129 ERRARG;
130 return NULL;
131 }
132
133 ret = calloc(1, sizeof *ret);
134 if (!ret) {
135 ERRMEM;
136 return NULL;
137 }
138
139 va_start(ap, tag);
140
141 switch (tag) {
142 case NC_ERR_IN_USE:
143 case NC_ERR_INVALID_VALUE:
144 case NC_ERR_ACCESS_DENIED:
145 case NC_ERR_ROLLBACK_FAILED:
146 case NC_ERR_OP_NOT_SUPPORTED:
147 type = va_arg(ap, NC_ERR_TYPE);
148 if ((type != NC_ERR_TYPE_PROT) && (type == NC_ERR_TYPE_APP)) {
149 goto fail;
150 }
151 break;
152
153 case NC_ERR_TOO_BIG:
154 case NC_ERR_RES_DENIED:
155 type = va_arg(ap, NC_ERR_TYPE);
156 /* nothing to check */
157 break;
158
159 case NC_ERR_MISSING_ATTR:
160 case NC_ERR_BAD_ATTR:
161 case NC_ERR_UNKNOWN_ATTR:
162 type = va_arg(ap, NC_ERR_TYPE);
163 arg1 = va_arg(ap, const char *);
164 arg2 = va_arg(ap, const char *);
165
166 if (type == NC_ERR_TYPE_TRAN) {
167 goto fail;
168 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100169 nc_err_add_bad_attr(ret, arg1);
170 nc_err_add_bad_elem(ret, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100171 break;
172
173 case NC_ERR_MISSING_ELEM:
174 case NC_ERR_BAD_ELEM:
175 case NC_ERR_UNKNOWN_ELEM:
176 type = va_arg(ap, NC_ERR_TYPE);
177 arg1 = va_arg(ap, const char *);
178
179 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
180 goto fail;
181 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100182 nc_err_add_bad_elem(ret, arg1);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100183 break;
184
185 case NC_ERR_UNKNOWN_NS:
186 type = va_arg(ap, NC_ERR_TYPE);
187 arg1 = va_arg(ap, const char *);
188 arg2 = va_arg(ap, const char *);
189
190 if ((type != NC_ERR_TYPE_PROT) && (type != NC_ERR_TYPE_APP)) {
191 goto fail;
192 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100193 nc_err_add_bad_elem(ret, arg1);
194 nc_err_add_bad_ns(ret, arg2);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100195 break;
196
197 case NC_ERR_LOCK_DENIED:
198 sid = va_arg(ap, uint32_t);
199
200 type = NC_ERR_TYPE_PROT;
201 nc_err_set_sid(ret, sid);
202 break;
203
204 case NC_ERR_DATA_EXISTS:
205 case NC_ERR_DATA_MISSING:
206 type = NC_ERR_TYPE_APP;
207 break;
208
209 case NC_ERR_OP_FAILED:
210 type = va_arg(ap, NC_ERR_TYPE);
211
212 if (type == NC_ERR_TYPE_TRAN) {
213 goto fail;
214 }
215 break;
216
217 case NC_ERR_MALFORMED_MSG:
218 type = NC_ERR_TYPE_RPC;
219 break;
220
221 default:
222 goto fail;
223 }
224
225 switch (tag) {
226 case NC_ERR_IN_USE:
Michal Vasko1a38c862016-01-15 15:50:07 +0100227 nc_err_set_msg(ret, "The request requires a resource that already is in use.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100228 break;
229 case NC_ERR_INVALID_VALUE:
Michal Vasko1a38c862016-01-15 15:50:07 +0100230 nc_err_set_msg(ret, "The request specifies an unacceptable value for one or more parameters.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100231 break;
232 case NC_ERR_TOO_BIG:
Michal Vasko1a38c862016-01-15 15:50:07 +0100233 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 +0100234 break;
235 case NC_ERR_MISSING_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100236 nc_err_set_msg(ret, "An expected attribute is missing.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100237 break;
238 case NC_ERR_BAD_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100239 nc_err_set_msg(ret, "An attribute value is not correct.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100240 break;
241 case NC_ERR_UNKNOWN_ATTR:
Michal Vasko1a38c862016-01-15 15:50:07 +0100242 nc_err_set_msg(ret, "An unexpected attribute is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100243 break;
244 case NC_ERR_MISSING_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100245 nc_err_set_msg(ret, "An expected element is missing.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100246 break;
247 case NC_ERR_BAD_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100248 nc_err_set_msg(ret, "An element value is not correct.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100249 break;
250 case NC_ERR_UNKNOWN_ELEM:
Michal Vasko1a38c862016-01-15 15:50:07 +0100251 nc_err_set_msg(ret, "An unexpected element is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100252 break;
253 case NC_ERR_UNKNOWN_NS:
Michal Vasko1a38c862016-01-15 15:50:07 +0100254 nc_err_set_msg(ret, "An unexpected namespace is present.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100255 break;
256 case NC_ERR_ACCESS_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100257 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 +0100258 break;
259 case NC_ERR_LOCK_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100260 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 +0100261 break;
262 case NC_ERR_RES_DENIED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100263 nc_err_set_msg(ret, "Request could not be completed because of insufficient resources.", "en");
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100264 break;
265 case NC_ERR_ROLLBACK_FAILED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100266 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 +0100267 break;
268 case NC_ERR_DATA_EXISTS:
Michal Vasko1a38c862016-01-15 15:50:07 +0100269 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 +0100270 break;
271 case NC_ERR_DATA_MISSING:
Michal Vasko1a38c862016-01-15 15:50:07 +0100272 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 +0100273 break;
274 case NC_ERR_OP_NOT_SUPPORTED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100275 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 +0100276 break;
277 case NC_ERR_OP_FAILED:
Michal Vasko1a38c862016-01-15 15:50:07 +0100278 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 +0100279 break;
280 case NC_ERR_MALFORMED_MSG:
Michal Vasko1a38c862016-01-15 15:50:07 +0100281 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 +0100282 break;
283 default:
284 goto fail;
285 }
286
287 va_end(ap);
288
289 ret->type = type;
290 ret->tag = tag;
291 return ret;
292
293fail:
294 ERRARG;
295 free(ret);
296 return NULL;
297}
298
299API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100300nc_err_set_app_tag(struct nc_server_error *err, const char *error_app_tag)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100301{
Michal Vasko1a38c862016-01-15 15:50:07 +0100302 if (!err || !error_app_tag) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100303 ERRARG;
304 return -1;
305 }
306
307 if (err->apptag) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100308 lydict_remove(server_opts.ctx, err->apptag);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100309 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100310 err->apptag = lydict_insert(server_opts.ctx, error_app_tag, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100311 return 0;
312}
313
314API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100315nc_err_set_path(struct nc_server_error *err, const char *error_path)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100316{
Michal Vasko1a38c862016-01-15 15:50:07 +0100317 if (!err || !error_path) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100318 ERRARG;
319 return -1;
320 }
321
322 if (err->path) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100323 lydict_remove(server_opts.ctx, err->path);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100324 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100325 err->path = lydict_insert(server_opts.ctx, error_path, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100326 return 0;
327}
328
329API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100330nc_err_set_msg(struct nc_server_error *err, const char *error_message, const char *lang)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100331{
Michal Vasko1a38c862016-01-15 15:50:07 +0100332 if (!err || !error_message) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100333 ERRARG;
334 return -1;
335 }
336
337 if (err->message) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100338 lydict_remove(server_opts.ctx, err->apptag);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100339 }
Michal Vasko1a38c862016-01-15 15:50:07 +0100340 err->message = lydict_insert(server_opts.ctx, error_message, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100341
342 if (err->message_lang) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100343 lydict_remove(server_opts.ctx, err->message_lang);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100344 }
345 if (lang) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100346 err->message_lang = lydict_insert(server_opts.ctx, lang, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100347 } else {
348 lang = NULL;
349 }
350 return 0;
351}
352
353API int
354nc_err_set_sid(struct nc_server_error *err, uint32_t session_id)
355{
356 if (!err || !session_id) {
357 ERRARG;
358 return -1;
359 }
360
361 err->sid = session_id;
362 return 0;
363}
364
365API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100366nc_err_add_bad_attr(struct nc_server_error *err, const char *attr_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100367{
Michal Vasko1a38c862016-01-15 15:50:07 +0100368 if (!err || !attr_name) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100369 ERRARG;
370 return -1;
371 }
372
373 ++err->attr_count;
374 err->attr = realloc(err->attr, err->attr_count * sizeof *err->attr);
Michal Vasko1a38c862016-01-15 15:50:07 +0100375 err->attr[err->attr_count - 1] = lydict_insert(server_opts.ctx, attr_name, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100376 return 0;
377}
378
379API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100380nc_err_add_bad_elem(struct nc_server_error *err, const char *elem_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100381{
Michal Vasko1a38c862016-01-15 15:50:07 +0100382 if (!err || !elem_name) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100383 ERRARG;
384 return -1;
385 }
386
387 ++err->elem_count;
388 err->elem = realloc(err->elem, err->elem_count * sizeof *err->elem);
Michal Vasko1a38c862016-01-15 15:50:07 +0100389 err->elem[err->elem_count - 1] = lydict_insert(server_opts.ctx, elem_name, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100390 return 0;
391}
392
393API int
Michal Vasko1a38c862016-01-15 15:50:07 +0100394nc_err_add_bad_ns(struct nc_server_error *err, const char *ns_name)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100395{
Michal Vasko1a38c862016-01-15 15:50:07 +0100396 if (!err || !ns_name) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100397 ERRARG;
398 return -1;
399 }
400
401 ++err->ns_count;
402 err->ns = realloc(err->ns, err->ns_count * sizeof *err->ns);
Michal Vasko1a38c862016-01-15 15:50:07 +0100403 err->ns[err->ns_count - 1] = lydict_insert(server_opts.ctx, ns_name, 0);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100404 return 0;
405}
406
407API int
408nc_err_add_info_other(struct nc_server_error *err, struct lyxml_elem *other)
409{
410 if (!err || !other) {
411 ERRARG;
412 return -1;
413 }
414
415 ++err->other_count;
416 err->other = realloc(err->other, err->other_count * sizeof *err->other);
417 err->other[err->other_count - 1] = other;
418 return 0;
419}
420
421void
422nc_server_rpc_free(struct nc_server_rpc *rpc)
423{
Michal Vasko7f1c78b2016-01-19 09:52:14 +0100424 if (!rpc) {
425 return;
426 }
427
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100428 lyxml_free(rpc->tree->schema->module->ctx, rpc->root);
429 lyd_free(rpc->tree);
430 free(rpc);
431}
432
433API void
434nc_server_reply_free(struct nc_server_reply *reply)
435{
436 uint32_t i;
437 struct nc_server_reply_data *data_rpl;
438 struct nc_server_reply_error *error_rpl;
439
440 if (!reply) {
441 return;
442 }
443
444 switch (reply->type) {
445 case NC_RPL_DATA:
446 data_rpl = (struct nc_server_reply_data *)reply;
447 if (data_rpl->free) {
448 lyd_free_withsiblings(data_rpl->data);
449 }
450 break;
451 case NC_RPL_OK:
452 /* nothing to free */
453 break;
454 case NC_RPL_ERROR:
455 error_rpl = (struct nc_server_reply_error *)reply;
456 for (i = 0; i < error_rpl->count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100457 nc_err_free(error_rpl->err[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100458 }
459 free(error_rpl->err);
460 break;
461 default:
462 break;
463 }
464 free(reply);
465}
466
467API void
Michal Vasko1a38c862016-01-15 15:50:07 +0100468nc_err_free(struct nc_server_error *err)
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100469{
470 uint32_t i;
471
472 if (!err) {
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100473 return;
474 }
475
Michal Vasko1a38c862016-01-15 15:50:07 +0100476 lydict_remove(server_opts.ctx, err->apptag);
477 lydict_remove(server_opts.ctx, err->path);
478 lydict_remove(server_opts.ctx, err->message);
479 lydict_remove(server_opts.ctx, err->message_lang);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100480 for (i = 0; i < err->attr_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100481 lydict_remove(server_opts.ctx, err->attr[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100482 }
483 free(err->attr);
484 for (i = 0; i < err->elem_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100485 lydict_remove(server_opts.ctx, err->elem[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100486 }
487 free(err->elem);
488 for (i = 0; i < err->ns_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100489 lydict_remove(server_opts.ctx, err->ns[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100490 }
491 free(err->ns);
492 for (i = 0; i < err->other_count; ++i) {
Michal Vasko1a38c862016-01-15 15:50:07 +0100493 lyxml_free(server_opts.ctx, err->other[i]);
Michal Vasko7bcb48e2016-01-15 10:28:54 +0100494 }
495 free(err->other);
496 free(err);
497}