4#include <QNetworkProxy>
6#include <QLoggingCategory>
9#include "ConvertKeyCode.h"
10#include "BackendLibVNCServer.h"
12static Q_LOGGING_CATEGORY(log,
"LibVNCServer.Backend")
13static Q_LOGGING_CATEGORY(logger,
"LibVNCServer.Backend.log")
14static Q_LOGGING_CATEGORY(logKey,
"LibVNCServer.Backend.Key")
15static Q_LOGGING_CATEGORY(logInputMethod,
"LibVNCServer.Backend.InputMethod")
16static Q_LOGGING_CATEGORY(logMouse,
"LibVNCServer.Backend.Mouse")
18const
char* gThis =
"This pointer";
19#define LOG_BUFFER_LENGTH 1024
20static void rfbQtClientLog(
const char *format, ...)
24 char buf[LOG_BUFFER_LENGTH];
26 if(!rfbEnableClientLogging)
29 va_start(args, format);
30 nRet = vsnprintf(buf, LOG_BUFFER_LENGTH, format, args);
34 qCritical(log) <<
"vsnprintf fail";
37 if(nRet >= LOG_BUFFER_LENGTH)
39 qCritical(log) <<
"vsprintf buf is short,"
40 << nRet <<
">" << LOG_BUFFER_LENGTH
41 <<
". Truncated it:" << nRet - LOG_BUFFER_LENGTH;
42 buf[LOG_BUFFER_LENGTH - 1] = 0;
44 qDebug(logger) << buf;
56 rfbClientLog = rfbQtClientLog;
58 if(!m_pParameter->GetLocalCursor())
60 emit sigUpdateCursor(QCursor(Qt::BlankCursor));
64CBackendLibVNCServer::~CBackendLibVNCServer()
66 qDebug(log) <<
"CConnectLibVNCServer::~CConnectLibVNCServer()";
77 qDebug(log) <<
"CConnectLibVNCServer::OnStart()";
78 if(m_pClient) Q_ASSERT(
false);
80 m_pClient = rfbGetClient(8, 3, 4);
84 szErr = tr(
"Protocol version error");
86 qCritical(log) <<
"rfbGetClient fail";
87 return OnStartReturnValue::Fail;
91 m_pClient->programName = strdup(qApp->applicationName().toStdString().c_str());
92 m_pClient->appData.shareDesktop = m_pParameter->GetShared();
93 m_pClient->appData.viewOnly = m_pParameter->GetOnlyView();
94 m_pClient->appData.useRemoteCursor = m_pParameter->GetLocalCursor();
133 m_pClient->appData.enableJPEG = m_pParameter->GetJpeg();
134 if(m_pClient->appData.enableJPEG)
135 m_pClient->appData.qualityLevel = m_pParameter->GetQualityLevel();
136 if(m_pParameter->GetEnableCompressLevel())
137 m_pClient->appData.compressLevel = m_pParameter->GetCompressLevel();
140 m_pClient->MallocFrameBuffer = cb_resize;
141 m_pClient->GotFrameBufferUpdate = cb_update;
142 m_pClient->HandleKeyboardLedState = cb_kbd_leds;
143 m_pClient->Bell = cb_bell;
144 m_pClient->HandleTextChat = cb_text_chat;
145 m_pClient->GotXCutText = cb_got_selection;
146 m_pClient->GetCredential = cb_get_credential;
147 m_pClient->GetPassword = cb_get_password;
148 m_pClient->HandleCursorPos = cb_cursor_pos;
149 m_pClient->GotCursorShape = cb_got_cursor_shape;
151 m_pClient->canHandleNewFBSize = TRUE;
152 rfbClientSetClientData(m_pClient, (
void*)gThis,
this);
155 switch(m_pParameter->m_Proxy.GetUsedType())
157 case CParameterProxy::TYPE::None:
160 if(m_pParameter->m_Net.GetHost().isEmpty())
163 szErr = tr(
"The server is empty, please input it");
164 qCritical(log) << szErr;
166 return OnStartReturnValue::Fail;
168 auto &net = m_pParameter->m_Net;
169 m_pClient->serverHost = strdup(net.GetHost().toStdString().c_str());
170 m_pClient->serverPort = net.GetPort();
172 if(!rfbInitClient(m_pClient,
nullptr,
nullptr))
177 szErr = tr(
"Fail: Connect to %1:%2").arg(m_pParameter->m_Net.GetHost(),
178 QString::number(m_pParameter->m_Net.GetPort()));
179 qCritical(log) << szErr;
181 return OnStartReturnValue::Fail;
184 QString szInfo = QString(
"Connected to ") + m_pClient->desktopName;
185 qInfo(log) << szInfo;
187 emit sigSetDesktopSize(m_pClient->width, m_pClient->height);
188 emit sigServerName(m_pClient->desktopName);
192 return OnStartReturnValue::UseOnProcess;
238 case CParameterProxy::TYPE::SSHTunnel:
244 &m_pParameter->m_Proxy.m_SSH, &m_pParameter->m_Net,
this);
247 return OnStartReturnValue::Fail;
248 bool check = connect(m_pThread, SIGNAL(sigServer(QString, quint16)),
251#if defined(HAVE_UNIX_DOMAIN_SOCKET)
252 check = connect(m_pThread, SIGNAL(sigServer(QString)),
256 check = connect(m_pThread, SIGNAL(
sigError(
int,QString)),
257 this, SIGNAL(
sigError(
int,QString)));
259 check = connect(m_pThread, SIGNAL(
sigStop()),
264 return OnStartReturnValue::NotUseOnProcess;
272 return OnStartReturnValue::UseOnProcess;
277 qDebug(log) <<
"CConnectLibVNCServer::OnStop()";
281 disconnect(m_pThread);
289 rfbClientCleanup(m_pClient);
320 struct timeval timeout = {0, DEFAULT_TIMEOUT};
323 if(RFB_INVALID_SOCKET != m_pClient->sock)
325 FD_SET(m_pClient->sock, &set);
327 rfbSocket eventFd = m_Event.GetFd();
328 if(RFB_INVALID_SOCKET != eventFd)
330 FD_SET(eventFd, &set);
332 rfbSocket fd = RFB_INVALID_SOCKET;
333 fd = std::max(eventFd, m_pClient->sock);
335 nRet = select(fd + 1, &set, NULL, NULL, &timeout);
338 qCritical(log) <<
"select fail:" << nRet <<
"errno" << errno << strerror(errno);
348 if(RFB_INVALID_SOCKET != eventFd && FD_ISSET(eventFd, &set))
354 if(RFB_INVALID_SOCKET != m_pClient->sock
355 && FD_ISSET(m_pClient->sock, &set)) {
357 if(!HandleRFBServerMessage(m_pClient))
359 qCritical(log) <<
"HandleRFBServerMessage fail";
369 return m_Event.WakeUp();
374 if(!m_pParameter || !m_pParameter->GetClipboard() || !m_pClient)
return;
375 QClipboard* pClipboard = QApplication::clipboard();
378 QString szText = pClipboard->text();
379 if(!szText.isEmpty() && m_pClient)
380 SendClientCutText(m_pClient,
381 (
char*)szText.toStdString().c_str(),
382 szText.toStdString().length());
386rfbBool CBackendLibVNCServer::cb_resize(rfbClient* client)
390 if(pThis->OnSize())
return FALSE;
394void CBackendLibVNCServer::cb_update(rfbClient *client,
int x,
int y,
int w,
int h)
399 CBackendLibVNCServer* pThis = (CBackendLibVNCServer*)rfbClientGetClientData(client, (
void*)gThis);
400 QRect rect(x, y, w, h);
401 QImage img = pThis->m_Image.copy(rect);
405void CBackendLibVNCServer::cb_got_selection(rfbClient *client,
const char *text,
int len)
408 CBackendLibVNCServer* pThis = (CBackendLibVNCServer*)rfbClientGetClientData(client, (
void*)gThis);
409 if(!pThis->m_pParameter->GetClipboard())
return;
410 QClipboard* pClipboard = QApplication::clipboard();
412 pClipboard->setText(text);
415void CBackendLibVNCServer::cb_kbd_leds(rfbClient *client,
int value,
int pad)
417 qDebug(log) <<
"CConnectLibVnc::cb_kbd_leds";
420void CBackendLibVNCServer::cb_bell(
struct _rfbClient *client)
425void CBackendLibVNCServer::cb_text_chat(rfbClient *client,
int value,
char *text)
427 qDebug(log) <<
"CConnectLibVnc::cb_text_chat";
430rfbCredential* CBackendLibVNCServer::cb_get_credential(rfbClient *cl,
int credentialType)
432 qDebug(log) <<
"CConnectLibVnc::cb_get_credential";
433 CBackendLibVNCServer* pThis = (CBackendLibVNCServer*)rfbClientGetClientData(cl, (
void*)gThis);
434 rfbCredential *c = (rfbCredential*)malloc(
sizeof(rfbCredential));
435 c->userCredential.username = (
char*)malloc(RFB_BUF_SIZE);
436 memset(c->userCredential.username, 0, RFB_BUF_SIZE);
437 c->userCredential.password = (
char*)malloc(RFB_BUF_SIZE);
438 memset(c->userCredential.password, 0, RFB_BUF_SIZE);
440 if(credentialType != rfbCredentialTypeUser) {
441 qCritical(log) <<
"something else than username and password required for authentication";
445 qDebug(log) <<
"Username and password required for authentication!";
447 memcpy(c->userCredential.username,
448 pThis->m_pParameter->m_Net.
m_User.GetUser().toStdString().c_str(),
449 pThis->m_pParameter->m_Net.
m_User.GetUser().toStdString().length());
450 memcpy(c->userCredential.password,
451 pThis->m_pParameter->m_Net.
m_User.GetPassword().toStdString().c_str(),
452 pThis->m_pParameter->m_Net.
m_User.GetPassword().toStdString().length());
457char* CBackendLibVNCServer::cb_get_password(rfbClient *client)
459 CBackendLibVNCServer* pThis = (CBackendLibVNCServer*)rfbClientGetClientData(client, (
void*)gThis);
460 QString szPassword = pThis->m_pParameter->m_Net.
m_User.GetPassword();
461 if(szPassword.isEmpty())
463 int nRet = QDialog::Rejected;
464 auto *net = &pThis->m_pParameter->m_Net;
466 if(QDialog::Accepted == nRet)
468 szPassword = net->m_User.GetPassword();
471 if(!szPassword.isEmpty())
472 pThis->m_SecurityLevel |= CSecurityLevel::Level::Authentication;
473 return strdup(szPassword.toStdString().c_str());
476int CBackendLibVNCServer::OnSize()
479 int nWidth = m_pClient->width;
480 int nHeight = m_pClient->height;
482 m_Image = QImage(nWidth, nHeight, QImage::Format_RGB32);
484 m_pClient->frameBuffer = m_Image.bits();
486 m_pClient->format.bitsPerPixel = 32;
487 m_pClient->format.depth = m_Image.depth();
488 m_pClient->format.redShift = 16;
489 m_pClient->format.greenShift = 8;
490 m_pClient->format.blueShift = 0;
491 m_pClient->format.redMax = 255;
492 m_pClient->format.greenMax = 255;
493 m_pClient->format.blueMax = 255;
494 SetFormatAndEncodings(m_pClient);
496 emit sigSetDesktopSize(m_pClient->width, m_pClient->height);
500rfbBool CBackendLibVNCServer::cb_cursor_pos(rfbClient *client,
int x,
int y)
508void CBackendLibVNCServer::cb_got_cursor_shape(rfbClient *client,
510 int width,
int height,
516 if(!client->rcSource)
518 qCritical(log) <<
"client->rcSource is null";
521 CBackendLibVNCServer* pThis = (CBackendLibVNCServer*)rfbClientGetClientData(client, (
void*)gThis);
522 if ((width == 0) || (height == 0)) {
523 QImage cursor(1, 1, QImage::Format_ARGB32);
524 uchar* buffer = cursor.bits();
525 memset(buffer, 0, 4);
526 emit pThis->sigUpdateCursor(QCursor(QPixmap::fromImage(cursor), xhot, yhot));
528 switch (bytesPerPixel) {
531 QImage cursor(width, height, QImage::Format_ARGB32);
532 uchar *buffer = cursor.bits();
533 memcpy(buffer, client->rcSource, width * height * 4);
534 uchar* pMask = client->rcMask;
537 uchar* pDest = buffer;
538 for(
int y = 0; y < height; y++)
540 for(
int w = 0; w < width; w++)
546 QColor c = cursor.pixel(w, y);
548 cursor.setPixelColor(w,y,c);
551 *((uint32_t*)pDest) = 0;
557 emit pThis->sigUpdateCursor(QCursor(QPixmap::fromImage(cursor), xhot, yhot));
566void CBackendLibVNCServer::mousePressEvent(QMouseEvent *event)
568 if(!m_pClient)
return;
569 if(m_pParameter && m_pParameter->GetOnlyView())
return;
571 unsigned char mask = 0;
572 if(event->button() & Qt::MouseButton::LeftButton)
574 if(event->button() & Qt::MouseButton::MiddleButton)
576 if(event->button() & Qt::MouseButton::RightButton)
578 if(event->button() & Qt::MouseButton::BackButton)
580 QPoint pos =
event->pos();
584 SendPointerEvent(m_pClient, pos.x(), pos.y(), mask);
587void CBackendLibVNCServer::mouseReleaseEvent(QMouseEvent *event)
589 if(!m_pClient)
return;
590 if(m_pParameter && m_pParameter->GetOnlyView())
return;
592 QPoint pos =
event->pos();
594 SendPointerEvent(m_pClient, pos.x(), pos.y(), mask);
597void CBackendLibVNCServer::mouseMoveEvent(QMouseEvent *event)
599 if(!m_pClient)
return;
600 if(m_pParameter && m_pParameter->GetOnlyView())
return;
602 if(event->buttons() & Qt::MouseButton::LeftButton)
604 if(event->buttons() & Qt::MouseButton::MiddleButton)
606 if(event->buttons() & Qt::MouseButton::RightButton)
608 if(event->buttons() & Qt::MouseButton::BackButton)
610 QPoint pos =
event->pos();
612 SendPointerEvent(m_pClient, pos.x(), pos.y(), mask);
616void CBackendLibVNCServer::wheelEvent(QWheelEvent *event)
618 if(!m_pClient)
return;
619 if(m_pParameter && m_pParameter->GetOnlyView())
return;
621 if(event->buttons() & Qt::MouseButton::LeftButton)
623 if(event->buttons() & Qt::MouseButton::MiddleButton)
625 if(event->buttons() & Qt::MouseButton::RightButton)
627 if(event->buttons() & Qt::MouseButton::BackButton)
630 QPoint d =
event->angleDelta();
641#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)
642 pos =
event->position();
649 SendPointerEvent(m_pClient, pos.x(), pos.y(), mask);
652void CBackendLibVNCServer::keyPressEvent(QKeyEvent *event)
654 if(!m_pClient)
return;
655 if(m_pParameter && m_pParameter->GetOnlyView())
return;
656 bool modifier =
false;
657 if (event->modifiers() & Qt::ShiftModifier)
661 SendKeyEvent(m_pClient, k, TRUE);
664void CBackendLibVNCServer::keyReleaseEvent(QKeyEvent *event)
666 if(!m_pClient)
return;
667 if(m_pParameter && m_pParameter->GetOnlyView())
return;
668 bool modifier =
false;
669 if (event->modifiers() & Qt::ShiftModifier)
673 SendKeyEvent(m_pClient, k, FALSE);
676void CBackendLibVNCServer::InputMethodEvent(QInputMethodEvent *event)
679 if(!m_pClient)
return;
680 if(m_pParameter && m_pParameter->GetOnlyView())
return;
682 QString szText =
event->commitString();
683 if (szText.isEmpty())
688 QVector<uint32_t> ucs4 = szText.toUcs4();
689 foreach (uint32_t cp, ucs4) {
690 quint32 keysym =
static_cast<quint32
>(cp);
691 SendKeyEvent(m_pClient, keysym, TRUE);
692 SendKeyEvent(m_pClient, keysym, FALSE);
700 auto &net = m_pParameter->m_Proxy.m_SSH.m_Net;
703 m_pClient->serverHost = strdup(szHost.toStdString().c_str());
704 m_pClient->serverPort = nPort;
705 szErr = tr(
"Will connect to local socket server: %1:%2")
706 .arg(m_pClient->serverHost,
707 QString::number(m_pClient->serverPort));
708 qDebug(log) << szErr;
709 if(!rfbInitClient(m_pClient,
nullptr,
nullptr))
714 szErr = tr(
"Fail: Connect to %1:%2 <- %3:%4 <- %5:%6")
715 .arg(m_pParameter->m_Net.GetHost(),
716 QString::number(m_pParameter->m_Net.GetPort()),
717 net.GetHost(), QString::number(net.GetPort()),
718 szHost, QString::number(nPort)
720 qCritical(log) << szErr;
725 QString szInfo = QString(
"Connected to %1 <- %2:%3 <- %4:%5")
726 .arg(m_pClient->desktopName,
727 net.GetHost(), QString::number(net.GetPort()),
728 szHost, QString::number(nPort));
729 qInfo(log) << szInfo;
731 emit sigSetDesktopSize(m_pClient->width, m_pClient->height);
732 emit sigServerName(m_pClient->desktopName);
738#if defined(HAVE_UNIX_DOMAIN_SOCKET)
744 m_pClient->serverHost = strdup(szFile.toStdString().c_str());
745 szErr = tr(
"Will connect to local socket server: ") + szFile;
746 qDebug(log) << szErr;
747 if(!rfbInitClient(m_pClient,
nullptr,
nullptr))
752 szErr = tr(
"Fail: Connect to %1:%2 with %3")
753 .arg(m_pParameter->m_Net.GetHost(),
754 QString::number(m_pParameter->m_Net.GetPort()),
756 qCritical(log) << szErr;
761 QString szInfo = QString(
"Connected to ") + m_pClient->desktopName +
" with " + szFile;
762 qInfo(log) << szInfo;
765 emit sigSetDesktopSize(m_pClient->width, m_pClient->height);
766 emit sigServerName(m_pClient->desktopName);
Remote desktop interface.
void sigUpdateRect(const QRect &r, const QImage &image)
Notify the CFrmView update image.
virtual OnStartReturnValue OnStart() override
void slotConnectProxyServer(QString szHost, quint16 nPort)
[connect local socket server]
virtual int WakeUp() override
Wake up backend thread(background thread).
virtual int OnStop() override
Clean.
virtual void slotClipBoardChanged() override
Be called when the clip board change.
virtual int OnProcess() override
Specific operation processing of plug-in connection.
void sigInformation(const QString &szInfo)
Triggering from a background thread displays information in the main thread without blocking the back...
void sigStop()
Notify the user to stop.
void sigShowMessageBox(const QString &szTitle, const QString &szMessage, const QMessageBox::Icon &icon=QMessageBox::Information)
Trigger the display of a message dialog (QMessageBox) in the main thread from a background thread wit...
void sigError(const int nError, const QString &szError=QString())
Triggered when an error is generated.
void sigRunning()
Emitted when the plugin is successfully started.
void sigFinished()
Successful stopped signal.
virtual void slotTimeOut()
a non-Qt event loop (that is, normal loop processing), It call OnProcess(), and start timer.
void sigSecurityLevel(CSecurityLevel::Levels level)
Triggered when the security level changes.
void sigBlockShowWidget(const QString &className, int &nRet, void *pContext)
Blocks the background thread and displays the window in the foreground thread.
static quint32 QtToRfbKey(int inkey, bool modifier)
CConvertKeyCode::QtToRfbKey.
CParameterUser m_User
[Instance user]
Data is forwarded over a local socket and SSH tunnel.