blob: d06bc77b6bc9e97e87ae8fe741f6383e5bb964e0 [file] [log] [blame]
Radek Krejci206fcd62015-10-07 15:42:48 +02001/**
2 * \file session.c
Michal Vasko086311b2016-01-08 09:53:11 +01003 * \author Michal Vasko <mvasko@cesnet.cz>
4 * \brief libnetconf2 - general session functions
Radek Krejci206fcd62015-10-07 15:42:48 +02005 *
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
Radek Krejci206fcd62015-10-07 15:42:48 +020023#include <errno.h>
Radek Krejci952eb862016-01-08 14:22:55 +010024#include <stdlib.h>
Radek Krejciac6d3472015-10-22 15:47:18 +020025#include <pthread.h>
Radek Krejci206fcd62015-10-07 15:42:48 +020026#include <libyang/libyang.h>
27
Michal Vasko086311b2016-01-08 09:53:11 +010028#ifdef ENABLE_SSH
Radek Krejci206fcd62015-10-07 15:42:48 +020029
Michal Vasko086311b2016-01-08 09:53:11 +010030# include <libssh/libssh.h>
Radek Krejci206fcd62015-10-07 15:42:48 +020031
Michal Vasko086311b2016-01-08 09:53:11 +010032#endif /* ENABLE_SSH */
Radek Krejci695d4fa2015-10-22 13:23:54 +020033
Michal Vasko086311b2016-01-08 09:53:11 +010034#include "config.h"
35#include "log_p.h"
36#include "session.h"
37#include "session_p.h"
Radek Krejci695d4fa2015-10-22 13:23:54 +020038
Michal Vasko086311b2016-01-08 09:53:11 +010039/* in seconds */
40#define NC_CLIENT_HELLO_TIMEOUT 60
Radek Krejci695d4fa2015-10-22 13:23:54 +020041
Michal Vasko086311b2016-01-08 09:53:11 +010042extern struct nc_server_opts server_opts;
43
44NC_MSG_TYPE
45nc_send_msg(struct nc_session *session, struct lyd_node *op)
Radek Krejci695d4fa2015-10-22 13:23:54 +020046{
Michal Vasko086311b2016-01-08 09:53:11 +010047 int r;
Radek Krejci695d4fa2015-10-22 13:23:54 +020048
Michal Vasko086311b2016-01-08 09:53:11 +010049 if (session->ctx != op->schema->module->ctx) {
50 ERR("RPC \"%s\" was created in different context than that of \"%s\" session %u.",
51 op->schema->name, session->username, session->id);
52 return NC_MSG_ERROR;
Michal Vasko7df39ec2015-12-09 15:26:24 +010053 }
54
Michal Vasko086311b2016-01-08 09:53:11 +010055 r = nc_write_msg(session, NC_MSG_RPC, op, NULL);
56
57 if (r) {
58 return NC_MSG_ERROR;
59 }
60
61 return NC_MSG_RPC;
Michal Vasko7df39ec2015-12-09 15:26:24 +010062}
63
Radek Krejci5686ff72015-10-09 13:33:56 +020064/*
65 * @return 0 - success
66 * -1 - timeout
67 * >0 - error
68 */
Michal Vasko086311b2016-01-08 09:53:11 +010069int
Michal Vaskoc111ac52015-12-08 14:36:36 +010070session_ti_lock(struct nc_session *session, int32_t timeout)
Radek Krejci206fcd62015-10-07 15:42:48 +020071{
72 int r;
Radek Krejci206fcd62015-10-07 15:42:48 +020073
74 if (timeout >= 0) {
75 /* limited waiting for lock */
76 do {
Radek Krejci695d4fa2015-10-22 13:23:54 +020077 r = pthread_mutex_trylock(session->ti_lock);
Radek Krejci206fcd62015-10-07 15:42:48 +020078 if (r == EBUSY) {
79 /* try later until timeout passes */
Michal Vasko086311b2016-01-08 09:53:11 +010080 usleep(NC_TIMEOUT_STEP);
81 timeout = timeout - NC_TIMEOUT_STEP;
Radek Krejci206fcd62015-10-07 15:42:48 +020082 continue;
83 } else if (r) {
84 /* error */
85 ERR("Acquiring session (%u) TI lock failed (%s).", session->id, strerror(r));
Radek Krejci5686ff72015-10-09 13:33:56 +020086 return r;
Radek Krejci206fcd62015-10-07 15:42:48 +020087 } else {
88 /* lock acquired */
Radek Krejci5686ff72015-10-09 13:33:56 +020089 return 0;
Radek Krejci206fcd62015-10-07 15:42:48 +020090 }
91 } while(timeout > 0);
92
Radek Krejci5686ff72015-10-09 13:33:56 +020093 /* timeout has passed */
94 return -1;
Radek Krejci206fcd62015-10-07 15:42:48 +020095 } else {
96 /* infinite waiting for lock */
Radek Krejci695d4fa2015-10-22 13:23:54 +020097 return pthread_mutex_lock(session->ti_lock);
Radek Krejci5686ff72015-10-09 13:33:56 +020098 }
99}
100
Michal Vasko086311b2016-01-08 09:53:11 +0100101int
Radek Krejci5686ff72015-10-09 13:33:56 +0200102session_ti_unlock(struct nc_session *session)
103{
Radek Krejci695d4fa2015-10-22 13:23:54 +0200104 return pthread_mutex_unlock(session->ti_lock);
105}
106
Radek Krejci695d4fa2015-10-22 13:23:54 +0200107API void
108nc_session_free(struct nc_session *session)
109{
110 int r, i;
111 int multisession = 0; /* flag for more NETCONF session on a single SSH session */
112 struct nc_session *siter;
Michal Vaskoad611702015-12-03 13:41:51 +0100113 struct nc_msg_cont *contiter;
Michal Vaskoadd4c792015-10-26 15:36:58 +0100114 struct lyxml_elem *rpl, *child;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200115 struct lyd_node *close_rpc;
Michal Vaskoad611702015-12-03 13:41:51 +0100116 const struct lys_module *ietfnc;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200117 void *p;
118
Michal Vaskoadd4c792015-10-26 15:36:58 +0100119 if (!session || session->status == NC_STATUS_CLOSING) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200120 return;
121 }
122
123 /* mark session for closing */
Michal Vaskoadd4c792015-10-26 15:36:58 +0100124 if (session->ti_lock) {
125 do {
126 r = session_ti_lock(session, 0);
127 } while (r < 0);
128 if (r) {
129 return;
130 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200131 }
132
133 /* stop notifications loop if any */
134 if (session->notif) {
135 pthread_cancel(*session->notif);
136 pthread_join(*session->notif, NULL);
137 }
138
139 if (session->side == NC_CLIENT && session->status == NC_STATUS_RUNNING) {
140 /* cleanup message queues */
141 /* notifications */
Michal Vaskoad611702015-12-03 13:41:51 +0100142 for (contiter = session->notifs; contiter; ) {
143 lyxml_free(session->ctx, contiter->msg);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200144
Michal Vaskoad611702015-12-03 13:41:51 +0100145 p = contiter;
146 contiter = contiter->next;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200147 free(p);
148 }
149
150 /* rpc replies */
Michal Vaskoad611702015-12-03 13:41:51 +0100151 for (contiter = session->replies; contiter; ) {
152 lyxml_free(session->ctx, contiter->msg);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200153
Michal Vaskoad611702015-12-03 13:41:51 +0100154 p = contiter;
155 contiter = contiter->next;
Radek Krejci695d4fa2015-10-22 13:23:54 +0200156 free(p);
157 }
158
159 /* send closing info to the other side */
160 ietfnc = ly_ctx_get_module(session->ctx, "ietf-netconf", NULL);
161 if (!ietfnc) {
Michal Vaskoad611702015-12-03 13:41:51 +0100162 WRN("%s: Missing ietf-netconf schema in context (session %u), unable to send <close-session\\>", __func__, session->id);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200163 } else {
164 close_rpc = lyd_new(NULL, ietfnc, "close-session");
Michal Vaskoad611702015-12-03 13:41:51 +0100165 nc_send_msg(session, close_rpc);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200166 lyd_free(close_rpc);
Michal Vaskofad6e912015-10-26 15:37:22 +0100167 switch (nc_read_msg(session, 200, &rpl)) {
168 case NC_MSG_REPLY:
169 LY_TREE_FOR(rpl->child, child) {
170 if (!strcmp(child->name, "ok") && child->ns && !strcmp(child->ns->value, NC_NS_BASE)) {
171 break;
172 }
173 }
174 if (!child) {
175 WRN("The reply to <close-session\\> was not <ok\\> as expected.");
176 }
Michal Vaskoad611702015-12-03 13:41:51 +0100177 lyxml_free(session->ctx, rpl);
Michal Vaskofad6e912015-10-26 15:37:22 +0100178 break;
179 case NC_MSG_WOULDBLOCK:
180 WRN("Timeout for receiving a reply to <close-session\\> elapsed.");
181 break;
182 case NC_MSG_ERROR:
183 ERR("Failed to receive a reply to <close-session\\>.");
184 break;
185 default:
186 /* cannot happen */
187 break;
188 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200189 }
190
191 /* list of server's capabilities */
192 if (session->cpblts) {
193 for (i = 0; session->cpblts[i]; i++) {
194 lydict_remove(session->ctx, session->cpblts[i]);
195 }
196 free(session->cpblts);
197 }
198 }
199
200 session->status = NC_STATUS_CLOSING;
201
202 /* transport implementation cleanup */
203 switch (session->ti_type) {
Michal Vasko38a7c6c2015-12-04 12:29:20 +0100204 case NC_TI_NONE:
205 break;
206
Radek Krejci695d4fa2015-10-22 13:23:54 +0200207 case NC_TI_FD:
208 /* nothing needed - file descriptors were provided by caller,
209 * so it is up to the caller to close them correctly
210 * TODO use callbacks
211 */
212 break;
213
Michal Vaskofb2fb762015-10-27 11:44:32 +0100214#ifdef ENABLE_SSH
Radek Krejci695d4fa2015-10-22 13:23:54 +0200215 case NC_TI_LIBSSH:
216 ssh_channel_free(session->ti.libssh.channel);
217 /* There can be multiple NETCONF sessions on the same SSH session (NETCONF session maps to
218 * SSH channel). So destroy the SSH session only if there is no other NETCONF session using
219 * it.
220 */
221 if (!session->ti.libssh.next) {
222 ssh_disconnect(session->ti.libssh.session);
223 ssh_free(session->ti.libssh.session);
224 } else {
225 /* multiple NETCONF sessions on a single SSH session */
226 multisession = 1;
227 /* remove the session from the list */
228 for (siter = session->ti.libssh.next; siter->ti.libssh.next != session; siter = siter->ti.libssh.next);
Michal Vaskoaec4f212015-10-26 15:37:45 +0100229 if (session->ti.libssh.next == siter) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200230 /* there will be only one session */
231 siter->ti.libssh.next = NULL;
232 } else {
233 /* there are still multiple sessions, keep the ring list */
234 siter->ti.libssh.next = session->ti.libssh.next;
235 }
236 }
237 break;
238#endif
239
240#ifdef ENABLE_TLS
241 case NC_TI_OPENSSL:
242 SSL_shutdown(session->ti.tls);
243 SSL_free(session->ti.tls);
244 break;
245#endif
246 }
Radek Krejciac6d3472015-10-22 15:47:18 +0200247 lydict_remove(session->ctx, session->username);
248 lydict_remove(session->ctx, session->host);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200249
250 /* final cleanup */
Michal Vaskoadd4c792015-10-26 15:36:58 +0100251 if (session->ti_lock) {
252 if (multisession) {
253 session_ti_unlock(session);
254 } else {
255 pthread_mutex_destroy(session->ti_lock);
256 free(session->ti_lock);
257 }
Radek Krejci695d4fa2015-10-22 13:23:54 +0200258 }
259
260 if (!(session->flags & NC_SESSION_SHAREDCTX)) {
261 ly_ctx_destroy(session->ctx);
262 }
263
264 free(session);
265}
266
Michal Vasko086311b2016-01-08 09:53:11 +0100267static void
268add_cpblt(struct ly_ctx *ctx, const char *capab, const char ***cpblts, int *size, int *count)
269{
270 if (*count == *size) {
271 *size += 5;
272 *cpblts = realloc(*cpblts, *size * sizeof **cpblts);
273 }
274
275 if (capab) {
276 (*cpblts)[*count] = lydict_insert(ctx, capab, 0);
277 } else {
278 (*cpblts)[*count] = NULL;
279 }
280 ++(*count);
281}
282
283static const char **
284create_cpblts(struct ly_ctx *ctx)
285{
286 struct lyd_node *child, *child2, *yanglib;
287 struct lyd_node_leaf_list **features = NULL, *ns = NULL, *rev = NULL, *name = NULL;
288 const char **cpblts;
289 const struct lys_module *mod;
290 int size = 10, count, feat_count = 0, i;
291 char str[512];
292
293 yanglib = ly_ctx_info(ctx);
294 if (!yanglib) {
295 return NULL;
296 }
297
298 cpblts = malloc(size * sizeof *cpblts);
299 cpblts[0] = lydict_insert(ctx, "urn:ietf:params:netconf:base:1.0", 0);
300 cpblts[1] = lydict_insert(ctx, "urn:ietf:params:netconf:base:1.1", 0);
301 count = 2;
302
303 /* capabilities */
304
305 mod = ly_ctx_get_module(ctx, "ietf-netconf", NULL);
306 if (mod) {
307 if (lys_features_state(mod, "writable-running") == 1) {
308 add_cpblt(ctx, "urn:ietf:params:netconf:writable-running:1.0", &cpblts, &size, &count);
309 }
310 if (lys_features_state(mod, "candidate") == 1) {
311 add_cpblt(ctx, "urn:ietf:params:netconf:candidate:1.0", &cpblts, &size, &count);
312 if (lys_features_state(mod, "confirmed-commit") == 1) {
313 add_cpblt(ctx, "urn:ietf:params:netconf:confirmed-commit:1.1", &cpblts, &size, &count);
314 }
315 }
316 if (lys_features_state(mod, "rollback-on-error") == 1) {
317 add_cpblt(ctx, "urn:ietf:params:netconf:rollback-on-error:1.0", &cpblts, &size, &count);
318 }
319 if (lys_features_state(mod, "validate") == 1) {
320 add_cpblt(ctx, "urn:ietf:params:netconf:validate:1.1", &cpblts, &size, &count);
321 }
322 if (lys_features_state(mod, "startup") == 1) {
323 add_cpblt(ctx, "urn:ietf:params:netconf:startup:1.0", &cpblts, &size, &count);
324 }
325 if (lys_features_state(mod, "url") == 1) {
326 add_cpblt(ctx, "urn:ietf:params:netconf:url:1.0", &cpblts, &size, &count);
327 }
328 if (lys_features_state(mod, "xpath") == 1) {
329 add_cpblt(ctx, "urn:ietf:params:netconf:xpath:1.0", &cpblts, &size, &count);
330 }
331 }
332
333 mod = ly_ctx_get_module(ctx, "ietf-netconf-with-defaults", NULL);
334 if (mod) {
335 if (!server_opts.wd_basic_mode) {
336 VRB("with-defaults capability will not be advertised even though \"ietf-netconf-with-defaults\" model is present, unknown basic-mode.");
337 } else {
338 strcpy(str, "urn:ietf:params:netconf:with-defaults:1.0");
339 switch (server_opts.wd_basic_mode) {
340 case NC_WD_ALL:
341 strcat(str, "?basic-mode=report-all");
342 break;
343 case NC_WD_TRIM:
344 strcat(str, "?basic-mode=trim");
345 break;
346 case NC_WD_EXPLICIT:
347 strcat(str, "?basic-mode=explicit");
348 break;
349 default:
Michal Vasko9e036d52016-01-08 10:49:26 +0100350 ERRINT;
Michal Vasko086311b2016-01-08 09:53:11 +0100351 break;
352 }
353
354 if (server_opts.wd_also_supported) {
Radek Krejcif9b28322016-01-08 14:56:43 +0100355 strcat(str, "&amp;also-supported=");
Michal Vasko086311b2016-01-08 09:53:11 +0100356 if (server_opts.wd_also_supported & NC_WD_ALL) {
357 strcat(str, "report-all,");
358 }
359 if (server_opts.wd_also_supported & NC_WD_ALL_TAG) {
360 strcat(str, "report-all-tagged,");
361 }
362 if (server_opts.wd_also_supported & NC_WD_TRIM) {
363 strcat(str, "trim,");
364 }
365 if (server_opts.wd_also_supported & NC_WD_EXPLICIT) {
366 strcat(str, "explicit,");
367 }
368 str[strlen(str) - 1] = '\0';
369
370 add_cpblt(ctx, str, &cpblts, &size, &count);
371 }
372 }
373 }
374
375 mod = ly_ctx_get_module(ctx, "ietf-netconf-notifications", NULL);
376 if (mod) {
377 add_cpblt(ctx, "urn:ietf:params:netconf:notification:1.0", &cpblts, &size, &count);
378 if (server_opts.interleave_capab) {
379 add_cpblt(ctx, "urn:ietf:params:netconf:interleave:1.0", &cpblts, &size, &count);
380 }
381 }
382
383 /* models */
384
385 LY_TREE_FOR(yanglib->child, child) {
386 if (!strcmp(child->schema->name, "module")) {
387 LY_TREE_FOR(child->child, child2) {
388 if (!strcmp(child2->schema->name, "namespace")) {
389 ns = (struct lyd_node_leaf_list *)child2;
390 } else if (!strcmp(child2->schema->name, "name")) {
391 name = (struct lyd_node_leaf_list *)child2;
392 } else if (!strcmp(child2->schema->name, "revision")) {
393 rev = (struct lyd_node_leaf_list *)child2;
394 } else if (!strcmp(child2->schema->name, "feature")) {
395 features = realloc(features, feat_count++ * sizeof *features);
396 features[feat_count - 1] = (struct lyd_node_leaf_list *)child2;
397 }
398 }
399
400 if (!ns || !name || !rev) {
Michal Vasko9e036d52016-01-08 10:49:26 +0100401 ERRINT;
Michal Vasko086311b2016-01-08 09:53:11 +0100402 continue;
403 }
404
Radek Krejcif9b28322016-01-08 14:56:43 +0100405 sprintf(str, "%s?module=%s&amp;revision=%s", ns->value_str, name->value_str, rev->value_str);
Michal Vasko086311b2016-01-08 09:53:11 +0100406 if (feat_count) {
Radek Krejcif9b28322016-01-08 14:56:43 +0100407 strcat(str, "&amp;features=");
Michal Vasko086311b2016-01-08 09:53:11 +0100408 for (i = 0; i < feat_count; ++i) {
409 if (i) {
410 strcat(str, ",");
411 }
412 strcat(str, features[i]->value_str);
413 }
414 }
415
416 add_cpblt(ctx, str, &cpblts, &size, &count);
417
418 ns = NULL;
419 name = NULL;
420 rev = NULL;
421 free(features);
422 features = NULL;
423 feat_count = 0;
424 }
425 }
426
427 lyd_free(yanglib);
428
429 /* ending NULL capability */
430 add_cpblt(ctx, NULL, &cpblts, &size, &count);
431
432 return cpblts;
433}
434
Radek Krejci695d4fa2015-10-22 13:23:54 +0200435static int
436parse_cpblts(struct lyxml_elem *xml, const char ***list)
437{
438 struct lyxml_elem *cpblt;
439 int ver = -1;
440 int i = 0;
441
442 if (list) {
443 /* get the storage for server's capabilities */
444 LY_TREE_FOR(xml->child, cpblt) {
445 i++;
446 }
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100447 /* last item remains NULL */
448 *list = calloc(i + 1, sizeof **list);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200449 if (!*list) {
450 ERRMEM;
451 return -1;
452 }
453 i = 0;
454 }
455
456 LY_TREE_FOR(xml->child, cpblt) {
457 if (strcmp(cpblt->name, "capability") && cpblt->ns && cpblt->ns->value &&
458 !strcmp(cpblt->ns->value, NC_NS_BASE)) {
459 ERR("Unexpected <%s> element in client's <hello>.", cpblt->name);
460 return -1;
461 } else if (!cpblt->ns || !cpblt->ns->value || strcmp(cpblt->ns->value, NC_NS_BASE)) {
462 continue;
463 }
464
465 /* detect NETCONF version */
466 if (ver < 0 && !strcmp(cpblt->content, "urn:ietf:params:netconf:base:1.0")) {
467 ver = 0;
468 } else if (ver < 1 && !strcmp(cpblt->content, "urn:ietf:params:netconf:base:1.1")) {
469 ver = 1;
470 }
471
472 /* store capabilities */
473 if (list) {
474 (*list)[i] = cpblt->content;
475 cpblt->content = NULL;
476 i++;
477 }
478 }
479
480 if (ver == -1) {
481 ERR("Peer does not support compatible NETCONF version.");
482 }
483
484 return ver;
485}
486
487static NC_MSG_TYPE
Michal Vasko086311b2016-01-08 09:53:11 +0100488nc_send_hello(struct nc_session *session)
489{
490 int r, i;
491 const char **cpblts;
492
493 if (session->side == NC_CLIENT) {
494 /* client side hello - send only NETCONF base capabilities */
495 cpblts = malloc(3 * sizeof *cpblts);
496 cpblts[0] = lydict_insert(session->ctx, "urn:ietf:params:netconf:base:1.0", 0);
497 cpblts[1] = lydict_insert(session->ctx, "urn:ietf:params:netconf:base:1.1", 0);
498 cpblts[2] = NULL;
499 } else {
500 cpblts = create_cpblts(session->ctx);
501 }
502
503 r = nc_write_msg(session, NC_MSG_HELLO, cpblts, NULL);
504 for (i = 0; cpblts[i]; ++i) {
505 lydict_remove(session->ctx, cpblts[i]);
506 }
507 free(cpblts);
508
509 if (r) {
510 return NC_MSG_ERROR;
511 } else {
512 return NC_MSG_HELLO;
513 }
514}
515
516static NC_MSG_TYPE
Radek Krejci695d4fa2015-10-22 13:23:54 +0200517nc_recv_hello(struct nc_session *session)
518{
519 struct lyxml_elem *xml = NULL, *node;
520 NC_MSG_TYPE msgtype = 0; /* NC_MSG_ERROR */
521 int ver = -1;
522 char *str;
523 long long int id;
524 int flag = 0;
525
Michal Vasko086311b2016-01-08 09:53:11 +0100526 msgtype = nc_read_msg(session, NC_CLIENT_HELLO_TIMEOUT * 1000, &xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200527
528 switch(msgtype) {
529 case NC_MSG_HELLO:
530 /* parse <hello> data */
531 if (session->side == NC_SERVER) {
532 /* get know NETCONF version */
533 LY_TREE_FOR(xml->child, node) {
534 if (!node->ns || !node->ns->value || strcmp(node->ns->value, NC_NS_BASE)) {
535 continue;
536 } else if (strcmp(node->name, "capabilities")) {
537 ERR("Unexpected <%s> element in client's <hello>.", node->name);
538 goto error;
539 }
540
541 if (flag) {
542 /* multiple capabilities elements */
543 ERR("Invalid <hello> message (multiple <capabilities> elements)");
544 goto error;
545 }
546 flag = 1;
547
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100548 if ((ver = parse_cpblts(node, &session->cpblts)) < 0) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200549 goto error;
550 }
551 session->version = ver;
552 }
553 } else { /* NC_CLIENT */
554 LY_TREE_FOR(xml->child, node) {
555 if (!node->ns || !node->ns->value || strcmp(node->ns->value, NC_NS_BASE)) {
556 continue;
557 } else if (!strcmp(node->name, "session-id")) {
558 if (!node->content || !strlen(node->content)) {
559 ERR("No value of <session-id> element in server's <hello>");
560 goto error;
561 }
562 str = NULL;
563 id = strtoll(node->content, &str, 10);
564 if (*str || id < 1 || id > UINT32_MAX) {
565 ERR("Invalid value of <session-id> element in server's <hello>");
566 goto error;
567 }
568 session->id = (uint32_t)id;
569 continue;
570 } else if (strcmp(node->name, "capabilities")) {
571 ERR("Unexpected <%s> element in client's <hello>.", node->name);
572 goto error;
573 }
574
575 if (flag) {
576 /* multiple capabilities elements */
577 ERR("Invalid <hello> message (multiple <capabilities> elements)");
578 goto error;
579 }
580 flag = 1;
581
Michal Vasko9e2d3a32015-11-10 13:09:18 +0100582 if ((ver = parse_cpblts(node, &session->cpblts)) < 0) {
Radek Krejci695d4fa2015-10-22 13:23:54 +0200583 goto error;
584 }
585 session->version = ver;
586 }
587
588 if (!session->id) {
589 ERR("Missing <session-id> in server's <hello>");
590 goto error;
591 }
592 }
593 break;
594 case NC_MSG_ERROR:
595 /* nothing special, just pass it out */
596 break;
597 default:
598 ERR("Unexpected message received instead of <hello>.");
599 msgtype = NC_MSG_ERROR;
600 }
601
602 /* cleanup */
Michal Vaskoad611702015-12-03 13:41:51 +0100603 lyxml_free(session->ctx, xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200604
605 return msgtype;
606
607error:
608 /* cleanup */
Michal Vaskoad611702015-12-03 13:41:51 +0100609 lyxml_free(session->ctx, xml);
Radek Krejci695d4fa2015-10-22 13:23:54 +0200610
611 return NC_MSG_ERROR;
Radek Krejci5686ff72015-10-09 13:33:56 +0200612}
613
Michal Vasko80cad7f2015-12-08 14:42:27 +0100614int
Michal Vasko086311b2016-01-08 09:53:11 +0100615nc_handshake(struct nc_session *session)
Michal Vasko80cad7f2015-12-08 14:42:27 +0100616{
Michal Vasko086311b2016-01-08 09:53:11 +0100617 NC_MSG_TYPE type;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100618
Michal Vasko086311b2016-01-08 09:53:11 +0100619 type = nc_send_hello(session);
620 if (type != NC_MSG_HELLO) {
621 return 1;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100622 }
623
Michal Vasko086311b2016-01-08 09:53:11 +0100624 type = nc_recv_hello(session);
625 if (type != NC_MSG_HELLO) {
626 return 1;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100627 }
628
Michal Vasko086311b2016-01-08 09:53:11 +0100629 return 0;
Michal Vasko80cad7f2015-12-08 14:42:27 +0100630}
Michal Vasko086311b2016-01-08 09:53:11 +0100631
632#ifdef ENABLE_SSH
633
634API void
635nc_ssh_init(void)
636{
637 ssh_threads_set_callbacks(ssh_threads_get_pthread());
638 ssh_init();
639 ssh_set_log_level(verbose_level);
640}
641
642API void
643nc_ssh_destroy(void)
644{
645 ssh_finalize();
646}
647
648#endif /* ENABLE_SSH */