玉兔远程控制 0.1.0-bate16
载入中...
搜索中...
未找到
BackendVnc.cpp
1// Author: Kang Lin <kl222@126.com>
2
3#include "BackendVnc.h"
4#include "OperateDesktop.h"
5
6#ifndef WIN32
7#include <string.h>
8#include "network/UnixSocket.h"
9#endif
10
11#include <rfb/CMsgWriter.h>
12#include <rfb/Hostname.h>
13#include "rfb/LogWriter.h"
14#include <rfb/util.h>
15#include <rfb/clipboardTypes.h>
16#include <rfb/LogWriter.h>
17#include <rfb/Logger_stdio.h>
18#include <rfb/fenceTypes.h>
19
20#include "FramePixelBuffer.h"
21
22#include <QDir>
23#include <QMimeData>
24#include <QClipboard>
25#include <QApplication>
26#include <QLoggingCategory>
27#include <QKeyEvent>
28#include <QMouseEvent>
29#include <QNetworkProxy>
30#include <QMutex>
31#include <QInputDialog>
32
33#include "rfb/Security.h"
34#include "rfb/Exception.h"
35#ifdef HAVE_GNUTLS
36#include "rfb/CSecurityTLS.h"
37#endif
38
39#ifdef HAVE_ICE
40 #include "Ice.h"
41 #include "ChannelIce.h"
42#endif
43
44#ifdef HAVE_LIBSSH
45 #include "ChannelSSHTunnel.h"
46#endif
47
48#include "ConvertKeyCode.h"
49
50static Q_LOGGING_CATEGORY(log, "VNC.Backend")
51static Q_LOGGING_CATEGORY(logVNC, "VNC.Log")
52static Q_LOGGING_CATEGORY(logKey, "VNC.Backend.Key")
53static Q_LOGGING_CATEGORY(logInputMethod, "VNC.Backend.InputMethod")
54static Q_LOGGING_CATEGORY(logMouse, "VNC.Backend.Mouse")
55
56class VncLogger: public rfb::Logger
57{
58public:
59 VncLogger(const char *name) : rfb::Logger(name)
60 {}
61 void write(int level, const char *logname, const char *text) override
62 {
63 if (level >= rfb::LogWriter::LEVEL_DEBUG) {
64 qDebug(logVNC) << logname << text;
65 } else if (level >= rfb::LogWriter::LEVEL_INFO) {
66 qInfo(logVNC) << logname << text;
67 } else if (level >= rfb::LogWriter::LEVEL_STATUS) {
68 qWarning(logVNC) << logname << text;
69 } else {
70 qCritical(logVNC) << logname << text;
71 }
72 }
73};
74
75static VncLogger g_logger("Rabbit");
76
77// 8 colours (1 bit per component)
78static const rfb::PixelFormat verylowColourPF(8, 3,false, true, 1, 1, 1, 2, 1, 0);
79// 64 colours (2 bits per component)
80static const rfb::PixelFormat lowColourPF(8, 6, false, true, 3, 3, 3, 4, 2, 0);
81// 256 colours (2-3 bits per component)
82static const rfb::PixelFormat mediumColourPF(8, 8, false, true, 7, 7, 3, 5, 2, 0);
83
84// RGB (4 bits per component)
85static const rfb::PixelFormat fullColourPF(32, 24, false, true, 255, 255, 255, 16, 8, 0);
86
87// Time new bandwidth estimates are weighted against (in ms)
88static const unsigned bpsEstimateWindow = 1000;
89
90CBackendVnc::CBackendVnc(COperateDesktop *pOperate)
91 : CBackendDesktop(pOperate)
92 , m_pOperate(pOperate)
93 , m_pPara(nullptr)
94 , m_SecurityLevel(CSecurityLevel::Level::Risk)
95{
96 static bool initlog = false;
97 if(!initlog)
98 {
99 g_logger.registerLogger();
100 rfb::LogWriter::setLogParams("*:Rabbit:100");
101 /*rfb::initStdIOLoggers();
102 rfb::LogWriter::setLogParams("*:stderr:100");
103 QString szFile = RabbitCommon::CDir::Instance()->GetDirLog()
104 + QDir::separator()
105 + "TigerVnc.log";
106 rfb::initFileLogger(szFile.toStdString().c_str());
107 rfb::LogWriter::setLogParams("*:file:100");
108 */
109 initlog = true;
110 }
111 m_pPara = dynamic_cast<CParameterVnc*>(pOperate->GetParameter());
112 Q_ASSERT(m_pPara);
113
114 if(!m_pPara->GetLocalCursor())
115 {
116 emit sigUpdateCursor(QCursor(Qt::BlankCursor));
117 }
118}
119
120CBackendVnc::~CBackendVnc()
121{
122 qDebug(log) << "CConnectVnc::~CConnectVnc()";
123}
124
125int CBackendVnc::SetPara()
126{
127 QDir d(os::getvncconfigdir());
128 if(!d.exists())
129 d.mkpath(os::getvncconfigdir());
130 QDir dstat(os::getvncstatedir());
131 if(!dstat.exists())
132 dstat.mkpath(os::getvncstatedir());
133 QDir dvnc(os::getvncdatadir());
134 if(!dvnc.exists())
135 dvnc.mkpath(os::getvncdatadir());
136
137 setServerName(m_pPara->m_Net.GetHost().toStdString().c_str());
138 setShared(m_pPara->GetShared());
139 supportsLocalCursor = m_pPara->GetLocalCursor();
140 supportsCursorPosition = m_pPara->GetCursorPosition();
141 supportsDesktopResize = m_pPara->GetSupportsDesktopResize();
142 supportsLEDState = m_pPara->GetLedState();
143
144 std::list<uint32_t> sec;
145 switch(m_pPara->m_Net.m_User.GetUsedType()) {
146 case CParameterUser::TYPE::None:
147 sec.push_back(rfb::secTypeNone);
148 break;
149 case CParameterUser::TYPE::OnlyPassword:
150 sec.push_back(rfb::secTypeVncAuth);
151 break;
152 case CParameterUser::TYPE::UserPassword:
153 sec.push_back(rfb::secTypePlain);
154 break;
156 sec.push_back(rfb::secTypeTLSVnc);
157 break;
158 case CParameterUser::TYPE::OnlyPasswordX509:
159 sec.push_back(rfb::secTypeX509Vnc);
160 break;
161 case CParameterUser::TYPE::UserPasswordX509None:
162 sec.push_back(rfb::secTypeTLSPlain);
163 break;
164 case CParameterUser::TYPE::UserPasswordX509:
165 sec.push_back(rfb::secTypeX509Plain);
166 break;
167 //TODO: add authentication
168 }
169 //*
170 qDebug(log) << "secTypes:" << security.GetEnabledSecTypes() << security.ToString()
171 << "new:" << sec; // << "Type:" << m_pPara->m_Net.m_User.GetType();//*/
172 security.SetSecTypes(sec);
173
174 // Set Preferred Encoding
175 setPreferredEncoding(m_pPara->GetPreferredEncoding());
176 setCompressLevel(m_pPara->GetCompressLevel());
177 setQualityLevel(m_pPara->GetQualityLevel());
178
179 // Set server pixmap format
180 updatePixelFormat();
181 return 0;
182}
183
184/*
185 * \return
186 * \li OnStartReturnValue::Fail: error
187 * \li OnStartReturnValue::UseOnProcess: Use OnProcess (non-Qt event loop)
188 * \li OnStartReturnValue::NotUseOnProcess: Don't use OnProcess (qt event loop)
189 */
190CBackendVnc::OnStartReturnValue CBackendVnc::OnStart()
191{
192 qDebug(log) << "CConnectVnc::OnStart()";
193 int nRet = 0;
194
195 if(m_pPara->GetIce())
196 nRet = IceInit();
197 else {
198#ifdef HAVE_LIBSSH
199 if(m_pPara->m_Proxy.GetUsedType() == CParameterProxy::TYPE::SSHTunnel) {
200 nRet = SSHInit();
201 if(nRet) return OnStartReturnValue::Fail; // error
202 return OnStartReturnValue::UseOnProcess;
203 }
204#endif
205 nRet = SocketInit();
206 }
207 if(nRet) return OnStartReturnValue::Fail; // error
208 // Don't use OnProcess (qt event loop)
209 return OnStartReturnValue::NotUseOnProcess;
210}
211
212int CBackendVnc::IceInit()
213{
214#ifdef HAVE_ICE
215 CIceSignal* pSignal = CICE::Instance()->GetSignal().data();
216 if(!pSignal || !pSignal->IsConnected())
217 {
218 qCritical(log) << "The g_pSignal is null. or signal don't connect server";
219 return -1;
220 }
221
222 qInfo(log, "Connected to signal server:%s:%d; user:%s",
223 CICE::Instance()->GetParameter()->getSignalServer().toStdString().c_str(),
224 CICE::Instance()->GetParameter()->getSignalPort(),
225 CICE::Instance()->GetParameter()->getSignalUser().toStdString().c_str());
226 auto channel = QSharedPointer<CChannelIce>(new CChannelIce(pSignal));
227 if(!channel)
228 {
229 qCritical(log) << "new CDataChannelIce fail";
230 return -2;
231 }
232 m_DataChannel = channel;
233 SetChannelConnect(channel);
234
235 rtc::Configuration config;
236 rtc::IceServer stun(CICE::Instance()->GetParameter()->getStunServer().toStdString().c_str(),
237 CICE::Instance()->GetParameter()->getStunPort());
238 rtc::IceServer turn(CICE::Instance()->GetParameter()->getTurnServer().toStdString().c_str(),
239 CICE::Instance()->GetParameter()->getTurnPort(),
240 CICE::Instance()->GetParameter()->getTurnUser().toStdString().c_str(),
241 CICE::Instance()->GetParameter()->getTurnPassword().toStdString().c_str());
242 config.iceServers.push_back(stun);
243 config.iceServers.push_back(turn);
244 channel->SetConfigure(config);
245
246 bool bRet = channel->open(CICE::Instance()->GetParameter()->getSignalUser(),
247 m_pPara->GetPeerUser(), true);
248 if(!bRet)
249 {
250 emit sigError(-1, "Open channel fail");
251 }
252
253#endif
254 return 0;
255}
256
257int CBackendVnc::SocketInit()
258{
259 int nRet = 0;
260 try{
261 QTcpSocket* pSock = new QTcpSocket(this);
262 if(!pSock)
263 return -1;
264 m_DataChannel = QSharedPointer<CChannel>(new CChannel(pSock));
265 if(!m_DataChannel) {
266 qCritical(log) << "New CChannel fail";
267 return -1;
268 }
269
270 SetChannelConnect(m_DataChannel);
271
272 if(!m_DataChannel->open(QIODevice::ReadWrite))
273 {
274 qCritical(log) << "Open channel fail";
275 return -1;
276 }
277
278 QNetworkProxy::ProxyType type = QNetworkProxy::NoProxy;
279 // Set sock
280 switch(m_pPara->m_Proxy.GetUsedType())
281 {
282 case CParameterProxy::TYPE::SockesV5:
283 type = QNetworkProxy::Socks5Proxy;
284 break;
285 case CParameterProxy::TYPE::System:
286 type = QNetworkProxy::DefaultProxy;
287 break;
288 case CParameterProxy::TYPE::Http:
289 type = QNetworkProxy::HttpProxy;
290 break;
291 case CParameterProxy::TYPE::None:
292 default:
293 break;
294 }
295
296 switch(type) {
297 case QNetworkProxy::DefaultProxy:
298 {
299 pSock->setProxy(QNetworkProxy::applicationProxy());
300 break;
301 }
302 case QNetworkProxy::HttpProxy:
303 case QNetworkProxy::Socks5Proxy:
304 {
305 QNetworkProxy proxy;
306 auto net = &m_pPara->m_Proxy.m_SockesV5;
307 if(QNetworkProxy::HttpProxy == type) {
308 net = &m_pPara->m_Proxy.m_Http;
309 }
310 if(net->GetHost().isEmpty())
311 {
312 QString szErr;
313 szErr = tr("The proxy server is empty, please input it");
314 qCritical(log) << szErr;
315 emit sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
316 return -1;
317 }
318 proxy.setHostName(net->GetHost());
319 proxy.setPort(net->GetPort());
320 auto &user = net->m_User;
321 if(((user.GetUsedType() == CParameterUser::TYPE::UserPassword)
322 && (user.GetPassword().isEmpty() || user.GetUser().isEmpty()))
323 || ((user.GetUsedType() == CParameterUser::TYPE::PublicKey)
324 && user.GetPassphrase().isEmpty())) {
325 int nRet = QDialog::Rejected;
326 emit sigBlockShowWidget("CDlgUserPassword", nRet, net);
327 if(QDialog::Accepted != nRet)
328 {
329 return -1;
330 }
331 }
332 proxy.setUser(user.GetUser());
333 proxy.setPassword(user.GetPassword());
334 proxy.setType(type);
335 pSock->setProxy(proxy);
336 break;
337 }
338 default:
339 break;
340 }
341
342 if(m_pPara->m_Net.GetHost().isEmpty())
343 {
344 QString szErr;
345 szErr = tr("The server is empty, please input it");
346 qCritical(log) << szErr;
347 emit sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
348 return -1;
349 }
350 pSock->connectToHost(m_pPara->m_Net.GetHost(), m_pPara->m_Net.GetPort());
351
352 QString serverHost;
353 serverHost = pSock->peerName();
354 qDebug(log) << "Server Host:" << serverHost;
355 setServerName(serverHost.toStdString().c_str());
356
357 return nRet;
358 } catch (rdr::Exception& e) {
359 qCritical(log) << "SocketInit exception:" << e.str();
360 emit sigError(-1, e.str());
361 nRet = -1;
362 }
363 return nRet;
364}
365
366int CBackendVnc::SSHInit()
367{
368#ifdef HAVE_LIBSSH
369 auto channel = QSharedPointer<CChannelSSHTunnel>(
370 new CChannelSSHTunnel(&m_pPara->m_Proxy.m_SSH, &m_pPara->m_Net, this));
371 if(!channel) {
372 qCritical(log) << "New CChannelSSHTunnel fail";
373 return -1;
374 }
375 m_DataChannel = channel;
376 SetChannelConnect(m_DataChannel);
377 if(!channel->open(QIODevice::ReadWrite))
378 {
379 QString szErr;
380 szErr = tr("Failed to open SSH tunnel:");
381 szErr += "(" + m_pPara->m_Proxy.m_SSH.m_Net.GetHost();
382 szErr += ":";
383 szErr += QString::number(m_pPara->m_Proxy.m_SSH.m_Net.GetPort());
384 szErr += " - ";
385 szErr += m_pPara->m_Net.GetHost();
386 szErr += ":";
387 szErr += QString::number(m_pPara->m_Net.GetPort()) + ")";
388 QString szMsg = szErr + "\n" + channel->errorString();
389 emit sigShowMessageBox(tr("Error"), szMsg, QMessageBox::Critical);
390 return -2;
391 }
392 m_SecurityLevel = CSecurityLevel::Level::Proxy;
393#endif
394 return 0;
395}
396
397int CBackendVnc::SetChannelConnect(QSharedPointer<CChannel> channel)
398{
399 bool check = false;
400 check = connect(channel.data(), SIGNAL(sigConnected()),
401 this, SLOT(slotConnected()));
402 Q_ASSERT(check);
403 check = connect(channel.data(), SIGNAL(sigDisconnected()),
404 this, SLOT(slotDisConnected()));
405 Q_ASSERT(check);
406 check = connect(channel.data(), SIGNAL(readyRead()),
407 this, SLOT(slotReadyRead()));
408 Q_ASSERT(check);
409 check = connect(channel.data(), SIGNAL(sigError(int, const QString&)),
410 this, SLOT(slotChannelError(int, const QString&)));
411 Q_ASSERT(check);
412 if(m_pOperate && m_pOperate->GetStats()) {
413 check = connect(channel.data(), SIGNAL(sigReceive(quint64)),
414 m_pOperate->GetStats(), SLOT(AddReceives(quint64)));
415 Q_ASSERT(check);
416 check = connect(channel.data(), SIGNAL(sigSend(quint64)),
417 m_pOperate->GetStats(), SLOT(AddSends(quint64)));
418 Q_ASSERT(check);
419 }
420 return 0;
421}
422
424{
425 qDebug(log) << "CConnectVnc::OnStop()";
426 close();
427 setStreams(nullptr, nullptr);
428 if(m_DataChannel) {
429 m_DataChannel->close();
430 }
431 emit sigFinished();
432 return 0;
433}
434
449{
450 int nRet = 0;
451#ifdef HAVE_LIBSSH
452 if(m_pPara->m_Proxy.GetUsedType() == CParameterProxy::TYPE::SSHTunnel) {
453 CChannelSSHTunnel* channel = (CChannelSSHTunnel*)m_DataChannel.data();
454 if(channel)
455 nRet = channel->Process();
456 }
457#endif
458
459 return nRet;
460}
461
463{
464#ifdef HAVE_LIBSSH
465 if(m_pPara->m_Proxy.GetUsedType() == CParameterProxy::TYPE::SSHTunnel) {
466 CChannelSSHTunnel* channel = (CChannelSSHTunnel*)m_DataChannel.data();
467 if(channel)
468 channel->WakeUp();
469 }
470#endif
471 return 0;
472}
473
474void CBackendVnc::slotConnected()
475{
476 qDebug(log) << Q_FUNC_INFO;
477 if(m_pPara->GetIce())
478 qInfo(log) << "Connected to peer " + m_pPara->GetPeerUser();
479 else {
480 auto &net = m_pPara->m_Net;
481 QString szInfo = "Connected to "
482 + net.GetHost() + ":" + QString::number(net.GetPort());
483#ifdef HAVE_LIBSSH
484 if(CParameterProxy::TYPE::SSHTunnel == m_pPara->m_Proxy.GetUsedType())
485 {
486 auto &sshNet = m_pPara->m_Proxy.m_SSH.m_Net;
487 szInfo += " with ssh turnnel: " + sshNet.GetHost()
488 + ":" + QString::number(sshNet.GetPort());
489 }
490#endif
491 qInfo(log) << szInfo;
492 }
493 int nRet = SetPara();
494 if(nRet)
495 {
496 emit sigStop();
497 return;
498 }
499 m_InStream = QSharedPointer<rdr::InStream>(new CInStreamChannel(m_DataChannel.data()));
500 m_OutStream = QSharedPointer<rdr::OutStream>(new COutStreamChannel(m_DataChannel.data()));
501 if(!(m_InStream && m_OutStream))
502 {
503 qCritical(log) << "m_InStream or m_OutStream is null";
504 emit sigStop();
505 return;
506 }
507 setStreams(m_InStream.data(), m_OutStream.data());
508 initialiseProtocol();
509}
510
511void CBackendVnc::slotDisConnected()
512{
513 QString szInfo;
514 szInfo = "CConnectVnc::slotDisConnected() from "
515 + m_pPara->m_Net.GetHost() + ":"
516 + QString::number(m_pPara->m_Net.GetPort());
517#ifdef HAVE_LIBSSH
518 if(CParameterProxy::TYPE::SSHTunnel == m_pPara->m_Proxy.GetUsedType())
519 {
520 auto &net = m_pPara->m_Proxy.m_SSH.m_Net;
521 szInfo += " with ssh turnnel: " + net.GetHost()
522 + ":" + QString::number(net.GetPort());
523 }
524#endif
525 qInfo(log) << szInfo;
526}
527
528void CBackendVnc::slotReadyRead()
529{
530 //qDebug(log) << "CConnectVnc::slotReadyRead";
531 QString szErr("processMsg exception: ");
532 int nRet = -1;
533 try {
534 getOutStream()->flush();
535
536 getOutStream()->cork(true);
537 while(processMsg())
538 ;
539 getOutStream()->cork(false);
540 return;
541 } catch (rfb::AuthFailureException& e) {
542 szErr = tr("Logon to ");
543 szErr += m_pPara->m_Net.GetHost();
544 szErr += ":";
545 szErr += QString::number(m_pPara->m_Net.GetPort());
546 szErr += tr(" fail.");
547 QString szMsg = szErr + "\n" + tr("Please check that the username and password are correct.") + "\n";
548 emit sigShowMessageBox(tr("Error"), szMsg, QMessageBox::Critical);
549
550 szErr += " [";
551 szErr += e.str();
552 szErr += "]";
553 } catch (rfb::ConnFailedException& e) {
554 QString szErr;
555 szErr = tr("Connect to ");
556 szErr += m_pPara->m_Net.GetHost();
557 szErr += ":";
558 szErr += QString::number(m_pPara->m_Net.GetPort());
559 szErr += tr(" fail.");
560 szErr += " [";
561 szErr += e.str();
562 szErr += "]";
563 emit sigShowMessageBox(tr("Error"), szErr, QMessageBox::Critical);
564 } catch (rdr::EndOfStream& e) {
565 szErr += e.str();
566 } catch(rdr::GAIException &e) {
567 nRet = e.err;
568 szErr += "[" + QString::number(e.err) + "] " + e.str();
569 } catch(rdr::SystemException &e) {
570 nRet = e.err;
571 szErr += "[" + QString::number(e.err) + "] " + e.str();
572 } catch (rdr::Exception& e) {
573 szErr += e.str();
574 } catch (std::exception &e) {
575 szErr += e.what();
576 } catch(...) {
577 szErr += "unknown exception";
578 }
579 qCritical(log) << szErr;
580 emit sigError(nRet, szErr);
581 emit sigStop();
582}
583
584void CBackendVnc::slotChannelError(int nErr, const QString& szErr)
585{
586 qDebug(log) << "Channel error:" << nErr << "-" << szErr;
587 emit sigError(nErr, szErr);
588 emit sigStop();
589}
590
591// initDone() is called when the serverInit message has been received. At
592// this point we create the desktop window and display it. We also tell the
593// server the pixel format and encodings to use and request the first update.
594void CBackendVnc::initDone()
595{
596 Q_ASSERT(m_pPara);
597 qDebug(log, "initDone: %s", ConnectInformation().toStdString().c_str());
598
599 emit sigSetDesktopSize(server.width(), server.height());
600 QString szName = QString::fromUtf8(server.name());
601 emit sigServerName(szName);
602
603 //Set viewer frame buffer
604 setFramebuffer(new CFramePixelBuffer(server.width(), server.height()));
605
606 // Force a switch to the format and encoding we'd like
607 // Set Preferred Encoding
608 setPreferredEncoding(m_pPara->GetPreferredEncoding());
609 updatePixelFormat();
610
611 emit sigSecurityLevel(m_SecurityLevel);
612 emit sigRunning();
613}
614
615void CBackendVnc::resizeFramebuffer()
616{
617 rfb::ModifiablePixelBuffer* buffer = getFramebuffer();
618
619 qDebug(log) << "CConnectVnc::resizeFramebuffer: new:"
620 << server.width() << server.height()
621 << "old:" << buffer->width() << buffer->height();
622
623 if(server.width() == buffer->width() && server.height() == buffer->height())
624 return;
625
626 //Set viewer frame buffer
627 setFramebuffer(new CFramePixelBuffer(server.width(), server.height()));
628 emit sigSetDesktopSize(server.width(), server.height());
629}
630
631void CBackendVnc::setColourMapEntries(int firstColour, int nColours, uint16_t *rgbs)
632{
633 qCritical(log) << "Invalid SetColourMapEntries from server!";
634}
635
636void CBackendVnc::bell()
637{
638 qApp->beep();
639}
640
641void CBackendVnc::setLEDState(unsigned int state)
642{
643 qDebug(log) << "CConnectVnc::setLEDState" << state;
644 CConnection::setLEDState(state);
645 emit sigUpdateLedState(state);
646}
647
648void CBackendVnc::setCursor(int width, int height, const rfb::Point &hotspot, const uint8_t *data)
649{
650 //qDebug(log) << "CConnectVnc::setCursor x:" << hotspot.x << ";y:" << hotspot.y;
651 if ((width == 0) || (height == 0)) {
652 QImage cursor(1, 1, QImage::Format_ARGB32);
653 uint8_t *buffer = cursor.bits();
654 memset(buffer, 0, 4);
655 emit sigUpdateCursor(QCursor(QPixmap::fromImage(cursor), hotspot.x, hotspot.y));
656 } else {
657 QImage cursor(width, height, QImage::Format_ARGB32);
658 uint8_t *buffer = cursor.bits();
659 memcpy(buffer, data, width * height * 4);
660 emit sigUpdateCursor(QCursor(QPixmap::fromImage(cursor), hotspot.x, hotspot.y));
661 }
662}
663
664void CBackendVnc::setCursorPos(const rfb::Point &pos)
665{
666 //qDebug(log) << "CConnectVnc::setCursorPos x:" << pos.x << ";y:" << pos.y;
667 emit sigUpdateCursorPosition(QPoint(pos.x, pos.y));
668}
669
670void CBackendVnc::fence(uint32_t flags, unsigned int len, const uint8_t data[])
671{
672 //qDebug(log, "CConnectVnc::fence:flags:0x%X; len:%d", flags, len);
673 CMsgHandler::fence(flags, len, data);
674 if (!(flags & rfb::fenceFlagRequest))
675 return;
676
677 // We handle everything synchronously so we trivially honor these modes
678 flags = flags & (rfb::fenceFlagBlockBefore | rfb::fenceFlagBlockAfter);
679 writer()->writeFence(flags, len, data);
680 return;
681}
682
683void CBackendVnc::getUserPasswd(bool secure, std::string *user, std::string *password)
684{
685 if(password)
686 {
687 auto &user = m_pPara->m_Net.m_User;
688 *password = user.GetPassword().toStdString();
689 if(user.GetPassword().isEmpty())
690 {
691 int nRet = QDialog::Rejected;
692 auto *net = &m_pPara->m_Net;
693 emit sigBlockShowWidget("CDlgUserPassword", nRet, net);
694 if(QDialog::Accepted == nRet)
695 {
696 *password = user.GetPassword().toStdString();
697 }
698 }
699 if(!password->empty())
700 m_SecurityLevel |= CSecurityLevel::Level::Authentication;
701 }
702}
703
704int CBackendVnc::getX509File(std::string *ca, std::string *crl)
705{
706 auto &user = m_pPara->m_Net.m_User;
707 if(ca)
708 *ca = user.GetCAFile().toStdString().c_str();
709 if(crl)
710 *crl = user.GetCRLFile().toStdString().c_str();
711 return 0;
712}
713
714bool CBackendVnc::showMsgBox(rfb::MsgBoxFlags flags, const char *title, const char *text)
715{
716 qDebug(log) << title << text;
717 QMessageBox::StandardButton nRet = QMessageBox::No;
718 QMessageBox::StandardButtons fgBtn = QMessageBox::No;
719 bool bCheckBox = 0;
720 if((int)flags & (int)rfb::MsgBoxFlags::M_OK)
721 fgBtn |= QMessageBox::Ok;
722
723 if((int)flags & (int)rfb::MsgBoxFlags::M_OKCANCEL)
724 fgBtn |= QMessageBox::Ok | QMessageBox::Cancel;
725 if((int)flags & (int)rfb::MsgBoxFlags::M_YESNO)
726 fgBtn |= QMessageBox::Yes | QMessageBox::No;
727
728 emit sigBlockShowMessageBox(QString(title), QString(text),
729 fgBtn, nRet, bCheckBox);
730 if(QMessageBox::Ok == nRet
731 || QMessageBox::Yes == nRet)
732 return true;
733 return false;
734}
735
736// setName() is called when the desktop name changes
737void CBackendVnc::setName(const char *name)
738{
739 qDebug(log) << "CConnectVnc::setName:" << name;
740 CConnection::setName(name);
741 QString szName = QString::fromUtf8(server.name());
742 emit sigServerName(szName);
743}
744
745// framebufferUpdateStart() is called at the beginning of an update.
746// Here we try to send out a new framebuffer update request so that the
747// next update can be sent out in parallel with us decoding the current
748// one.
749void CBackendVnc::framebufferUpdateStart()
750{
751 //qDebug(log) << "CConnectVnc::framebufferUpdateStart()";
752 CConnection::framebufferUpdateStart();
753}
754
755// framebufferUpdateEnd() is called at the end of an update.
756// For each rectangle, the FdInStream will have timed the speed
757// of the connection, allowing us to select format and encoding
758// appropriately, and then request another incremental update.
759void CBackendVnc::framebufferUpdateEnd()
760{
761 //qDebug(log) << "CConnectVnc::framebufferUpdateEnd()";
762 rfb::CConnection::framebufferUpdateEnd();
763
764 if(m_pPara /*&& m_pPara->GetBufferEndRefresh()*/)
765 {
766 const QImage& img = dynamic_cast<CFramePixelBuffer*>(getFramebuffer())->getImage();
767 emit sigUpdateRect(img);
768 }
769}
770
771// requestNewUpdate() requests an update from the server, having set the
772// format and encoding appropriately.
773void CBackendVnc::updatePixelFormat()
774{
775 Q_ASSERT(m_pPara);
776
777 if(!m_pPara) return;
778 rfb::PixelFormat pf;
779
780 switch (m_pPara->GetColorLevel()) {
781 case CParameterVnc::Full:
782 pf = fullColourPF;
783 break;
784 case CParameterVnc::Medium:
785 pf = mediumColourPF;
786 break;
787 case CParameterVnc::Low:
788 pf = lowColourPF;
789 break;
790 case CParameterVnc::VeryLow:
791 pf = verylowColourPF;
792 break;
793 }
794
795 char str[256];
796 pf.print(str, 256);
797 qInfo(log) << "Update pixel format:" << str;
798 setPF(pf);
799}
800
801void CBackendVnc::mousePressEvent(QMouseEvent *event)
802{
803 if(!writer()) return;
804 if(m_pPara && m_pPara->GetOnlyView()) return;
805
806 uint8_t mask = 0;
807 if(event->button() & Qt::MouseButton::LeftButton)
808 mask |= 0x1;
809 if(event->button() & Qt::MouseButton::MiddleButton)
810 mask |= 0x2;
811 if(event->button() & Qt::MouseButton::RightButton)
812 mask |= 0x4;
813 if(event->button() & Qt::MouseButton::BackButton)
814 mask |= 0x80;
815
816 QPoint pos = event->pos();
817 rfb::Point p(pos.x(), pos.y());
818
819 //qDebug(logMouse) << Q_FUNC_INFO << event->buttons() << event->button() << pos << mask;
820
821 try{
822 writer()->writePointerEvent(p, mask);
823 } catch (rdr::Exception& e) {
824 emit sigError(-1, e.str());
825 }
826}
827
828void CBackendVnc::mouseReleaseEvent(QMouseEvent *event)
829{
830 if(!writer()) return;
831 if(m_pPara && m_pPara->GetOnlyView()) return;
832 uint8_t mask = 0;
833 QPoint pos = event->pos();
834 rfb::Point p(pos.x(), pos.y());
835 //qDebug(logMouse) << Q_FUNC_INFO << event->buttons() << event->button() << pos << mask;
836 try{
837 writer()->writePointerEvent(p, mask);
838 } catch (rdr::Exception& e) {
839 emit sigError(-1, e.str());
840 }
841}
842
843void CBackendVnc::mouseMoveEvent(QMouseEvent *event)
844{
845 if(!writer()) return;
846 if(m_pPara && m_pPara->GetOnlyView()) return;
847
848 QPoint pos = event->pos();
849 rfb::Point p(pos.x(), pos.y());
850 uint8_t mask = 0;
851 if(event->buttons() & Qt::MouseButton::LeftButton)
852 mask |= 0x1;
853 if(event->buttons() & Qt::MouseButton::MiddleButton)
854 mask |= 0x2;
855 if(event->buttons() & Qt::MouseButton::RightButton)
856 mask |= 0x4;
857 if(event->buttons() & Qt::MouseButton::BackButton)
858 mask |= 0x80;
859
860 //qDebug(logMouse) << Q_FUNC_INFO << event->buttons() << event->button() << pos << mask;
861
862 try{
863 writer()->writePointerEvent(p, mask);
864 } catch (rdr::Exception& e) {
865 emit sigError(-1, e.str());
866 }
867}
868
869// https://github.com/rfbproto/rfbproto/blob/master/rfbproto.rst#pointerevent
870void CBackendVnc::wheelEvent(QWheelEvent *event)
871{
872 if(!writer()) return;
873 if(m_pPara && m_pPara->GetOnlyView()) return;
874 uint8_t mask = 0;
875 if(event->buttons() & Qt::MouseButton::LeftButton)
876 mask |= 0x1;
877 if(event->buttons() & Qt::MouseButton::MiddleButton)
878 mask |= 0x2;
879 if(event->buttons() & Qt::MouseButton::RightButton)
880 mask |= 0x4;
881 if(event->buttons() & Qt::MouseButton::BackButton)
882 mask |= 0x80;
883
884 QPoint d = event->angleDelta();
885 if(d.y() > 0)
886 mask |= 0x8;
887 if(d.y() < 0)
888 mask |= 0x10;
889 if(d.x() < 0)
890 mask |= 0x20;
891 if(d.x() > 0)
892 mask |= 0x40;
893
894 QPointF pos;
895#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
896 pos = event->position();
897#else
898 pos = event->pos();
899#endif
900
901 rfb::Point p(pos.x(), pos.y());
902 /*
903 qDebug(logMouse) << Q_FUNC_INFO << event->buttons()
904#if QT_VERSION > QT_VERSION_CHECK(6, 0, 0)
905 << event->button()
906#endif
907 << pos << mask; //*/
908
909 try{
910 writer()->writePointerEvent(p, mask);
911 } catch (rdr::Exception& e) {
912 emit sigError(-1, e.str());
913 }
914}
915
916void CBackendVnc::keyPressEvent(QKeyEvent *event)
917{
918 if(!writer()) return;
919 if(m_pPara && m_pPara->GetOnlyView()) return;
920 bool modifier = false;
921 if (event->modifiers() & Qt::ShiftModifier)
922 modifier = true;
923
924 uint32_t k = CConvertKeyCode::QtToRfbKey(event->key(), modifier);
925 //qDebug(logKey) << Q_FUNC_INFO << event << k << modifier;
926
927 try{
928 writer()->writeKeyEvent(k, 0, true);
929 } catch (rdr::Exception& e) {
930 emit sigError(-1, e.str());
931 }
932}
933
934void CBackendVnc::keyReleaseEvent(QKeyEvent *event)
935{
936 if(m_pPara && m_pPara->GetOnlyView()) return;
937 if(!writer()) return;
938 bool modifier = false;
939 if (event->modifiers() & Qt::ShiftModifier)
940 modifier = true;
941
942 uint32_t k = CConvertKeyCode::QtToRfbKey(event->key(), modifier);
943 //qDebug(logKey) << Q_FUNC_INFO << event << k << modifier;
944
945 try{
946 writer()->writeKeyEvent(k, 0, false);
947 } catch (rdr::Exception& e) {
948 emit sigError(-1, e.str());
949 }
950}
951
952void CBackendVnc::InputMethodEvent(QInputMethodEvent *event)
953{
954 //qDebug(logInputMethod) << Q_FUNC_INFO << event;
955 if (m_pPara && m_pPara->GetOnlyView()) return;
956 if (!writer()) return;
957
958 QString szText = event->commitString();
959 if (szText.isEmpty())
960 return;
961
962 //qDebug(logInputMethod) << Q_FUNC_INFO << szText;
963
964 QVector<uint32_t> ucs4 = szText.toUcs4();
965 foreach (uint32_t cp, ucs4) {
966 quint32 keysym = static_cast<quint32>(cp); // 直接用 Unicode code point 作为 keysym
967 try {
968 writer()->writeKeyEvent(keysym, 0, true);
969 writer()->writeKeyEvent(keysym, 0, false);
970 } catch (rdr::Exception &e) {
971 emit sigError(-1, e.str());
972 }
973 }
974}
975
976QString CBackendVnc::ConnectInformation()
977{
978 const int len = 128;
979 char buf[len];
980 QString szInfo;
981 szInfo = QString("Desktop name: ") + server.name() + "\n";
982 szInfo += QString("Size: %1 x %2").arg(server.width()).arg(server.height()) + "\n";
983
984 // TRANSLATORS: Will be filled in with a string describing the
985 // protocol pixel format in a fairly language neutral way
986 server.pf().print(buf, len);
987 szInfo += QString("Pixel format: ") + buf + "\n";
988 szInfo += QString("Requested encoding: ") + rfb::encodingName(getPreferredEncoding()) + "\n";
989 szInfo += QString("Protocol version: %1.%2").arg(server.majorVersion).arg(server.minorVersion) + "\n";
990 szInfo += QString("Security method: ") + rfb::secTypeName(csecurity->getType()) + "\n";
991 szInfo += QString("Support local cursor: %1").arg(supportsLocalCursor) + "\n";
992 szInfo += QString("Support cursor position: %1").arg(supportsCursorPosition) + "\n";
993 szInfo += QString("Support desktop resize: %1").arg(supportsDesktopResize) + "\n";
994 szInfo += QString("Support LED state: %1").arg(supportsLEDState) + "\n";
995 szInfo += QString("Led state: %1").arg(server.ledState()) + "\n";
996 szInfo += QString("Supports QEMU KeyEvent: %1").arg(server.supportsQEMUKeyEvent) + "\n";
997 szInfo += QString("Supports Set Desktop Size: %1").arg(server.supportsSetDesktopSize) + "\n";
998 szInfo += QString("Support fance: %1").arg(server.supportsFence) + "\n";
999 szInfo += QString("Support continue updates: %1").arg(server.supportsContinuousUpdates) + "\n";
1000
1001 return szInfo;
1002}
1003
1005{
1006 //qDebug(log) << "CConnectVnc::slotClipBoardChanged()";
1007 if(!m_pPara->GetClipboard() || !getOutStream() || !writer()) return;
1008 QClipboard* pClip = QApplication::clipboard();
1009 if(pClip->ownsClipboard()) return;
1010 announceClipboard(true);
1011}
1012
1013void CBackendVnc::handleClipboardRequest()
1014{
1015 //qDebug(log) << "CConnectVnc::handleClipboardRequest";
1016 if(!m_pPara->GetClipboard() || !getOutStream() || !writer()) return;
1017 const QClipboard *clipboard = QApplication::clipboard();
1018 const QMimeData *mimeData = clipboard->mimeData();
1019
1020 /*if (mimeData->hasImage()) {
1021 // setPixmap(qvariant_cast<QPixmap>(mimeData->imageData()));
1022 } else */if (mimeData->hasText()) {
1023 QString szText = mimeData->text();
1024 qDebug(log)
1025 << "CConnectVnc::handleClipboardRequest:szText:" << szText;
1026 try{
1027 sendClipboardData(szText.toStdString().c_str());
1028 } catch (rdr::Exception& e) {
1029 qCritical(log) << "sendClipboardData exception" << e.str();
1030 }
1031 } /*else if (mimeData->hasHtml()) {
1032 QString szHtml = mimeData->html();
1033 qDebug(log)
1034 << "CConnectVnc::handleClipboardRequest:html:" << szHtml;
1035 try{
1036 sendClipboardData(mimeData->html().toStdString().c_str());
1037 } catch (rdr::Exception& e) {
1038 qCritical(log) << "sendClipboardData exception" << e.str();
1039 }
1040 }*/ else {
1041 qCritical(log) << "Cannot display data";
1042 }
1043}
1044
1045void CBackendVnc::handleClipboardAnnounce(bool available)
1046{
1047 //qDebug(log) << "CConnectVnc::handleClipboardAnnounce";
1048 if(!m_pPara->GetClipboard() || !getOutStream() || !writer()) return;
1049 if(available)
1050 this->requestClipboard();
1051}
1052
1053void CBackendVnc::handleClipboardData(const char *data)
1054{
1055 //qDebug(log) << "CConnectVnc::handleClipboardData";
1056 if(!m_pPara->GetClipboard() || !getOutStream() || !writer()) return;
1057
1058 QMimeData* pData = new QMimeData();
1059 pData->setText(QString::fromUtf8(data));
1060 emit sigSetClipboard(pData);
1061}
1062
1063void CBackendVnc::authSuccess()
1064{
1065 qDebug(log) << "CConnectVnc::authSuccess";
1066}
远程桌面接口。它由协议插件实现。
void sigUpdateRect(const QRect &r, const QImage &image)
通知视图,图像更新
virtual void slotClipBoardChanged()=0
当剪切板发生改变时调用
virtual OnStartReturnValue OnStart() override
初始化
virtual int OnStop() override
清理
virtual int WakeUp() override
唤醒后台线程。
virtual int OnProcess() override
插件连接的具体操作处理。因为此插件是非Qt事件,所以在此函数中等待。
void sigStop()
需要通知用户停止时触发。仅由插件触发。 当从插件中需要停止时触发。例如:对端断开连接、重置连接或者连接出错。
void sigShowMessageBox(const QString &szTitle, const QString &szMessage, const QMessageBox::Icon &icon=QMessageBox::Information)
从后台线程中触发在主线程中显示消息对话框(QMessageBox),不阻塞后台线程
void sigError(const int nError, const QString &szError=QString())
当有错误产生时触发
void sigBlockShowMessageBox(const QString &szTitle, const QString &szMessage, QMessageBox::StandardButtons buttons, QMessageBox::StandardButton &nRet, bool &checkBox, QString checkBoxContext=QString())
阻塞后台线程,并在前台线程中显示消息对话框(QMessageBox)
void sigRunning()
当插件开始成功后触发。仅由插件触发
void sigFinished()
停止成功信号。仅由插件触发
void sigSecurityLevel(CSecurityLevel::Levels level)
当安全级别改变时触发
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
阻塞后台线程,并在前台线程中显示窗口。
CChannel(QTcpSocket *pSocket, QObject *parent=nullptr)
CChannel
static quint32 QtToRfbKey(int inkey, bool modifier)
CConvertKeyCode::QtToRfbKey
static CICE * Instance()
Single instance
定义 Ice.cpp:55
ICE 信令接口类
远程桌面操作接口
virtual CParameterDesktop * GetParameter() const
Get parameter
@ OnlyPasswordX509None
Internet X.509 Public Key Infrastructure Certificate and Certificate Revocation List (CRL) Profile
安全级别
定义 Stats.h:97