blob: dfc7485909e5154289ef9c42728d8838660f9eb0 [file] [log] [blame]
Michal Vasko7bcb48e2016-01-15 10:28:54 +01001/**
2 * \file messages.c
3 * \author Radek Krejci <rkrejci@cesnet.cz>
4 * \brief libnetconf2 - 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
33const char *rpcedit_dfltop2str[] = {NULL, "merge", "replace", "none"};
34const char *rpcedit_testopt2str[] = {NULL, "test-then-set", "set", "test-only"};
35const char *rpcedit_erropt2str[] = {NULL, "stop-on-error", "continue-on-error", "rollback-on-error"};
36
37API NC_RPC_TYPE
38nc_rpc_get_type(const struct nc_rpc *rpc)
39{
40 return rpc->type;
41}
42
43API struct nc_rpc *
44nc_rpc_generic(const struct lyd_node *data, NC_PARAMTYPE paramtype)
45{
46 struct nc_rpc_generic *rpc;
47
48 if (data->next || (data->prev != data)) {
49 ERR("Generic RPC must have a single root node.");
50 return NULL;
51 }
52
53 rpc = malloc(sizeof *rpc);
54 if (!rpc) {
55 ERRMEM;
56 return NULL;
57 }
58
59 rpc->type = NC_RPC_GENERIC;
60 rpc->has_data = 1;
61 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
62 rpc->content.data = lyd_dup(data, 1);
63 } else {
64 rpc->content.data = (struct lyd_node *)data;
65 }
66 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
67
68 return (struct nc_rpc *)rpc;
69}
70
71API struct nc_rpc *
72nc_rpc_generic_xml(const char *xml_str, NC_PARAMTYPE paramtype)
73{
74 struct nc_rpc_generic *rpc;
75
76 rpc = malloc(sizeof *rpc);
77 if (!rpc) {
78 ERRMEM;
79 return NULL;
80 }
81
82 rpc->type = NC_RPC_GENERIC;
83 rpc->has_data = 0;
84 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
85 rpc->content.xml_str = strdup(xml_str);
86 } else {
87 rpc->content.xml_str = (char *)xml_str;
88 }
89 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
90
91 return (struct nc_rpc *)rpc;
92}
93
94API struct nc_rpc *
95nc_rpc_getconfig(NC_DATASTORE source, const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
96{
97 struct nc_rpc_getconfig *rpc;
98
99 if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
100 ERR("Filter must either be an XML subtree or an XPath expression.");
101 return NULL;
102 }
103
104 rpc = malloc(sizeof *rpc);
105 if (!rpc) {
106 ERRMEM;
107 return NULL;
108 }
109
110 rpc->type = NC_RPC_GETCONFIG;
111 rpc->source = source;
112 if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
113 rpc->filter = strdup(filter);
114 } else {
115 rpc->filter = (char *)filter;
116 }
117 rpc->wd_mode = wd_mode;
118 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
119
120 return (struct nc_rpc *)rpc;
121}
122
123API struct nc_rpc *
124nc_rpc_edit(NC_DATASTORE target, NC_RPC_EDIT_DFLTOP default_op, NC_RPC_EDIT_TESTOPT test_opt,
125 NC_RPC_EDIT_ERROPT error_opt, const char *edit_content, NC_PARAMTYPE paramtype)
126{
127 struct nc_rpc_edit *rpc;
128
129 if ((edit_content[0] != '<') && !isalpha(edit_content[0])) {
130 ERR("<edit-config> content must either be a URL or a config (XML).");
131 return NULL;
132 }
133
134 rpc = malloc(sizeof *rpc);
135 if (!rpc) {
136 ERRMEM;
137 return NULL;
138 }
139
140 rpc->type = NC_RPC_EDIT;
141 rpc->target = target;
142 rpc->default_op = default_op;
143 rpc->test_opt = test_opt;
144 rpc->error_opt = error_opt;
145 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
146 rpc->edit_cont = strdup(edit_content);
147 } else {
148 rpc->edit_cont = (char *)edit_content;
149 }
150 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
151
152 return (struct nc_rpc *)rpc;
153}
154
155API struct nc_rpc *
156nc_rpc_copy(NC_DATASTORE target, const char *url_trg, NC_DATASTORE source, const char *url_or_config_src,
157 NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
158{
159 struct nc_rpc_copy *rpc;
160
161 if (url_or_config_src && (url_or_config_src[0] != '<') && !isalpha(url_or_config_src[0])) {
162 ERR("<copy-config> source is neither a URL nor a config (XML).");
163 return NULL;
164 }
165
166 rpc = malloc(sizeof *rpc);
167 if (!rpc) {
168 ERRMEM;
169 return NULL;
170 }
171
172 rpc->type = NC_RPC_COPY;
173 rpc->target = target;
174 if (url_trg && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
175 rpc->url_trg = strdup(url_trg);
176 } else {
177 rpc->url_trg = (char *)url_trg;
178 }
179 rpc->source = source;
180 if (url_or_config_src && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
181 rpc->url_config_src = strdup(url_or_config_src);
182 } else {
183 rpc->url_config_src = (char *)url_or_config_src;
184 }
185 rpc->wd_mode = wd_mode;
186 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
187
188 return (struct nc_rpc *)rpc;
189}
190
191API struct nc_rpc *
192nc_rpc_delete(NC_DATASTORE target, const char *url, NC_PARAMTYPE paramtype)
193{
194 struct nc_rpc_delete *rpc;
195
196 rpc = malloc(sizeof *rpc);
197 if (!rpc) {
198 ERRMEM;
199 return NULL;
200 }
201
202 rpc->type = NC_RPC_DELETE;
203 rpc->target = target;
204 if (url && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
205 rpc->url = strdup(url);
206 } else {
207 rpc->url = (char *)url;
208 }
209 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
210
211 return (struct nc_rpc *)rpc;
212}
213
214API struct nc_rpc *
215nc_rpc_lock(NC_DATASTORE target)
216{
217 struct nc_rpc_lock *rpc;
218
219 rpc = malloc(sizeof *rpc);
220 if (!rpc) {
221 ERRMEM;
222 return NULL;
223 }
224
225 rpc->type = NC_RPC_LOCK;
226 rpc->target = target;
227
228 return (struct nc_rpc *)rpc;
229}
230
231API struct nc_rpc *
232nc_rpc_unlock(NC_DATASTORE target)
233{
234 struct nc_rpc_lock *rpc;
235
236 rpc = malloc(sizeof *rpc);
237 if (!rpc) {
238 ERRMEM;
239 return NULL;
240 }
241
242 rpc->type = NC_RPC_UNLOCK;
243 rpc->target = target;
244
245 return (struct nc_rpc *)rpc;
246}
247
248API struct nc_rpc *
249nc_rpc_get(const char *filter, NC_WD_MODE wd_mode, NC_PARAMTYPE paramtype)
250{
251 struct nc_rpc_get *rpc;
252
253 if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
254 ERR("Filter must either be an XML subtree or an XPath expression.");
255 return NULL;
256 }
257
258 rpc = malloc(sizeof *rpc);
259 if (!rpc) {
260 ERRMEM;
261 return NULL;
262 }
263
264 rpc->type = NC_RPC_GET;
265 if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
266 rpc->filter = strdup(filter);
267 } else {
268 rpc->filter = (char *)filter;
269 }
270 rpc->wd_mode = wd_mode;
271 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
272
273 return (struct nc_rpc *)rpc;
274}
275
276API struct nc_rpc *
277nc_rpc_kill(uint32_t session_id)
278{
279 struct nc_rpc_kill *rpc;
280
281 rpc = malloc(sizeof *rpc);
282 if (!rpc) {
283 ERRMEM;
284 return NULL;
285 }
286
287 rpc->type = NC_RPC_KILL;
288 rpc->sid = session_id;
289
290 return (struct nc_rpc *)rpc;
291}
292
293API struct nc_rpc *
294nc_rpc_commit(int confirmed, uint32_t confirm_timeout, const char *persist, const char *persist_id,
295 NC_PARAMTYPE paramtype)
296{
297 struct nc_rpc_commit *rpc;
298
299 rpc = malloc(sizeof *rpc);
300 if (!rpc) {
301 ERRMEM;
302 return NULL;
303 }
304
305 rpc->type = NC_RPC_COMMIT;
306 rpc->confirmed = confirmed;
307 rpc->confirm_timeout = confirm_timeout;
308 if (persist && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
309 rpc->persist = strdup(persist);
310 } else {
311 rpc->persist = (char *)persist;
312 }
313 if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
314 rpc->persist_id = strdup(persist_id);
315 } else {
316 rpc->persist_id = (char *)persist_id;
317 }
318 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
319
320 return (struct nc_rpc *)rpc;
321}
322
323API struct nc_rpc *
324nc_rpc_discard(void)
325{
326 struct nc_rpc *rpc;
327
328 rpc = malloc(sizeof *rpc);
329 if (!rpc) {
330 ERRMEM;
331 return NULL;
332 }
333
334 rpc->type = NC_RPC_DISCARD;
335
336 return rpc;
337}
338
339API struct nc_rpc *
340nc_rpc_cancel(const char *persist_id, NC_PARAMTYPE paramtype)
341{
342 struct nc_rpc_cancel *rpc;
343
344 rpc = malloc(sizeof *rpc);
345 if (!rpc) {
346 ERRMEM;
347 return NULL;
348 }
349
350 rpc->type = NC_RPC_CANCEL;
351 if (persist_id && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
352 rpc->persist_id = strdup(persist_id);
353 } else {
354 rpc->persist_id = (char *)persist_id;
355 }
356 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
357
358 return (struct nc_rpc *)rpc;
359}
360
361API struct nc_rpc *
362nc_rpc_validate(NC_DATASTORE source, const char *url_or_config, NC_PARAMTYPE paramtype)
363{
364 struct nc_rpc_validate *rpc;
365
366 if (url_or_config && (url_or_config[0] != '<') && !isalpha(url_or_config[0])) {
367 ERR("<validate> source is neither a URL nor a config (XML).");
368 return NULL;
369 }
370
371 rpc = malloc(sizeof *rpc);
372 if (!rpc) {
373 ERRMEM;
374 return NULL;
375 }
376
377 rpc->type = NC_RPC_VALIDATE;
378 rpc->source = source;
379 if (url_or_config && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
380 rpc->url_config_src = strdup(url_or_config);
381 } else {
382 rpc->url_config_src = (char *)url_or_config;
383 }
384 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
385
386 return (struct nc_rpc *)rpc;
387}
388
389API struct nc_rpc *
390nc_rpc_getschema(const char *identifier, const char *version, const char *format, NC_PARAMTYPE paramtype)
391{
392 struct nc_rpc_getschema *rpc;
393
394 rpc = malloc(sizeof *rpc);
395 if (!rpc) {
396 ERRMEM;
397 return NULL;
398 }
399
400 rpc->type = NC_RPC_GETSCHEMA;
401 if (paramtype == NC_PARAMTYPE_DUP_AND_FREE) {
402 rpc->identifier = strdup(identifier);
403 } else {
404 rpc->identifier = (char *)identifier;
405 }
406 if (version && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
407 rpc->version = strdup(version);
408 } else {
409 rpc->version = (char *)version;
410 }
411 if (format && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
412 rpc->format = strdup(format);
413 } else {
414 rpc->format = (char *)format;
415 }
416 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
417
418 return (struct nc_rpc *)rpc;
419}
420
421API struct nc_rpc *
422nc_rpc_subscribe(const char *stream_name, const char *filter, const char *start_time, const char *stop_time,
423 NC_PARAMTYPE paramtype)
424{
425 struct nc_rpc_subscribe *rpc;
426
427 if (filter && (filter[0] != '<') && (filter[0] != '/') && !isalpha(filter[0])) {
428 ERR("Filter must either be an XML subtree or an XPath expression.");
429 return NULL;
430 }
431
432 rpc = malloc(sizeof *rpc);
433 if (!rpc) {
434 ERRMEM;
435 return NULL;
436 }
437
438 rpc->type = NC_RPC_SUBSCRIBE;
439 if (stream_name && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
440 rpc->stream = strdup(stream_name);
441 } else {
442 rpc->stream = (char *)stream_name;
443 }
444 if (filter && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
445 rpc->filter = strdup(filter);
446 } else {
447 rpc->filter = (char *)filter;
448 }
449 if (start_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
450 rpc->start = strdup(start_time);
451 } else {
452 rpc->start = (char *)start_time;
453 }
454 if (stop_time && (paramtype == NC_PARAMTYPE_DUP_AND_FREE)) {
455 rpc->stop = strdup(stop_time);
456 } else {
457 rpc->stop = (char *)stop_time;
458 }
459 rpc->free = (paramtype == NC_PARAMTYPE_CONST ? 0 : 1);
460
461 return (struct nc_rpc *)rpc;
462}
463
464API void
465nc_rpc_free(struct nc_rpc *rpc)
466{
467 struct nc_rpc_generic *rpc_generic;
468 struct nc_rpc_getconfig *rpc_getconfig;
469 struct nc_rpc_edit *rpc_edit;
470 struct nc_rpc_copy *rpc_copy;
471 struct nc_rpc_delete *rpc_delete;
472 struct nc_rpc_get *rpc_get;
473 struct nc_rpc_commit *rpc_commit;
474 struct nc_rpc_cancel *rpc_cancel;
475 struct nc_rpc_validate *rpc_validate;
476 struct nc_rpc_getschema *rpc_getschema;
477 struct nc_rpc_subscribe *rpc_subscribe;
478
479 if (!rpc) {
480 return;
481 }
482
483 switch (rpc->type) {
484 case NC_RPC_GENERIC:
485 rpc_generic = (struct nc_rpc_generic *)rpc;
486 if (rpc_generic->free) {
487 if (rpc_generic->has_data) {
488 lyd_free(rpc_generic->content.data);
489 } else {
490 free(rpc_generic->content.xml_str);
491 }
492 }
493 break;
494 case NC_RPC_GETCONFIG:
495 rpc_getconfig = (struct nc_rpc_getconfig *)rpc;
496 if (rpc_getconfig->free) {
497 free(rpc_getconfig->filter);
498 }
499 break;
500 case NC_RPC_EDIT:
501 rpc_edit = (struct nc_rpc_edit *)rpc;
502 if (rpc_edit->free) {
503 free(rpc_edit->edit_cont);
504 }
505 break;
506 case NC_RPC_COPY:
507 rpc_copy = (struct nc_rpc_copy *)rpc;
508 if (rpc_copy->free) {
509 free(rpc_copy->url_config_src);
510 }
511 break;
512 case NC_RPC_DELETE:
513 rpc_delete = (struct nc_rpc_delete *)rpc;
514 if (rpc_delete->free) {
515 free(rpc_delete->url);
516 }
517 break;
518 case NC_RPC_GET:
519 rpc_get = (struct nc_rpc_get *)rpc;
520 if (rpc_get->free) {
521 free(rpc_get->filter);
522 }
523 break;
524 case NC_RPC_COMMIT:
525 rpc_commit = (struct nc_rpc_commit *)rpc;
526 if (rpc_commit->free) {
527 free(rpc_commit->persist);
528 free(rpc_commit->persist_id);
529 }
530 break;
531 case NC_RPC_CANCEL:
532 rpc_cancel = (struct nc_rpc_cancel *)rpc;
533 if (rpc_cancel->free) {
534 free(rpc_cancel->persist_id);
535 }
536 break;
537 case NC_RPC_VALIDATE:
538 rpc_validate = (struct nc_rpc_validate *)rpc;
539 if (rpc_validate->free) {
540 free(rpc_validate->url_config_src);
541 }
542 break;
543 case NC_RPC_GETSCHEMA:
544 rpc_getschema = (struct nc_rpc_getschema *)rpc;
545 if (rpc_getschema->free) {
546 free(rpc_getschema->identifier);
547 free(rpc_getschema->version);
548 free(rpc_getschema->format);
549 }
550 break;
551 case NC_RPC_SUBSCRIBE:
552 rpc_subscribe = (struct nc_rpc_subscribe *)rpc;
553 if (rpc_subscribe->free) {
554 free(rpc_subscribe->stream);
555 free(rpc_subscribe->filter);
556 free(rpc_subscribe->start);
557 free(rpc_subscribe->stop);
558 }
559 break;
560 case NC_RPC_KILL:
561 case NC_RPC_DISCARD:
562 case NC_RPC_LOCK:
563 case NC_RPC_UNLOCK:
564 /* nothing special needed */
565 break;
566 }
567
568 free(rpc);
569}
570
571API void
572nc_reply_free(struct nc_reply *reply)
573{
574 struct nc_reply_error *error;
575 struct nc_reply_data *data;
576 uint32_t i, j;
577
578 if (!reply) {
579 return;
580 }
581
582 switch (reply->type) {
583 case NC_RPL_DATA:
584 data = (struct nc_reply_data *)reply;
585 lyd_free_withsiblings(data->data);
586 break;
587
588 case NC_RPL_OK:
589 /* nothing to free */
590 break;
591
592 case NC_RPL_ERROR:
593 error = (struct nc_reply_error *)reply;
594 for (i = 0; i < error->count; ++i) {
595 lydict_remove(error->ctx, error->err[i].type);
596 lydict_remove(error->ctx, error->err[i].tag);
597 lydict_remove(error->ctx, error->err[i].severity);
598 lydict_remove(error->ctx, error->err[i].apptag);
599 lydict_remove(error->ctx, error->err[i].path);
600 lydict_remove(error->ctx, error->err[i].message);
601 lydict_remove(error->ctx, error->err[i].message_lang);
602 lydict_remove(error->ctx, error->err[i].sid);
603 for (j = 0; j < error->err[i].attr_count; ++j) {
604 lydict_remove(error->ctx, error->err[i].attr[j]);
605 }
606 free(error->err[i].attr);
607 for (j = 0; j < error->err[i].elem_count; ++j) {
608 lydict_remove(error->ctx, error->err[i].elem[j]);
609 }
610 free(error->err[i].elem);
611 for (j = 0; j < error->err[i].ns_count; ++j) {
612 lydict_remove(error->ctx, error->err[i].ns[j]);
613 }
614 free(error->err[i].ns);
615 for (j = 0; j < error->err[i].other_count; ++j) {
616 lyxml_free(error->ctx, error->err[i].other[j]);
617 }
618 free(error->err[i].other);
619 }
620 free(error->err);
621 break;
622
623 case NC_RPL_NOTIF:
624 nc_notif_free((struct nc_notif *)reply);
625 break;
626 }
627
628 free(reply);
629}