#pragma once
|
|
#include <libssh2.h>
|
#include <libssh2_sftp.h>
|
#include <string>
|
#include <iostream>
|
#include <fstream>
|
#include <functional>
|
using namespace std;
|
struct SSHServer {
|
string host;
|
int port;
|
string username;
|
string password;
|
};
|
|
class SSHUtil {
|
private:
|
static int _download_file(LIBSSH2_SESSION* session, const std::string& remote_path, const std::string& local_path, std::function<void(uint64_t transferred, uint64_t total)> progress_callback = nullptr) {
|
LIBSSH2_SFTP* sftp_session = libssh2_sftp_init(session);
|
if (!sftp_session) {
|
throw string("Failed to init SFTP session!");
|
}
|
|
// ´ò¿ªÔ¶³ÌÎļþ£¨Ö»¶Á£©
|
LIBSSH2_SFTP_HANDLE* sftp_handle = libssh2_sftp_open(sftp_session, remote_path.c_str(), LIBSSH2_FXF_READ, 0);
|
if (!sftp_handle) {
|
throw string("Failed to open remote file : ").append(remote_path);
|
libssh2_sftp_shutdown(sftp_session);
|
return -1;
|
}
|
|
// »ñÈ¡Îļþ´óС
|
LIBSSH2_SFTP_ATTRIBUTES attrs;
|
if (libssh2_sftp_fstat(sftp_handle, &attrs)) {
|
libssh2_sftp_close(sftp_handle);
|
libssh2_sftp_shutdown(sftp_session);
|
throw string("Unable to get file size");
|
}
|
const long totalSize = attrs.filesize;
|
|
// ´´½¨±¾µØÎļþ
|
std::ofstream local_file(local_path, std::ios::binary);
|
if (!local_file) {
|
libssh2_sftp_close(sftp_handle);
|
libssh2_sftp_shutdown(sftp_session);
|
throw string("Failed to create local file: ").append(local_path);
|
}
|
|
// ¶ÁȡԶ³ÌÎļþ²¢Ð´Èë±¾µØ
|
char buffer[32 * 1024];
|
long receivedSize = 0;
|
try {
|
while (true) {
|
int rc = libssh2_sftp_read(sftp_handle, buffer, sizeof(buffer));
|
|
if (rc == LIBSSH2_ERROR_EAGAIN) {
|
continue;
|
}
|
else if (rc <= 0) {
|
break; // ÏÂÔØÍê³É»ò³ö´í
|
}
|
|
// дÈë±¾µØÎļþ
|
local_file.write(buffer, rc);
|
if (!local_file) {
|
throw string("Failed to write to local file");
|
break;
|
}
|
|
// ¸üнø¶È
|
receivedSize += rc;
|
if (progress_callback) {
|
progress_callback(receivedSize, totalSize);
|
}
|
}
|
if (receivedSize != totalSize) {
|
throw string("The download file sizes are not equal");
|
}
|
}
|
catch (string msg) {
|
libssh2_sftp_close(sftp_handle);
|
libssh2_sftp_shutdown(sftp_session);
|
local_file.close();
|
throw msg;
|
}
|
|
// ¹Ø±Õ×ÊÔ´
|
libssh2_sftp_close(sftp_handle);
|
libssh2_sftp_shutdown(sftp_session);
|
local_file.close();
|
return 0;
|
}
|
|
static int _upload_file(LIBSSH2_SESSION* session, const std::string& local_path, const std::string& remote_path, std::function<void(uint64_t transferred, uint64_t total)> progress_callback = nullptr) {
|
LIBSSH2_SFTP* sftp_session = libssh2_sftp_init(session);
|
if (!sftp_session) {
|
throw string("Failed to init SFTP session!");
|
}
|
|
// ´ò¿ªÔ¶³ÌÎļþ£¨Ð´Èë + ´´½¨£©
|
LIBSSH2_SFTP_HANDLE* sftp_handle = libssh2_sftp_open(
|
sftp_session,
|
remote_path.c_str(),
|
LIBSSH2_FXF_WRITE | LIBSSH2_FXF_CREAT | LIBSSH2_FXF_TRUNC,
|
LIBSSH2_SFTP_S_IRUSR | LIBSSH2_SFTP_S_IWUSR // ȨÏÞ: Óû§¿É¶Á¿Éд
|
);
|
if (!sftp_handle) {
|
libssh2_sftp_shutdown(sftp_session);
|
throw string("Failed to open remote file:").append(remote_path);
|
}
|
|
// ´ò¿ª±¾µØÎļþ
|
std::ifstream local_file(local_path, std::ios::binary | std::ios::ate);
|
if (!local_file) {
|
libssh2_sftp_close(sftp_handle);
|
libssh2_sftp_shutdown(sftp_session);
|
throw string("Failed to open local file : ").append(local_path);
|
}
|
// »ñÈ¡×ÜÎļþ´óС
|
uint64_t file_size = local_file.tellg();
|
local_file.seekg(0, std::ios::beg);
|
|
// ¶ÁÈ¡±¾µØÎļþ²¢Ð´ÈëÔ¶³Ì
|
uint64_t transferred = 0;
|
char buffer[1024 * 32];
|
try {
|
while (!local_file.eof())
|
{
|
local_file.read(buffer, sizeof(buffer));
|
ssize_t bytes_read = local_file.gcount();
|
if (bytes_read > 0) {
|
ssize_t bytes_sent = 0;
|
while (bytes_sent < bytes_read) {
|
ssize_t rc = libssh2_sftp_write(
|
sftp_handle,
|
buffer + bytes_sent,
|
bytes_read - bytes_sent
|
);
|
|
if (rc < 0) {
|
throw string("Upload error: ").append(local_path);
|
break;
|
}
|
bytes_sent += rc;
|
transferred += rc;
|
if (progress_callback) {
|
progress_callback(transferred, file_size);
|
}
|
}
|
}
|
}
|
}
|
catch (...) {
|
libssh2_sftp_close(sftp_handle);
|
libssh2_sftp_shutdown(sftp_session);
|
local_file.close();
|
throw string("ÉÏ´«Îļþ³ö´í£¡");
|
}
|
// ¹Ø±Õ×ÊÔ´
|
libssh2_sftp_close(sftp_handle);
|
libssh2_sftp_shutdown(sftp_session);
|
local_file.close();
|
return 0;
|
}
|
|
public:
|
/**
|
* Ö´ÐÐÃüÁî
|
*/
|
static void excuteCmd(string cmd, SSHServer server) {
|
int port = server.port;
|
libssh2_init(0);
|
|
// ´´½¨socket
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
sockaddr_in sin;
|
sin.sin_family = AF_INET;
|
sin.sin_port = htons(port);
|
|
// ʹÓà inet_pton Ìæ´ú inet_addr
|
if (inet_pton(AF_INET, server.host.c_str(), &sin.sin_addr) <= 0) {
|
throw string("IPµØÖ·´íÎó£º").append(server.host);
|
}
|
|
if (connect(sock, (sockaddr*)(&sin), sizeof(sockaddr_in)) != 0) {
|
throw string("Á¬½Óʧ°Ü£º").append(server.host);
|
}
|
|
// ´´½¨SSH»á»°
|
LIBSSH2_SESSION* session = libssh2_session_init();
|
if (!session) {
|
throw string("ÎÞ·¨´´½¨SSH»á»°£º").append(server.host);
|
}
|
|
// ÎÕÊÖ
|
if (libssh2_session_handshake(session, sock)) {
|
throw string("SSHÎÕÊÖʧ°Ü£º").append(server.host);
|
}
|
|
// ÈÏÖ¤
|
if (libssh2_userauth_password(session, server.username.c_str(), server.password.c_str())) {
|
throw string("ÈÏ֤ʧ°Ü£º").append(server.host);
|
}
|
|
// Ö´ÐÐÃüÁî
|
LIBSSH2_CHANNEL* channel = libssh2_channel_open_session(session);
|
if (!channel) {
|
throw string("ÎÞ·¨´ò¿ªÍ¨µÀ£º").append(server.host);
|
}
|
|
if (libssh2_channel_exec(channel, cmd.c_str())) {
|
throw string("Ö´ÐÐÃüÁîʧ°Ü£º").append(server.host);
|
}
|
|
char buffer[1024];
|
int nbytes;
|
while ((nbytes = libssh2_channel_read(channel, buffer, sizeof(buffer))) > 0) {
|
std::cout.write(buffer, nbytes);
|
}
|
libssh2_channel_close(channel);
|
libssh2_channel_free(channel);
|
libssh2_session_disconnect(session, "Õý³£Í˳ö");
|
libssh2_session_free(session);
|
closesocket(sock);
|
}
|
/*
|
* ÏÂÔØÎļþ
|
*/
|
static void downloadFile(string remote_path,string local_path, SSHServer server, std::function<void(uint64_t transferred, uint64_t total)> progress_callback = nullptr) {
|
int port = 22;
|
libssh2_init(0);
|
|
// ´´½¨socket
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
sockaddr_in sin;
|
sin.sin_family = AF_INET;
|
sin.sin_port = htons(port);
|
|
// ʹÓà inet_pton Ìæ´ú inet_addr
|
if (inet_pton(AF_INET, server.host.c_str(), &sin.sin_addr) <= 0) {
|
throw string("IPµØÖ·´íÎó").append(server.host);
|
}
|
|
if (connect(sock, (sockaddr*)(&sin), sizeof(sockaddr_in)) != 0) {
|
throw string("Á¬½Óʧ°Ü").append(server.host);
|
}
|
|
// ´´½¨SSH»á»°
|
LIBSSH2_SESSION* session = libssh2_session_init();
|
if (!session) {
|
throw string("ÎÞ·¨´´½¨SSH»á»°").append(server.host);
|
}
|
|
// ÎÕÊÖ
|
if (libssh2_session_handshake(session, sock)) {
|
throw string("SSHÎÕÊÖʧ°Ü").append(server.host);
|
}
|
|
// ÈÏÖ¤
|
if (libssh2_userauth_password(session, server.username.c_str(), server.password.c_str())) {
|
throw string("ÈÏ֤ʧ°Ü").append(server.host);
|
}
|
_download_file(session, remote_path, local_path, progress_callback);
|
libssh2_session_disconnect(session, "Õý³£Í˳ö");
|
libssh2_session_free(session);
|
closesocket(sock);
|
}
|
|
/**
|
* ÉÏ´«Îļþ
|
*/
|
static void uploadFile(string remote_path, string local_path, SSHServer server, std::function<void(uint64_t transferred, uint64_t total)> progress_callback = nullptr) {
|
int port = 22;
|
libssh2_init(0);
|
|
// ´´½¨socket
|
int sock = socket(AF_INET, SOCK_STREAM, 0);
|
|
sockaddr_in sin;
|
sin.sin_family = AF_INET;
|
sin.sin_port = htons(port);
|
|
// ʹÓà inet_pton Ìæ´ú inet_addr
|
if (inet_pton(AF_INET, server.host.c_str(), &sin.sin_addr) <= 0) {
|
throw string("IPµØÖ·´íÎó£º").append(server.host);
|
}
|
|
if (connect(sock, (sockaddr*)(&sin), sizeof(sockaddr_in)) != 0) {
|
throw string("Á¬½Óʧ°Ü£º").append(server.host);
|
}
|
|
// ´´½¨SSH»á»°
|
LIBSSH2_SESSION* session = libssh2_session_init();
|
if (!session) {
|
throw string("ÎÞ·¨´´½¨SSH»á»°£º").append(server.host);
|
}
|
|
// ÎÕÊÖ
|
if (libssh2_session_handshake(session, sock)) {
|
throw string("SSHÎÕÊÖʧ°Ü£º").append(server.host);
|
}
|
|
// ÈÏÖ¤
|
if (libssh2_userauth_password(session, server.username.c_str(), server.password.c_str())) {
|
throw string("ÈÏ֤ʧ°Ü£º").append(server.host);
|
}
|
_upload_file(session, local_path, remote_path, progress_callback);
|
libssh2_session_disconnect(session, "Õý³£Í˳ö");
|
libssh2_session_free(session);
|
closesocket(sock);
|
}
|
|
|
|
|
|
|
|
};
|