session CHANGE basic code for connecting via libssh
diff --git a/src/libnetconf.h b/src/libnetconf.h
index 6ddd623..5c08e71 100644
--- a/src/libnetconf.h
+++ b/src/libnetconf.h
@@ -26,5 +26,12 @@
#include "config.h"
#include "netconf.h"
#include "log_p.h"
+#include "session_p.h"
+#include "messages_p.h"
+#include "datastore_p.h"
+
+/* Tests whether string is empty or non-empty. */
+#define strisempty(str) ((str)[0] == '\0')
+#define strnonempty(str) ((str)[0] != '\0')
#endif /* NC_LIBNETCONF_H_ */
diff --git a/src/netconf.h b/src/netconf.h
index d66d1d7..47dac1b 100644
--- a/src/netconf.h
+++ b/src/netconf.h
@@ -32,6 +32,11 @@
#define NC_NS_BASE "urn:ietf:params:xml:ns:netconf:base:1.0"
#define NC_NS_NOTIF "urn:ietf:params:xml:ns:netconf:notification:1.0"
+/** @brief Default NETCONF over SSH port */
+#define NC_PORT_SSH 830;
+/** @brief Default NETCONF over TLS port */
+#define NC_PORT_TLS 6513;
+
/**
* @brief Enumeration of reasons of the NETCONF session termination as defined in RFC 6470.
*/
diff --git a/src/session.c b/src/session.c
index aae0373..65e9a4e 100644
--- a/src/session.c
+++ b/src/session.c
@@ -23,20 +23,18 @@
#include <assert.h>
#include <errno.h>
#include <fcntl.h>
+#include <netdb.h>
+#include <pthread.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/socket.h>
#include <sys/stat.h>
#include <sys/types.h>
-#include <pthread.h>
#include <unistd.h>
#include <libyang/libyang.h>
-#include "config.h"
#include "libnetconf.h"
-#include "messages_p.h"
-#include "session_p.h"
-#include "datastore_p.h"
#define TIMEOUT_STEP 50
@@ -102,6 +100,24 @@
return pthread_mutex_unlock(session->ti_lock);
}
+int
+handshake(struct nc_session *session)
+{
+ NC_MSG_TYPE type;
+
+ type = nc_send_hello_(session);
+ if (type != NC_MSG_HELLO) {
+ return 1;
+ }
+
+ type = nc_recv_hello(session);
+ if (type != NC_MSG_HELLO) {
+ return 1;
+ }
+
+ return 0;
+}
+
static int
connect_load_schemas(struct ly_ctx *ctx)
{
@@ -132,18 +148,12 @@
return 0;
}
-API struct nc_session *
-nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx)
+struct nc_session *
+connect_init(struct ly_ctx *ctx)
{
- int r;
- NC_MSG_TYPE type;
- const char *str;
struct nc_session *session = NULL;
-
- if (fdin < 0 || fdout < 0) {
- ERR("%s: Invalid parameter", __func__);
- return NULL;
- }
+ const char *str;
+ int r;
/* prepare session structure */
session = calloc(1, sizeof *session);
@@ -153,9 +163,6 @@
}
session->status = NC_STATUS_STARTING;
session->side = NC_CLIENT;
- session->ti_type = NC_TI_FD;
- session->ti.fd.in = fdin;
- session->ti.fd.out = fdout;
/* transport lock */
session->ti_lock = malloc(sizeof *session->ti_lock);
@@ -178,7 +185,8 @@
ly_ctx_set_searchdir(session->ctx, str);
if (r) {
- goto error;
+ nc_session_free(session);
+ return NULL;
}
}
} else {
@@ -186,20 +194,39 @@
/* load basic NETCONF schemas required for libnetconf work */
if (connect_load_schemas(session->ctx)) {
- goto error;
+ nc_session_free(session);
+ return NULL;
}
ly_ctx_set_searchdir(session->ctx, schema_searchpath);
}
- /* NETCONF handshake */
- type = nc_send_hello_(session);
- if (type != NC_MSG_HELLO) {
- goto error;
+ return session;
+}
+
+API struct nc_session *
+nc_connect_inout(int fdin, int fdout, struct ly_ctx *ctx)
+{
+ struct nc_session *session = NULL;
+
+ if (fdin < 0 || fdout < 0) {
+ ERR("%s: Invalid parameter", __func__);
+ return NULL;
}
- type = nc_recv_hello(session);
- if (type != NC_MSG_HELLO) {
+ /* prepare session structure */
+ session = connect_init(ctx);
+ if (!session) {
+ return NULL;
+ }
+
+ /* transport specific data */
+ session->ti_type = NC_TI_FD;
+ session->ti.fd.in = fdin;
+ session->ti.fd.out = fdout;
+
+ /* NETCONF handshake */
+ if (handshake(session)) {
goto error;
}
@@ -211,38 +238,61 @@
return NULL;
}
-#ifdef ENABLE_LIBSSH
-
-API struct nc_session *
-nc_connect_ssh(const char *host, unsigned short port, const char* username, struct ly_ctx *ctx)
+int
+connect_getsocket(const char* host, unsigned short port)
{
- (void) host;
- (void) port;
- (void) username;
- (void) ctx;
+ int sock = -1;
+ int i;
+ struct addrinfo hints, *res_list, *res;
+ char port_s[6]; /* length of string representation of short int */
- return NULL;
+ snprintf(port_s, 6, "%u", port);
+
+ /* Connect to a server */
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = IPPROTO_TCP;
+ i = getaddrinfo(host, port_s, &hints, &res_list);
+ if (i != 0) {
+ ERR("Unable to translate the host address (%s).", gai_strerror(i));
+ return -1;
+ }
+
+ for (i = 0, res = res_list; res != NULL; res = res->ai_next) {
+ sock = socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (sock == -1) {
+ /* socket was not created, try another resource */
+ i = errno;
+ goto errloop;
+ }
+
+ if (connect(sock, res->ai_addr, res->ai_addrlen) == -1) {
+ /* network connection failed, try another resource */
+ i = errno;
+ close(sock);
+ sock = -1;
+ goto errloop;
+ }
+
+ /* we're done, network connection established */
+ break;
+errloop:
+ VRB("Unable to connect to %s:%s over %s (%s).", host, port,
+ (res->ai_family == AF_INET6) ? "IPv6" : "IPv4", strerror(i));
+ continue;
+ }
+
+ if (sock == -1) {
+ ERR("Unable to connect to %s:%s.", host, port);
+ } else {
+ VRB("Successfully connected to %s:%s over %s", host, port, (res->ai_family == AF_INET6) ? "IPv6" : "IPv4");
+ }
+ freeaddrinfo(res_list);
+
+ return sock;
}
-API struct nc_session *
-nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx)
-{
- (void) ssh_session;
- (void) ctx;
-
- return NULL;
-}
-
-API struct nc_session *
-nc_connect_ssh_channel(struct nc_session *session)
-{
- (void) session;
-
- return NULL;
-}
-
-#endif /* ENABLE_LIBSSH */
-
#ifdef ENABLE_TLS
API struct nc_session *
@@ -380,6 +430,8 @@
break;
#endif
}
+ lydict_remove(session->ctx, session->username);
+ lydict_remove(session->ctx, session->host);
/* final cleanup */
if (multisession) {
diff --git a/src/session_p.h b/src/session_p.h
index d52691a..5e37e55 100644
--- a/src/session_p.h
+++ b/src/session_p.h
@@ -129,6 +129,9 @@
SSL *tls;
#endif
} ti; /**< transport implementation data */
+ const char *username;
+ const char *host;
+ unsigned short port;
/* other */
struct ly_ctx *ctx; /**< libyang context of the session */
diff --git a/src/session_ssh.c b/src/session_ssh.c
new file mode 100644
index 0000000..80ab22f
--- /dev/null
+++ b/src/session_ssh.c
@@ -0,0 +1,138 @@
+/**
+ * \file session_ssh.c
+ * \author Radek Krejci <rkrejci@cesnet.cz>
+ * \brief libnetconf2 - SSH specific session transport functions
+ *
+ * This source is compiled only with libssh.
+ *
+ * Copyright (c) 2015 CESNET, z.s.p.o.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * 3. Neither the name of the Company nor the names of its contributors
+ * may be used to endorse or promote products derived from this
+ * software without specific prior written permission.
+ *
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <pwd.h>
+#include <sys/types.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <libyang/libyang.h>
+
+#include "libnetconf.h"
+
+/* seconds */
+#define SSH_TIMEOUT 10
+
+/* 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
+connect_ssh_socket(struct nc_session *session, int sock)
+{
+ const int timeout = SSH_TIMEOUT;
+
+ if (sock == -1) {
+ return 1;
+ }
+
+ session->ti_type = NC_TI_LIBSSH;
+ session->ti.libssh.session = ssh_new();
+ if (!session->ti.libssh.session) {
+ ERR("Unable to initialize SSH session.");
+ return 1;
+ }
+
+ ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_HOST, session->host);
+ ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_USER, session->username);
+ ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_FD, &sock);
+ ssh_options_set(session->ti.libssh.session, SSH_OPTIONS_TIMEOUT, &timeout);
+
+ /* TODO - libssh magic with authentication and all other stuff */
+
+ return 0;
+}
+
+API struct nc_session *
+nc_connect_ssh(const char *host, unsigned short port, const char* username, struct ly_ctx *ctx)
+{
+ struct passwd *pw;
+ struct nc_session *session = NULL;
+
+ /* process parameters */
+ if (!host || strisempty(host)) {
+ host = "localhost";
+ }
+
+ if (!port) {
+ port = NC_PORT_SSH;
+ }
+
+ if (!username) {
+ pw = getpwuid(getuid());
+ if (!pw) {
+ ERR("Unknwon username for the SSH connection (%s).", strerror(errno));
+ return (NULL);
+ } else {
+ username = pw->pw_name;
+ }
+ }
+
+ /* prepare session structure */
+ session = connect_init(ctx);
+ if (!session) {
+ return NULL;
+ }
+
+ /* transport specific data */
+ session->username = lydict_insert(session->ctx, username, 0);
+ session->host = lydict_insert(session->ctx, host, 0);
+ session->port = port;
+
+ if (connect_ssh_socket(session, connect_getsocket(host, port))) {
+ goto error;
+ }
+
+ /* NETCONF handshake */
+ if (handshake(session)) {
+ goto error;
+ }
+
+ session->status = NC_STATUS_RUNNING;
+ return session;
+
+error:
+ nc_session_free(session);
+ return NULL;
+}
+
+API struct nc_session *
+nc_connect_libssh(ssh_session ssh_session, struct ly_ctx *ctx)
+{
+ (void) ssh_session;
+ (void) ctx;
+
+ return NULL;
+}
+
+API struct nc_session *
+nc_connect_ssh_channel(struct nc_session *session)
+{
+ (void) session;
+
+ return NULL;
+}