From 68d25d195de3642d1318700ece14bb320f37b454 Mon Sep 17 00:00:00 2001 From: Tim Warren Date: Wed, 24 Jun 2015 14:12:05 -0400 Subject: [PATCH] Some SFTP refactoring --- Makefile | 6 +- src/base/network/SFTP.cpp | 122 +++++++++++++++++++++++++------------- src/base/network/SFTP.h | 21 ++++--- src/common.h | 5 ++ src/definitions.h | 4 -- tests/SFTPTest.cpp | 12 ++++ 6 files changed, 113 insertions(+), 57 deletions(-) create mode 100644 tests/SFTPTest.cpp diff --git a/Makefile b/Makefile index 874a241..5757ea2 100644 --- a/Makefile +++ b/Makefile @@ -39,7 +39,7 @@ endif # Platform compiler flags ifeq ($(OS),Darwin) CXX = $(shell wx-config --cxx) -D__WXMAC__ -D_WCHAR_H_CPLUSPLUS_98_CONFORMANCE_ -std=gnu++11 - LDLIBS += /usr/local/lib/libssh2.a + LDLIBS += $(shell pkg-config libssh2 --libs) else LDLIBS += -lssh2 endif @@ -47,7 +47,7 @@ endif ifeq ($(OS),Windows_NT) CXXFLAGS += -static CXX += -std=gnu++11 -Wno-unknown-pragmas -Wno-missing-field-initializers -I/include -DWIN32 - LDLIBS += -L/lib -lwsock32 + LDLIBS += -L/lib -lws2_32 -lssh2 endif ifeq ($(OS),Linux) @@ -158,7 +158,7 @@ $(TESTS): .PHONY: tests tests: $(TESTS) json_wrapper $(BASE_LIB) $(WIDGET_LIB) - $(CXX) $(CXXFLAGS) $(WX_CXXFLAGS) tests/main.cpp $(TESTS) $(WIDGET_LIB) $(BASE_LIB) $(WX_LDLIBS) $(LDLIBS) -o tests/runner + $(CXX) $(CXXFLAGS) $(WX_CXXFLAGS) tests/main.cpp $(TESTS) $(WIDGET_LIB) $(BASE_LIB) $(LDLIBS) $(WX_LDLIBS) -o tests/runner run-tests: tests diff --git a/src/base/network/SFTP.cpp b/src/base/network/SFTP.cpp index 7d63bc9..b1d12b6 100644 --- a/src/base/network/SFTP.cpp +++ b/src/base/network/SFTP.cpp @@ -1,23 +1,47 @@ #include "SFTP.h" -SFTP::SFTP(const char *host, const char *user, const char *pass, const char *port) +/** + * Basic username/password auth + * @param string host + * @param string user + * @param string pass + * @param string base_path + * @param string port + */ +SFTP::SFTP(const char *host, const char *user, const char *pass, const char *base_path, const char *port) { - this->ssh_connect(host, user, pass, port); + this->create_socket(host, port); + + // Create ssh session + this->ssh_connect(); + + // Authenticate (by password) + if (libssh2_userauth_password(this->session, user, pass)) + { + cerr << "Authentication by password failed." << endl; + return; + } + + // Create sftp session this->sftp_connect(); }; SFTP::~SFTP() { - libssh2_sftp_shutdown(sftp_session); - libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing"); - libssh2_session_free(session); -#ifdef WIN32 - closesocket(sock); -#else - close(sock); -#endif + // Free libssh2 sessions + if (this->sftp_session != nullptr) + { + libssh2_sftp_shutdown(this->sftp_session); + this->sftp_session = nullptr; + } + if (this->session != nullptr) + { + libssh2_session_disconnect(this->session, "Normal Shutdown, Thank you for playing"); + libssh2_session_free(this->session); + this->session = nullptr; + } + libssh2_exit(); - freeaddrinfo(host_info_list); - freeaddrinfo(&host_info); + this->destroy_socket(); }; string SFTP::getFingerprint() @@ -47,12 +71,12 @@ string SFTP::getFile(const char *path) string output = ""; LIBSSH2_SFTP_HANDLE *sftp_handle; - sftp_handle = libssh2_sftp_open(sftp_session, path, LIBSSH2_FXF_READ, 0); + sftp_handle = libssh2_sftp_open(this->sftp_session, path, LIBSSH2_FXF_READ, 0); if ( ! sftp_handle) { cerr << "Unable to open file with SFTP: "; - cerr << libssh2_sftp_last_error(sftp_session) << endl; + cerr << libssh2_sftp_last_error(this->sftp_session) << endl; return output; } @@ -60,7 +84,7 @@ string SFTP::getFile(const char *path) char mem[1024]; // loop until fail - rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem)); + int rc = libssh2_sftp_read(sftp_handle, mem, sizeof(mem)); if (rc > 0) { @@ -75,7 +99,7 @@ string SFTP::getFile(const char *path) return output; } -void SFTP::ssh_connect(const char *host, const char *user, const char *pass, const char *port) +void SFTP::create_socket(const char *host, const char *port) { #ifdef WIN32 WSADATA wsadata; @@ -92,18 +116,47 @@ void SFTP::ssh_connect(const char *host, const char *user, const char *pass, con // Clear out memory in addr structure memset(&host_info, 0, sizeof host_info); - host_info.ai_family = AF_UNSPEC; - host_info.ai_socktype = SOCK_STREAM; + host_info.ai_family = AF_UNSPEC; // IPv4/IPv6 + host_info.ai_socktype = SOCK_STREAM; // TCP stream sockets + host_info.ai_flags = AI_PASSIVE; // fill in my IP for me - status = getaddrinfo(host, port, &host_info, &host_info_list); + int status = getaddrinfo(host, port, &host_info, &host_info_list); if (status != 0) { - cerr << "getaddrinfo error" << gai_strerror(status) << endl; + cerr << "getaddrinfo error: " << gai_strerror(status) << endl; } + this->sock = socket( + host_info_list->ai_family, + host_info_list->ai_socktype, + host_info_list->ai_protocol + ); + + if (connect(this->sock, host_info_list->ai_addr, host_info_list->ai_addrlen) != 0) + { + cerr << "Failed to connect to socket." << endl; + return; + } +} + +void SFTP::destroy_socket() +{ +#ifdef WIN32 + closesocket(sock); + WSACleanup(); +#else + close(sock); + + freeaddrinfo(host_info_list); + freeaddrinfo(&host_info); +#endif +} + +void SFTP::ssh_connect() +{ // Start libssh2 - rc = libssh2_init(0); + int rc = libssh2_init(0); if (rc != 0) { @@ -111,21 +164,13 @@ void SFTP::ssh_connect(const char *host, const char *user, const char *pass, con return; } - sock = socket(AF_INET, SOCK_STREAM, 0); + this->session = libssh2_session_init(); - if (connect(sock, host_info_list->ai_addr, host_info_list->ai_addrlen) != 0) - { - cerr << "Failed to connect to socket." << endl; - return; - } - - session = libssh2_session_init(); - - /* Since we have set non-blocking, tell libssh2 we are blocking */ - libssh2_session_set_blocking(session, 1); + // Since we have set non-blocking, tell libssh2 we are blocking + libssh2_session_set_blocking(this->session, 1); // Actually do the ssh handshake - rc = libssh2_session_handshake(session, sock); + rc = libssh2_session_handshake(this->session, this->sock); if (rc) { @@ -134,20 +179,13 @@ void SFTP::ssh_connect(const char *host, const char *user, const char *pass, con } //@TODO do something with the handling of known hosts - - // Authenticate (by password) - if (libssh2_userauth_password(session, user, pass)) - { - cerr << "Authentication by password failed." << endl; - return; - } } void SFTP::sftp_connect() { - sftp_session = libssh2_sftp_init(session); + this->sftp_session = libssh2_sftp_init(this->session); - if ( ! sftp_session) + if ( ! this->sftp_session) { cerr << "Unable to start SFTP session" << endl; return; diff --git a/src/base/network/SFTP.h b/src/base/network/SFTP.h index 424b28e..80ed831 100644 --- a/src/base/network/SFTP.h +++ b/src/base/network/SFTP.h @@ -17,8 +17,10 @@ // Define this so I actually get functions out of the windows header file #undef _WIN32_WINNT #define _WIN32_WINNT 0x0501 - #include + #include + #include #else + #include #include #include #endif @@ -31,20 +33,23 @@ class SFTP { public: - SFTP(const char *host, const char *user, const char *pass, const char *port="22"); + SFTP(const char *host, const char *user, const char *pass, const char *base_path="~", const char *port="22"); ~SFTP(); string getFingerprint(); string getFile(const char *path); + bool createDir(const char *path); + bool writeFile(const char *path, const char *data); + //StringVector getDirList(const char *path); private: struct addrinfo host_info; - struct addrinfo *host_info_list; + struct addrinfo *host_info_list = nullptr; const char *fingerprint; int sock; - int status; - int rc; - LIBSSH2_SESSION *session; - LIBSSH2_SFTP *sftp_session; - void ssh_connect(const char *host, const char *user, const char *pass, const char *port); + LIBSSH2_SESSION *session = nullptr; + LIBSSH2_SFTP *sftp_session = nullptr; + void create_socket(const char *host, const char *port); + void destroy_socket(); + void ssh_connect(); void sftp_connect(); }; diff --git a/src/common.h b/src/common.h index 0cf6142..ecf8440 100644 --- a/src/common.h +++ b/src/common.h @@ -22,5 +22,10 @@ typedef Json::Value JsonValue; typedef Json::Reader JsonReader; typedef Json::Writer JsonWriter; +// Typedef some common templates +typedef map StringConstMap; +typedef map StringMap; +typedef vector StringVector; + #endif // TYRO_COMMON_H diff --git a/src/definitions.h b/src/definitions.h index dec066b..54fd802 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -45,10 +45,6 @@ const int TYRO_DEFAULT_FONT_SIZE = 14; const int TYRO_DEFAULT_FONT_SIZE = 10; #endif -// Typedef some common templates -typedef map StringConstMap; -typedef map StringMap; - // Editor margins enum myMargins { diff --git a/tests/SFTPTest.cpp b/tests/SFTPTest.cpp new file mode 100644 index 0000000..d845207 --- /dev/null +++ b/tests/SFTPTest.cpp @@ -0,0 +1,12 @@ +#include "catch.hpp" +#include "../src/base/network/SFTP.h" + +TEST_CASE("SFTP Library") +{ + SFTP *sftp = new SFTP("localhost", "user", "pass", "/", "22"); + + SECTION("Sanity check") + { + REQUIRE(sftp != nullptr); + } +} \ No newline at end of file