mirror of
https://github.com/ultimatepp/ultimatepp.git
synced 2026-08-22 06:12:32 -06:00
Core/SSH: Ssh class is refactored.
Core/SSH: Read/write methods are improved. Core/SSH: Stream operations and abort mechanism in MT are improved. Core/SSH: Minor cleanup & cosmetics. git-svn-id: svn://ultimatepp.org/upp/trunk@15484 f0d560ea-af0d-0410-9eb7-867de7ffcac7
This commit is contained in:
parent
adb097ace6
commit
fd99bb03fb
6 changed files with 131 additions and 144 deletions
|
|
@ -35,7 +35,7 @@ void SshChannel::Exit()
|
|||
LLOG("Channel succesfully freed.");
|
||||
}
|
||||
return !rc;
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
bool SshChannel::Open()
|
||||
|
|
@ -203,11 +203,11 @@ int SshChannel::Get(void *ptr, int size, int sid)
|
|||
{
|
||||
done = 0;
|
||||
Run([=]() mutable {
|
||||
while(done < size && InProgress() && !IsEof() && !IsTimeout()) {
|
||||
while(done < size && !IsEof() && !IsTimeout()) {
|
||||
int rc = Read(ptr, size, sid);
|
||||
if(rc == 0) break;
|
||||
if(rc > 0) RefreshUI();
|
||||
if(rc > 0) UpdateClient();
|
||||
if(rc < 0) return false;
|
||||
if(!rc) break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
|
@ -219,7 +219,7 @@ String SshChannel::Get(int size, int sid)
|
|||
StringBuffer sb(size);
|
||||
int len = Get(~sb, size, sid);
|
||||
sb.SetCount(len);
|
||||
return sb;
|
||||
return pick(String(sb));
|
||||
}
|
||||
|
||||
String SshChannel::GetLine(int maxlen, int sid)
|
||||
|
|
@ -243,7 +243,7 @@ String SshChannel::GetLine(int maxlen, int sid)
|
|||
done++;
|
||||
}
|
||||
}
|
||||
while(!eol && !IsEof() && !IsTimeout() && InProgress());
|
||||
while(!eol && !IsEof() && !IsTimeout());
|
||||
return eol || IsEof();
|
||||
});
|
||||
return line;
|
||||
|
|
@ -253,11 +253,11 @@ int SshChannel::Put(const void *ptr, int size, int sid)
|
|||
{
|
||||
done = 0;
|
||||
Run([=]() mutable {
|
||||
while(done < size && InProgress() && !IsEof() && !IsTimeout()) {
|
||||
while(done < size && !IsEof() && !IsTimeout()) {
|
||||
int rc = Write(ptr, size, sid);
|
||||
if(rc == 0) break;
|
||||
if(rc > 0) RefreshUI();
|
||||
if(rc > 0) UpdateClient();
|
||||
if(rc < 0) return false;
|
||||
if(!rc) break;
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
|
@ -271,9 +271,10 @@ int SshChannel::Read(void *ptr, int size, int sid)
|
|||
int rc = static_cast<int>(
|
||||
libssh2_channel_read_ex(*channel, sid, (char*) ptr + done, size_t(sz))
|
||||
);
|
||||
|
||||
if(rc < 0 && !WouldBlock(rc))
|
||||
if(rc < 0 && !WouldBlock(rc)) {
|
||||
SetError(rc);
|
||||
}
|
||||
else
|
||||
if(rc > 0) {
|
||||
done += rc;
|
||||
ssh->start_time = msecs();
|
||||
|
|
@ -296,9 +297,10 @@ int SshChannel::Write(const void *ptr, int size, int sid)
|
|||
int rc = static_cast<int>(
|
||||
libssh2_channel_write_ex(*channel, sid, (const char*) ptr + done, size_t(sz))
|
||||
);
|
||||
|
||||
if(!WouldBlock(rc) && rc < 0)
|
||||
if(rc < 0 && !WouldBlock(rc)) {
|
||||
SetError(rc);
|
||||
}
|
||||
else
|
||||
if(rc > 0) {
|
||||
done += rc;
|
||||
ssh->start_time = msecs();
|
||||
|
|
|
|||
|
|
@ -47,38 +47,32 @@ String GetName(int type, int64 id)
|
|||
|
||||
static StaticMutex sLoopLock;
|
||||
|
||||
void Ssh::Check()
|
||||
bool Ssh::Run(Gate<>&& fn, bool abortable)
|
||||
{
|
||||
auto sock = ssh->socket;
|
||||
auto Do = [=, &fn]()
|
||||
{
|
||||
Mutex::Lock __(sLoopLock);
|
||||
|
||||
if(IsTimeout())
|
||||
SetError(-1, "Operation timed out.");
|
||||
if(IsTimeout())
|
||||
SetError(-1, "Operation timed out.");
|
||||
|
||||
if(ssh->status == ABORTED)
|
||||
SetError(-1, "Operation aborted.");
|
||||
if(abortable && ssh->status == ABORTED)
|
||||
SetError(-1, "Operation aborted.");
|
||||
|
||||
if(ssh->socket && ssh->socket->IsError())
|
||||
SetError(-1, "[Socket error]: " << ssh->socket->GetErrorDesc());
|
||||
|
||||
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)
|
||||
{
|
||||
if(!ssh->init)
|
||||
ssh->init = Init();
|
||||
|
||||
return !ssh->init || ! fn();
|
||||
};
|
||||
|
||||
try {
|
||||
ssh->status = WORKING;
|
||||
ssh->start_time = msecs();
|
||||
|
||||
while(Do(fn))
|
||||
Wait();
|
||||
|
||||
while(Do()) Wait();
|
||||
|
||||
ssh->status = IDLE;
|
||||
}
|
||||
|
|
@ -88,12 +82,13 @@ bool Ssh::Run(Gate<>&& fn)
|
|||
catch(...) {
|
||||
ReportError(-1, "Unhandled exception.");
|
||||
}
|
||||
|
||||
return !IsError();
|
||||
}
|
||||
|
||||
void Ssh::Wait()
|
||||
{
|
||||
RefreshUI();
|
||||
UpdateClient();
|
||||
if(!ssh->socket || !ssh->session)
|
||||
return;
|
||||
dword q = 0, r = libssh2_session_block_directions(ssh->session);
|
||||
|
|
@ -131,8 +126,8 @@ void Ssh::ReportError(int rc, const String& reason)
|
|||
|
||||
int64 Ssh::GetNewId()
|
||||
{
|
||||
static int64 objectid;
|
||||
return objectid == INT64_MAX ? objectid = 1 : ++objectid;
|
||||
static int64 objectid = 0;
|
||||
return ++objectid;
|
||||
}
|
||||
|
||||
Ssh::Ssh()
|
||||
|
|
|
|||
|
|
@ -57,15 +57,13 @@ protected:
|
|||
virtual bool Init() { return true; }
|
||||
virtual void Exit() {}
|
||||
void Wait();
|
||||
void Check();
|
||||
bool Do(Gate<>& fn);
|
||||
bool Run(Gate<>&& fn);
|
||||
bool Run(Gate<>&& fn, bool abortable = true);
|
||||
bool WouldBlock(int rc) { return rc == LIBSSH2_ERROR_EAGAIN; }
|
||||
bool WouldBlock() { return ssh->session && WouldBlock(libssh2_session_last_errno(ssh->session)); }
|
||||
bool IsTimeout() const { return !IsNull(ssh->timeout) && ssh->timeout > 0 && msecs(ssh->start_time) >= ssh->timeout; }
|
||||
void SetError(int rc, const String& reason = Null);
|
||||
void ReportError(int rc, const String& reason);
|
||||
void RefreshUI() { WhenWait ? WhenWait() : ssh->whenwait(); }
|
||||
void UpdateClient() { WhenWait ? WhenWait() : ssh->whenwait(); }
|
||||
|
||||
private:
|
||||
static int64 GetNewId();
|
||||
|
|
|
|||
|
|
@ -31,7 +31,7 @@ void SFtp::Exit()
|
|||
sftp_session.Clear();
|
||||
LLOG("Session deinitalized.");
|
||||
return true;
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
int SFtp::FStat(SFtpHandle handle, SFtpAttrs& a, bool set)
|
||||
|
|
@ -70,7 +70,7 @@ void SFtp::Close(SFtpHandle handle)
|
|||
int rc = libssh2_sftp_close_handle(handle);
|
||||
if(!rc) LLOG("File handle freed.");
|
||||
return !rc;
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
bool SFtp::Rename(const String& oldpath, const String& newpath)
|
||||
|
|
@ -113,7 +113,7 @@ SFtp& SFtp::Seek(SFtpHandle handle, int64 position)
|
|||
{
|
||||
INTERLOCKED
|
||||
{
|
||||
LLOG("Seeking to offset: " << position);
|
||||
// LLOG("Seeking to offset: " << position);
|
||||
libssh2_sftp_seek64(handle, position);
|
||||
}
|
||||
return *this;
|
||||
|
|
@ -126,103 +126,98 @@ int64 SFtp::GetPos(SFtpHandle handle)
|
|||
INTERLOCKED
|
||||
{
|
||||
pos = libssh2_sftp_tell64(handle);
|
||||
LLOG("File position: " << pos);
|
||||
// LLOG("File position: " << pos);
|
||||
};
|
||||
return pos;
|
||||
}
|
||||
|
||||
int SFtp::Read(SFtpHandle handle, void* ptr, int size)
|
||||
{
|
||||
int sz = min(size - done, ssh->chunk_size);
|
||||
|
||||
int rc = static_cast<int>(
|
||||
libssh2_sftp_read(handle, (char*) ptr + done, size_t(sz))
|
||||
);
|
||||
|
||||
if(!WouldBlock(rc) && rc < 0)
|
||||
SetError(rc);
|
||||
if(rc > 0) {
|
||||
done += rc;
|
||||
ssh->start_time = msecs();
|
||||
RefreshUI();
|
||||
}
|
||||
if(!rc)
|
||||
LLOG("EOF received.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int SFtp::Write(SFtpHandle handle, const void* ptr, int size)
|
||||
{
|
||||
int sz = min(size - done, ssh->chunk_size);
|
||||
|
||||
int rc = static_cast<int>(
|
||||
libssh2_sftp_write(handle, (const char*) ptr + done, size_t(sz))
|
||||
);
|
||||
|
||||
if(!WouldBlock(rc) && rc < 0)
|
||||
SetError(rc);
|
||||
if(rc > 0) {
|
||||
done += rc;
|
||||
ssh->start_time = msecs();
|
||||
RefreshUI();
|
||||
}
|
||||
if(!rc)
|
||||
LLOG("EOF received.");
|
||||
return rc;
|
||||
}
|
||||
|
||||
int SFtp::Get(SFtpHandle handle, void *ptr, int size)
|
||||
{
|
||||
done = 0;
|
||||
|
||||
Run([=]() mutable {
|
||||
while(done < size && !IsTimeout() && InProgress()) {
|
||||
int rc = Read(handle, ptr, size);
|
||||
if(rc < 0) return false;
|
||||
if(!rc) break;
|
||||
while(done < size && !IsTimeout()) {
|
||||
int rc = static_cast<int>(
|
||||
libssh2_sftp_read(handle, (char*) ptr + done, min(size - done, ssh->chunk_size))
|
||||
);
|
||||
if(rc < 0) {
|
||||
if(!WouldBlock(rc))
|
||||
SetError(rc);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if(rc == 0) {
|
||||
LLOG("EOF received.");
|
||||
break;
|
||||
}
|
||||
done += rc;
|
||||
ssh->start_time = msecs();
|
||||
UpdateClient();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return GetDone();
|
||||
}
|
||||
|
||||
int SFtp::Put(SFtpHandle handle, const void *ptr, int size)
|
||||
{
|
||||
done = 0;
|
||||
|
||||
Run([=]() mutable {
|
||||
while(done < size && !IsTimeout() && InProgress()) {
|
||||
int rc = Write(handle, ptr, size);
|
||||
if(rc < 0) return false;
|
||||
if(!rc) break;
|
||||
while(done < size && !IsTimeout()) {
|
||||
int rc = static_cast<int>(
|
||||
libssh2_sftp_write(handle, (const char*) ptr + done, min(size - done, ssh->chunk_size))
|
||||
);
|
||||
if(rc < 0) {
|
||||
if(!WouldBlock(rc))
|
||||
SetError(rc);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
if(rc == 0) {
|
||||
LLOG("EOF received.");
|
||||
break;
|
||||
}
|
||||
done += rc;
|
||||
ssh->start_time = msecs();
|
||||
UpdateClient();
|
||||
}
|
||||
return true;
|
||||
});
|
||||
|
||||
return GetDone();
|
||||
}
|
||||
|
||||
bool SFtp::CopyData(Stream& dest, Stream& src, int64 maxsize)
|
||||
{
|
||||
int64 size = src.GetSize();
|
||||
String err;
|
||||
|
||||
if(IsError())
|
||||
return false;
|
||||
|
||||
if(size < 0 || size >= maxsize) {
|
||||
err = Format("Buffer overflow. size = %d (allowed size >= 0 && < %d", size, maxsize);
|
||||
goto Bailout;
|
||||
}
|
||||
LLOG("Transfer chunk size: " << ssh->chunk_size);
|
||||
if(CopyStream(dest, src, src.GetSize(), WhenProgress, ssh->chunk_size) < 0) {
|
||||
err = "File transfer is aborted.";
|
||||
goto Bailout;
|
||||
}
|
||||
return !IsError();
|
||||
|
||||
Bailout:
|
||||
src.Close();
|
||||
dest.Close();
|
||||
ReportError(-1, err);
|
||||
return false;
|
||||
int64 size = src.GetSize(), count = 0;
|
||||
Buffer<byte> chunk(ssh->chunk_size, 0);
|
||||
|
||||
WhenProgress(0, size);
|
||||
|
||||
while(!src.IsEof()) {
|
||||
int n = src.Get(chunk, (int) min<int64>(size - count, ssh->chunk_size));
|
||||
if(n > 0) {
|
||||
dest.Put(chunk, n);
|
||||
if(dest.IsError()) {
|
||||
LLOG("Stream write error. " + src.GetErrorText());
|
||||
return false;
|
||||
}
|
||||
count += n;
|
||||
if(WhenProgress(count, size)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(src.IsError()) {
|
||||
LLOG("Stream read error. " + src.GetErrorText());
|
||||
break;
|
||||
}
|
||||
}
|
||||
return !src.IsError();
|
||||
}
|
||||
|
||||
bool SFtp::SaveFile(const char *path, const String& data)
|
||||
|
|
|
|||
|
|
@ -44,21 +44,22 @@ bool Scp::Load(Stream& s, ScpAttrs a, int64 maxsize)
|
|||
int64 done_ = 0;
|
||||
int64 size = a.st_size;
|
||||
String msg;
|
||||
|
||||
|
||||
if(size < 0 || size >= maxsize) {
|
||||
msg = "Invald stream size.";
|
||||
}
|
||||
else
|
||||
while(done_ < size && !IsEof() && !IsError()) {
|
||||
int csz = (int) min<int64>(size - done_, ssh->chunk_size);
|
||||
Buffer<char> chunk(csz, 0);
|
||||
int n = Get(chunk, csz);
|
||||
if(n > 0) {
|
||||
done_ += n;
|
||||
s.Put(chunk, n);
|
||||
if((nowait = WhenProgress(done_, size))) {
|
||||
msg = "File transfer is aborted.";
|
||||
break;
|
||||
else {
|
||||
WhenProgress(0, size);
|
||||
Buffer<byte> chunk(ssh->chunk_size);
|
||||
while(done_ < size && !IsEof() && !IsError()) {
|
||||
int n = Get(chunk, (int) min<int64>(size - done_, ssh->chunk_size));
|
||||
if(n > 0) {
|
||||
done_ += n;
|
||||
s.Put(chunk, n);
|
||||
if((nowait = WhenProgress(done_, size))) {
|
||||
msg = "File transfer is aborted.";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -72,8 +73,8 @@ bool Scp::Save(Stream& s)
|
|||
int64 size = s.GetSize();
|
||||
String msg;
|
||||
|
||||
Buffer<char> chunk(ssh->chunk_size, 0);
|
||||
|
||||
WhenProgress(0, size);
|
||||
Buffer<byte> chunk(ssh->chunk_size);
|
||||
while(done_ < size && !IsEof() && !IsError()) {
|
||||
int l = s.Get(chunk, (int) min<int64>(size - done_, ssh->chunk_size));
|
||||
int n = Put(chunk, l);
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ static void ssh_keyboard_callback(const char *name, int name_len, const char *in
|
|||
int instruction_len, int num_prompts, const LIBSSH2_USERAUTH_KBDINT_PROMPT *prompts,
|
||||
LIBSSH2_USERAUTH_KBDINT_RESPONSE *responses, void **abstract)
|
||||
{
|
||||
SshSession *session = static_cast<SshSession*>(*abstract);
|
||||
SshSession *session = reinterpret_cast<SshSession*>(*abstract);
|
||||
for(auto i = 0; i < num_prompts; i++) {
|
||||
auto response = session->WhenKeyboard(
|
||||
String(name, name_len),
|
||||
|
|
@ -36,7 +36,7 @@ static void ssh_keyboard_callback(const char *name, int name_len, const char *in
|
|||
|
||||
static void ssh_password_change(LIBSSH2_SESSION *session, char **pwd, int *len, void **abstract)
|
||||
{
|
||||
String newpwd = static_cast<SshSession*>(*abstract)->WhenPasswordChange();
|
||||
String newpwd = reinterpret_cast<SshSession*>(*abstract)->WhenPasswordChange();
|
||||
#ifdef UPP_HEAP
|
||||
*pwd = (char*) ssh_malloc(newpwd.GetLength(), abstract);
|
||||
memcpy(*pwd, ~newpwd, newpwd.GetLength());
|
||||
|
|
@ -49,17 +49,17 @@ static void ssh_password_change(LIBSSH2_SESSION *session, char **pwd, int *len,
|
|||
|
||||
static void ssh_x11_request(LIBSSH2_SESSION *session, LIBSSH2_CHANNEL *channel, char *shost, int sport, void **abstract)
|
||||
{
|
||||
static_cast<SshSession*>(*abstract)->WhenX11((SshX11Handle) channel);
|
||||
reinterpret_cast<SshSession*>(*abstract)->WhenX11((SshX11Handle) channel);
|
||||
}
|
||||
|
||||
// ssh_session_libtrace: Allows full-level logging (redirection) of libsssh2 diagnostic messages.
|
||||
|
||||
#ifdef flagLIBSSH2TRACE
|
||||
static void ssh_session_libtrace(LIBSSH2_SESSION *session, void* context, const char*data, size_t length)
|
||||
static void ssh_session_libtrace(LIBSSH2_SESSION *session, void *context, const char *data, size_t length)
|
||||
{
|
||||
if(!session || !SSH::sTraceVerbose)
|
||||
return;
|
||||
auto* ssh_obj = static_cast<SshSession*>(context);
|
||||
auto* ssh_obj = reinterpret_cast<SshSession*>(context);
|
||||
RLOG(SSH::GetName(ssh_obj->GetType(), ssh_obj->GetId()) << String(data, int64(length)));
|
||||
}
|
||||
#endif
|
||||
|
|
@ -91,22 +91,18 @@ void SshSession::Exit()
|
|||
session->connected = false;
|
||||
LLOG("Session handles freed.");
|
||||
return true;
|
||||
});
|
||||
}, false);
|
||||
}
|
||||
|
||||
bool SshSession::Connect(const String& url)
|
||||
{
|
||||
UrlInfo u(url);
|
||||
|
||||
auto b = u.scheme == "ssh" ||
|
||||
u.scheme == "scp" ||
|
||||
u.scheme == "sftp" ||
|
||||
u.scheme == "exec" ||
|
||||
(u.scheme.IsEmpty() && !u.host.IsEmpty());
|
||||
auto b = findarg(u.scheme, "ssh", "sftp", "scp", "exec") >= 0 || (u.scheme.IsEmpty() && !u.host.IsEmpty());
|
||||
int port = (u.port.IsEmpty() || !b) ? 22 : StrInt(u.port);
|
||||
|
||||
return b ? Connect(u.host, port, u.username, u.password)
|
||||
: Run([=]{ SetError(-1, "Malformed secure shell URL."); return false; });
|
||||
if(b) return Connect(u.host, port, u.username, u.password);
|
||||
ReportError(-1, "Malformed secure shell URL.");
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SshSession::Connect(const String& host, int port, const String& user, const String& password)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue