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.