3#include "libssh/libssh.h" 
    4#include "libssh/callbacks.h" 
    6#include "ChannelSSHTunnel.h" 
    7#include <QLoggingCategory> 
   10#include <QAbstractEventDispatcher> 
   11#include <QScopedArrayPointer> 
   13#if defined(Q_OS_LINUX) 
   14    #include <sys/eventfd.h> 
   21static Q_LOGGING_CATEGORY(log, 
"SSH.Tunnel")
 
   30    , m_pRemoteNet(remote)
 
   37    qDebug(log) << 
"CChannelSSHTunnel::CChannelSSHTunnel()";
 
   38    qDebug(log) << 
"libssh version:" << ssh_version(0);
 
   41CChannelSSHTunnel::~CChannelSSHTunnel()
 
   43    qDebug(log) << 
"CChannelSSHTunnel::~CChannelSSHTunnel()";
 
   48int CChannelSSHTunnel::GetSocket()
 
   51        return ssh_get_fd(m_Session);
 
   52    return SSH_INVALID_SOCKET;
 
   55void CChannelSSHTunnel::OnClose()
 
   57    qDebug(log) << 
"CChannelSSHTunnel::close()";
 
   82        if(ssh_channel_is_open(m_Channel)) {
 
   83            ssh_channel_close(m_Channel);
 
   85        ssh_channel_free(m_Channel);
 
   90int CChannelSSHTunnel::OnOpen(ssh_session session)
 
   96    m_Channel = ssh_channel_new(session);
 
   97    if(NULL == m_Channel) {
 
   98        qCritical(log) << 
"ssh_channel_new fail." << ssh_get_error(session);
 
  104    nRet = ssh_channel_open_forward(
 
  106        m_pRemoteNet->GetHost().toStdString().c_str(),
 
  107        m_pRemoteNet->GetPort(),
 
  108        pPara->GetSourceHost().toStdString().c_str(),
 
  109        pPara->GetSourcePort());
 
  111        ssh_channel_free(m_Channel);
 
  115        szErr = tr(
"SSH failed: open forward.") + ssh_get_error(session);
 
  116        szErr += 
"(" + m_pRemoteNet->GetHost()
 
  117                + 
":" + QString::number(m_pRemoteNet->GetPort()) + 
")";
 
  118        qCritical(log) << szErr;
 
  119        setErrorString(szErr);
 
  123    qInfo(log) << 
"Connected:" 
  124               << m_pRemoteNet->GetHost()
 
  125                      + 
":" + QString::number(m_pRemoteNet->GetPort())
 
  126               << 
"with ssh turnnel:" 
  127               << m_pParameter->m_Net.GetHost()
 
  128                      + 
":" + QString::number(m_pParameter->m_Net.GetPort());
 
  145    if(!m_Channel || !ssh_channel_is_open(m_Channel)
 
  146        || ssh_channel_is_eof(m_Channel)) {
 
  147        QString szErr = 
"The channel is not open";
 
  148        qCritical(log) << szErr;
 
  149        setErrorString(szErr);
 
  153    struct timeval timeout = {0, DEFAULT_TIMEOUT};
 
  154    ssh_channel channels[2], channel_out[2];
 
  155    channels[0] = m_Channel;
 
  156    channels[1] = 
nullptr;
 
  160    socket_t fd = SSH_INVALID_SOCKET;
 
  162        fd = m_pEvent->GetFd();
 
  163    if(SSH_INVALID_SOCKET != fd)
 
  167    nRet = ssh_select(channels, channel_out, fd + 1, &set, &timeout);
 
  174        szErr = 
"ssh_channel_select failed: " + QString::number(nRet);
 
  175        szErr += ssh_get_error(m_Session);
 
  176        qCritical(log) << szErr;
 
  177        setErrorString(szErr);
 
  181    if(SSH_INVALID_SOCKET != fd && FD_ISSET(fd, &set)) {
 
  184            nRet = m_pEvent->Reset();
 
  189    if(!channel_out[0]) {
 
  194    if(ssh_channel_is_eof(m_Channel)) {
 
  195        qWarning(log) << 
"Channel is eof";
 
  196        setErrorString(tr(
"The channel is eof"));
 
  202    nRet = ssh_channel_poll(m_Channel, 0);
 
  204    if(SSH_ERROR == nRet)
 
  207        szErr = 
"ssh_channel_poll failed. nRet:";
 
  208        szErr += QString::number(nRet);
 
  209        szErr += ssh_get_error(m_Session);
 
  210        setErrorString(szErr);
 
  211        qCritical(log) << szErr;
 
  213    } 
else if(SSH_EOF == nRet) {
 
  216    } 
else if(0 > nRet) {
 
  218        szErr = 
"ssh_channel_poll failed. nRet:";
 
  219        szErr += QString::number(nRet);
 
  220        szErr += ssh_get_error(m_Session);
 
  221        setErrorString(szErr);
 
  222        qCritical(log) << szErr;
 
  225    } 
else if(0 == nRet) {
 
 
  236qint64 CChannelSSHTunnel::readData(
char *data, qint64 maxlen)
 
  242    Q_ASSERT(data && maxlen >= 0);
 
  243    if(
nullptr == data || 0 > maxlen) {
 
  244        qCritical(log) << Q_FUNC_INFO << 
"The parameters is invalid" << maxlen;
 
  249        qCritical(log) << Q_FUNC_INFO << 
"maxlen:" << maxlen;
 
  253    if(!m_Channel || !ssh_channel_is_open(m_Channel))
 
  256        szErr = 
"The channel is not opened";
 
  257        qCritical(log) << szErr;
 
  258        setErrorString(szErr);
 
  262    nRet = ssh_channel_read_nonblocking(m_Channel, data, maxlen, 0);
 
  263    if(SSH_AGAIN == nRet) {
 
  264        qDebug(log) << Q_FUNC_INFO << 
"ssh again read";
 
  266    } 
else if(0 > nRet) {
 
  268        szErr = 
"Read data from channel failed. nRet:";
 
  269        szErr += QString::number(nRet);
 
  270        szErr += ssh_get_error(m_Session);
 
  271        qCritical(log) << szErr;
 
  278qint64 CChannelSSHTunnel::writeData(
const char *data, qint64 len)
 
  282    Q_ASSERT(data && len >= 0);
 
  283    if(
nullptr == data || 0 > len) {
 
  284        qCritical(log) << Q_FUNC_INFO << 
"The parameters is invalid" << len;
 
  289        qCritical(log) << Q_FUNC_INFO << 
"len:" << len;
 
  293    if(!m_Channel || !ssh_channel_is_open(m_Channel) || ssh_channel_is_eof(m_Channel))
 
  296        szErr = 
"The channel is not opened";
 
  297        qCritical(log) << szErr;
 
  298        setErrorString(szErr);
 
  302    nRet = ssh_channel_write(m_Channel, data, len);
 
  303    if(SSH_AGAIN == nRet) {
 
  304        qDebug(log) << Q_FUNC_INFO << 
"ssh again write";
 
  306    } 
else if(nRet < 0) {
 
  308        szErr = 
"Write data from channel failed:";
 
  309        szErr += ssh_get_error(m_Session);
 
  310        qCritical(log) << szErr;
 
  311        setErrorString(szErr);
 
  318int CChannelSSHTunnel::DoWait(
bool bWrite, 
int timeout)
 
  321    if(!m_Channel || !ssh_channel_is_open(m_Channel)
 
  322        || ssh_channel_is_eof(m_Channel)) {
 
  323        QString szErr = 
"The channel is not open";
 
  324        qCritical(log) << szErr;
 
  325        setErrorString(szErr);
 
  332    struct timeval tm = {0, timeout};
 
  333    ssh_channel channels[2], channel_out[2];
 
  334    channels[0] = m_Channel;
 
  335    channels[1] = 
nullptr;
 
  338        socket_t fd = SSH_INVALID_SOCKET;
 
  341        if(SSH_INVALID_SOCKET != fd)
 
  343        nRet = select(fd + 1, 
nullptr, &set, 
nullptr, &tm);
 
  344        if(0 > nRet) 
return nRet;
 
  349    nRet = ssh_select(channels, channel_out, 1, &set, &tm);
 
  356        szErr = 
"ssh_channel_select failed: " + QString::number(nRet);
 
  357        szErr += ssh_get_error(m_Session);
 
  358        qCritical(log) << szErr;
 
  359        setErrorString(szErr);
 
  363    if(!channel_out[0]) {
 
  368    if(ssh_channel_is_eof(m_Channel)) {
 
  369        qWarning(log) << 
"Channel is eof";
 
  370        setErrorString(tr(
"The channel is eof"));
 
  376    nRet = ssh_channel_poll(m_Channel, 0);
 
  378    if(SSH_ERROR == nRet)
 
  381        szErr = 
"ssh_channel_poll failed. nRet:";
 
  382        szErr += QString::number(nRet);
 
  383        szErr += ssh_get_error(m_Session);
 
  384        setErrorString(szErr);
 
  385        qCritical(log) << szErr;
 
  387    } 
else if(SSH_EOF == nRet) {
 
  390    } 
else if(0 > nRet) {
 
  392        szErr = 
"ssh_channel_poll failed. nRet:";
 
  393        szErr += QString::number(nRet);
 
  394        szErr += ssh_get_error(m_Session);
 
  395        setErrorString(szErr);
 
  396        qCritical(log) << szErr;
 
  399    } 
else if(0 == nRet) {
 
Basic network parameters.