FEATURE new session context checking and creation
TODO get schemas using <get-schema>
diff --git a/src/session.c b/src/session.c
index 58309bf..9898e71 100644
--- a/src/session.c
+++ b/src/session.c
@@ -104,7 +104,7 @@
}
int
-handshake(struct nc_session *session)
+nc_handshake(struct nc_session *session)
{
NC_MSG_TYPE type;
@@ -122,9 +122,89 @@
}
static int
-connect_load_schemas(struct ly_ctx *ctx)
+ctx_load_model(struct nc_session *session, const char *cpblt, int get_schema_support)
{
- int fd;
+ struct lys_module *module;
+ char *ptr, *ptr2;
+ char *model_name, *revision = NULL, *features = NULL;
+
+ /*if (get_schema_support) {
+ * TODO *
+ } else*/ {
+ /* parse module */
+ ptr = strstr(cpblt, "module=");
+ if (!ptr) {
+ WRN("Unknown capability \"%s\" could not be parsed.");
+ return 1;
+ }
+ ptr += 7;
+ ptr2 = strchr(ptr, '&');
+ if (!ptr2) {
+ ptr2 = ptr + strlen(ptr);
+ }
+ model_name = strndup(ptr, ptr2 - ptr);
+
+ /* parse revision */
+ ptr = strstr(cpblt, "revision=");
+ if (ptr) {
+ ptr += 9;
+ ptr2 = strchr(ptr, '&');
+ if (!ptr2) {
+ ptr2 = ptr + strlen(ptr);
+ }
+ revision = strndup(ptr, ptr2 - ptr);
+ }
+
+ /* load module */
+ module = ly_ctx_load_module(session->ctx, NULL, model_name, revision);
+
+ free(model_name);
+ free(revision);
+ if (!module) {
+ return 1;
+ }
+
+ /* parse features */
+ ptr = strstr(cpblt, "features=");
+ if (ptr) {
+ ptr += 9;
+ ptr2 = strchr(ptr, '&');
+ if (!ptr2) {
+ ptr2 = ptr + strlen(ptr);
+ }
+ features = strndup(ptr, ptr2 - ptr);
+ }
+
+ /* enable features */
+ if (features) {
+ /* basically manual strtok_r (to avoid macro) */
+ ptr2 = features;
+ for (ptr = features; *ptr; ++ptr) {
+ if (*ptr == ',') {
+ *ptr = '\0';
+ /* remember last feature */
+ ptr2 = ptr + 1;
+ }
+ }
+
+ ptr = features;
+ lys_features_enable(module, ptr);
+ while (ptr != ptr2) {
+ ptr += strlen(ptr) + 1;
+ lys_features_enable(module, ptr);
+ }
+
+ free(features);
+ }
+ }
+
+ return 0;
+}
+
+static int
+ctx_load_ietf_netconf(struct ly_ctx *ctx, const char **cpblts)
+{
+ int fd, i;
struct lys_module *ietfnc;
fd = open(SCHEMAS_DIR"ietf-netconf.yin", O_RDONLY);
@@ -134,69 +214,87 @@
}
if (!(ietfnc = lys_read(ctx, fd, LYS_IN_YIN))) {
ERR("Loading base NETCONF schema (%s) failed.", SCHEMAS_DIR"ietf-netconf");
+ close(fd);
return 1;
}
close(fd);
/* set supported capabilities from ietf-netconf */
- lys_features_enable(ietfnc, "writable-running");
- lys_features_enable(ietfnc, "candidate");
- //lys_features_enable(ietfnc, "confirmed-commit");
- lys_features_enable(ietfnc, "rollback-on-error");
- lys_features_enable(ietfnc, "validate");
- lys_features_enable(ietfnc, "startup");
- lys_features_enable(ietfnc, "url");
- lys_features_enable(ietfnc, "xpath");
+ for (i = 0; cpblts[i]; ++i) {
+ if (!strncmp(cpblts[i], "urn:ietf:params:netconf:capability:", 35)) {
+ if (!strncmp(cpblts[i] + 35, "writable-running", 16)) {
+ lys_features_enable(ietfnc, "writable-running");
+ } else if (!strncmp(cpblts[i] + 35, "candidate", 9)) {
+ lys_features_enable(ietfnc, "candidate");
+ } else if (!strcmp(cpblts[i] + 35, "confirmed-commit:1.1")) {
+ lys_features_enable(ietfnc, "confirmed-commit");
+ } else if (!strncmp(cpblts[i] + 35, "rollback-on-error", 17)) {
+ lys_features_enable(ietfnc, "rollback-on-error");
+ } else if (!strcmp(cpblts[i] + 35, "validate:1.1")) {
+ lys_features_enable(ietfnc, "validate");
+ } else if (!strncmp(cpblts[i] + 35, "startup", 7)) {
+ lys_features_enable(ietfnc, "startup");
+ } else if (!strncmp(cpblts[i] + 35, "url", 3)) {
+ lys_features_enable(ietfnc, "url");
+ } else if (!strncmp(cpblts[i] + 35, "xpath", 5)) {
+ lys_features_enable(ietfnc, "xpath");
+ }
+ }
+ }
return 0;
}
-struct nc_session *
-connect_init(struct ly_ctx *ctx)
+/* session with an empty context is assumed */
+int
+nc_ctx_fill(struct nc_session *session)
{
- struct nc_session *session = NULL;
- const char *str;
- int r;
+ int i, get_schema_support;
- /* prepare session structure */
- session = calloc(1, sizeof *session);
- if (!session) {
- ERRMEM;
- return NULL;
- }
- session->status = NC_STATUS_STARTING;
- session->side = NC_CLIENT;
+ assert(session->cpblts && session->ctx);
- /* YANG context for the session */
- if (ctx) {
- session->flags |= NC_SESSION_SHAREDCTX;
- session->ctx = ctx;
-
- /* check presence of the required schemas */
- if (!ly_ctx_get_module(session->ctx, "ietf-netconf", NULL)) {
- str = ly_ctx_get_searchdir(session->ctx);
- ly_ctx_set_searchdir(session->ctx, SCHEMAS_DIR);
- r = connect_load_schemas(session->ctx);
- ly_ctx_set_searchdir(session->ctx, str);
-
- if (r) {
- nc_session_free(session);
- return NULL;
- }
+ /* check if get-schema is supported */
+ get_schema_support = 0;
+ for (i = 0; session->cpblts[i]; ++i) {
+ if (!strncmp(session->cpblts[i], "urn:ietf:params:xml:ns:yang:ietf-netconf-monitoring", 51)) {
+ get_schema_support = 1;
+ break;
}
- } else {
- session->ctx = ly_ctx_new(SCHEMAS_DIR);
-
- /* load basic NETCONF schemas required for libnetconf work */
- if (connect_load_schemas(session->ctx)) {
- nc_session_free(session);
- return NULL;
- }
-
- ly_ctx_set_searchdir(session->ctx, schema_searchpath);
}
- return session;
+ /* load base model disregarding whether it's in capabilities (but NETCONF capabilities are used to enable features) */
+ if (ctx_load_ietf_netconf(session->ctx, session->cpblts)) {
+ goto fail;
+ }
+
+ /* load all other models */
+ for (i = 0; session->cpblts[i]; ++i) {
+ if (!strncmp(session->cpblts[i], "urn:ietf:params:netconf:capability", 34)
+ || !strncmp(session->cpblts[i], "urn:ietf:params:netconf:base", 28)) {
+ continue;
+ }
+
+ ctx_load_model(session, session->cpblts[i], get_schema_support);
+ }
+
+ return 0;
+
+fail:
+ free(session->ctx);
+ return 1;
+}
+
+int
+nc_ctx_check(struct nc_session *session)
+{
+ /* check presence of the required base schema */
+ if (!ly_ctx_get_module(session->ctx, "ietf-netconf", NULL)) {
+ if (ctx_load_ietf_netconf(session->ctx, session->cpblts)) {
+ return 1;
+ }
+ }
+
+ return 0;
}
API struct nc_session *
@@ -210,31 +308,53 @@
}
/* prepare session structure */
- session = connect_init(ctx);
+ session = calloc(1, sizeof *session);
if (!session) {
+ ERRMEM;
return NULL;
}
+ session->status = NC_STATUS_STARTING;
+ session->side = NC_CLIENT;
/* transport specific data */
session->ti_type = NC_TI_FD;
session->ti.fd.in = fdin;
session->ti.fd.out = fdout;
+ /* assign context (dicionary needed for handshake) */
+ if (!ctx) {
+ ctx = ly_ctx_new(SCHEMAS_DIR);
+ } else {
+ session->flags |= NC_SESSION_SHAREDCTX;
+ }
+ session->ctx = ctx;
+
/* NETCONF handshake */
- if (handshake(session)) {
- goto error;
+ if (nc_handshake(session)) {
+ goto fail;
+ }
+
+ /* check/fill libyang context */
+ if (session->flags & NC_SESSION_SHAREDCTX) {
+ if (nc_ctx_check(session)) {
+ goto fail;
+ }
+ } else {
+ if (nc_ctx_fill(session)) {
+ goto fail;
+ }
}
session->status = NC_STATUS_RUNNING;
return session;
-error:
+fail:
nc_session_free(session);
return NULL;
}
int
-connect_getsocket(const char* host, unsigned short port)
+nc_connect_getsocket(const char* host, unsigned short port)
{
int sock = -1;
int i;
@@ -458,7 +578,8 @@
LY_TREE_FOR(xml->child, cpblt) {
i++;
}
- *list = calloc(i, sizeof **list);
+ /* last item remains NULL */
+ *list = calloc(i + 1, sizeof **list);
if (!*list) {
ERRMEM;
return -1;
@@ -529,7 +650,7 @@
}
flag = 1;
- if ((ver = parse_cpblts(node, NULL)) < 0) {
+ if ((ver = parse_cpblts(node, &session->cpblts)) < 0) {
goto error;
}
session->version = ver;
@@ -563,7 +684,7 @@
}
flag = 1;
- if ((ver = parse_cpblts(node, NULL)) < 0) {
+ if ((ver = parse_cpblts(node, &session->cpblts)) < 0) {
goto error;
}
session->version = ver;
diff --git a/src/session.h b/src/session.h
index cb7478b..e2bca47 100644
--- a/src/session.h
+++ b/src/session.h
@@ -83,7 +83,9 @@
* (ignoring what is actually supported by the server side). If not set,
* YANG context is created for the session using \<get-schema\> (if supported
* by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()).
+ * (see nc_schema_searchpath()). In every case except not providing context
+ * to connect to a server supporting \<get-schema\> it is possible that
+ * the session context will not include all the models supported by the server.
* @return Created NETCONF session object or NULL in case of error.
*/
struct nc_session *nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx);
@@ -128,7 +130,9 @@
* (ignoring what is actually supported by the server side). If not set,
* YANG context is created for the session using \<get-schema\> (if supported
* by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()).
+ * (see nc_schema_searchpath()). In every case except not providing context
+ * to connect to a server supporting \<get-schema\> it is possible that
+ * the session context will not include all the models supported by the server.
* @return Created NETCONF session object or NULL in case of error.
*/
struct nc_session *nc_connect_ssh(const char *host, unsigned short port, const char* username, struct ly_ctx *ctx);
@@ -149,7 +153,9 @@
* (ignoring what is actually supported by the server side). If not set,
* YANG context is created for the session using \<get-schema\> (if supported
* by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()).
+ * (see nc_schema_searchpath()). In every case except not providing context
+ * to connect to a server supporting \<get-schema\> it is possible that
+ * the session context will not include all the models supported by the server.
* @return Created NETCONF session object or NULL in case of error.
*/
struct nc_session *nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx);
@@ -165,7 +171,9 @@
* (ignoring what is actually supported by the server side). If not set,
* YANG context is created for the session using \<get-schema\> (if supported
* by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()).
+ * (see nc_schema_searchpath()). In every case except not providing context
+ * to connect to a server supporting \<get-schema\> it is possible that
+ * the session context will not include all the models supported by the server.
* @return Created NETCONF session object or NULL in case of error.
*/
struct nc_session *nc_connect_ssh_channel(struct nc_session *session, struct ly_ctx *ctx);
@@ -249,7 +257,9 @@
* (ignoring what is actually supported by the server side). If not set,
* YANG context is created for the session using \<get-schema\> (if supported
* by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()).
+ * (see nc_schema_searchpath()). In every case except not providing context
+ * to connect to a server supporting \<get-schema\> it is possible that
+ * the session context will not include all the models supported by the server.
* @return Created NETCONF session object or NULL in case of error.
*/
struct nc_session *nc_connect_tls(const char *host, unsigned short port, const char *username, struct ly_ctx *ctx);
@@ -266,7 +276,9 @@
* (ignoring what is actually supported by the server side). If not set,
* YANG context is created for the session using \<get-schema\> (if supported
* by the server side) or/and by searching for YANG schemas in the searchpath
- * (see nc_schema_searchpath()).
+ * (see nc_schema_searchpath()). In every case except not providing context
+ * to connect to a server supporting \<get-schema\> it is possible that
+ * the session context will not include all the models supported by the server.
* @return Created NETCONF session object or NULL in case of error.
*/
struct nc_session *nc_connect_libssl(SSL *tls, struct ly_ctx *ctx);
diff --git a/src/session_p.h b/src/session_p.h
index dd80974..c5eee5b 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -179,6 +179,43 @@
};
/**
+ * @brief Fill libyang context in \p session. Context models are based on the stored session
+ * capabilities. If the server does not support \<get-schema\>, the models are searched
+ * for in the directory set using nc_schema_searchpath().
+ *
+ * @param[in] session Session to create the context for.
+ * @return 0 on success, non-zero on failure.
+ */
+int nc_ctx_fill(struct nc_session *session);
+
+/**
+ * @brief Check whether the libyang context in \p session is suitable for NETCONF use
+ * meaning whether the ietf-netconf model is loaded.
+ *
+ * @param[in] session Session with the capabilities to be supported if loading ietf-netconf
+ * explicitly.
+ * @return 0 on success, non-zero on failure.
+ */
+int nc_ctx_check(struct nc_session *session);
+
+/**
+ * @brief Create and connect a socket.
+ *
+ * @param[in] host Hostname to connect to.
+ * @param[in] port Port to connect on.
+ * @return Connected socket or -1 on error.
+ */
+int nc_connect_getsocket(const char *host, unsigned short port);
+
+/**
+ * @brief Perform NETCONF handshake on \p session.
+ *
+ * @param[in] session NETCONF session to use.
+ * @return 0 on success, non-zero on failure.
+ */
+int nc_handshake(struct nc_session *session);
+
+/**
* Functions
* - io.c
*/
diff --git a/src/session_ssh.c b/src/session_ssh.c
index a9b874c..382cf9f 100644
--- a/src/session_ssh.c
+++ b/src/session_ssh.c
@@ -46,16 +46,12 @@
#include "libnetconf.h"
#include "session.h"
+#include "session_p.h"
static struct nc_ssh_auth_opts ssh_opts = {
.auth_pref = {{NC_SSH_AUTH_INTERACTIVE, 3}, {NC_SSH_AUTH_PASSWORD, 2}, {NC_SSH_AUTH_PUBLIC_KEYS, 1}}
};
-/* internal functions from session.c */
-struct nc_session *connect_init(struct ly_ctx *ctx);
-int connect_getsocket(const char *host, unsigned short port);
-int handshake(struct nc_session *session);
-
API void
nc_client_init_ssh(void)
{
@@ -859,11 +855,13 @@
}
/* prepare session structure */
- session = connect_init(ctx);
+ session = calloc(1, sizeof *session);
if (!session) {
+ ERRMEM;
return NULL;
}
- session->ti_type = NC_TI_LIBSSH;
+ session->status = NC_STATUS_STARTING;
+ session->side = NC_CLIENT;
/* transport lock */
session->ti_lock = malloc(sizeof *session->ti_lock);
@@ -874,9 +872,7 @@
pthread_mutex_init(session->ti_lock, NULL);
/* other transport-specific data */
- session->username = lydict_insert(session->ctx, username, 0);
- session->host = lydict_insert(session->ctx, host, 0);
- session->port = port;
+ session->ti_type = NC_TI_LIBSSH;
session->ti.libssh.session = ssh_new();
if (!session->ti.libssh.session) {
ERR("Unable to initialize SSH session.");
@@ -884,27 +880,54 @@
}
/* set some basic SSH session options */
- ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_HOST, session->host);
- ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_PORT, &session->port);
- ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, session->username);
+ ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_HOST, host);
+ ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_PORT, &port);
+ ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, username);
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_TIMEOUT, &timeout);
/* create and assign communication socket */
- sock = connect_getsocket(host, port);
+ sock = nc_connect_getsocket(host, port);
if (sock == -1) {
goto fail;
}
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_FD, &sock);
+ /* temporarily, for session connection */
+ session->host = host;
+ session->username = username;
if (connect_ssh_session_netconf(session)) {
goto fail;
}
+ /* assign context (dicionary needed for handshake) */
+ if (!ctx) {
+ ctx = ly_ctx_new(SCHEMAS_DIR);
+ } else {
+ session->flags |= NC_SESSION_SHAREDCTX;
+ }
+ session->ctx = ctx;
+
/* NETCONF handshake */
- if (handshake(session)) {
+ if (nc_handshake(session)) {
goto fail;
}
+ /* check/fill libyang context */
+ if (session->flags & NC_SESSION_SHAREDCTX) {
+ if (nc_ctx_check(session)) {
+ goto fail;
+ }
+ } else {
+ if (nc_ctx_fill(session)) {
+ goto fail;
+ }
+ }
+
+ /* store information into the dictionary */
+ session->host = lydict_insert(ctx, host, 0);
+ session->port = port;
+ session->username = lydict_insert(ctx, username, 0);
+
session->status = NC_STATUS_RUNNING;
return session;
@@ -916,18 +939,20 @@
API struct nc_session *
nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx)
{
- const char *host, *username;
- unsigned short port;
+ char *host = NULL, *username = NULL;
+ unsigned short port = 0;
int sock;
struct passwd *pw;
struct nc_session *session = NULL;
/* prepare session structure */
- session = connect_init(ctx);
+ session = calloc(1, sizeof *session);
if (!session) {
+ ERRMEM;
return NULL;
}
- session->ti_type = NC_TI_LIBSSH;
+ session->status = NC_STATUS_STARTING;
+ session->side = NC_CLIENT;
/* transport lock */
session->ti_lock = malloc(sizeof *session->ti_lock);
@@ -937,37 +962,28 @@
}
pthread_mutex_init(session->ti_lock, NULL);
+ session->ti_type = NC_TI_LIBSSH;
session->ti.libssh.session = ssh_session;
- if (!ctx) {
- ctx = session->ctx;
- }
-
if (ssh_get_fd(ssh_session) == -1) {
/*
* There is no file descriptor, we need to create it. (TCP/IP layer)
*/
/* was host, port set? */
- if (ssh_options_get(ssh_session, SSH_OPTIONS_HOST, (char **)&host) != SSH_OK) {
+ if (ssh_options_get(ssh_session, SSH_OPTIONS_HOST, &host) != SSH_OK) {
host = NULL;
}
ssh_options_get_port(ssh_session, (unsigned int *)&port);
/* remember host */
if (!host) {
- host = lydict_insert(ctx, "localhost", 0);
+ host = strdup("localhost");
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_HOST, host);
- } else {
- host = lydict_insert_zc(ctx, (char *)host);
}
- session->host = host;
-
- /* remember port (even if not set, dumb libssh returns 22, no way to know if it was actually set) */
- session->port = port;
/* create and connect socket */
- sock = connect_getsocket(host, port);
+ sock = nc_connect_getsocket(host, port);
if (sock == -1) {
goto fail;
}
@@ -980,7 +996,7 @@
*/
/* was username set? */
- if (ssh_options_get(ssh_session, SSH_OPTIONS_USER, (char **)&username) != SSH_OK) {
+ if (ssh_options_get(ssh_session, SSH_OPTIONS_USER, &username) != SSH_OK) {
username = NULL;
}
@@ -992,14 +1008,13 @@
goto fail;
}
- username = lydict_insert(ctx, pw->pw_name, 0);
+ username = strdup(pw->pw_name);
ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, username);
- } else {
- username = lydict_insert_zc(ctx, (char *)username);
}
- session->username = username;
/* authenticate SSH session */
+ session->host = host;
+ session->username = username;
if (connect_ssh_session_netconf(session)) {
goto fail;
}
@@ -1009,11 +1024,41 @@
* SSH session is established, create NETCONF session. (Application layer)
*/
+ /* assign context (dicionary needed for handshake) */
+ if (!ctx) {
+ ctx = ly_ctx_new(SCHEMAS_DIR);
+ } else {
+ session->flags |= NC_SESSION_SHAREDCTX;
+ }
+ session->ctx = ctx;
+
/* NETCONF handshake */
- if (handshake(session)) {
+ if (nc_handshake(session)) {
goto fail;
}
+ /* check/fill libyang context */
+ if (session->flags & NC_SESSION_SHAREDCTX) {
+ if (nc_ctx_check(session)) {
+ goto fail;
+ }
+ } else {
+ if (nc_ctx_fill(session)) {
+ goto fail;
+ }
+ }
+
+ /* store information into the dictionary */
+ if (host) {
+ session->host = lydict_insert_zc(ctx, host);
+ }
+ if (port) {
+ session->port = port;
+ }
+ if (username) {
+ session->username = lydict_insert_zc(ctx, username);
+ }
+
session->status = NC_STATUS_RUNNING;
return session;
@@ -1028,20 +1073,17 @@
struct nc_session *new_session, *ptr;
/* prepare session structure */
- new_session = connect_init(ctx);
+ new_session = calloc(1, sizeof *new_session);
if (!new_session) {
+ ERRMEM;
return NULL;
}
- if (!ctx) {
- ctx = new_session->ctx;
- }
+ new_session->status = NC_STATUS_STARTING;
+ new_session->side = NC_CLIENT;
/* share some parameters including the session lock */
new_session->ti_type = NC_TI_LIBSSH;
new_session->ti_lock = session->ti_lock;
- new_session->host = lydict_insert(ctx, session->host, 0);
- new_session->port = session->port;
- new_session->username = lydict_insert(ctx, session->username, 0);
new_session->ti.libssh.session = session->ti.libssh.session;
/* create the channel safely */
@@ -1050,21 +1092,44 @@
/* open a channel */
new_session->ti.libssh.channel = ssh_channel_new(new_session->ti.libssh.session);
if (ssh_channel_open_session(new_session->ti.libssh.channel) != SSH_OK) {
- nc_session_free(new_session);
ERR("Opening an SSH channel failed (%s)", ssh_get_error(session->ti.libssh.session));
- return NULL;
+ goto fail;
}
/* execute the NETCONF subsystem on the channel */
if (ssh_channel_request_subsystem(new_session->ti.libssh.channel, "netconf") != SSH_OK) {
- nc_session_free(new_session);
ERR("Starting the \"netconf\" SSH subsystem failed (%s)", ssh_get_error(session->ti.libssh.session));
- return NULL;
+ goto fail;
}
+
+ /* assign context (dicionary needed for handshake) */
+ if (!ctx) {
+ ctx = ly_ctx_new(SCHEMAS_DIR);
+ } else {
+ session->flags |= NC_SESSION_SHAREDCTX;
+ }
+ session->ctx = ctx;
+
/* NETCONF handshake */
- if (handshake(new_session)) {
- nc_session_free(new_session);
- return NULL;
+ if (nc_handshake(new_session)) {
+ goto fail;
}
+
+ /* check/fill libyang context */
+ if (session->flags & NC_SESSION_SHAREDCTX) {
+ if (nc_ctx_check(session)) {
+ goto fail;
+ }
+ } else {
+ if (nc_ctx_fill(session)) {
+ goto fail;
+ }
+ }
+
+ /* store information into session and the dictionary */
+ session->host = lydict_insert(ctx, session->host, 0);
+ session->port = session->port;
+ session->username = lydict_insert(ctx, session->username, 0);
+
new_session->status = NC_STATUS_RUNNING;
pthread_mutex_unlock(new_session->ti_lock);
@@ -1080,4 +1145,8 @@
}
return new_session;
+
+fail:
+ nc_session_free(new_session);
+ return NULL;
}
diff --git a/src/session_tls.c b/src/session_tls.c
index 3592910..c195907 100644
--- a/src/session_tls.c
+++ b/src/session_tls.c
@@ -34,6 +34,7 @@
#include "libnetconf.h"
#include "session.h"
+#include "session_p.h"
/* TLS certificate verification error messages */
static const char* verify_ret_msg[] = {
@@ -74,11 +75,6 @@
static struct nc_tls_auth_opts tls_opts;
-/* internal functions from session.c */
-struct nc_session *connect_init(struct ly_ctx *ctx);
-int connect_getsocket(const char* host, unsigned short port);
-int handshake(struct nc_session *session);
-
static int
tlsauth_verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx)
{
@@ -294,11 +290,13 @@
}
/* prepare session structure */
- session = connect_init(ctx);
+ session = calloc(1, sizeof *session);
if (!session) {
+ ERRMEM;
return NULL;
}
- session->ti_type = NC_TI_OPENSSL;
+ session->status = NC_STATUS_STARTING;
+ session->side = NC_CLIENT;
/* transport lock */
session->ti_lock = malloc(sizeof *session->ti_lock);
@@ -309,16 +307,14 @@
pthread_mutex_init(session->ti_lock, NULL);
/* fill the session */
- session->username = lydict_insert(session->ctx, username, 0);
- session->host = lydict_insert(session->ctx, host, 0);
- session->port = port;
+ session->ti_type = NC_TI_OPENSSL;
if (!(session->ti.tls = SSL_new(tls_opts.tls_ctx))) {
ERR("Failed to create new TLS session structure (%s)", ERR_reason_error_string(ERR_get_error()));
goto fail;
}
/* create and assign socket */
- sock = connect_getsocket(host, port);
+ sock = nc_connect_getsocket(host, port);
if (sock == -1) {
goto fail;
}
@@ -343,11 +339,35 @@
WRN("Server certificate verification problem (%s).", verify_ret_msg[verify]);
}
+ /* assign context (dicionary needed for handshake) */
+ if (!ctx) {
+ ctx = ly_ctx_new(SCHEMAS_DIR);
+ } else {
+ session->flags |= NC_SESSION_SHAREDCTX;
+ }
+ session->ctx = ctx;
+
/* NETCONF handshake */
- if (handshake(session)) {
+ if (nc_handshake(session)) {
goto fail;
}
+ /* check/fill libyang context */
+ if (session->flags & NC_SESSION_SHAREDCTX) {
+ if (nc_ctx_check(session)) {
+ goto fail;
+ }
+ } else {
+ if (nc_ctx_fill(session)) {
+ goto fail;
+ }
+ }
+
+ /* store information into session and the dictionary */
+ session->host = lydict_insert(ctx, host, 0);
+ session->port = port;
+ session->username = lydict_insert(ctx, username, 0);
+
session->status = NC_STATUS_RUNNING;
return session;
@@ -368,11 +388,13 @@
}
/* prepare session structure */
- session = connect_init(ctx);
+ session = calloc(1, sizeof *session);
if (!session) {
+ ERRMEM;
return NULL;
}
- session->ti_type = NC_TI_OPENSSL;
+ session->status = NC_STATUS_STARTING;
+ session->side = NC_CLIENT;
/* transport lock */
session->ti_lock = malloc(sizeof *session->ti_lock);
@@ -382,17 +404,33 @@
}
pthread_mutex_init(session->ti_lock, NULL);
+ session->ti_type = NC_TI_OPENSSL;
session->ti.tls = tls;
+ /* assign context (dicionary needed for handshake) */
if (!ctx) {
- ctx = session->ctx;
+ ctx = ly_ctx_new(SCHEMAS_DIR);
+ } else {
+ session->flags |= NC_SESSION_SHAREDCTX;
}
+ session->ctx = ctx;
/* NETCONF handshake */
- if (handshake(session)) {
+ if (nc_handshake(session)) {
goto fail;
}
+ /* check/fill libyang context */
+ if (session->flags & NC_SESSION_SHAREDCTX) {
+ if (nc_ctx_check(session)) {
+ goto fail;
+ }
+ } else {
+ if (nc_ctx_fill(session)) {
+ goto fail;
+ }
+ }
+
session->status = NC_STATUS_RUNNING;
return session;