// Ресурс libssh_init/libssh_exit
struct SshInit
{
bool initialized;
SshInit(bool init_flag = false) : initialized(init_flag) {}
SshInit(SshInit &&old) noexcept { old.initialized = false; }
SshInit &operator=(SshInit &&old) noexcept { old.initialized = false; }
~SshInit()
{
if (initialized) libssh2_exit();
}
};
// Ресурс socket/close
struct Socket
{
int socket;
Socket(int s = -1) : socket(s) {}
Socket(Socket &&old) noexcept
{
socket = old.socket;
old.socket = -1;
}
Socket &operator=(Socket &&old) noexcept
{
deinit();
socket = old.socket;
old.socket = -1;
return *this;
}
~Socket() { deinit(); }
void deinit()
{
if (socket != -1)
{
#ifdef WIN32
closesocket(sock);
#else
close(socket);
#endif
}
}
};
// Ресурс libssh_session_init/libssh_session_free
struct Session
{
LIBSSH2_SESSION *session;
Session(LIBSSH2_SESSION *s) : session(s) {}
Session(Session &&old) noexcept
{
session = old.session;
old.session = nullptr;
}
Session &operator=(Session &&old) noexcept
{
deinit();
session = old.session;
old.session = nullptr;
return *this;
}
~Session() { deinit(); }
void deinit()
{
if (session)
{
libssh2_session_disconnect(session, "Normal Shutdown, Thank you for playing!");
libssh2_session_free(session);
}
}
};
sftp_error slotLoginInternal()
{
struct addrinfo hint;
struct addrinfo *addrs;
struct sockaddr_in *sin;
const char *fingerprint;
struct addrinfo *p;
int ret;
bool found;
// инициализация библиотеки
if (libssh2_init(0) != 0)
{
return sftp_error::libssh2_error
}
SshInit local_ssh(true);
// поиск адреса хоста
memset(&hint, 0, sizeof(hint));
hint.ai_flags = AI_NUMERICHOST;
hint.ai_family = AF_UNSPEC;
hint.ai_socktype = SOCK_STREAM;
hint.ai_protocol = IPPROTO_TCP;
ret = getaddrinfo(Host.toLocal8Bit().data(), NULL, &hint, &addrs);
if (ret == EAI_NONAME)
{
hint.ai_flags = 0;
ret = getaddrinfo(Host.toLocal8Bit().data(), NULL, &hint, &addrs);
}
if (ret != 0)
{
return sftp_error::resolve_error;
}
found = false;
for (p = addrs; p != nullptr; p = p->ai_next)
{
if (p->ai_family == AF_INET)
{
found = true;
sin = reinterpret_cast(p->ai_addr);
break;
}
}
if (!found)
{
return sftp_error::ip4_error;
}
// создание сокета
int socket_id = socket(AF_INET, SOCK_STREAM, 0);
if (socket_id == INVALID_SOCKET)
{
return sftp_error::socket_error;
}
Socket local_socket(socket_id);
sin->sin_family = AF_INET;
sin->sin_port = htons(Port);
// коннект
ret = ::connect(sock, (struct sockaddr *)(sin), sizeof(struct sockaddr_in));
if (ret != 0)
{
return sftp_error::connect_error;
}
// создание сессии
LIBSSH2_SESSION *session = libssh2_session_init();
if (!session)
{
return sftp_error::session_error;
}
Session local_session(session);
// установка баннера
if (libssh2_session_banner_set(session, "SSH-2.0-OpenSSH_LIBSSH2_1.9.0") != 0)
{
return sftp_error::session_error;
}
// рукопожатие
if (libssh2_session_handshake(session, sock))
{
return sftp_error::handshake_error;
}
// перевод в неблокируемый режим
libssh2_session_set_blocking(session, 0);
// получение отпечатка
fingerprint = libssh2_hostkey_hash(session, LIBSSH2_HOSTKEY_HASH_SHA1);
// авторизация
if (Auth->authType == auth_type::login)
{
while ((ret = libssh2_userauth_password(session, Auth->login.toLocal8Bit().data(),
Auth->password.toLocal8Bit().data())) ==
LIBSSH2_ERROR_EAGAIN)
;
if (ret)
{
return sftp_error::auth_error;
}
}
else
{
while ((ret = libssh2_userauth_publickey_frommemory(
session, Auth->login.toLocal8Bit().data(), Auth->login.length(),
Auth->public_array.data(), Auth->public_array.size(),
Auth->private_array.data(), Auth->private_array.size(),
Auth->password.toLocal8Bit().data())) == LIBSSH2_ERROR_EAGAIN)
;
if (ret)
{
return sftp_error::auth_error;
}
}
// инициализация ftp-сессии
do
{
sftp_session = libssh2_sftp_init(session);
if (!sftp_session)
{
if (libssh2_session_last_errno(session) == LIBSSH2_ERROR_EAGAIN)
waitsocket(sock, session);
else
{
return sftp_error::auth_error;
}
}
} while (!sftp_session);
// все четко и дерзко
sftpState = sftp_state::logged_in;
// Сохранение локальных ресурсов в переменные класса
session = std::move(local_session);
socket = std::move(local_socket);
ssh_init = std::move(local_ssh);
return sftp_error::no;
}
void mov::qt::sftp_class::slotLogin()
{
if (sftpState == sftp_state::ready && Auth->authState == auth_state : k)
{
sftpError = slotLoginInternal();
}
}