玉兔远程控制 0.1.0-bate8
载入中...
搜索中...
未找到
ChannelSSHTunnel.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include "libssh/libssh.h"
4#include "libssh/callbacks.h"
5
6#include "ChannelSSHTunnel.h"
7#include <QLoggingCategory>
8#include <QThread>
9
10#include <QAbstractEventDispatcher>
11#include <QScopedArrayPointer>
12#include <QtGlobal>
13#if defined(Q_OS_LINUX)
14 #include <sys/eventfd.h>
15#endif
16#if defined(Q_OS_WIN)
17 #include <WinSock2.h>
18 //#pragma comment(lib,"ws2_32.lib")
19#endif
20
21static Q_LOGGING_CATEGORY(log, "SSH.Tunnel")
22
24 CParameterSSHTunnel* parameter,
25 CParameterNet *remote,
26 CBackend *pBackend,
27 bool bWakeUp,
28 QObject *parent)
29 : CChannelSSH(pBackend, parameter, bWakeUp, parent)
30 , m_pRemoteNet(remote)
31/*
32 m_pSocketRead(nullptr),
33 m_pSocketWrite(nullptr),
34 m_pSocketException(nullptr),
35*/
36{
37 qDebug(log) << "CChannelSSHTunnel::CChannelSSHTunnel()";
38 qDebug(log) << "libssh version:" << ssh_version(0);
39}
40
41CChannelSSHTunnel::~CChannelSSHTunnel()
42{
43 qDebug(log) << "CChannelSSHTunnel::~CChannelSSHTunnel()";
44 if(m_pEvent)
45 delete m_pEvent;
46}
47
48int CChannelSSHTunnel::GetSocket()
49{
50 if(m_Session)
51 return ssh_get_fd(m_Session);
52 return SSH_INVALID_SOCKET;
53}
54
55void CChannelSSHTunnel::OnClose()
56{
57 qDebug(log) << "CChannelSSHTunnel::close()";
58
59 if(!isOpen()) return;
60
61 WakeUp();
62
63 /*
64 QAbstractEventDispatcher* pDispatcher = QAbstractEventDispatcher::instance();
65 if(m_pSocketRead) {
66 pDispatcher->unregisterSocketNotifier(m_pSocketRead);
67 m_pSocketRead->deleteLater();
68 m_pSocketRead = nullptr;
69 }
70 if(m_pSocketWrite) {
71 pDispatcher->unregisterSocketNotifier(m_pSocketWrite);
72 m_pSocketWrite->deleteLater();
73 m_pSocketWrite = nullptr;
74 }
75 if(m_pSocketException) {
76 pDispatcher->unregisterSocketNotifier(m_pSocketException);
77 m_pSocketException->deleteLater();
78 m_pSocketException = nullptr;
79 }//*/
80
81 if(m_Channel) {
82 if(ssh_channel_is_open(m_Channel)) {
83 ssh_channel_close(m_Channel);
84 }
85 ssh_channel_free(m_Channel);
86 m_Channel = NULL;
87 }
88}
89
90int CChannelSSHTunnel::OnOpen(ssh_session session)
91{
92 int nRet = 0;
93
94 Q_ASSERT(session);
95
96 m_Channel = ssh_channel_new(session);
97 if(NULL == m_Channel) {
98 qCritical(log) << "ssh_channel_new fail." << ssh_get_error(session);
99 return -1;
100 }
101
102 CParameterSSHTunnel* pPara = qobject_cast<CParameterSSHTunnel*>(m_pParameter);
103 Q_ASSERT(pPara);
104 nRet = ssh_channel_open_forward(
105 m_Channel,
106 m_pRemoteNet->GetHost().toStdString().c_str(),
107 m_pRemoteNet->GetPort(),
108 pPara->GetSourceHost().toStdString().c_str(),
109 pPara->GetSourcePort());
110 if(SSH_OK != nRet) {
111 ssh_channel_free(m_Channel);
112 m_Channel = NULL;
113
114 QString szErr;
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);
120 return nRet;
121 }
122
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());
129
130 //ssh_channel_set_blocking(m_Channel, 0);
131
132 return nRet;
133}
134
142{
143 int nRet = 0;
144
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);
150 return -1;
151 }
152
153 struct timeval timeout = {0, DEFAULT_TIMEOUT};
154 ssh_channel channels[2], channel_out[2];
155 channels[0] = m_Channel;
156 channels[1] = nullptr;
157
158 fd_set set;
159 FD_ZERO(&set);
160 socket_t fd = SSH_INVALID_SOCKET;
161 if(m_pEvent)
162 fd = m_pEvent->GetFd();
163 if(SSH_INVALID_SOCKET != fd)
164 FD_SET(fd, &set);
165
166 //qDebug(log) << "ssh_select:" << fd;
167 nRet = ssh_select(channels, channel_out, fd + 1, &set, &timeout);
168 //qDebug(log) << "ssh_select end:" << nRet;
169 if(EINTR == nRet)
170 return 0;
171
172 if(SSH_OK != nRet) {
173 QString szErr;
174 szErr = "ssh_channel_select failed: " + QString::number(nRet);
175 szErr += ssh_get_error(m_Session);
176 qCritical(log) << szErr;
177 setErrorString(szErr);
178 return -3;
179 }
180
181 if(SSH_INVALID_SOCKET != fd && FD_ISSET(fd, &set)) {
182 //qDebug(log) << "fires event";
183 if(m_pEvent) {
184 nRet = m_pEvent->Reset();
185 if(nRet) return -4;
186 }
187 }
188
189 if(!channel_out[0]) {
190 //qDebug(log) << "The channel is not select";
191 return 0;
192 }
193
194 if(ssh_channel_is_eof(m_Channel)) {
195 qWarning(log) << "Channel is eof";
196 setErrorString(tr("The channel is eof"));
197 // Stop
198 return -1;
199 }
200
201 // Get channel data length
202 nRet = ssh_channel_poll(m_Channel, 0);
203 //qDebug(log) << "Get channel data length:" << nRet;
204 if(SSH_ERROR == nRet)
205 {
206 QString szErr;
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;
212 return -6;
213 } else if(SSH_EOF == nRet) {
214 // Stop
215 return -1;
216 } else if(0 > nRet) {
217 QString szErr;
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;
223 // Error
224 return -7;
225 } else if(0 == nRet) {
226 //qDebug(log) << "The channel has not data";
227 return 0;
228 }
229
230 emit readyRead();
231
232 return 0;
233}
234
235// Because is same thread
236qint64 CChannelSSHTunnel::readData(char *data, qint64 maxlen)
237{
238 qint64 nRet = 0;
239
240 //qDebug(log) << Q_FUNC_INFO << maxlen;
241
242 Q_ASSERT(data && maxlen >= 0);
243 if(nullptr == data || 0 > maxlen) {
244 qCritical(log) << Q_FUNC_INFO << "The parameters is invalid" << maxlen;
245 return -1;
246 }
247
248 if(0 == maxlen) {
249 qCritical(log) << Q_FUNC_INFO << "maxlen:" << maxlen;
250 return 0;
251 }
252
253 if(!m_Channel || !ssh_channel_is_open(m_Channel))
254 {
255 QString szErr;
256 szErr = "The channel is not opened";
257 qCritical(log) << szErr;
258 setErrorString(szErr);
259 return -1;
260 }
261
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";
265 return 0;
266 } else if(0 > nRet) {
267 QString szErr;
268 szErr = "Read data from channel failed. nRet:";
269 szErr += QString::number(nRet);
270 szErr += ssh_get_error(m_Session);
271 qCritical(log) << szErr;
272 return nRet;
273 }
274
275 if(nRet)
276 emit sigReceive(nRet);
277
278 return nRet;
279}
280
281qint64 CChannelSSHTunnel::writeData(const char *data, qint64 len)
282{
283 qint64 nRet = 0;
284
285 Q_ASSERT(data && len >= 0);
286 if(nullptr == data || 0 > len) {
287 qCritical(log) << Q_FUNC_INFO << "The parameters is invalid" << len;
288 return -1;
289 }
290
291 if(0 == len) {
292 qCritical(log) << Q_FUNC_INFO << "len:" << len;
293 return 0;
294 }
295
296 if(!m_Channel || !ssh_channel_is_open(m_Channel) || ssh_channel_is_eof(m_Channel))
297 {
298 QString szErr;
299 szErr = "The channel is not opened";
300 qCritical(log) << szErr;
301 setErrorString(szErr);
302 return -1;
303 }
304
305 nRet = ssh_channel_write(m_Channel, data, len);
306 if(SSH_AGAIN == nRet) {
307 qDebug(log) << Q_FUNC_INFO << "ssh again write";
308 return 0;
309 } else if(nRet < 0) {
310 QString szErr;
311 szErr = "Write data from channel failed:";
312 szErr += ssh_get_error(m_Session);
313 qCritical(log) << szErr;
314 setErrorString(szErr);
315 return -2;
316 }
317
318 if(nRet)
319 emit sigSend(nRet);
320
321 return nRet;
322}
323
324int CChannelSSHTunnel::DoWait(bool bWrite, int timeout)
325{
326 int nRet = 0;
327 if(!m_Channel || !ssh_channel_is_open(m_Channel)
328 || ssh_channel_is_eof(m_Channel)) {
329 QString szErr = "The channel is not open";
330 qCritical(log) << szErr;
331 setErrorString(szErr);
332 return -1;
333 }
334
335 fd_set set;
336 FD_ZERO(&set);
337
338 struct timeval tm = {0, timeout};
339 ssh_channel channels[2], channel_out[2];
340 channels[0] = m_Channel;
341 channels[1] = nullptr;
342
343 if(bWrite) {
344 socket_t fd = SSH_INVALID_SOCKET;
345 if(m_pEvent)
346 fd = GetSocket();
347 if(SSH_INVALID_SOCKET != fd)
348 FD_SET(fd, &set);
349 nRet = select(fd + 1, nullptr, &set, nullptr, &tm);
350 if(0 > nRet) return nRet;
351 return 0;
352 }
353
354 //qDebug(log) << "ssh_select:" << fd;
355 nRet = ssh_select(channels, channel_out, 1, &set, &tm);
356 //qDebug(log) << "ssh_select end:" << nRet;
357 if(EINTR == nRet)
358 return 0;
359
360 if(SSH_OK != nRet) {
361 QString szErr;
362 szErr = "ssh_channel_select failed: " + QString::number(nRet);
363 szErr += ssh_get_error(m_Session);
364 qCritical(log) << szErr;
365 setErrorString(szErr);
366 return -3;
367 }
368
369 if(!channel_out[0]) {
370 //qDebug(log) << "The channel is not select";
371 return 0;
372 }
373
374 if(ssh_channel_is_eof(m_Channel)) {
375 qWarning(log) << "Channel is eof";
376 setErrorString(tr("The channel is eof"));
377 // Stop
378 return -1;
379 }
380
381 // Get channel data length
382 nRet = ssh_channel_poll(m_Channel, 0);
383 //qDebug(log) << "Get channel data length:" << nRet;
384 if(SSH_ERROR == nRet)
385 {
386 QString szErr;
387 szErr = "ssh_channel_poll failed. nRet:";
388 szErr += QString::number(nRet);
389 szErr += ssh_get_error(m_Session);
390 setErrorString(szErr);
391 qCritical(log) << szErr;
392 return -6;
393 } else if(SSH_EOF == nRet) {
394 // Stop
395 return -1;
396 } else if(0 > nRet) {
397 QString szErr;
398 szErr = "ssh_channel_poll failed. nRet:";
399 szErr += QString::number(nRet);
400 szErr += ssh_get_error(m_Session);
401 setErrorString(szErr);
402 qCritical(log) << szErr;
403 // Error
404 return -7;
405 } else if(0 == nRet) {
406 //qDebug(log) << "The channel has not data";
407 return 0;
408 }
409 return 0;
410}
411
412/*
413int CChannelSSHTunnel::ProcessSocket()
414{
415 int nRet = 0;
416 bool check = false;
417 socket_t fd = ssh_get_fd(m_Session);
418 m_pSocketRead = new QSocketNotifier(fd, QSocketNotifier::Read, this);
419 if(m_pSocketRead) {
420 check = connect(
421 m_pSocketRead, &QSocketNotifier::activated,
422 this, [&](int fd) {
423 qDebug(log) << "QSocketNotifier::activated: read";
424 Q_UNUSED(fd)
425 emit this->readyRead();
426 });
427 Q_ASSERT(check);
428 }
429
430 // m_pSocketWrite = new QSocketNotifier(fd, QSocketNotifier::Write, this);
431 // if(m_pSocketWrite) {
432 // check = connect(
433 // m_pSocketWrite, &QSocketNotifier::activated,
434 // this, [&](int fd){
435 // Q_UNUSED(fd)
436 // qDebug(log) << "QSocketNotifier::activated: write";
437 // });
438 // Q_ASSERT(check);
439 // }
440
441 m_pSocketException = new QSocketNotifier(fd, QSocketNotifier::Exception, this);
442 if(m_pSocketException) {
443 check = connect(
444 m_pSocketException, &QSocketNotifier::activated,
445 this, [&](int) {
446 qDebug(log) << "QSocketNotifier::activated: Exception";
447 QString szErr;
448 szErr = "Channel exception:";
449 szErr += ssh_get_error(m_Session);
450 qCritical(log) << szErr;
451 emit sigError(-1, szErr);
452 });
453 Q_ASSERT(check);
454 }
455
456 return nRet;
457}
458//*/
后端接口。它由协议插件实现。 它默认启动一个定时器来开启一个非 Qt 事件循环(就是普通的循环处理)。 详见: Start()、 slotTimeOut()、 OnProcess() 。 当然,它仍然支...
Definition Backend.h:42
void sigSend(quint64 counts)
Send data counts
void sigReceive(quint64 counts)
Receive data counts
网络连接参数接口。此类仅在插件内有效。 其界面为 CParameterNetUI