blob: aba830726e8f92b197e5b43540d3f271ee3a59e9 [file] [log] [blame]
/**
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef __SFTP_CLIENT_H__
#define __SFTP_CLIENT_H__
#include <curl/curl.h>
#include <libssh2.h>
#include <libssh2_sftp.h>
#include <vector>
#include <iostream>
#include <string>
#include <vector>
#include "Exception.h"
#include "utils/Enum.h"
#include "utils/HTTPClient.h"
#include "core/logging/Logger.h"
#include "core/logging/LoggerConfiguration.h"
#include "properties/Configure.h"
#include "io/validation.h"
#include "io/BaseStream.h"
namespace org {
namespace apache {
namespace nifi {
namespace minifi {
namespace utils {
SMART_ENUM(SFTPError,
(Ok, "Ok"),
(PermissionDenied, "Permission denied"),
(FileDoesNotExist, "File does not exist"),
(FileAlreadyExists, "File already exists"),
(CommunicationFailure, "Communication failure"),
(IoError, "IO error"),
(Unexpected, "Unexpected"));
class SFTPException : public Exception {
public:
explicit SFTPException(const SFTPError err)
:Exception{ExceptionType::FILE_OPERATION_EXCEPTION, fmt::format("SFTP Error: {0}", err.toString())},
error_{err}
{}
SFTPError error() const noexcept { return error_; }
private:
SFTPError error_;
};
class LastSFTPError {
public:
LastSFTPError();
LastSFTPError(const LastSFTPError&) = delete;
LastSFTPError(LastSFTPError&&) = delete;
LastSFTPError& operator=(const LastSFTPError&) = delete;
LastSFTPError& operator=(LastSFTPError&&) = delete;
LastSFTPError& setLibssh2Error(unsigned long libssh2_sftp_error);
LastSFTPError& setSftpError(const SFTPError& sftp_error);
operator unsigned long() const;
operator SFTPError() const;
private:
bool sftp_error_set_;
unsigned long libssh2_sftp_error_;
SFTPError sftp_error_;
};
class SFTPClient {
public:
SFTPClient(const std::string &hostname, uint16_t port, const std::string& username);
~SFTPClient();
SFTPClient(const SFTPClient&) = delete;
SFTPClient& operator=(const SFTPClient&) = delete;
bool setVerbose();
bool setHostKeyFile(const std::string& host_key_file_path, bool strict_host_checking);
void setPasswordAuthenticationCredentials(const std::string& password);
void setPublicKeyAuthenticationCredentials(const std::string& private_key_file_path, const std::string& private_key_passphrase);
enum class ProxyType : uint8_t {
Http,
Socks
};
bool setProxy(ProxyType type, const utils::HTTPProxy& proxy);
bool setConnectionTimeout(int64_t timeout);
void setDataTimeout(int64_t timeout);
void setSendKeepAlive(bool send_keepalive);
bool setUseCompression(bool use_compression);
bool connect();
bool sendKeepAliveIfNeeded(int &seconds_to_next);
/**
* If any function below this returns false, this function provides the last SFTP-related error.
* If a function did not fail because of an SFTP-related error, this function will return SFTP_ERROR_OK.
* If this function is called after a function returns true, the return value is UNDEFINED.
*/
SFTPError getLastError() const;
bool getFile(const std::string& path, io::BaseStream& output, int64_t expected_size = -1);
bool putFile(const std::string& path, io::BaseStream& input, bool overwrite, int64_t expected_size = -1);
bool rename(const std::string& source_path, const std::string& target_path, bool overwrite);
bool createDirectoryHierarchy(const std::string& path);
bool removeFile(const std::string& path);
bool removeDirectory(const std::string& path);
bool listDirectory(const std::string& path, bool follow_symlinks,
std::vector<std::tuple<std::string /* filename */, std::string /* longentry */, LIBSSH2_SFTP_ATTRIBUTES /* attrs */>>& children_result);
bool stat(const std::string& path, bool follow_symlinks, LIBSSH2_SFTP_ATTRIBUTES& result);
static const uint32_t SFTP_ATTRIBUTE_PERMISSIONS = 0x00000001;
static const uint32_t SFTP_ATTRIBUTE_UID = 0x00000002;
static const uint32_t SFTP_ATTRIBUTE_GID = 0x00000004;
static const uint32_t SFTP_ATTRIBUTE_MTIME = 0x00000008;
static const uint32_t SFTP_ATTRIBUTE_ATIME = 0x00000010;
struct SFTPAttributes {
uint32_t flags;
uint32_t permissions;
uint64_t uid;
uint64_t gid;
int64_t mtime;
int64_t atime;
};
bool setAttributes(const std::string& path, const SFTPAttributes& attrs);
protected:
/*
* The maximum size libssh2 is willing to read or write in one go is 30000 bytes.
* (See MAX_SFTP_OUTGOING_SIZE and MAX_SFTP_READ_SIZE).
* So we will choose that as our read-write buffer size.
*/
static constexpr size_t MAX_BUFFER_SIZE = 30000U;
std::shared_ptr<logging::Logger> logger_;
const std::string hostname_;
const uint16_t port_;
const std::string username_;
LIBSSH2_KNOWNHOSTS *ssh_known_hosts_ = nullptr;
bool strict_host_checking_ = false;
bool password_authentication_enabled_ = false;
std::string password_;
bool public_key_authentication_enabled_ = false;
std::string private_key_file_path_;
std::string private_key_passphrase_;
int64_t data_timeout_ = 0;
bool send_keepalive_ = false;
std::vector<char> curl_errorbuffer_;
CURL *easy_ = nullptr;
LIBSSH2_SESSION *ssh_session_ = nullptr;
LIBSSH2_SFTP *sftp_session_ = nullptr;
bool connected_ = false;
LastSFTPError last_error_;
};
} /* namespace utils */
} /* namespace minifi */
} /* namespace nifi */
} /* namespace apache */
} /* namespace org */
#endif