blob: 046748358c44b3397099bbbcd2d13a18fcb50f66 [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"
31#include "messages_p.h"
32
33API struct nc_server_reply *
34nc_server_reply_ok(void)
35{
36 struct nc_server_reply *ret;
37
38 ret = malloc(sizeof *ret);
39 if (!ret) {
40 ERRMEM;
41 return NULL;
42 }
43
44 ret->type = NC_RPL_OK;
45 return ret;
46}
47
48API struct nc_server_reply *
49nc_server_reply_data(struct lyd_node *data, NC_PARAMTYPE paramtype)
50{
51 struct nc_server_reply_data *ret;
52
53 if (!data) {
54 ERRARG;
55 return NULL;
56 }
57
58 ret = malloc(sizeof *ret);
59 if (!ret) {
60 ERRMEM;
61 return NULL;
62 }
63
64 ret->type = NC_RPL_DATA;
65 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
66 ret->data = lyd_dup(data, 1);
67 } else {
68 ret->data = data;
69 }
70 if (paramtype != NC_PARAMTYPE_CONST) {
71 ret->free = 1;
72 } else {
73 ret->free = 0;
74 }
75 return (struct nc_server_reply *)ret;
76}
77
78API struct nc_server_reply *
79nc_server_reply_err(struct ly_ctx *ctx, struct nc_server_error *err)
80{
81 struct nc_server_reply_error *ret;
82
83 if (!ctx || !err) {
84 ERRARG;
85 return NULL;
86 }
87
88 ret = malloc(sizeof *ret);
89 if (!ret) {
90 ERRMEM;
91 return NULL;
92 }
93
94 ret->type = NC_RPL_ERROR;
95 ret->ctx = ctx;
96 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 *
120nc_err(struct ly_ctx *ctx, NC_ERR tag, ...)
121{
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
128 if (!ctx || !tag) {
129 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 }
169 nc_err_add_bad_attr(ctx, ret, arg1);
170 nc_err_add_bad_elem(ctx, ret, arg2);
171 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 }
182 nc_err_add_bad_elem(ctx, ret, arg1);
183 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 }
193 nc_err_add_bad_elem(ctx, ret, arg1);
194 nc_err_add_bad_ns(ctx, ret, arg2);
195 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:
227 nc_err_set_msg(ctx, ret, "The request requires a resource that already is in use.", "en");
228 break;
229 case NC_ERR_INVALID_VALUE:
230 nc_err_set_msg(ctx, ret, "The request specifies an unacceptable value for one or more parameters.", "en");
231 break;
232 case NC_ERR_TOO_BIG:
233 nc_err_set_msg(ctx, ret, "The request or response (that would be generated) is too large for the implementation to handle.", "en");
234 break;
235 case NC_ERR_MISSING_ATTR:
236 nc_err_set_msg(ctx, ret, "An expected attribute is missing.", "en");
237 break;
238 case NC_ERR_BAD_ATTR:
239 nc_err_set_msg(ctx, ret, "An attribute value is not correct.", "en");
240 break;
241 case NC_ERR_UNKNOWN_ATTR:
242 nc_err_set_msg(ctx, ret, "An unexpected attribute is present.", "en");
243 break;
244 case NC_ERR_MISSING_ELEM:
245 nc_err_set_msg(ctx, ret, "An expected element is missing.", "en");
246 break;
247 case NC_ERR_BAD_ELEM:
248 nc_err_set_msg(ctx, ret, "An element value is not correct.", "en");
249 break;
250 case NC_ERR_UNKNOWN_ELEM:
251 nc_err_set_msg(ctx, ret, "An unexpected element is present.", "en");
252 break;
253 case NC_ERR_UNKNOWN_NS:
254 nc_err_set_msg(ctx, ret, "An unexpected namespace is present.", "en");
255 break;
256 case NC_ERR_ACCESS_DENIED:
257 nc_err_set_msg(ctx, ret, "Access to the requested protocol operation or data model is denied because authorization failed.", "en");
258 break;
259 case NC_ERR_LOCK_DENIED:
260 nc_err_set_msg(ctx, ret, "Access to the requested lock is denied because the lock is currently held by another entity.", "en");
261 break;
262 case NC_ERR_RES_DENIED:
263 nc_err_set_msg(ctx, ret, "Request could not be completed because of insufficient resources.", "en");
264 break;
265 case NC_ERR_ROLLBACK_FAILED:
266 nc_err_set_msg(ctx, ret, "Request to roll back some configuration change was not completed for some reason.", "en");
267 break;
268 case NC_ERR_DATA_EXISTS:
269 nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content already exists.", "en");
270 break;
271 case NC_ERR_DATA_MISSING:
272 nc_err_set_msg(ctx, ret, "Request could not be completed because the relevant data model content does not exist.", "en");
273 break;
274 case NC_ERR_OP_NOT_SUPPORTED:
275 nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation is not supported by this implementation.", "en");
276 break;
277 case NC_ERR_OP_FAILED:
278 nc_err_set_msg(ctx, ret, "Request could not be completed because the requested operation failed for a non-specific reason.", "en");
279 break;
280 case NC_ERR_MALFORMED_MSG:
281 nc_err_set_msg(ctx, ret, "A message could not be handled because it failed to be parsed correctly.", "en");
282 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
300nc_err_set_app_tag(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_app_tag)
301{
302 if (!ctx || !err || !error_app_tag) {
303 ERRARG;
304 return -1;
305 }
306
307 if (err->apptag) {
308 lydict_remove(ctx, err->apptag);
309 }
310 err->apptag = lydict_insert(ctx, error_app_tag, 0);
311 return 0;
312}
313
314API int
315nc_err_set_path(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_path)
316{
317 if (!ctx || !err || !error_path) {
318 ERRARG;
319 return -1;
320 }
321
322 if (err->path) {
323 lydict_remove(ctx, err->path);
324 }
325 err->path = lydict_insert(ctx, error_path, 0);
326 return 0;
327}
328
329API int
330nc_err_set_msg(struct ly_ctx *ctx, struct nc_server_error *err, const char *error_message, const char *lang)
331{
332 if (!ctx || !err || !error_message) {
333 ERRARG;
334 return -1;
335 }
336
337 if (err->message) {
338 lydict_remove(ctx, err->apptag);
339 }
340 err->message = lydict_insert(ctx, error_message, 0);
341
342 if (err->message_lang) {
343 lydict_remove(ctx, err->message_lang);
344 }
345 if (lang) {
346 err->message_lang = lydict_insert(ctx, lang, 0);
347 } 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
366nc_err_add_bad_attr(struct ly_ctx *ctx, struct nc_server_error *err, const char *attr_name)
367{
368 if (!ctx || !err || !attr_name) {
369 ERRARG;
370 return -1;
371 }
372
373 ++err->attr_count;
374 err->attr = realloc(err->attr, err->attr_count * sizeof *err->attr);
375 err->attr[err->attr_count - 1] = lydict_insert(ctx, attr_name, 0);
376 return 0;
377}
378
379API int
380nc_err_add_bad_elem(struct ly_ctx *ctx, struct nc_server_error *err, const char *elem_name)
381{
382 if (!ctx || !err || !elem_name) {
383 ERRARG;
384 return -1;
385 }
386
387 ++err->elem_count;
388 err->elem = realloc(err->elem, err->elem_count * sizeof *err->elem);
389 err->elem[err->elem_count - 1] = lydict_insert(ctx, elem_name, 0);
390 return 0;
391}
392
393API int
394nc_err_add_bad_ns(struct ly_ctx *ctx, struct nc_server_error *err, const char *ns_name)
395{
396 if (!ctx || !err || !ns_name) {
397 ERRARG;
398 return -1;
399 }
400
401 ++err->ns_count;
402 err->ns = realloc(err->ns, err->ns_count * sizeof *err->ns);
403 err->ns[err->ns_count - 1] = lydict_insert(ctx, ns_name, 0);
404 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{
424 lyxml_free(rpc->tree->schema->module->ctx, rpc->root);
425 lyd_free(rpc->tree);
426 free(rpc);
427}
428
429API void
430nc_server_reply_free(struct nc_server_reply *reply)
431{
432 uint32_t i;
433 struct nc_server_reply_data *data_rpl;
434 struct nc_server_reply_error *error_rpl;
435
436 if (!reply) {
437 return;
438 }
439
440 switch (reply->type) {
441 case NC_RPL_DATA:
442 data_rpl = (struct nc_server_reply_data *)reply;
443 if (data_rpl->free) {
444 lyd_free_withsiblings(data_rpl->data);
445 }
446 break;
447 case NC_RPL_OK:
448 /* nothing to free */
449 break;
450 case NC_RPL_ERROR:
451 error_rpl = (struct nc_server_reply_error *)reply;
452 for (i = 0; i < error_rpl->count; ++i) {
453 nc_err_free(error_rpl->ctx, error_rpl->err[i]);
454 }
455 free(error_rpl->err);
456 break;
457 default:
458 break;
459 }
460 free(reply);
461}
462
463API void
464nc_err_free(struct ly_ctx *ctx, struct nc_server_error *err)
465{
466 uint32_t i;
467
468 if (!err) {
469 ERRARG;
470 return;
471 }
472
473 lydict_remove(ctx, err->apptag);
474 lydict_remove(ctx, err->path);
475 lydict_remove(ctx, err->message);
476 lydict_remove(ctx, err->message_lang);
477 for (i = 0; i < err->attr_count; ++i) {
478 lydict_remove(ctx, err->attr[i]);
479 }
480 free(err->attr);
481 for (i = 0; i < err->elem_count; ++i) {
482 lydict_remove(ctx, err->elem[i]);
483 }
484 free(err->elem);
485 for (i = 0; i < err->ns_count; ++i) {
486 lydict_remove(ctx, err->ns[i]);
487 }
488 free(err->ns);
489 for (i = 0; i < err->other_count; ++i) {
490 lyxml_free(ctx, err->other[i]);
491 }
492 free(err->other);
493 free(err);
494}