SshBasics
Demonstrates the basic capabilities of SSH package.
SshBasics.h
#ifndef _SshBasic_SshBasic_h
#define _SshBasic_SshBasic_h
#include <Core/Core.h>
#include <Core/SSH/SSH.h>
using namespace Upp;
void SFtpGet(SshSession& session);
void SFtpStreamGet(SshSession& session);
void SFtpTransparency(SshSession& session);
void SFtpAsyncGet(SshSession& session);
void SFtpAsyncGet2(SshSession& session);
void ExecListDir(SshSession& session);
void ExecAsyncListDir(SshSession& session);
void ShellConsole(SshSession& session);
void ScpGet(SshSession& session);
void ForwardTcpIp(SshSession& session);
void X11Forwarding(SshSession& session);
void SshPick(SshSession& session);
void SshPolymorphism(SshSession& session);
void TraceVerbose();
#endif
Shell.cpp
#include "SshBasics.h"
// ShellConsole:
// Demonstrates an interactive shell in console mode.
void ShellConsole(SshSession& session)
{
SshShell shell(session);
shell.Timeout(Null);
if(!shell.Console("ansi"))
LOG(shell.GetErrorDesc());
}
main.cpp
#include "SshBasics.h"
//#define SSH_KBAUTH // Enables ssh keyboard authentication method.
#define SSH_SFTP
// Important note: The scp, X11 forwarding and tcp-ip/port forwarding (tunnel) examples will not
// work with the public ssh test server used in this reference example (test.rebex.net). In order
// to run these examples you can set up an easy-to-use ssh server (e.g. OpenSSH) on a local
// machine for testing purposes.
CONSOLE_APP_MAIN
{
StdLogSetup(LOG_COUT|LOG_FILE);
#ifdef flagLIBSSH2TRACE
VerboseLogging();
#else
// Ssh::Trace();
#endif
SshSession session;
#if defined(SSH_KBAUTH)
session.KeyboardAuth();
session.WhenKeyboard = [](String title, String instructions, String prompt)
{
// Title and insctructions are optional and might be empty.
if(!IsNull(title))
LOG(title);
if(!IsNull(instructions))
LOG(instructions);
Cout() << prompt;
return ReadSecret(); // "password"
};
#endif
if(session.Timeout(30000).Connect("demo:password@test.rebex.net:22")) {
#if defined(SSH_SFTP)
SFtpGet(session);
#elif defined(SSH_SFTP_STREAM)
SFtpStreamGet(session);
#elif defined(SSH_SFTP_TRANSPARENCY)
SFtpTransparency(session);
#elif defined(SSH_SFTP_MT)
SFtpAsyncGet(session);
#elif defined(SSH_SFTP_MT_LOOP)
SFtpAsyncGet2(session);
#elif defined(SSH_EXEC)
ExecListDir(session);
#elif defined(SSH_EXEC_MT)
ExecAsyncListDir(session);
#elif defined(SSH_SCP)
ScpGet(session);
#elif defined(SSH_SHELL)
ShellConsole(session);
#elif defined(SSH_SHELL_X11)
X11Forwarding(session);
#elif defined(SSH_TUNNEL)
ForwardTcpIp(session);
#elif defined(SSH_PICK_SEMANTICS)
SshPick(session);
#elif defined(SSH_POLYMORPHISM)
SshPolymorphism(session);
#endif
return;
}
LOG(session.GetErrorDesc());
}
Polymorphism.cpp
#include "SshBasics.h"
// SshPolymorphism:
// Demonstrates polymorphism and RTTI for Ssh objects.
void SshPolymorphism(SshSession& session)
{
constexpr const char *path = "/readme.txt";
Array<Ssh> channels;
channels.Create<Scp>(session);
channels.Create<SFtp>(session);
channels.Create<SshExec>(session);
for(Ssh& channel : channels){
if(channel.Is<Scp>()) {
LOG("\nFound: Scp object");
LOG("-----------------\n");
LOG(channel.To<Scp>().LoadFile(path));
}
else
if(channel.Is<SFtp>()) {
LOG("\nFound: Sftp object");
LOG("------------------\n");
LOG(channel.To<SFtp>().GetInfo(path).GetName());
}
else
if(channel.Is<SshExec>()) {
LOG("\nFound: Exec object");
LOG("------------------\n");
String out, err;
channel.To<SshExec>().Execute("ls -l", out, err);
LOG(out);
LOG(err);
}
if(channel.IsError()) {
LOG("Operation failed. Reason: " << channel.GetErrorDesc());
}
}
}
SFtp.cpp
#include "SshBasics.h"
// SFtpGet:
// Demonstrates a file download, using sftp.
void SFtpGet(SshSession& session)
{
const char *path = "/readme.txt";
SFtp sftp(session);
String file = sftp.LoadFile(path);
LOG((!sftp.IsError() ? file : sftp.GetErrorDesc()));
}
SFtpStream.cpp
#include "SshBasics.h"
// SFtpStreamGet:
// Demonstrates a basic stream operation on an sftp remote file object.
void SFtpStreamGet(SshSession& session)
{
const char *path = "/readme.txt";
SFtp sftp(session);
SFtpFileIn fi(sftp, path);
while(!fi.IsEof()) {
int64 pos = fi.GetPos();
String line = fi.GetLine();
if(!line.IsEmpty())
LOG(Format("Offset: %3d, Line: [%s]", pos, line));
}
if(fi.IsError())
LOG(fi.GetErrorText());
}
Exec.cpp
#include "SshBasics.h"
// ExecListDir:
// Demonstrates a remote command execution.
void ExecListDir(SshSession& session)
{
const char *cmdline = "ls -l /pub/example";
SshExec exec(session);
String cout, cerr;
int exit_code = exec(cmdline, cout, cerr);
if(!exec.IsError()) {
DUMP(exit_code);
LOG("Stdout:\n" << cout);
LOG("Stderr:\n" << cerr);
return;
}
LOG(exec.GetErrorDesc());
// Or you can use one of the helper functions instead:
// LOG("Stdout:\n" << SshExecute(session, cmdline));
}
Scp.cpp
#include "SshBasics.h"
// ScpGet:
// Demonstrates a file download using scp.
void ScpGet(SshSession& session)
{
const char *path = "the/full/path/of/the/file/to/downlad";
Scp scp(session);
String file = scp.LoadFile(path);
LOG((!scp.IsError() ? file : scp.GetErrorDesc()));
}
VerboseLogging.cpp
#include "SshBasics.h"
// TraceVerbose:
// To activate verbose logging, you need to set the LIBSSH2TRACE flag via
// TheIDE->Main Configuration settings.
void TraceVerbose()
{
Ssh::TraceVerbose(
// LIBSSH2_TRACE_SOCKET |
// LIBSSH2_TRACE_KEX |
LIBSSH2_TRACE_AUTH |
LIBSSH2_TRACE_CONN |
// LIBSSH2_TRACE_SCP |
// LIBSSH2_TRACE_SFTP |
// LIBSSH2_TRACE_PUBLICKEY |
LIBSSH2_TRACE_ERROR
);
}
SFtpMT2.cpp
#include "SshBasics.h"
// SFtpAsyncGet2: Demonstrates multiple file downloads, using a parallelization loop.
void SFtpAsyncGet2(SshSession& session)
{
const int MAXDOWNLOADS = 4;
const char *path = "/pub/example/";
SFtp::DirList ls;
{
// Get a remote dir listing.
SFtp browser(session);
if(!browser.ListDir(path, ls)) {
RLOG(browser.GetErrorDesc());
return;
}
}
// Filter the dir list.
auto files = FilterRange(ls, [](const SFtp::DirEntry& e) { return e.IsFile() && e.GetSize() <= 65536; });
// Loop over.
CoFor(min(files.GetCount(), MAXDOWNLOADS), [&files, &path, &session](int i){
const SFtp::DirEntry& e = files[i];
String fpath = AppendFileName(path, e.GetName());
RLOG("Downloading " << fpath);
SFtp sftp(session);
String file = sftp.LoadFile(fpath);
if(sftp.IsError())
RLOG(Format("Worker #%d: %s", sftp.GetId(), sftp.GetErrorDesc()));
else
RLOG("File " << e.GetName() << " is successfully downloaded.");
});
}
PickSemantics.cpp
#include "SshBasics.h"
// SshPick:
// Demonstrates the pick (move) semantics for ssh objects.
void SshPick(SshSession& session)
{
SshSession psession = pick(session); // All Ssh-based objects are pickable.
if(!session)
LOG("SshSession object is picked.");
SFtpGet(psession);
}
SFtpMT.cpp
#include "SshBasics.h"
// SFtpAsyncGet: DEmonstrates multiple file downloads, using worker threads.
AsyncWork<void> AsyncGet(SshSession& session, const String& path)
{
auto worker = Upp::Async([=, &session] {
LOG("Downloading " << path);
SFtp sftp(session);
String file = sftp.LoadFile(path);
if(sftp.IsError())
throw Ssh::Error(Format("Worker #%d: %s", sftp.GetId(), sftp.GetErrorDesc()));
LOG("File " << GetFileName(path) << " is successfully downloaded.");
});
return pick(worker);
}
void CheckError(AsyncWork<void>& w)
{
try {
w.Get();
}
catch(const Ssh::Error& e) {
LOG(e);
}
}
void SFtpAsyncGet(SshSession& session)
{
const int MAXDOWNLOADS = 4;
const char *path = "/pub/example/";
SFtp browser(session);
SFtp::DirList ls;
if(!browser.ListDir(path, ls)) { // Get a dir listing to extract file names on-the-fly.
LOG(browser.GetErrorDesc());
return;
}
Array<AsyncWork<void>> workers;
for(const auto& e : ls) {
if(!e.IsFile() || (e.GetSize() > 65535))
continue;
if(workers.GetCount() == MAXDOWNLOADS)
break;
workers.Add(AsyncGet(session, AppendFileName(path, e.GetName())));
}
while(!workers.IsEmpty()) {
for(int i = 0; i < workers.GetCount(); i++) {
auto& worker = workers[i];
if(worker.IsFinished()) {
CheckError(worker);
workers.Remove(i);
break;
}
Sleep(1);
}
}
}
ExecMT.cpp
#include "SshBasics.h"
// ExecAsyncListDir: Demonstrates remote command execution in worker threads.
AsyncWork<void> AsyncListDir(SshSession& session, const String& path)
{
auto worker = Upp::Async([=, &session] {
SshExec exec(session);
String cout, cerr;
int exit_code = exec("ls -l " + path, cout, cerr);
if(exec.IsError())
throw Ssh::Error(Format("Worker #%d: %s", exec.GetId(), exec.GetErrorDesc()));
LOG("Directory: " << path);
LOG("Exit code: " << exit_code);
LOG("Stdout:\n" << cout);
LOG("Stderr:\n" << cerr);
});
return pick(worker);
}
void GetResult(AsyncWork<void>& w)
{
try {
w.Get();
}
catch(const Ssh::Error& e) {
LOG(e);
}
}
void ExecAsyncListDir(SshSession& session)
{
const char *path1 = "/";
const char *path2 = "/pub/example/";
auto worker1 = AsyncListDir(session, path1);
auto worker2 = AsyncListDir(session, path2);
GetResult(worker2);
GetResult(worker1);
}
SFtpFileSystemInfo.cpp
#include "SshBasics.h"
// SFtpTransparency:
// Demonstrates access to sftp directory hierarcy in a file-system-agnostic (transparent) way.
void ReadDirEntries(FileSystemInfo& fsi, const String& path)
{
int maxentry = 5;
for(FileSystemInfo::FileInfo entry : fsi.Find(path, maxentry)) {
DUMP(entry.filename);
DUMP(entry.is_folder);
DUMP(entry.length);
DUMP(entry.last_access_time);
//...
}
}
void SFtpTransparency(SshSession& session)
{
LOG("Local file system objects----------------------------------------------------------");
ReadDirEntries(StdFileSystemInfo(), GetCurrentDirectory());
SFtp sftp(session);
SFtpFileSystemInfo sfsi(sftp);
LOG("Remote file system objects---------------------------------------------------------");
ReadDirEntries((FileSystemInfo&) sfsi, "/pub/example/*.png");
if(sftp.IsError())
LOG(sftp.GetErrorDesc());
}
Tunnel.cpp
#include "SshBasics.h"
// OpenTcpTunnel:
// Demonstrates tcp-ip and port forwarding feature of the ssh protocol.
// This example requires upp/reference/SocketServer and upp/reference/SocketClient examples.
// SocketClient: Set the port number to 3215.
bool ServerSendRecv(SshSession& session, String& data)
{
// SshTunnel <-> SocketServer
SshTunnel tunnel(session);
if(!tunnel.Connect("127.0.0.1", 3214)) {
LOG("ServerSendRecv(): " << tunnel.GetErrorDesc());
return false;
}
tunnel.Put(data + '\n');
data = tunnel.GetLine();
return !data.IsEmpty();
}
void ForwardTcpIp(SshSession& session)
{
SshTunnel listener(session);
if(!listener.Listen(3215, 5)) {
LOG("ForwardTcpIp(): " << listener.GetErrorDesc());
return;
}
LOG("SSH tunnel (server mode): Waiting for the requests to be tunneled...");
for(;;) {
SshTunnel tunnel(session);
if(!tunnel.Accept(listener)) {
LOG("ForwardTcpIp(): " << tunnel.GetErrorDesc());
return;
}
// SocketClient <-> SshTunnel
String data = tunnel.GetLine();
LOG("Tunneled Request: " << data);
if(!data.IsEmpty() && ServerSendRecv(session, data)) {
LOG("Tunneled Response: " << data);
tunnel.Put(data + '\n');
}
}
}
X11Shell.cpp
#include "SshBasics.h"
// X11Forwarding:
// Demonstrates an interactive shell with X11 forwarding, in console mode.
// This example requires a running X server.
void X11Forwarding(SshSession& session)
{
SshShell x11shell(session);
x11shell.Timeout(Null);
session.WhenX11 = [&x11shell](SshX11Handle xhandle)
{
x11shell.AcceptX11(xhandle);
};
if(!x11shell.ForwardX11().Console("ansi"))
LOG(x11shell.GetErrorDesc());
}
|