mirror of https://github.com/aria2/aria2
Merge branch 'sftp'
commit
89c1916fa5
23
README.rst
23
README.rst
|
@ -33,10 +33,10 @@ Features
|
||||||
Here is a list of features:
|
Here is a list of features:
|
||||||
|
|
||||||
* Command-line interface
|
* Command-line interface
|
||||||
* Download files through HTTP(S)/FTP/BitTorrent
|
* Download files through HTTP(S)/FTP/SFTP/BitTorrent
|
||||||
* Segmented downloading
|
* Segmented downloading
|
||||||
* Metalink version 4 (RFC 5854) support(HTTP/FTP/BitTorrent)
|
* Metalink version 4 (RFC 5854) support(HTTP/FTP/SFTP/BitTorrent)
|
||||||
* Metalink version 3.0 support(HTTP/FTP/BitTorrent)
|
* Metalink version 3.0 support(HTTP/FTP/SFTP/BitTorrent)
|
||||||
* Metalink/HTTP (RFC 6249) support
|
* Metalink/HTTP (RFC 6249) support
|
||||||
* HTTP/1.1 implementation
|
* HTTP/1.1 implementation
|
||||||
* HTTP Proxy support
|
* HTTP Proxy support
|
||||||
|
@ -54,7 +54,7 @@ Here is a list of features:
|
||||||
* Save Cookies in the Mozilla/Firefox (1.x/2.x)/Netscape format.
|
* Save Cookies in the Mozilla/Firefox (1.x/2.x)/Netscape format.
|
||||||
* Custom HTTP Header support
|
* Custom HTTP Header support
|
||||||
* Persistent Connections support
|
* Persistent Connections support
|
||||||
* FTP through HTTP Proxy
|
* FTP/SFTP through HTTP Proxy
|
||||||
* Download/Upload speed throttling
|
* Download/Upload speed throttling
|
||||||
* BitTorrent extensions: Fast extension, DHT, PEX, MSE/PSE,
|
* BitTorrent extensions: Fast extension, DHT, PEX, MSE/PSE,
|
||||||
Multi-Tracker, UDP tracker
|
Multi-Tracker, UDP tracker
|
||||||
|
@ -98,6 +98,7 @@ Dependency
|
||||||
features dependency
|
features dependency
|
||||||
======================== ========================================
|
======================== ========================================
|
||||||
HTTPS OSX or GnuTLS or OpenSSL or Windows
|
HTTPS OSX or GnuTLS or OpenSSL or Windows
|
||||||
|
SFTP libssh2
|
||||||
BitTorrent None. Optional: libnettle+libgmp or libgcrypt
|
BitTorrent None. Optional: libnettle+libgmp or libgcrypt
|
||||||
or OpenSSL (see note)
|
or OpenSSL (see note)
|
||||||
Metalink libxml2 or Expat.
|
Metalink libxml2 or Expat.
|
||||||
|
@ -183,6 +184,7 @@ distribution you use):
|
||||||
* libgnutls-dev (Required for HTTPS, BitTorrent, Checksum support)
|
* libgnutls-dev (Required for HTTPS, BitTorrent, Checksum support)
|
||||||
* nettle-dev (Required for BitTorrent, Checksum support)
|
* nettle-dev (Required for BitTorrent, Checksum support)
|
||||||
* libgmp-dev (Required for BitTorrent)
|
* libgmp-dev (Required for BitTorrent)
|
||||||
|
* libssh2-1-dev (Required for SFTP support)
|
||||||
* libc-ares-dev (Required for async DNS support)
|
* libc-ares-dev (Required for async DNS support)
|
||||||
* libxml2-dev (Required for Metalink support)
|
* libxml2-dev (Required for Metalink support)
|
||||||
* zlib1g-dev (Required for gzip, deflate decoding support in HTTP)
|
* zlib1g-dev (Required for gzip, deflate decoding support in HTTP)
|
||||||
|
@ -454,9 +456,9 @@ Other things should be noted
|
||||||
Metalink
|
Metalink
|
||||||
--------
|
--------
|
||||||
|
|
||||||
The current implementation supports HTTP(S)/FTP/BitTorrent. The other
|
The current implementation supports HTTP(S)/FTP/SFTP/BitTorrent. The
|
||||||
P2P protocols are ignored. Both Metalink4 (RFC 5854) and Metalink
|
other P2P protocols are ignored. Both Metalink4 (RFC 5854) and
|
||||||
version 3.0 documents are supported.
|
Metalink version 3.0 documents are supported.
|
||||||
|
|
||||||
For checksum verification, md5, sha-1, sha-224, sha-256, sha-384 and
|
For checksum verification, md5, sha-1, sha-224, sha-256, sha-384 and
|
||||||
sha-512 are supported. If multiple hash algorithms are provided, aria2
|
sha-512 are supported. If multiple hash algorithms are provided, aria2
|
||||||
|
@ -502,9 +504,10 @@ which location you prefer, you can use ``--metalink-location`` option.
|
||||||
|
|
||||||
netrc
|
netrc
|
||||||
-----
|
-----
|
||||||
netrc support is enabled by default for HTTP(S)/FTP. To disable netrc
|
|
||||||
support, specify -n command-line option. Your .netrc file should have
|
netrc support is enabled by default for HTTP(S)/FTP/SFTP. To disable
|
||||||
correct permissions(600).
|
netrc support, specify -n command-line option. Your .netrc file
|
||||||
|
should have correct permissions(600).
|
||||||
|
|
||||||
WebSocket
|
WebSocket
|
||||||
---------
|
---------
|
||||||
|
|
19
configure.ac
19
configure.ac
|
@ -58,6 +58,7 @@ ARIA2_ARG_WITHOUT([libcares])
|
||||||
ARIA2_ARG_WITHOUT([libz])
|
ARIA2_ARG_WITHOUT([libz])
|
||||||
ARIA2_ARG_WITH([tcmalloc])
|
ARIA2_ARG_WITH([tcmalloc])
|
||||||
ARIA2_ARG_WITH([jemalloc])
|
ARIA2_ARG_WITH([jemalloc])
|
||||||
|
ARIA2_ARG_WITHOUT([libssh2])
|
||||||
|
|
||||||
ARIA2_ARG_DISABLE([ssl])
|
ARIA2_ARG_DISABLE([ssl])
|
||||||
ARIA2_ARG_DISABLE([bittorrent])
|
ARIA2_ARG_DISABLE([bittorrent])
|
||||||
|
@ -298,6 +299,20 @@ if test "x$with_sqlite3" = "xyes"; then
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
if test "x$with_libssh2" = "xyes"; then
|
||||||
|
PKG_CHECK_MODULES([LIBSSH2], [libssh2], [have_libssh2=yes], [have_libssh2=no])
|
||||||
|
if test "x$have_libssh2" = "xyes"; then
|
||||||
|
AC_DEFINE([HAVE_LIBSSH2], [1], [Define to 1 if you have libssh2.])
|
||||||
|
LIBS="$LIBSSH2_LIBS $LIBS"
|
||||||
|
CPPFLAGS="$LIBSSH2_CFLAGS $CPPFLAGS"
|
||||||
|
else
|
||||||
|
AC_MSG_WARN([$LIBSSH2_PKG_ERRORS])
|
||||||
|
if test "x$with_libssh2_requested" = "yes"; then
|
||||||
|
ARIA2_DEP_NOT_MET([libssh2])
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
case "$host" in
|
case "$host" in
|
||||||
*darwin*)
|
*darwin*)
|
||||||
have_osx="yes"
|
have_osx="yes"
|
||||||
|
@ -613,6 +628,9 @@ AM_CONDITIONAL([HAVE_ZLIB], [test "x$have_zlib" = "xyes"])
|
||||||
# Set conditional for sqlite3
|
# Set conditional for sqlite3
|
||||||
AM_CONDITIONAL([HAVE_SQLITE3], [test "x$have_sqlite3" = "xyes"])
|
AM_CONDITIONAL([HAVE_SQLITE3], [test "x$have_sqlite3" = "xyes"])
|
||||||
|
|
||||||
|
# Set conditional for libssh2
|
||||||
|
AM_CONDITIONAL([HAVE_LIBSSH2], [test "x$have_libssh2" = "xyes"])
|
||||||
|
|
||||||
AC_SEARCH_LIBS([clock_gettime], [rt])
|
AC_SEARCH_LIBS([clock_gettime], [rt])
|
||||||
|
|
||||||
case "$host" in
|
case "$host" in
|
||||||
|
@ -1062,6 +1080,7 @@ echo "LibXML2: $have_libxml2"
|
||||||
echo "LibExpat: $have_libexpat"
|
echo "LibExpat: $have_libexpat"
|
||||||
echo "LibCares: $have_libcares"
|
echo "LibCares: $have_libcares"
|
||||||
echo "Zlib: $have_zlib"
|
echo "Zlib: $have_zlib"
|
||||||
|
echo "Libssh2: $have_libssh2"
|
||||||
echo "Epoll: $have_epoll"
|
echo "Epoll: $have_epoll"
|
||||||
echo "Bittorrent: $enable_bittorrent"
|
echo "Bittorrent: $enable_bittorrent"
|
||||||
echo "Metalink: $enable_metalink"
|
echo "Metalink: $enable_metalink"
|
||||||
|
|
|
@ -677,7 +677,7 @@ std::string getProxyUri(const std::string& protocol, const Option* option)
|
||||||
option);
|
option);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (protocol == "ftp") {
|
if (protocol == "ftp" || protocol == "sftp") {
|
||||||
return getProxyOptionFor
|
return getProxyOptionFor
|
||||||
(PREF_FTP_PROXY, PREF_FTP_PROXY_USER, PREF_FTP_PROXY_PASSWD, option);
|
(PREF_FTP_PROXY, PREF_FTP_PROXY_USER, PREF_FTP_PROXY_PASSWD, option);
|
||||||
}
|
}
|
||||||
|
@ -883,7 +883,8 @@ bool AbstractCommand::checkIfConnectionEstablished
|
||||||
const std::string&
|
const std::string&
|
||||||
AbstractCommand::resolveProxyMethod(const std::string& protocol) const
|
AbstractCommand::resolveProxyMethod(const std::string& protocol) const
|
||||||
{
|
{
|
||||||
if (getOption()->get(PREF_PROXY_METHOD) == V_TUNNEL || protocol == "https") {
|
if (getOption()->get(PREF_PROXY_METHOD) == V_TUNNEL || protocol == "https" ||
|
||||||
|
protocol == "sftp") {
|
||||||
return V_TUNNEL;
|
return V_TUNNEL;
|
||||||
}
|
}
|
||||||
return V_GET;
|
return V_GET;
|
||||||
|
|
|
@ -87,7 +87,8 @@ AuthConfigFactory::createAuthConfig
|
||||||
createHttpAuthResolver(op)->resolveAuthConfig(request->getHost());
|
createHttpAuthResolver(op)->resolveAuthConfig(request->getHost());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(request->getProtocol() == "ftp") {
|
} else if(request->getProtocol() == "ftp" ||
|
||||||
|
request->getProtocol() == "sftp") {
|
||||||
if(!request->getUsername().empty()) {
|
if(!request->getUsername().empty()) {
|
||||||
if(request->hasPassword()) {
|
if(request->hasPassword()) {
|
||||||
return AuthConfig::create(request->getUsername(),
|
return AuthConfig::create(request->getUsername(),
|
||||||
|
|
|
@ -134,6 +134,7 @@ bool DownloadCommand::executeInternal() {
|
||||||
|| getRequestGroup()->doesDownloadSpeedExceed()) {
|
|| getRequestGroup()->doesDownloadSpeedExceed()) {
|
||||||
addCommandSelf();
|
addCommandSelf();
|
||||||
disableReadCheckSocket();
|
disableReadCheckSocket();
|
||||||
|
disableWriteCheckSocket();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
setReadCheckSocket(getSocket());
|
setReadCheckSocket(getSocket());
|
||||||
|
@ -195,7 +196,8 @@ bool DownloadCommand::executeInternal() {
|
||||||
// Note that GrowSegment::complete() always returns false.
|
// Note that GrowSegment::complete() always returns false.
|
||||||
if(sinkFilterOnly_) {
|
if(sinkFilterOnly_) {
|
||||||
if(segment->complete() ||
|
if(segment->complete() ||
|
||||||
segment->getPositionToWrite() == getFileEntry()->getLastOffset()) {
|
(getFileEntry()->getLength() != 0 &&
|
||||||
|
segment->getPositionToWrite() == getFileEntry()->getLastOffset())) {
|
||||||
segmentPartComplete = true;
|
segmentPartComplete = true;
|
||||||
} else if(segment->getLength() == 0 && eof) {
|
} else if(segment->getLength() == 0 && eof) {
|
||||||
segmentPartComplete = true;
|
segmentPartComplete = true;
|
||||||
|
@ -275,13 +277,17 @@ bool DownloadCommand::executeInternal() {
|
||||||
return prepareForNextSegment();
|
return prepareForNextSegment();
|
||||||
} else {
|
} else {
|
||||||
checkLowestDownloadSpeed();
|
checkLowestDownloadSpeed();
|
||||||
setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
|
setWriteCheckSocketIf(getSocket(), shouldEnableWriteCheck());
|
||||||
checkSocketRecvBuffer();
|
checkSocketRecvBuffer();
|
||||||
addCommandSelf();
|
addCommandSelf();
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool DownloadCommand::shouldEnableWriteCheck() {
|
||||||
|
return getSocket()->wantWrite();
|
||||||
|
}
|
||||||
|
|
||||||
void DownloadCommand::checkLowestDownloadSpeed() const
|
void DownloadCommand::checkLowestDownloadSpeed() const
|
||||||
{
|
{
|
||||||
if(lowestDownloadSpeedLimit_ > 0 &&
|
if(lowestDownloadSpeedLimit_ > 0 &&
|
||||||
|
|
|
@ -76,6 +76,12 @@ protected:
|
||||||
|
|
||||||
// This is file local offset
|
// This is file local offset
|
||||||
virtual int64_t getRequestEndOffset() const = 0;
|
virtual int64_t getRequestEndOffset() const = 0;
|
||||||
|
|
||||||
|
// Returns true if socket should be monitored for writing. The
|
||||||
|
// default implementation is return the return value of
|
||||||
|
// getSocket()->wantWrite().
|
||||||
|
virtual bool shouldEnableWriteCheck();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DownloadCommand(cuid_t cuid,
|
DownloadCommand(cuid_t cuid,
|
||||||
const std::shared_ptr<Request>& req,
|
const std::shared_ptr<Request>& req,
|
||||||
|
|
|
@ -67,7 +67,9 @@
|
||||||
#ifdef HAVE_SYS_UTSNAME_H
|
#ifdef HAVE_SYS_UTSNAME_H
|
||||||
# include <sys/utsname.h>
|
# include <sys/utsname.h>
|
||||||
#endif // HAVE_SYS_UTSNAME_H
|
#endif // HAVE_SYS_UTSNAME_H
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
# include <libssh2.h>
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
@ -80,6 +82,8 @@ uint16_t getDefaultPort(const std::string& protocol)
|
||||||
return 443;
|
return 443;
|
||||||
} else if(protocol == "ftp") {
|
} else if(protocol == "ftp") {
|
||||||
return 21;
|
return 21;
|
||||||
|
} else if(protocol == "sftp") {
|
||||||
|
return 22;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -166,6 +170,14 @@ const char* strSupportedFeature(int feature)
|
||||||
#endif // !ENABLE_XML_RPC
|
#endif // !ENABLE_XML_RPC
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case(FEATURE_SFTP):
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
return "SFTP";
|
||||||
|
#else // !HAVE_LIBSSH2
|
||||||
|
return nullptr;
|
||||||
|
#endif // !HAVE_LIBSSH2
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
@ -221,6 +233,11 @@ std::string usedLibs()
|
||||||
#ifdef HAVE_LIBCARES
|
#ifdef HAVE_LIBCARES
|
||||||
res += "c-ares/" ARES_VERSION_STR " ";
|
res += "c-ares/" ARES_VERSION_STR " ";
|
||||||
#endif // HAVE_LIBCARES
|
#endif // HAVE_LIBCARES
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
res += "libssh2/" LIBSSH2_VERSION " ";
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
if(!res.empty()) {
|
if(!res.empty()) {
|
||||||
res.erase(res.length()-1);
|
res.erase(res.length()-1);
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ enum FeatureType {
|
||||||
FEATURE_MESSAGE_DIGEST,
|
FEATURE_MESSAGE_DIGEST,
|
||||||
FEATURE_METALINK,
|
FEATURE_METALINK,
|
||||||
FEATURE_XML_RPC,
|
FEATURE_XML_RPC,
|
||||||
|
FEATURE_SFTP,
|
||||||
MAX_FEATURE
|
MAX_FEATURE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,10 @@
|
||||||
#include "FtpNegotiationConnectChain.h"
|
#include "FtpNegotiationConnectChain.h"
|
||||||
#include "FtpTunnelRequestConnectChain.h"
|
#include "FtpTunnelRequestConnectChain.h"
|
||||||
#include "HttpRequestConnectChain.h"
|
#include "HttpRequestConnectChain.h"
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
# include "SftpNegotiationConnectChain.h"
|
||||||
|
# include "SftpNegotiationCommand.h"
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -82,6 +86,7 @@ std::unique_ptr<Command> FtpInitiateConnectionCommand::createNextCommandProxied
|
||||||
std::shared_ptr<SocketCore> pooledSocket;
|
std::shared_ptr<SocketCore> pooledSocket;
|
||||||
std::string proxyMethod = resolveProxyMethod(getRequest()->getProtocol());
|
std::string proxyMethod = resolveProxyMethod(getRequest()->getProtocol());
|
||||||
|
|
||||||
|
// sftp always use tunnel mode
|
||||||
if(proxyMethod == V_GET) {
|
if(proxyMethod == V_GET) {
|
||||||
pooledSocket = getDownloadEngine()->popPooledSocket
|
pooledSocket = getDownloadEngine()->popPooledSocket
|
||||||
(getRequest()->getHost(), getRequest()->getPort(),
|
(getRequest()->getHost(), getRequest()->getPort(),
|
||||||
|
@ -127,18 +132,33 @@ std::unique_ptr<Command> FtpInitiateConnectionCommand::createNextCommandProxied
|
||||||
|
|
||||||
setConnectedAddrInfo(getRequest(), hostname, pooledSocket);
|
setConnectedAddrInfo(getRequest(), hostname, pooledSocket);
|
||||||
if(proxyMethod == V_TUNNEL) {
|
if(proxyMethod == V_TUNNEL) {
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
if (getRequest()->getProtocol() == "sftp") {
|
||||||
|
return make_unique<SftpNegotiationCommand>
|
||||||
|
(getCuid(),
|
||||||
|
getRequest(),
|
||||||
|
getFileEntry(),
|
||||||
|
getRequestGroup(),
|
||||||
|
getDownloadEngine(),
|
||||||
|
pooledSocket,
|
||||||
|
SftpNegotiationCommand::SEQ_SFTP_OPEN);
|
||||||
|
}
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
// options contains "baseWorkingDir"
|
// options contains "baseWorkingDir"
|
||||||
return make_unique<FtpNegotiationCommand>
|
return make_unique<FtpNegotiationCommand>
|
||||||
(getCuid(),
|
(getCuid(),
|
||||||
getRequest(),
|
getRequest(),
|
||||||
getFileEntry(),
|
getFileEntry(),
|
||||||
getRequestGroup(),
|
getRequestGroup(),
|
||||||
getDownloadEngine(),
|
getDownloadEngine(),
|
||||||
pooledSocket,
|
pooledSocket,
|
||||||
FtpNegotiationCommand::SEQ_SEND_CWD_PREP,
|
FtpNegotiationCommand::SEQ_SEND_CWD_PREP,
|
||||||
options);
|
options);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
assert(getRequest()->getProtocol() == "ftp");
|
||||||
|
|
||||||
if(proxyMethod != V_GET) {
|
if(proxyMethod != V_GET) {
|
||||||
assert(0);
|
assert(0);
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
@ -180,30 +200,51 @@ std::unique_ptr<Command> FtpInitiateConnectionCommand::createNextCommandPlain
|
||||||
getSocket()->establishConnection(addr, port);
|
getSocket()->establishConnection(addr, port);
|
||||||
getRequest()->setConnectedAddrInfo(hostname, addr, port);
|
getRequest()->setConnectedAddrInfo(hostname, addr, port);
|
||||||
auto c = make_unique<ConnectCommand>(getCuid(),
|
auto c = make_unique<ConnectCommand>(getCuid(),
|
||||||
getRequest(),
|
getRequest(),
|
||||||
nullptr,
|
nullptr,
|
||||||
getFileEntry(),
|
getFileEntry(),
|
||||||
getRequestGroup(),
|
getRequestGroup(),
|
||||||
getDownloadEngine(),
|
getDownloadEngine(),
|
||||||
getSocket());
|
getSocket());
|
||||||
|
|
||||||
c->setControlChain(std::make_shared<FtpNegotiationConnectChain>());
|
if(getRequest()->getProtocol() == "sftp") {
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
c->setControlChain(std::make_shared<SftpNegotiationConnectChain>());
|
||||||
|
#else // !HAVE_LIBSSH2
|
||||||
|
assert(0);
|
||||||
|
#endif // !HAVE_LIBSSH2
|
||||||
|
} else {
|
||||||
|
c->setControlChain(std::make_shared<FtpNegotiationConnectChain>());
|
||||||
|
}
|
||||||
setupBackupConnection(hostname, addr, port, c.get());
|
setupBackupConnection(hostname, addr, port, c.get());
|
||||||
return std::move(c);
|
return std::move(c);
|
||||||
}
|
}
|
||||||
|
|
||||||
// options contains "baseWorkingDir"
|
|
||||||
auto command = make_unique<FtpNegotiationCommand>
|
|
||||||
(getCuid(),
|
|
||||||
getRequest(),
|
|
||||||
getFileEntry(),
|
|
||||||
getRequestGroup(),
|
|
||||||
getDownloadEngine(),
|
|
||||||
pooledSocket,
|
|
||||||
FtpNegotiationCommand::SEQ_SEND_CWD_PREP,
|
|
||||||
options);
|
|
||||||
setConnectedAddrInfo(getRequest(), hostname, pooledSocket);
|
setConnectedAddrInfo(getRequest(), hostname, pooledSocket);
|
||||||
return std::move(command);
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
if (getRequest()->getProtocol() == "sftp") {
|
||||||
|
return make_unique<SftpNegotiationCommand>
|
||||||
|
(getCuid(),
|
||||||
|
getRequest(),
|
||||||
|
getFileEntry(),
|
||||||
|
getRequestGroup(),
|
||||||
|
getDownloadEngine(),
|
||||||
|
pooledSocket,
|
||||||
|
SftpNegotiationCommand::SEQ_SFTP_OPEN);
|
||||||
|
}
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
|
// options contains "baseWorkingDir"
|
||||||
|
return make_unique<FtpNegotiationCommand>
|
||||||
|
(getCuid(),
|
||||||
|
getRequest(),
|
||||||
|
getFileEntry(),
|
||||||
|
getRequestGroup(),
|
||||||
|
getDownloadEngine(),
|
||||||
|
pooledSocket,
|
||||||
|
FtpNegotiationCommand::SEQ_SEND_CWD_PREP,
|
||||||
|
options);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::unique_ptr<Command> FtpInitiateConnectionCommand::createNextCommand
|
std::unique_ptr<Command> FtpInitiateConnectionCommand::createNextCommand
|
||||||
|
|
|
@ -40,6 +40,9 @@
|
||||||
#include "Segment.h"
|
#include "Segment.h"
|
||||||
#include "SocketCore.h"
|
#include "SocketCore.h"
|
||||||
#include "SocketRecvBuffer.h"
|
#include "SocketRecvBuffer.h"
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
# include "SftpNegotiationCommand.h"
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -59,6 +62,15 @@ FtpTunnelResponseCommand::~FtpTunnelResponseCommand() {}
|
||||||
|
|
||||||
std::unique_ptr<Command> FtpTunnelResponseCommand::getNextCommand()
|
std::unique_ptr<Command> FtpTunnelResponseCommand::getNextCommand()
|
||||||
{
|
{
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
if (getRequest()->getProtocol() == "sftp") {
|
||||||
|
return make_unique<SftpNegotiationCommand>
|
||||||
|
(getCuid(), getRequest(), getFileEntry(),
|
||||||
|
getRequestGroup(), getDownloadEngine(),
|
||||||
|
getSocket());
|
||||||
|
}
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
return make_unique<FtpNegotiationCommand>
|
return make_unique<FtpNegotiationCommand>
|
||||||
(getCuid(), getRequest(), getFileEntry(),
|
(getCuid(), getRequest(), getFileEntry(),
|
||||||
getRequestGroup(), getDownloadEngine(),
|
getRequestGroup(), getDownloadEngine(),
|
||||||
|
|
|
@ -71,10 +71,14 @@ InitiateConnectionCommandFactory::createInitiateConnectionCommand
|
||||||
|
|
||||||
return make_unique<HttpInitiateConnectionCommand>(cuid, req, fileEntry,
|
return make_unique<HttpInitiateConnectionCommand>(cuid, req, fileEntry,
|
||||||
requestGroup, e);
|
requestGroup, e);
|
||||||
} else if(req->getProtocol() == "ftp") {
|
} else if(req->getProtocol() == "ftp"
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
|| req->getProtocol() == "sftp"
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
) {
|
||||||
if(req->getFile().empty()) {
|
if(req->getFile().empty()) {
|
||||||
throw DL_ABORT_EX
|
throw DL_ABORT_EX
|
||||||
(fmt("FTP URI %s doesn't contain file path.",
|
(fmt("FTP/SFTP URI %s doesn't contain file path.",
|
||||||
req->getUri().c_str()));
|
req->getUri().c_str()));
|
||||||
}
|
}
|
||||||
return make_unique<FtpInitiateConnectionCommand>(cuid, req, fileEntry,
|
return make_unique<FtpInitiateConnectionCommand>(cuid, req, fileEntry,
|
||||||
|
|
|
@ -427,6 +427,14 @@ SRCS += \
|
||||||
Sqlite3CookieParserImpl.cc Sqlite3CookieParserImpl.h
|
Sqlite3CookieParserImpl.cc Sqlite3CookieParserImpl.h
|
||||||
endif # HAVE_SQLITE3
|
endif # HAVE_SQLITE3
|
||||||
|
|
||||||
|
if HAVE_LIBSSH2
|
||||||
|
SRCS += SSHSession.cc SSHSession.h \
|
||||||
|
SftpNegotiationCommand.cc SftpNegotiationCommand.h \
|
||||||
|
SftpNegotiationConnectChain.h \
|
||||||
|
SftpDownloadCommand.cc SftpDownloadCommand.h \
|
||||||
|
SftpFinishDownloadCommand.cc SftpFinishDownloadCommand.h
|
||||||
|
endif # HAVE_LIBSSH2
|
||||||
|
|
||||||
if ENABLE_ASYNC_DNS
|
if ENABLE_ASYNC_DNS
|
||||||
SRCS += \
|
SRCS += \
|
||||||
AsyncNameResolver.cc AsyncNameResolver.h\
|
AsyncNameResolver.cc AsyncNameResolver.h\
|
||||||
|
|
|
@ -193,7 +193,7 @@ void MetalinkParserController::setTypeOfResource(std::string type)
|
||||||
if(!tResource_) {
|
if(!tResource_) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if(type == "ftp") {
|
if(type == "ftp" || type == "sftp") {
|
||||||
tResource_->type = MetalinkResource::TYPE_FTP;
|
tResource_->type = MetalinkResource::TYPE_FTP;
|
||||||
} else if(type == "http") {
|
} else if(type == "http") {
|
||||||
tResource_->type = MetalinkResource::TYPE_HTTP;
|
tResource_->type = MetalinkResource::TYPE_HTTP;
|
||||||
|
|
|
@ -56,6 +56,10 @@
|
||||||
# include <ares.h>
|
# include <ares.h>
|
||||||
#endif // ENABLE_ASYNC_DNS
|
#endif // ENABLE_ASYNC_DNS
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
# include <libssh2.h>
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
#include "a2netcompat.h"
|
#include "a2netcompat.h"
|
||||||
#include "DlAbortEx.h"
|
#include "DlAbortEx.h"
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
@ -149,6 +153,15 @@ bool Platform::setUp()
|
||||||
}
|
}
|
||||||
#endif // CARES_HAVE_ARES_LIBRARY_INIT
|
#endif // CARES_HAVE_ARES_LIBRARY_INIT
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
{
|
||||||
|
auto rv = libssh2_init(0);
|
||||||
|
if (rv != 0) {
|
||||||
|
throw DL_ABORT_EX(fmt("libssh2_init() failed, code: %d", rv));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
#ifdef HAVE_WINSOCK2_H
|
#ifdef HAVE_WINSOCK2_H
|
||||||
WSADATA wsaData;
|
WSADATA wsaData;
|
||||||
memset(reinterpret_cast<char*>(&wsaData), 0, sizeof(wsaData));
|
memset(reinterpret_cast<char*>(&wsaData), 0, sizeof(wsaData));
|
||||||
|
@ -181,6 +194,10 @@ bool Platform::tearDown()
|
||||||
ares_library_cleanup();
|
ares_library_cleanup();
|
||||||
#endif // CARES_HAVE_ARES_LIBRARY_CLEANUP
|
#endif // CARES_HAVE_ARES_LIBRARY_CLEANUP
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
libssh2_exit();
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
#ifdef HAVE_WINSOCK2_H
|
#ifdef HAVE_WINSOCK2_H
|
||||||
WSACleanup();
|
WSACleanup();
|
||||||
#endif // HAVE_WINSOCK2_H
|
#endif // HAVE_WINSOCK2_H
|
||||||
|
|
|
@ -0,0 +1,240 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#include "SSHSession.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
SSHSession::SSHSession()
|
||||||
|
: ssh2_(nullptr),
|
||||||
|
sftp_(nullptr),
|
||||||
|
sftph_(nullptr),
|
||||||
|
fd_(-1)
|
||||||
|
{}
|
||||||
|
|
||||||
|
SSHSession::~SSHSession()
|
||||||
|
{
|
||||||
|
closeConnection();
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::closeConnection()
|
||||||
|
{
|
||||||
|
if (sftph_) {
|
||||||
|
// TODO this could return LIBSSH2_ERROR_EAGAIN
|
||||||
|
libssh2_sftp_close(sftph_);
|
||||||
|
sftph_ = nullptr;
|
||||||
|
}
|
||||||
|
if (sftp_) {
|
||||||
|
// TODO this could return LIBSSH2_ERROR_EAGAIN
|
||||||
|
libssh2_sftp_shutdown(sftp_);
|
||||||
|
sftp_ = nullptr;
|
||||||
|
}
|
||||||
|
if (ssh2_) {
|
||||||
|
// TODO this could return LIBSSH2_ERROR_EAGAIN
|
||||||
|
libssh2_session_disconnect(ssh2_, "bye");
|
||||||
|
libssh2_session_free(ssh2_);
|
||||||
|
ssh2_ = nullptr;
|
||||||
|
}
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::gracefulShutdown()
|
||||||
|
{
|
||||||
|
if (sftph_) {
|
||||||
|
auto rv = libssh2_sftp_close(sftph_);
|
||||||
|
if (rv == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
sftph_ = nullptr;
|
||||||
|
}
|
||||||
|
if (sftp_) {
|
||||||
|
auto rv = libssh2_sftp_shutdown(sftp_);
|
||||||
|
if (rv == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
sftp_ = nullptr;
|
||||||
|
}
|
||||||
|
if (ssh2_) {
|
||||||
|
auto rv = libssh2_session_disconnect(ssh2_, "bye");
|
||||||
|
if (rv == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
libssh2_session_free(ssh2_);
|
||||||
|
ssh2_ = nullptr;
|
||||||
|
}
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::sftpClose()
|
||||||
|
{
|
||||||
|
if (!sftph_) {
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto rv = libssh2_sftp_close(sftph_);
|
||||||
|
if (rv == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
sftph_ = nullptr;
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::init(sock_t sockfd)
|
||||||
|
{
|
||||||
|
ssh2_ = libssh2_session_init();
|
||||||
|
if (!ssh2_) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
libssh2_session_set_blocking(ssh2_, 0);
|
||||||
|
fd_ = sockfd;
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int SSHSession::checkDirection()
|
||||||
|
{
|
||||||
|
auto dir = libssh2_session_block_directions(ssh2_);
|
||||||
|
if (dir & LIBSSH2_SESSION_BLOCK_OUTBOUND) {
|
||||||
|
return SSH_WANT_WRITE;
|
||||||
|
}
|
||||||
|
return SSH_WANT_READ;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t SSHSession::writeData(const void* data, size_t len)
|
||||||
|
{
|
||||||
|
// net implemented yet
|
||||||
|
assert(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t SSHSession::readData(void* data, size_t len)
|
||||||
|
{
|
||||||
|
auto nread = libssh2_sftp_read(sftph_, static_cast<char*>(data), len);
|
||||||
|
if (nread == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (nread < 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
return nread;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::handshake()
|
||||||
|
{
|
||||||
|
auto rv = libssh2_session_handshake(ssh2_, fd_);
|
||||||
|
if (rv == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
// TODO we have to validate server's fingerprint
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::authPassword(const std::string& user,
|
||||||
|
const std::string& password)
|
||||||
|
{
|
||||||
|
auto rv = libssh2_userauth_password(ssh2_, user.c_str(), password.c_str());
|
||||||
|
if (rv == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::sftpOpen(const std::string& path)
|
||||||
|
{
|
||||||
|
if (!sftp_) {
|
||||||
|
sftp_ = libssh2_sftp_init(ssh2_);
|
||||||
|
if (!sftp_) {
|
||||||
|
if (libssh2_session_last_errno(ssh2_) == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!sftph_) {
|
||||||
|
sftph_ = libssh2_sftp_open(sftp_, path.c_str(), LIBSSH2_FXF_READ, 0);
|
||||||
|
if (!sftph_) {
|
||||||
|
if (libssh2_session_last_errno(ssh2_) == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int SSHSession::sftpStat(int64_t& totalLength, time_t& mtime)
|
||||||
|
{
|
||||||
|
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
||||||
|
auto rv = libssh2_sftp_fstat_ex(sftph_, &attrs, 0);
|
||||||
|
if (rv == LIBSSH2_ERROR_EAGAIN) {
|
||||||
|
return SSH_ERR_WOULDBLOCK;
|
||||||
|
}
|
||||||
|
if (rv != 0) {
|
||||||
|
return SSH_ERR_ERROR;
|
||||||
|
}
|
||||||
|
totalLength = attrs.filesize;
|
||||||
|
mtime = attrs.mtime;
|
||||||
|
return SSH_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SSHSession::getLastErrorString()
|
||||||
|
{
|
||||||
|
if (!ssh2_) {
|
||||||
|
return "SSH session has not been initialized yet";
|
||||||
|
}
|
||||||
|
char* errmsg;
|
||||||
|
libssh2_session_last_error(ssh2_, &errmsg, nullptr, 0);
|
||||||
|
return errmsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -0,0 +1,137 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#ifndef SSH_SESSION_H
|
||||||
|
#define SSH_SESSION_H
|
||||||
|
|
||||||
|
#include "common.h"
|
||||||
|
#include "a2netcompat.h"
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
#include <libssh2.h>
|
||||||
|
#include <libssh2_sftp.h>
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
enum SSHDirection {
|
||||||
|
SSH_WANT_READ = 1,
|
||||||
|
SSH_WANT_WRITE
|
||||||
|
};
|
||||||
|
|
||||||
|
enum SSHErrorCode {
|
||||||
|
SSH_ERR_OK = 0,
|
||||||
|
SSH_ERR_ERROR = -1,
|
||||||
|
SSH_ERR_WOULDBLOCK = -2
|
||||||
|
};
|
||||||
|
|
||||||
|
class SSHSession {
|
||||||
|
public:
|
||||||
|
SSHSession();
|
||||||
|
|
||||||
|
// MUST deallocate all resources
|
||||||
|
~SSHSession();
|
||||||
|
|
||||||
|
SSHSession(const SSHSession&) = delete;
|
||||||
|
SSHSession& operator=(const SSHSession&) = delete;
|
||||||
|
|
||||||
|
// Initializes SSH session. The |sockfd| is the underlying
|
||||||
|
// transport socket. This function returns SSH_ERR_OK if it
|
||||||
|
// succeeds, or SSH_ERR_ERROR.
|
||||||
|
int init(sock_t sockfd);
|
||||||
|
|
||||||
|
// Closes the SSH session. Don't close underlying transport
|
||||||
|
// socket. This function returns SSH_ERR_OK if it succeeds, or
|
||||||
|
// SSH_ERR_ERROR.
|
||||||
|
int closeConnection();
|
||||||
|
|
||||||
|
int gracefulShutdown();
|
||||||
|
|
||||||
|
// Returns SSH_WANT_READ if SSH session needs more data from remote
|
||||||
|
// endpoint to proceed, or SSH_WANT_WRITE if SSH session needs to
|
||||||
|
// write more data to proceed. If SSH session needs neither read nor
|
||||||
|
// write data at the moment, SSH_WANT_READ must be returned.
|
||||||
|
int checkDirection();
|
||||||
|
|
||||||
|
// Sends |data| with length |len|. This function returns the number
|
||||||
|
// of bytes sent if it succeeds, or SSH_ERR_WOULDBLOCK if the
|
||||||
|
// underlying transport blocks, or SSH_ERR_ERROR.
|
||||||
|
ssize_t writeData(const void* data, size_t len);
|
||||||
|
|
||||||
|
// Receives data into |data| with length |len|. This function
|
||||||
|
// returns the number of bytes received if it succeeds, or
|
||||||
|
// SSH_ERR_WOULDBLOCK if the underlying transport blocks, or
|
||||||
|
// SSH_ERR_ERROR.
|
||||||
|
ssize_t readData(void* data, size_t len);
|
||||||
|
|
||||||
|
// Performs handshake. This function returns SSH_ERR_OK
|
||||||
|
// if it succeeds, or SSH_ERR_WOULDBLOCK if the underlying transport
|
||||||
|
// blocks, or SSH_ERR_ERROR.
|
||||||
|
int handshake();
|
||||||
|
|
||||||
|
// Performs authentication using username and password. This
|
||||||
|
// function returns SSH_ERR_OK if it succeeds, or SSH_ERR_WOULDBLOCK
|
||||||
|
// if the underlying transport blocks, or SSH_ERR_ERROR.
|
||||||
|
int authPassword(const std::string& user, const std::string& password);
|
||||||
|
|
||||||
|
// Starts SFTP session and opens remote file |path|. This function
|
||||||
|
// returns SSH_ERR_OK if it succeeds, or SSH_ERR_WOULDBLOCK if the
|
||||||
|
// underlying transport blocks, or SSH_ERR_ERROR.
|
||||||
|
int sftpOpen(const std::string& path);
|
||||||
|
|
||||||
|
// Closes remote file opened by sftpOpen(). This function returns
|
||||||
|
// SSH_ERR_OK if it succeeds, or SSH_ERR_WOULDBLOCK if the
|
||||||
|
// underlying transport blocks, or SSH_ERR_ERROR.
|
||||||
|
int sftpClose();
|
||||||
|
|
||||||
|
// Gets total length and modified time of opened file by sftpOpen().
|
||||||
|
// On success, total length and modified time are assigned to
|
||||||
|
// |totalLength| and |mtime|. This function returns SSH_ERR_OK if
|
||||||
|
// it succeeds, or SSH_ERR_WOULDBLOCK if the underlying transport
|
||||||
|
// blocks, or SSH_ERR_ERROR.
|
||||||
|
int sftpStat(int64_t& totalLength, time_t& mtime);
|
||||||
|
|
||||||
|
// Returns last error string
|
||||||
|
std::string getLastErrorString();
|
||||||
|
|
||||||
|
private:
|
||||||
|
LIBSSH2_SESSION* ssh2_;
|
||||||
|
LIBSSH2_SFTP* sftp_;
|
||||||
|
LIBSSH2_SFTP_HANDLE* sftph_;
|
||||||
|
sock_t fd_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // SSH_SESSION_H
|
|
@ -0,0 +1,99 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#include "SftpDownloadCommand.h"
|
||||||
|
#include "Request.h"
|
||||||
|
#include "SocketCore.h"
|
||||||
|
#include "Segment.h"
|
||||||
|
#include "DownloadEngine.h"
|
||||||
|
#include "RequestGroup.h"
|
||||||
|
#include "Option.h"
|
||||||
|
#include "FileEntry.h"
|
||||||
|
#include "SocketRecvBuffer.h"
|
||||||
|
#include "AuthConfig.h"
|
||||||
|
#include "SftpFinishDownloadCommand.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
SftpDownloadCommand::SftpDownloadCommand
|
||||||
|
(cuid_t cuid,
|
||||||
|
const std::shared_ptr<Request>& req,
|
||||||
|
const std::shared_ptr<FileEntry>& fileEntry,
|
||||||
|
RequestGroup* requestGroup,
|
||||||
|
DownloadEngine* e,
|
||||||
|
const std::shared_ptr<SocketCore>& socket,
|
||||||
|
std::unique_ptr<AuthConfig> authConfig)
|
||||||
|
: DownloadCommand(cuid, req, fileEntry, requestGroup, e, socket,
|
||||||
|
std::make_shared<SocketRecvBuffer>(socket)),
|
||||||
|
authConfig_(std::move(authConfig))
|
||||||
|
{
|
||||||
|
setWriteCheckSocket(getSocket());
|
||||||
|
}
|
||||||
|
|
||||||
|
SftpDownloadCommand::~SftpDownloadCommand() {}
|
||||||
|
|
||||||
|
bool SftpDownloadCommand::prepareForNextSegment()
|
||||||
|
{
|
||||||
|
if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION) &&
|
||||||
|
getFileEntry()->gtoloff(getSegments().front()->getPositionToWrite()) ==
|
||||||
|
getFileEntry()->getLength()) {
|
||||||
|
|
||||||
|
auto c = make_unique<SftpFinishDownloadCommand>
|
||||||
|
(getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
|
||||||
|
getDownloadEngine(), getSocket());
|
||||||
|
|
||||||
|
c->setStatus(Command::STATUS_ONESHOT_REALTIME);
|
||||||
|
getDownloadEngine()->setNoWait(true);
|
||||||
|
getDownloadEngine()->addCommand(std::move(c));
|
||||||
|
|
||||||
|
if(getRequestGroup()->downloadFinished()) {
|
||||||
|
// To run checksum checking, we had to call following function here.
|
||||||
|
DownloadCommand::prepareForNextSegment();
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return DownloadCommand::prepareForNextSegment();
|
||||||
|
}
|
||||||
|
|
||||||
|
int64_t SftpDownloadCommand::getRequestEndOffset() const
|
||||||
|
{
|
||||||
|
return getFileEntry()->getLength();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SftpDownloadCommand::shouldEnableWriteCheck() {
|
||||||
|
return getSocket()->wantWrite() || !getSocket()->wantRead();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#ifndef D_SFTP_DOWNLOAD_COMMAND_H
|
||||||
|
#define D_SFTP_DOWNLOAD_COMMAND_H
|
||||||
|
|
||||||
|
#include "DownloadCommand.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
class AuthConfig;
|
||||||
|
|
||||||
|
class SftpDownloadCommand : public DownloadCommand {
|
||||||
|
private:
|
||||||
|
std::unique_ptr<AuthConfig> authConfig_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool prepareForNextSegment() CXX11_OVERRIDE;
|
||||||
|
virtual int64_t getRequestEndOffset() const CXX11_OVERRIDE;
|
||||||
|
virtual bool shouldEnableWriteCheck() CXX11_OVERRIDE;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SftpDownloadCommand(cuid_t cuid,
|
||||||
|
const std::shared_ptr<Request>& req,
|
||||||
|
const std::shared_ptr<FileEntry>& fileEntry,
|
||||||
|
RequestGroup* requestGroup,
|
||||||
|
DownloadEngine* e,
|
||||||
|
const std::shared_ptr<SocketCore>& socket,
|
||||||
|
std::unique_ptr<AuthConfig> authConfig);
|
||||||
|
virtual ~SftpDownloadCommand();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aria2
|
||||||
|
|
||||||
|
#endif // D_SFTP_DOWNLOAD_COMMAND_H
|
|
@ -0,0 +1,119 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#include "SftpFinishDownloadCommand.h"
|
||||||
|
|
||||||
|
#include "Request.h"
|
||||||
|
#include "DownloadEngine.h"
|
||||||
|
#include "prefs.h"
|
||||||
|
#include "Option.h"
|
||||||
|
#include "message.h"
|
||||||
|
#include "fmt.h"
|
||||||
|
#include "DlAbortEx.h"
|
||||||
|
#include "SocketCore.h"
|
||||||
|
#include "RequestGroup.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
#include "LogFactory.h"
|
||||||
|
#include "wallclock.h"
|
||||||
|
#include "AuthConfigFactory.h"
|
||||||
|
#include "AuthConfig.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
SftpFinishDownloadCommand::SftpFinishDownloadCommand
|
||||||
|
(cuid_t cuid,
|
||||||
|
const std::shared_ptr<Request>& req,
|
||||||
|
const std::shared_ptr<FileEntry>& fileEntry,
|
||||||
|
RequestGroup* requestGroup,
|
||||||
|
DownloadEngine* e,
|
||||||
|
const std::shared_ptr<SocketCore>& socket)
|
||||||
|
: AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket)
|
||||||
|
{
|
||||||
|
disableReadCheckSocket();
|
||||||
|
setWriteCheckSocket(getSocket());
|
||||||
|
}
|
||||||
|
|
||||||
|
SftpFinishDownloadCommand::~SftpFinishDownloadCommand() {}
|
||||||
|
|
||||||
|
// overrides AbstractCommand::execute().
|
||||||
|
// AbstractCommand::_segments is empty.
|
||||||
|
bool SftpFinishDownloadCommand::execute()
|
||||||
|
{
|
||||||
|
if(getRequestGroup()->isHaltRequested()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
if(readEventEnabled() || writeEventEnabled() || hupEventEnabled()) {
|
||||||
|
getCheckPoint() = global::wallclock();
|
||||||
|
|
||||||
|
if (!getSocket()->sshSFTPClose()) {
|
||||||
|
setWriteCheckSocketIf(getSocket(), getSocket()->wantWrite());
|
||||||
|
setReadCheckSocketIf(getSocket(), getSocket()->wantRead());
|
||||||
|
addCommandSelf();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto authConfig =
|
||||||
|
getDownloadEngine()->getAuthConfigFactory()->createAuthConfig
|
||||||
|
(getRequest(), getRequestGroup()->getOption().get());
|
||||||
|
|
||||||
|
getDownloadEngine()->poolSocket
|
||||||
|
(getRequest(), authConfig->getUser(), createProxyRequest(),
|
||||||
|
getSocket(), "");
|
||||||
|
} else if(getCheckPoint().difference(global::wallclock()) >= getTimeout()) {
|
||||||
|
A2_LOG_INFO(fmt("CUID#%" PRId64
|
||||||
|
" - Timeout before receiving transfer complete.",
|
||||||
|
getCuid()));
|
||||||
|
} else {
|
||||||
|
addCommandSelf();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} catch(RecoverableException& e) {
|
||||||
|
A2_LOG_INFO_EX(fmt("CUID#%" PRId64
|
||||||
|
" - Exception was thrown, but download was"
|
||||||
|
" finished, so we can ignore the exception.",
|
||||||
|
getCuid()),
|
||||||
|
e);
|
||||||
|
}
|
||||||
|
if(getRequestGroup()->downloadFinished()) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return prepareForRetry(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This function never be called.
|
||||||
|
bool SftpFinishDownloadCommand::executeInternal() { return true; }
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -0,0 +1,59 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#ifndef D_SFTP_FINISH_DOWNLOAD_COMMAND_H
|
||||||
|
#define D_SFTP_FINISH_DOWNLOAD_COMMAND_H
|
||||||
|
|
||||||
|
#include "AbstractCommand.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
class SftpFinishDownloadCommand : public AbstractCommand {
|
||||||
|
protected:
|
||||||
|
virtual bool execute() CXX11_OVERRIDE;
|
||||||
|
|
||||||
|
virtual bool executeInternal() CXX11_OVERRIDE;
|
||||||
|
public:
|
||||||
|
SftpFinishDownloadCommand(cuid_t cuid,
|
||||||
|
const std::shared_ptr<Request>& req,
|
||||||
|
const std::shared_ptr<FileEntry>& fileEntry,
|
||||||
|
RequestGroup* requestGroup,
|
||||||
|
DownloadEngine* e,
|
||||||
|
const std::shared_ptr<SocketCore>& socket);
|
||||||
|
virtual ~SftpFinishDownloadCommand();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aria2
|
||||||
|
|
||||||
|
#endif // D_SFTP_FINISH_DOWNLOAD_COMMAND_H
|
|
@ -0,0 +1,320 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#include "SftpNegotiationCommand.h"
|
||||||
|
|
||||||
|
#include <cassert>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "Request.h"
|
||||||
|
#include "DownloadEngine.h"
|
||||||
|
#include "RequestGroup.h"
|
||||||
|
#include "PieceStorage.h"
|
||||||
|
#include "FileEntry.h"
|
||||||
|
#include "message.h"
|
||||||
|
#include "util.h"
|
||||||
|
#include "Option.h"
|
||||||
|
#include "Logger.h"
|
||||||
|
#include "LogFactory.h"
|
||||||
|
#include "Segment.h"
|
||||||
|
#include "DownloadContext.h"
|
||||||
|
#include "DefaultBtProgressInfoFile.h"
|
||||||
|
#include "RequestGroupMan.h"
|
||||||
|
#include "SocketCore.h"
|
||||||
|
#include "fmt.h"
|
||||||
|
#include "DiskAdaptor.h"
|
||||||
|
#include "SegmentMan.h"
|
||||||
|
#include "AuthConfigFactory.h"
|
||||||
|
#include "AuthConfig.h"
|
||||||
|
#include "a2functional.h"
|
||||||
|
#include "URISelector.h"
|
||||||
|
#include "CheckIntegrityEntry.h"
|
||||||
|
#include "NullProgressInfoFile.h"
|
||||||
|
#include "ChecksumCheckIntegrityEntry.h"
|
||||||
|
#include "SftpDownloadCommand.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
SftpNegotiationCommand::SftpNegotiationCommand
|
||||||
|
(cuid_t cuid,
|
||||||
|
const std::shared_ptr<Request>& req,
|
||||||
|
const std::shared_ptr<FileEntry>& fileEntry,
|
||||||
|
RequestGroup* requestGroup,
|
||||||
|
DownloadEngine* e,
|
||||||
|
const std::shared_ptr<SocketCore>& socket,
|
||||||
|
Seq seq)
|
||||||
|
: AbstractCommand(cuid, req, fileEntry, requestGroup, e, socket),
|
||||||
|
sequence_(seq),
|
||||||
|
authConfig_(e->getAuthConfigFactory()->createAuthConfig
|
||||||
|
(req, requestGroup->getOption().get()))
|
||||||
|
|
||||||
|
{
|
||||||
|
path_ = getPath();
|
||||||
|
disableReadCheckSocket();
|
||||||
|
setWriteCheckSocket(getSocket());
|
||||||
|
}
|
||||||
|
|
||||||
|
SftpNegotiationCommand::~SftpNegotiationCommand() {}
|
||||||
|
|
||||||
|
bool SftpNegotiationCommand::executeInternal() {
|
||||||
|
disableWriteCheckSocket();
|
||||||
|
for (;;) {
|
||||||
|
switch(sequence_) {
|
||||||
|
case SEQ_HANDSHAKE:
|
||||||
|
setReadCheckSocket(getSocket());
|
||||||
|
if (!getSocket()->sshHandshake()) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
A2_LOG_DEBUG(fmt("CUID#%" PRId64 " - SSH handshake success", getCuid()));
|
||||||
|
sequence_ = SEQ_AUTH_PASSWORD;
|
||||||
|
break;
|
||||||
|
case SEQ_AUTH_PASSWORD:
|
||||||
|
if (!getSocket()->sshAuthPassword(authConfig_->getUser(),
|
||||||
|
authConfig_->getPassword())) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
A2_LOG_DEBUG(fmt("CUID#%" PRId64 " - SSH authentication success",
|
||||||
|
getCuid()));
|
||||||
|
sequence_ = SEQ_SFTP_OPEN;
|
||||||
|
break;
|
||||||
|
case SEQ_SFTP_OPEN: {
|
||||||
|
if (!getSocket()->sshSFTPOpen(path_)) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
A2_LOG_DEBUG(fmt("CUID#%" PRId64 " - SFTP file %s opened", getCuid(),
|
||||||
|
path_.c_str()));
|
||||||
|
sequence_ = SEQ_SFTP_STAT;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SEQ_SFTP_STAT: {
|
||||||
|
int64_t totalLength;
|
||||||
|
time_t mtime;
|
||||||
|
if (!getSocket()->sshSFTPStat(totalLength, mtime, path_)) {
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
Time t(mtime);
|
||||||
|
A2_LOG_INFO(fmt("CUID#%" PRId64 " - SFTP File %s, size=%" PRId64
|
||||||
|
", mtime=%s",
|
||||||
|
getCuid(), path_.c_str(), totalLength,
|
||||||
|
t.toHTTPDate().c_str()));
|
||||||
|
if (!getPieceStorage()) {
|
||||||
|
getRequestGroup()->updateLastModifiedTime(Time(mtime));
|
||||||
|
onFileSizeDetermined(totalLength);
|
||||||
|
} else {
|
||||||
|
getRequestGroup()->validateTotalLength(getFileEntry()->getLength(),
|
||||||
|
totalLength);
|
||||||
|
sequence_ = SEQ_NEGOTIATION_COMPLETED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case SEQ_FILE_PREPARATION:
|
||||||
|
sequence_ = SEQ_NEGOTIATION_COMPLETED;
|
||||||
|
disableReadCheckSocket();
|
||||||
|
disableWriteCheckSocket();
|
||||||
|
return false;
|
||||||
|
case SEQ_NEGOTIATION_COMPLETED: {
|
||||||
|
auto command = make_unique<SftpDownloadCommand>
|
||||||
|
(getCuid(), getRequest(), getFileEntry(), getRequestGroup(),
|
||||||
|
getDownloadEngine(), getSocket(), std::move(authConfig_));
|
||||||
|
command->setStartupIdleTime
|
||||||
|
(getOption()->getAsInt(PREF_STARTUP_IDLE_TIME));
|
||||||
|
command->setLowestDownloadSpeedLimit
|
||||||
|
(getOption()->getAsInt(PREF_LOWEST_SPEED_LIMIT));
|
||||||
|
command->setStatus(Command::STATUS_ONESHOT_REALTIME);
|
||||||
|
|
||||||
|
getDownloadEngine()->setNoWait(true);
|
||||||
|
|
||||||
|
if(getFileEntry()->isUniqueProtocol()) {
|
||||||
|
getFileEntry()->removeURIWhoseHostnameIs(getRequest()->getHost());
|
||||||
|
}
|
||||||
|
getRequestGroup()->getURISelector()->tuneDownloadCommand
|
||||||
|
(getFileEntry()->getRemainingUris(), command.get());
|
||||||
|
getDownloadEngine()->addCommand(std::move(command));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
case SEQ_DOWNLOAD_ALREADY_COMPLETED:
|
||||||
|
case SEQ_HEAD_OK:
|
||||||
|
case SEQ_EXIT:
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
again:
|
||||||
|
addCommandSelf();
|
||||||
|
if (getSocket()->wantWrite()) {
|
||||||
|
setWriteCheckSocket(getSocket());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SftpNegotiationCommand::onFileSizeDetermined(int64_t totalLength)
|
||||||
|
{
|
||||||
|
getFileEntry()->setLength(totalLength);
|
||||||
|
if(getFileEntry()->getPath().empty()) {
|
||||||
|
auto suffixPath = util::createSafePath
|
||||||
|
(util::percentDecode(std::begin(getRequest()->getFile()),
|
||||||
|
std::end(getRequest()->getFile())));
|
||||||
|
|
||||||
|
getFileEntry()->setPath
|
||||||
|
(util::applyDir(getOption()->get(PREF_DIR), suffixPath));
|
||||||
|
getFileEntry()->setSuffixPath(suffixPath);
|
||||||
|
}
|
||||||
|
getRequestGroup()->preDownloadProcessing();
|
||||||
|
|
||||||
|
if(totalLength == 0) {
|
||||||
|
sequence_ = SEQ_NEGOTIATION_COMPLETED;
|
||||||
|
|
||||||
|
if(getOption()->getAsBool(PREF_DRY_RUN)) {
|
||||||
|
getRequestGroup()->initPieceStorage();
|
||||||
|
onDryRunFileFound();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getDownloadContext()->knowsTotalLength() &&
|
||||||
|
getRequestGroup()->downloadFinishedByFileLength()) {
|
||||||
|
// TODO Known issue: if .aria2 file exists, it will not be
|
||||||
|
// deleted on successful verification, because .aria2 file is
|
||||||
|
// not loaded. See also
|
||||||
|
// HttpResponseCommand::handleOtherEncoding()
|
||||||
|
getRequestGroup()->initPieceStorage();
|
||||||
|
if(getDownloadContext()->isChecksumVerificationNeeded()) {
|
||||||
|
A2_LOG_DEBUG("Zero length file exists. Verify checksum.");
|
||||||
|
auto entry = make_unique<ChecksumCheckIntegrityEntry>
|
||||||
|
(getRequestGroup());
|
||||||
|
entry->initValidator();
|
||||||
|
getPieceStorage()->getDiskAdaptor()->openExistingFile();
|
||||||
|
getDownloadEngine()->getCheckIntegrityMan()->pushEntry
|
||||||
|
(std::move(entry));
|
||||||
|
sequence_ = SEQ_EXIT;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
getPieceStorage()->markAllPiecesDone();
|
||||||
|
getDownloadContext()->setChecksumVerified(true);
|
||||||
|
sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED;
|
||||||
|
A2_LOG_NOTICE
|
||||||
|
(fmt(MSG_DOWNLOAD_ALREADY_COMPLETED,
|
||||||
|
GroupId::toHex(getRequestGroup()->getGID()).c_str(),
|
||||||
|
getRequestGroup()->getFirstFilePath().c_str()));
|
||||||
|
}
|
||||||
|
poolConnection();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
getRequestGroup()->adjustFilename
|
||||||
|
(std::make_shared<NullProgressInfoFile>());
|
||||||
|
getRequestGroup()->initPieceStorage();
|
||||||
|
getPieceStorage()->getDiskAdaptor()->initAndOpenFile();
|
||||||
|
|
||||||
|
if(getDownloadContext()->knowsTotalLength()) {
|
||||||
|
A2_LOG_DEBUG("File length becomes zero and it means download completed.");
|
||||||
|
// TODO Known issue: if .aria2 file exists, it will not be
|
||||||
|
// deleted on successful verification, because .aria2 file is
|
||||||
|
// not loaded. See also
|
||||||
|
// HttpResponseCommand::handleOtherEncoding()
|
||||||
|
if(getDownloadContext()->isChecksumVerificationNeeded()) {
|
||||||
|
A2_LOG_DEBUG("Verify checksum for zero-length file");
|
||||||
|
auto entry = make_unique<ChecksumCheckIntegrityEntry>
|
||||||
|
(getRequestGroup());
|
||||||
|
entry->initValidator();
|
||||||
|
getDownloadEngine()->getCheckIntegrityMan()->pushEntry
|
||||||
|
(std::move(entry));
|
||||||
|
sequence_ = SEQ_EXIT;
|
||||||
|
} else
|
||||||
|
{
|
||||||
|
sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED;
|
||||||
|
getPieceStorage()->markAllPiecesDone();
|
||||||
|
}
|
||||||
|
poolConnection();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// We have to make sure that command that has Request object must
|
||||||
|
// have segment after PieceStorage is initialized. See
|
||||||
|
// AbstractCommand::execute()
|
||||||
|
getSegmentMan()->getSegmentWithIndex(getCuid(), 0);
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
auto progressInfoFile = std::make_shared<DefaultBtProgressInfoFile>
|
||||||
|
(getDownloadContext(), nullptr, getOption().get());
|
||||||
|
getRequestGroup()->adjustFilename(progressInfoFile);
|
||||||
|
getRequestGroup()->initPieceStorage();
|
||||||
|
|
||||||
|
if(getOption()->getAsBool(PREF_DRY_RUN)) {
|
||||||
|
onDryRunFileFound();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto checkIntegrityEntry = getRequestGroup()->createCheckIntegrityEntry();
|
||||||
|
if(!checkIntegrityEntry) {
|
||||||
|
sequence_ = SEQ_DOWNLOAD_ALREADY_COMPLETED;
|
||||||
|
poolConnection();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
checkIntegrityEntry->pushNextCommand(std::unique_ptr<Command>(this));
|
||||||
|
// We have to make sure that command that has Request object must
|
||||||
|
// have segment after PieceStorage is initialized. See
|
||||||
|
// AbstractCommand::execute()
|
||||||
|
getSegmentMan()->getSegmentWithIndex(getCuid(), 0);
|
||||||
|
|
||||||
|
prepareForNextAction(std::move(checkIntegrityEntry));
|
||||||
|
|
||||||
|
disableReadCheckSocket();
|
||||||
|
|
||||||
|
sequence_ = SEQ_FILE_PREPARATION;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SftpNegotiationCommand::poolConnection() const
|
||||||
|
{
|
||||||
|
if(getOption()->getAsBool(PREF_FTP_REUSE_CONNECTION)) {
|
||||||
|
// TODO we don't need options. Probably, we need to pool socket
|
||||||
|
// using scheme, port and auth info as key
|
||||||
|
getDownloadEngine()->poolSocket(getRequest(), authConfig_->getUser(),
|
||||||
|
createProxyRequest(), getSocket(), "");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SftpNegotiationCommand::onDryRunFileFound()
|
||||||
|
{
|
||||||
|
getPieceStorage()->markAllPiecesDone();
|
||||||
|
getDownloadContext()->setChecksumVerified(true);
|
||||||
|
poolConnection();
|
||||||
|
sequence_ = SEQ_HEAD_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SftpNegotiationCommand::getPath() const {
|
||||||
|
auto &req = getRequest();
|
||||||
|
auto path = req->getDir() + req->getFile();
|
||||||
|
return util::percentDecode(std::begin(path), std::end(path));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace aria2
|
|
@ -0,0 +1,87 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#ifndef D_SFTP_NEGOTIATION_COMMAND_H
|
||||||
|
#define D_SFTP_NEGOTIATION_COMMAND_H
|
||||||
|
|
||||||
|
#include "AbstractCommand.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
class SocketCore;
|
||||||
|
class AuthConfig;
|
||||||
|
|
||||||
|
class SftpNegotiationCommand : public AbstractCommand {
|
||||||
|
public:
|
||||||
|
enum Seq {
|
||||||
|
SEQ_HANDSHAKE,
|
||||||
|
SEQ_AUTH_PASSWORD,
|
||||||
|
SEQ_SFTP_OPEN,
|
||||||
|
SEQ_SFTP_STAT,
|
||||||
|
SEQ_NEGOTIATION_COMPLETED,
|
||||||
|
SEQ_DOWNLOAD_ALREADY_COMPLETED,
|
||||||
|
SEQ_HEAD_OK,
|
||||||
|
SEQ_FILE_PREPARATION,
|
||||||
|
SEQ_EXIT,
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
void onFileSizeDetermined(int64_t totalLength);
|
||||||
|
void poolConnection() const;
|
||||||
|
void onDryRunFileFound();
|
||||||
|
std::string getPath() const;
|
||||||
|
|
||||||
|
std::shared_ptr<SocketCore> socket_;
|
||||||
|
Seq sequence_;
|
||||||
|
std::unique_ptr<AuthConfig> authConfig_;
|
||||||
|
// remote file path
|
||||||
|
std::string path_;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
virtual bool executeInternal() CXX11_OVERRIDE;
|
||||||
|
|
||||||
|
public:
|
||||||
|
SftpNegotiationCommand(cuid_t cuid,
|
||||||
|
const std::shared_ptr<Request>& req,
|
||||||
|
const std::shared_ptr<FileEntry>& fileEntry,
|
||||||
|
RequestGroup* requestGroup,
|
||||||
|
DownloadEngine* e,
|
||||||
|
const std::shared_ptr<SocketCore>& s,
|
||||||
|
Seq seq = SEQ_HANDSHAKE);
|
||||||
|
virtual ~SftpNegotiationCommand();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aria2
|
||||||
|
|
||||||
|
#endif // D_SFTP_NEGOTIATION_COMMAND_H
|
|
@ -0,0 +1,66 @@
|
||||||
|
/* <!-- copyright */
|
||||||
|
/*
|
||||||
|
* aria2 - The high speed download utility
|
||||||
|
*
|
||||||
|
* Copyright (C) 2015 Tatsuhiro Tsujikawa
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation; either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||||
|
*
|
||||||
|
* In addition, as a special exception, the copyright holders give
|
||||||
|
* permission to link the code of portions of this program with the
|
||||||
|
* OpenSSL library under certain conditions as described in each
|
||||||
|
* individual source file, and distribute linked combinations
|
||||||
|
* including the two.
|
||||||
|
* You must obey the GNU General Public License in all respects
|
||||||
|
* for all of the code used other than OpenSSL. If you modify
|
||||||
|
* file(s) with this exception, you may extend this exception to your
|
||||||
|
* version of the file(s), but you are not obligated to do so. If you
|
||||||
|
* do not wish to do so, delete this exception statement from your
|
||||||
|
* version. If you delete this exception statement from all source
|
||||||
|
* files in the program, then also delete it here.
|
||||||
|
*/
|
||||||
|
/* copyright --> */
|
||||||
|
#ifndef SFTP_NEGOTIATION_CONNECT_CHAIN_H
|
||||||
|
#define SFTP_NEGOTIATION_CONNECT_CHAIN_H
|
||||||
|
|
||||||
|
#include "ControlChain.h"
|
||||||
|
#include "ConnectCommand.h"
|
||||||
|
#include "DownloadEngine.h"
|
||||||
|
#include "SftpNegotiationCommand.h"
|
||||||
|
|
||||||
|
namespace aria2 {
|
||||||
|
|
||||||
|
struct SftpNegotiationConnectChain : public ControlChain<ConnectCommand*> {
|
||||||
|
SftpNegotiationConnectChain() {}
|
||||||
|
virtual ~SftpNegotiationConnectChain() {}
|
||||||
|
virtual int run(ConnectCommand* t, DownloadEngine* e) CXX11_OVERRIDE
|
||||||
|
{
|
||||||
|
auto c = make_unique<SftpNegotiationCommand>
|
||||||
|
(t->getCuid(),
|
||||||
|
t->getRequest(),
|
||||||
|
t->getFileEntry(),
|
||||||
|
t->getRequestGroup(),
|
||||||
|
t->getDownloadEngine(),
|
||||||
|
t->getSocket());
|
||||||
|
c->setStatus(Command::STATUS_ONESHOT_REALTIME);
|
||||||
|
e->setNoWait(true);
|
||||||
|
e->addCommand(std::move(c));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace aria2
|
||||||
|
|
||||||
|
#endif // SFTP_NEGOTIATION_CONNECT_CHAIN_H
|
|
@ -45,6 +45,7 @@
|
||||||
|
|
||||||
#include <cerrno>
|
#include <cerrno>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
#include <cassert>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "message.h"
|
#include "message.h"
|
||||||
|
@ -60,6 +61,9 @@
|
||||||
# include "TLSContext.h"
|
# include "TLSContext.h"
|
||||||
# include "TLSSession.h"
|
# include "TLSSession.h"
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
# include "SSHSession.h"
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
namespace aria2 {
|
namespace aria2 {
|
||||||
|
|
||||||
|
@ -608,6 +612,14 @@ void SocketCore::closeConnection()
|
||||||
tlsSession_.reset();
|
tlsSession_.reset();
|
||||||
}
|
}
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
if(sshSession_) {
|
||||||
|
sshSession_->closeConnection();
|
||||||
|
sshSession_.reset();
|
||||||
|
}
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
if(sockfd_ != (sock_t) -1) {
|
if(sockfd_ != (sock_t) -1) {
|
||||||
shutdown(sockfd_, SHUT_WR);
|
shutdown(sockfd_, SHUT_WR);
|
||||||
CLOSE(sockfd_);
|
CLOSE(sockfd_);
|
||||||
|
@ -796,7 +808,23 @@ void SocketCore::readData(void* data, size_t& len)
|
||||||
wantRead_ = false;
|
wantRead_ = false;
|
||||||
wantWrite_ = 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()
|
// Cast for Windows recv()
|
||||||
while((ret = recv(sockfd_, reinterpret_cast<char*>(data), len, 0)) == -1 &&
|
while((ret = recv(sockfd_, reinterpret_cast<char*>(data), len, 0)) == -1 &&
|
||||||
SOCKET_ERRNO == A2_EINTR);
|
SOCKET_ERRNO == A2_EINTR);
|
||||||
|
@ -957,6 +985,137 @@ bool SocketCore::tlsHandshake(TLSContext* tlsctx, const std::string& hostname)
|
||||||
|
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
|
||||||
|
bool SocketCore::sshHandshake()
|
||||||
|
{
|
||||||
|
wantRead_ = false;
|
||||||
|
wantWrite_ = false;
|
||||||
|
|
||||||
|
if (!sshSession_) {
|
||||||
|
sshSession_ = make_unique<SSHSession>();
|
||||||
|
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::sshSFTPClose()
|
||||||
|
{
|
||||||
|
assert(sshSession_);
|
||||||
|
|
||||||
|
wantRead_ = false;
|
||||||
|
wantWrite_ = false;
|
||||||
|
|
||||||
|
auto rv = sshSession_->sftpClose();
|
||||||
|
if (rv == SSH_ERR_WOULDBLOCK) {
|
||||||
|
sshCheckDirection();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rv == SSH_ERR_ERROR) {
|
||||||
|
throw DL_ABORT_EX(fmt("SSH closing SFTP failed: %s",
|
||||||
|
sshSession_->getLastErrorString().c_str()));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SocketCore::sshSFTPStat(int64_t& totalLength, time_t& mtime,
|
||||||
|
const std::string& path)
|
||||||
|
{
|
||||||
|
assert(sshSession_);
|
||||||
|
|
||||||
|
wantRead_ = false;
|
||||||
|
wantWrite_ = false;
|
||||||
|
|
||||||
|
auto rv = sshSession_->sftpStat(totalLength, mtime);
|
||||||
|
if (rv == SSH_ERR_WOULDBLOCK) {
|
||||||
|
sshCheckDirection();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (rv == SSH_ERR_ERROR) {
|
||||||
|
throw DL_ABORT_EX(fmt("SSH stat SFTP path %s filed: %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,
|
ssize_t SocketCore::writeData(const void* data, size_t len,
|
||||||
const std::string& host, uint16_t port)
|
const std::string& host, uint16_t port)
|
||||||
{
|
{
|
||||||
|
|
|
@ -55,6 +55,10 @@ class TLSContext;
|
||||||
class TLSSession;
|
class TLSSession;
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
class SSHSession;
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
class SocketCore {
|
class SocketCore {
|
||||||
friend bool operator==(const SocketCore& s1, const SocketCore& s2);
|
friend bool operator==(const SocketCore& s1, const SocketCore& s2);
|
||||||
friend bool operator!=(const SocketCore& s1, const SocketCore& s2);
|
friend bool operator!=(const SocketCore& s1, const SocketCore& s2);
|
||||||
|
@ -95,6 +99,12 @@ private:
|
||||||
bool tlsHandshake(TLSContext* tlsctx, const std::string& hostname);
|
bool tlsHandshake(TLSContext* tlsctx, const std::string& hostname);
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
std::unique_ptr<SSHSession> sshSession_;
|
||||||
|
|
||||||
|
void sshCheckDirection();
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
void init();
|
void init();
|
||||||
|
|
||||||
void bind(const struct sockaddr* addr, socklen_t addrlen);
|
void bind(const struct sockaddr* addr, socklen_t addrlen);
|
||||||
|
@ -290,6 +300,22 @@ public:
|
||||||
bool tlsConnect(const std::string& hostname);
|
bool tlsConnect(const std::string& hostname);
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
// Performs SSH handshake
|
||||||
|
bool sshHandshake();
|
||||||
|
// Performs SSH authentication using username and password.
|
||||||
|
bool sshAuthPassword(const std::string& user, const std::string& password);
|
||||||
|
// Starts sftp session and open remote file |path|.
|
||||||
|
bool sshSFTPOpen(const std::string& path);
|
||||||
|
// Closes sftp remote file gracefully
|
||||||
|
bool sshSFTPClose();
|
||||||
|
// Gets total length and modified time for remote file currently
|
||||||
|
// opened. |path| is used for logging.
|
||||||
|
bool sshSFTPStat(int64_t& totalLength, time_t& mtime,
|
||||||
|
const std::string& path);
|
||||||
|
bool sshGracefulShutdown();
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
|
|
||||||
bool operator==(const SocketCore& s) {
|
bool operator==(const SocketCore& s) {
|
||||||
return sockfd_ == s.sockfd_;
|
return sockfd_ == s.sockfd_;
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,6 +30,7 @@ void FeatureConfigTest::testGetDefaultPort() {
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)80, getDefaultPort("http"));
|
CPPUNIT_ASSERT_EQUAL((uint16_t)80, getDefaultPort("http"));
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)443, getDefaultPort("https"));
|
CPPUNIT_ASSERT_EQUAL((uint16_t)443, getDefaultPort("https"));
|
||||||
CPPUNIT_ASSERT_EQUAL((uint16_t)21, getDefaultPort("ftp"));
|
CPPUNIT_ASSERT_EQUAL((uint16_t)21, getDefaultPort("ftp"));
|
||||||
|
CPPUNIT_ASSERT_EQUAL((uint16_t)22, getDefaultPort("sftp"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeatureConfigTest::testStrSupportedFeature() {
|
void FeatureConfigTest::testStrSupportedFeature() {
|
||||||
|
@ -40,6 +41,13 @@ void FeatureConfigTest::testStrSupportedFeature() {
|
||||||
CPPUNIT_ASSERT(!https);
|
CPPUNIT_ASSERT(!https);
|
||||||
#endif // ENABLE_SSL
|
#endif // ENABLE_SSL
|
||||||
CPPUNIT_ASSERT(!strSupportedFeature(MAX_FEATURE));
|
CPPUNIT_ASSERT(!strSupportedFeature(MAX_FEATURE));
|
||||||
|
|
||||||
|
auto sftp = strSupportedFeature(FEATURE_SFTP);
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
CPPUNIT_ASSERT(sftp);
|
||||||
|
#else // !HAVE_LIBSSH2
|
||||||
|
CPPUNIT_ASSERT(!sftp);
|
||||||
|
#endif // !HAVE_LIBSSH2
|
||||||
}
|
}
|
||||||
|
|
||||||
void FeatureConfigTest::testFeatureSummary() {
|
void FeatureConfigTest::testFeatureSummary() {
|
||||||
|
@ -75,6 +83,9 @@ void FeatureConfigTest::testFeatureSummary() {
|
||||||
"XML-RPC",
|
"XML-RPC",
|
||||||
#endif // ENABLE_XML_RPC
|
#endif // ENABLE_XML_RPC
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBSSH2
|
||||||
|
"SFTP",
|
||||||
|
#endif // HAVE_LIBSSH2
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string featuresString = strjoin(std::begin(features),
|
std::string featuresString = strjoin(std::begin(features),
|
||||||
|
|
Loading…
Reference in New Issue