ultimatepp/uppsrc/Core/SSH/Core.cpp
oblivion 31191dc3f7 SSH: Core::Wait() is moved out of the critical section. (MT fix)
git-svn-id: svn://ultimatepp.org/upp/trunk@13617 f0d560ea-af0d-0410-9eb7-867de7ffcac7
2019-09-26 07:50:11 +00:00

173 lines
No EOL
3.1 KiB
C++

#include "SSH.h"
namespace Upp {
namespace SSH {
bool sTrace = false;
int sTraceVerbose = 0;
// SSH diagnostic utilities.
String GetName(int type, int64 id)
{
String s;
switch(type) {
case Ssh::SESSION:
s = "Session";
break;
case Ssh::SFTP:
s = "SFtp";
break;
case Ssh::CHANNEL:
s = "Channel";
break;
case Ssh::SCP:
s = "Scp";
break;
case Ssh::EXEC:
s = "Exec";
break;
case Ssh::SHELL:
s = "Shell";
break;
case Ssh::TUNNEL:
s = "Tunnel";
break;
default:
return "";
}
return pick(Format("SSH: %s, oid: %d: ", s, id));
}
}
#define LLOG(x) do { if(SSH::sTrace) RLOG(SSH::GetName(ssh->otype, ssh->oid) << x); } while(false)
#define LDUMPHEX(x) do { if(SSH::sTraceVerbose) RDUMPHEX(x); } while(false)
// Ssh: SSH objects core class.
static StaticMutex sLoopLock;
void Ssh::Check()
{
auto sock = ssh->socket;
if(IsTimeout())
SetError(-1, "Operation timed out.");
if(ssh->status == ABORTED)
SetError(-1, "Operation aborted.");
if(sock && ssh->socket->IsError())
SetError(-1, "[Socket error]: " << ssh->socket->GetErrorDesc());
}
bool Ssh::Do(Gate<>& fn)
{
Mutex::Lock __(sLoopLock);
Check();
if(!ssh->init)
ssh->init = Init();
return !ssh->init || !fn();
}
bool Ssh::Run(Gate<>&& fn)
{
try {
ssh->status = WORKING;
ssh->start_time = msecs();
while(Do(fn))
Wait();
ssh->status = IDLE;
}
catch(const Error& e) {
ReportError(e.code, e);
}
catch(...) {
ReportError(-1, "Unhandled exception.");
}
return !IsError();
}
void Ssh::Wait()
{
while(!IsTimeout()) {
RefreshUI();
if(!ssh->socket)
return;
SocketWaitEvent we;
AddTo(we);
if(we.Wait(ssh->waitstep) || ssh->noblock)
return;
}
}
dword Ssh::GetWaitEvents()
{
dword events = 0;
if(ssh->socket && ssh->session)
events = libssh2_session_block_directions(ssh->session);
return !!(events & LIBSSH2_SESSION_BLOCK_INBOUND) * WAIT_READ +
!!(events & LIBSSH2_SESSION_BLOCK_OUTBOUND) * WAIT_WRITE;
}
void Ssh::SetError(int rc, const String& reason)
{
if(IsNull(reason) && ssh && ssh->session) {
Buffer<char*> libmsg(256, 0);
rc = libssh2_session_last_error(ssh->session, libmsg, nullptr, 0);
throw Error(rc, *libmsg);
}
else
throw Error(rc, reason);
}
void Ssh::ReportError(int rc, const String& reason)
{
ssh->status = FAILED;
ssh->error.a = rc;
ssh->error.b = reason;
if(ssh->socket) {
ssh->socket->ClearAbort();
ssh->socket->ClearError();
}
LLOG("Failed. Code = " << rc << ", " << reason);
}
int64 Ssh::GetNewId()
{
static int64 objectid;
return objectid == INT64_MAX ? objectid = 1 : ++objectid;
}
Ssh::Ssh()
{
ssh.Create();
ssh->session = nullptr;
ssh->socket = nullptr;
ssh->init = false;
ssh->noblock = false;
ssh->timeout = Null;
ssh->start_time = 0;
ssh->waitstep = 10;
ssh->chunk_size = CHUNKSIZE;
ssh->status = IDLE;
ssh->oid = GetNewId();
ssh->otype = CORE;
}
Ssh::~Ssh()
{
}
INITIALIZER(SSH) {
RLOG("Initializing libssh2...");
libssh2_init(0);
}
EXITBLOCK {
RLOG("Deinitializing libssh2...");
libssh2_exit();
}
}