From 82ba00320923319943cfb79282ada5aaad4d5334 Mon Sep 17 00:00:00 2001 From: Tatsuhiro Tsujikawa Date: Sun, 10 May 2015 00:00:23 +0900 Subject: Add basic ssh/sftp code to SocketCore and introduce SSHSession We use libssh2 to implement sftp feature. SSHSession is closely designed to TLSSession, but it differs in several aspects. In this code, we only implements read part of sftp, since aria2 won't offer uploading feature. Adding SSH/sftp to SocketCore is a bit bloat. But by doing this we can reuse DownloadCommand, without mostly no modification. We can just create SSHDownloadCommand by inheriting it, just like existing ftp. --- src/SocketCore.cc | 121 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) (limited to 'src/SocketCore.cc') diff --git a/src/SocketCore.cc b/src/SocketCore.cc index b42c7ecd..5469b8bf 100644 --- a/src/SocketCore.cc +++ b/src/SocketCore.cc @@ -45,6 +45,7 @@ #include #include +#include #include #include "message.h" @@ -60,6 +61,9 @@ # include "TLSContext.h" # include "TLSSession.h" #endif // ENABLE_SSL +#ifdef HAVE_LIBSSH2 +# include "SSHSession.h" +#endif // HAVE_LIBSSH2 namespace aria2 { @@ -608,6 +612,14 @@ void SocketCore::closeConnection() tlsSession_.reset(); } #endif // ENABLE_SSL + +#ifdef HAVE_LIBSSH2 + if(sshSession_) { + sshSession_->closeConnection(); + sshSession_.reset(); + } +#endif // HAVE_LIBSSH2 + if(sockfd_ != (sock_t) -1) { shutdown(sockfd_, SHUT_WR); CLOSE(sockfd_); @@ -796,7 +808,23 @@ void SocketCore::readData(void* data, size_t& len) wantRead_ = false; wantWrite_ = false; - if(!secure_) { + if(sshSession_) { +#ifdef HAVE_LIBSSH2 + ret = sshSession_->readData(data, len); + if(ret < 0) { + if(ret != SSH_ERR_WOULDBLOCK) { + throw DL_RETRY_EX(fmt(EX_SOCKET_RECV, + sshSession_->getLastErrorString().c_str())); + } + if(sshSession_->checkDirection() == SSH_WANT_READ) { + wantRead_ = true; + } else { + wantWrite_ = true; + } + ret = 0; + } +#endif // HAVE_LIBSSH2 + } else if(!secure_) { // Cast for Windows recv() while((ret = recv(sockfd_, reinterpret_cast(data), len, 0)) == -1 && SOCKET_ERRNO == A2_EINTR); @@ -957,6 +985,97 @@ bool SocketCore::tlsHandshake(TLSContext* tlsctx, const std::string& hostname) #endif // ENABLE_SSL +#ifdef HAVE_LIBSSH2 + +bool SocketCore::sshHandshake() +{ + wantRead_ = false; + wantWrite_ = false; + + if (!sshSession_) { + sshSession_ = make_unique(); + if (sshSession_->init(sockfd_) == SSH_ERR_ERROR) { + throw DL_ABORT_EX("Could not create SSH session"); + } + } + auto rv = sshSession_->handshake(); + if (rv == SSH_ERR_WOULDBLOCK) { + sshCheckDirection(); + return false; + } + if (rv == SSH_ERR_ERROR) { + throw DL_ABORT_EX(fmt("SSH handshake failure: %s", + sshSession_->getLastErrorString().c_str())); + } + return true; +} + +bool SocketCore::sshAuthPassword(const std::string& user, + const std::string& password) +{ + assert(sshSession_); + + wantRead_ = false; + wantWrite_ = false; + + auto rv = sshSession_->authPassword(user, password); + if (rv == SSH_ERR_WOULDBLOCK) { + sshCheckDirection(); + return false; + } + if (rv == SSH_ERR_ERROR) { + throw DL_ABORT_EX(fmt("SSH authentication failure: %s", + sshSession_->getLastErrorString().c_str())); + } + return true; +} + +bool SocketCore::sshSFTPOpen(const std::string& path) +{ + assert(sshSession_); + + wantRead_ = false; + wantWrite_ = false; + + auto rv = sshSession_->sftpOpen(path); + if (rv == SSH_ERR_WOULDBLOCK) { + sshCheckDirection(); + return false; + } + if (rv == SSH_ERR_ERROR) { + throw DL_ABORT_EX(fmt("SSH opening SFTP path %s failed: %s", + path.c_str(), + sshSession_->getLastErrorString().c_str())); + } + return true; +} + +bool SocketCore::sshGracefulShutdown() +{ + assert(sshSession_); + auto rv = sshSession_->gracefulShutdown(); + if (rv == SSH_ERR_WOULDBLOCK) { + sshCheckDirection(); + return false; + } + if (rv == SSH_ERR_ERROR) { + throw DL_ABORT_EX(fmt("SSH graceful shutdown failed: %s", + sshSession_->getLastErrorString().c_str())); + } + return true; +} + +void SocketCore::sshCheckDirection() +{ + if (sshSession_->checkDirection() == SSH_WANT_READ) { + wantRead_ = true; + } else { + wantWrite_ = true; + } +} + +#endif // HAVE_LIBSSH2 + ssize_t SocketCore::writeData(const void* data, size_t len, const std::string& host, uint16_t port) { -- cgit