File indexing completed on 2024-04-28 08:51:01
0001 /* 0002 SPDX-FileCopyrightText: 2007-2013 Urs Wolfer <uwolfer@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "vncclientthread.h" 0008 #include "krdc_debug.h" 0009 0010 #include <cerrno> 0011 #include <netinet/in.h> 0012 #include <netinet/tcp.h> 0013 #include <sys/types.h> 0014 #include <sys/socket.h> 0015 #include <QMutexLocker> 0016 #include <QTimer> 0017 #include <QBitmap> 0018 #include <QPixmap> 0019 #include <QCursor> 0020 0021 //for detecting intel AMT KVM vnc server 0022 static const QString INTEL_AMT_KVM_STRING = QLatin1String("Intel(r) AMT KVM"); 0023 0024 // Dispatch from this static callback context to the member context. 0025 rfbBool VncClientThread::newclientStatic(rfbClient *cl) 0026 { 0027 VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, nullptr); 0028 Q_ASSERT(t); 0029 0030 return t->newclient(); 0031 } 0032 0033 // Dispatch from this static callback context to the member context. 0034 void VncClientThread::updatefbStaticPartial(rfbClient *cl, int x, int y, int w, int h) 0035 { 0036 VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, nullptr); 0037 Q_ASSERT(t); 0038 0039 return t->updatefbPartial(x, y, w, h); 0040 } 0041 0042 // Dispatch from this static callback context to the member context. 0043 void VncClientThread::updateFbStaticFinished(rfbClient *cl) 0044 { 0045 VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, nullptr); 0046 Q_ASSERT(t); 0047 0048 return t->updatefbFinished(); 0049 } 0050 0051 // Dispatch from this static callback context to the member context. 0052 void VncClientThread::cuttextStatic(rfbClient *cl, const char *text, int textlen) 0053 { 0054 VncClientThread *t = (VncClientThread *)rfbClientGetClientData(cl, nullptr); 0055 Q_ASSERT(t); 0056 0057 t->cuttext(text, textlen); 0058 } 0059 0060 // Dispatch from this static callback context to the member context. 0061 char *VncClientThread::passwdHandlerStatic(rfbClient *cl) 0062 { 0063 VncClientThread *t = (VncClientThread *) rfbClientGetClientData(cl, nullptr); 0064 Q_ASSERT(t); 0065 0066 return t->passwdHandler(); 0067 } 0068 0069 // Dispatch from this static callback context to the member context. 0070 rfbCredential *VncClientThread::credentialHandlerStatic(rfbClient *cl, int credentialType) 0071 { 0072 VncClientThread *t = (VncClientThread *) rfbClientGetClientData(cl, nullptr); 0073 Q_ASSERT(t); 0074 0075 return t->credentialHandler(credentialType); 0076 } 0077 0078 // Dispatch from this static callback context to the member context. 0079 void VncClientThread::outputHandlerStatic(const char *format, ...) 0080 { 0081 VncClientThread *t = qobject_cast<VncClientThread *>(QThread::currentThread()); 0082 Q_ASSERT(t); 0083 0084 va_list args; 0085 va_start(args, format); 0086 t->outputHandler(format, args); 0087 va_end(args); 0088 } 0089 0090 void VncClientThread::cursorShapeHandlerStatic(rfbClient *cl, int xhot, int yhot, int width, int height, int bpp) { 0091 VncClientThread *t = (VncClientThread *) rfbClientGetClientData(cl, nullptr); 0092 Q_ASSERT(t); 0093 0094 // get cursor shape from remote cursor field 0095 // it's important to set stride for images, pictures in VNC are not always 32-bit aligned 0096 QImage cursorImg; 0097 switch (bpp) { 0098 case 4: 0099 cursorImg = QImage(cl->rcSource, width, height, bpp * width, QImage::Format_RGB32); 0100 break; 0101 case 2: 0102 cursorImg = QImage(cl->rcSource, width, height, bpp * width, QImage::Format_RGB16); 0103 break; 0104 case 1: 0105 cursorImg = QImage(cl->rcSource, width, height, bpp * width, QImage::Format_Indexed8); 0106 cursorImg.setColorTable(t->m_colorTable); 0107 break; 0108 default: 0109 qCWarning(KRDC) << "Unsupported bpp value for cursor shape:" << bpp; 0110 return; 0111 } 0112 0113 // get alpha channel 0114 QImage alpha(cl->rcMask, width, height, 1 * width, QImage::Format_Indexed8); 0115 alpha.setColorTable({qRgb(255, 255, 255), qRgb(0, 0, 0)}); 0116 0117 // apply transparency mask 0118 QPixmap cursorPixmap(QPixmap::fromImage(cursorImg)); 0119 cursorPixmap.setMask(QBitmap::fromImage(alpha)); 0120 0121 Q_EMIT t->gotCursor(QCursor{cursorPixmap, xhot, yhot}); 0122 } 0123 0124 void VncClientThread::setClientColorDepth(rfbClient* cl, VncClientThread::ColorDepth cd) 0125 { 0126 switch(cd) { 0127 case bpp8: 0128 if (m_colorTable.isEmpty()) { 0129 m_colorTable.resize(256); 0130 int r, g, b; 0131 for (int i = 0; i < 256; ++i) { 0132 //pick out the red (3 bits), green (3 bits) and blue (2 bits) bits and make them maximum significant in 8bits 0133 //this gives a colortable for 8bit true colors 0134 r= (i & 0x07) << 5; 0135 g= (i & 0x38) << 2; 0136 b= i & 0xc0; 0137 m_colorTable[i] = qRgb(r, g, b); 0138 } 0139 } 0140 cl->format.depth = 8; 0141 cl->format.bitsPerPixel = 8; 0142 cl->format.redShift = 0; 0143 cl->format.greenShift = 3; 0144 cl->format.blueShift = 6; 0145 cl->format.redMax = 7; 0146 cl->format.greenMax = 7; 0147 cl->format.blueMax = 3; 0148 break; 0149 case bpp16: 0150 cl->format.depth = 16; 0151 cl->format.bitsPerPixel = 16; 0152 cl->format.redShift = 11; 0153 cl->format.greenShift = 5; 0154 cl->format.blueShift = 0; 0155 cl->format.redMax = 0x1f; 0156 cl->format.greenMax = 0x3f; 0157 cl->format.blueMax = 0x1f; 0158 break; 0159 case bpp32: 0160 default: 0161 cl->format.depth = 24; 0162 cl->format.bitsPerPixel = 32; 0163 cl->format.redShift = 16; 0164 cl->format.greenShift = 8; 0165 cl->format.blueShift = 0; 0166 cl->format.redMax = 0xff; 0167 cl->format.greenMax = 0xff; 0168 cl->format.blueMax = 0xff; 0169 } 0170 } 0171 0172 rfbBool VncClientThread::newclient() 0173 { 0174 //8bit color hack for Intel(r) AMT KVM "classic vnc" = vnc server built in in Intel Vpro chipsets. 0175 if (INTEL_AMT_KVM_STRING == QLatin1String(cl->desktopName)) { 0176 qCDebug(KRDC) << "Intel(R) AMT KVM: switching to 8 bit color depth (workaround, recent libvncserver needed)"; 0177 setColorDepth(bpp8); 0178 } 0179 setClientColorDepth(cl, colorDepth()); 0180 0181 const int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel; 0182 const int size = width * height * (depth / 8); 0183 if (size <= 0) { 0184 return false; 0185 } 0186 if (frameBuffer) 0187 delete [] frameBuffer; // do not leak if we get a new framebuffer size 0188 frameBuffer = new uint8_t[size]; 0189 cl->frameBuffer = frameBuffer; 0190 memset(cl->frameBuffer, '\0', size); 0191 0192 switch (quality()) { 0193 case RemoteView::High: 0194 cl->appData.encodingsString = "copyrect zlib hextile raw"; 0195 cl->appData.compressLevel = 0; 0196 cl->appData.qualityLevel = 9; 0197 break; 0198 case RemoteView::Medium: 0199 cl->appData.encodingsString = "copyrect tight zrle ultra zlib hextile corre rre raw"; 0200 cl->appData.compressLevel = 5; 0201 cl->appData.qualityLevel = 7; 0202 break; 0203 case RemoteView::Low: 0204 case RemoteView::Unknown: 0205 default: 0206 // bpp8 and tight encoding is not supported in libvnc 0207 cl->appData.encodingsString = "copyrect zrle ultra zlib hextile corre rre raw"; 0208 cl->appData.compressLevel = 9; 0209 cl->appData.qualityLevel = 1; 0210 } 0211 0212 SetFormatAndEncodings(cl); 0213 qCDebug(KRDC) << "Client created"; 0214 return true; 0215 } 0216 0217 void VncClientThread::updatefbPartial(int x, int y, int w, int h) 0218 { 0219 // qCDebug(KRDC) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h; 0220 0221 m_dirtyRect = m_dirtyRect.united(QRect(x, y, w, h)); 0222 } 0223 0224 void VncClientThread::updatefbFinished() 0225 { 0226 const int width = cl->width, height = cl->height; 0227 QImage img; 0228 switch(colorDepth()) { 0229 case bpp8: 0230 img = QImage(cl->frameBuffer, width, height, width, QImage::Format_Indexed8); 0231 img.setColorTable(m_colorTable); 0232 break; 0233 case bpp16: 0234 img = QImage(cl->frameBuffer, width, height, 2 * width, QImage::Format_RGB16); 0235 break; 0236 case bpp32: 0237 img = QImage(cl->frameBuffer, width, height, 4 * width, QImage::Format_RGB32); 0238 break; 0239 } 0240 0241 if (img.isNull()) { 0242 qCDebug(KRDC) << "image not loaded"; 0243 } 0244 0245 if (m_stopped) { 0246 return; // sending data to a stopped thread is not a good idea 0247 } 0248 0249 img.setDevicePixelRatio(m_devicePixelRatio); 0250 setImage(img); 0251 0252 // Compute bounding rect. 0253 QRect updateRect = m_dirtyRect; 0254 m_dirtyRect = QRect(); 0255 0256 // qCDebug(KRDC) << Q_FUNC_INFO << updateRect; 0257 emitUpdated(updateRect.x(), updateRect.y(), updateRect.width(), updateRect.height()); 0258 } 0259 0260 void VncClientThread::cuttext(const char *text, int textlen) 0261 { 0262 const QString cutText = QString::fromLatin1(text, textlen); 0263 qCDebug(KRDC) << cutText; 0264 0265 if (!cutText.isEmpty()) { 0266 emitGotCut(cutText); 0267 } 0268 } 0269 0270 char *VncClientThread::passwdHandler() 0271 { 0272 qCDebug(KRDC) << "password request"; 0273 0274 // Never request a password during a reconnect attempt. 0275 if (!m_keepalive.failed) { 0276 passwordRequest(); 0277 m_passwordError = true; 0278 } 0279 return strdup(m_password.toUtf8().constData()); 0280 } 0281 0282 rfbCredential *VncClientThread::credentialHandler(int credentialType) 0283 { 0284 qCDebug(KRDC) << "credential request" << credentialType; 0285 0286 rfbCredential *cred = nullptr; 0287 0288 switch (credentialType) { 0289 case rfbCredentialTypeUser: 0290 passwordRequest(true); 0291 m_passwordError = true; 0292 0293 cred = new rfbCredential; 0294 cred->userCredential.username = strdup(username().toUtf8().constData()); 0295 cred->userCredential.password = strdup(password().toUtf8().constData()); 0296 break; 0297 default: 0298 qCritical(KRDC) << "credential request failed, unsupported credentialType:" << credentialType; 0299 outputErrorMessage(i18n("VNC authentication type is not supported.")); 0300 break; 0301 } 0302 return cred; 0303 } 0304 0305 void VncClientThread::outputHandler(const char *format, va_list args) 0306 { 0307 auto message = QString::vasprintf(format, args); 0308 0309 message = message.trimmed(); 0310 0311 qCDebug(KRDC) << message; 0312 0313 if ((message.contains(QLatin1String("Couldn't convert "))) || 0314 (message.contains(QLatin1String("Unable to connect to VNC server")))) { 0315 // Don't show a dialog if a reconnection is needed. Never contemplate 0316 // reconnection if we don't have a password. 0317 QString tmp = i18n("Server not found."); 0318 if (m_keepalive.set && !m_password.isNull()) { 0319 m_keepalive.failed = true; 0320 if (m_previousDetails != tmp) { 0321 m_previousDetails = tmp; 0322 clientStateChange(RemoteView::Disconnected, tmp); 0323 } 0324 } else { 0325 outputErrorMessageString = tmp; 0326 } 0327 } 0328 0329 // Process general authentication failures before more specific authentication 0330 // failures. All authentication failures cancel any auto-reconnection that 0331 // may be in progress. 0332 if (message.contains(QLatin1String("VNC connection failed: Authentication failed"))) { 0333 m_keepalive.failed = false; 0334 outputErrorMessageString = i18n("VNC authentication failed."); 0335 } 0336 if ((message.contains(QLatin1String("VNC connection failed: Authentication failed, too many tries"))) || 0337 (message.contains(QLatin1String("VNC connection failed: Too many authentication failures")))) { 0338 m_keepalive.failed = false; 0339 outputErrorMessageString = i18n("VNC authentication failed because of too many authentication tries."); 0340 } 0341 0342 if (message.contains(QLatin1String("VNC server closed connection"))) 0343 outputErrorMessageString = i18n("VNC server closed connection."); 0344 0345 // If we are not going to attempt a reconnection, at least tell the user 0346 // the connection went away. 0347 if (message.contains(QLatin1String("read ("))) { 0348 // Don't show a dialog if a reconnection is needed. Never contemplate 0349 // reconnection if we don't have a password. 0350 #ifdef QTONLY 0351 QString tmp = i18n("Disconnected: %1.", message.toStdString().c_str()); 0352 #else 0353 QString tmp = i18n("Disconnected: %1.", message); 0354 #endif 0355 if (m_keepalive.set && !m_password.isNull()) { 0356 m_keepalive.failed = true; 0357 clientStateChange(RemoteView::Disconnected, tmp); 0358 } else { 0359 outputErrorMessageString = tmp; 0360 } 0361 } 0362 0363 // internal messages, not displayed to user 0364 if (message.contains(QLatin1String("VNC server supports protocol version 3.889"))) // see https://bugs.kde.org/162640 0365 outputErrorMessageString = QLatin1String("INTERNAL:APPLE_VNC_COMPATIBILTY"); 0366 } 0367 0368 VncClientThread::VncClientThread(QObject *parent) 0369 : QThread(parent) 0370 , frameBuffer(nullptr) 0371 , cl(nullptr) 0372 , m_devicePixelRatio(1.0) 0373 , m_stopped(false) 0374 { 0375 // We choose a small value for interval...after all if the connection is 0376 // supposed to sustain a VNC session, a reasonably frequent ping should 0377 // be perfectly supportable. 0378 m_keepalive.intervalSeconds = 1; 0379 m_keepalive.failedProbes = 3; 0380 m_keepalive.set = false; 0381 m_keepalive.failed = false; 0382 m_previousDetails = QString(); 0383 outputErrorMessageString.clear(); //don't deliver error messages of old instances... 0384 QMutexLocker locker(&mutex); 0385 0386 QTimer *outputErrorMessagesCheckTimer = new QTimer(this); 0387 outputErrorMessagesCheckTimer->setInterval(500); 0388 connect(outputErrorMessagesCheckTimer, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage())); 0389 outputErrorMessagesCheckTimer->start(); 0390 } 0391 0392 VncClientThread::~VncClientThread() 0393 { 0394 if(isRunning()) { 0395 stop(); 0396 terminate(); 0397 const bool quitSuccess = wait(1000); 0398 qCDebug(KRDC) << "Attempting to stop in deconstructor, will crash if this fails:" << quitSuccess; 0399 } 0400 0401 clientDestroy(); 0402 0403 delete [] frameBuffer; 0404 } 0405 0406 void VncClientThread::checkOutputErrorMessage() 0407 { 0408 if (!outputErrorMessageString.isEmpty()) { 0409 qCDebug(KRDC) << outputErrorMessageString; 0410 QString errorMessage = outputErrorMessageString; 0411 outputErrorMessageString.clear(); 0412 // show authentication failure error only after the 3rd unsuccessful try 0413 if ((errorMessage != i18n("VNC authentication failed.")) || m_passwordError) 0414 outputErrorMessage(errorMessage); 0415 } 0416 } 0417 0418 void VncClientThread::setHost(const QString &host) 0419 { 0420 QMutexLocker locker(&mutex); 0421 m_host = host; 0422 } 0423 0424 void VncClientThread::setPort(int port) 0425 { 0426 QMutexLocker locker(&mutex); 0427 m_port = port; 0428 } 0429 0430 void VncClientThread::setShowLocalCursor(bool show) { 0431 QMutexLocker locker(&mutex); 0432 m_showLocalCursor = show; 0433 0434 if (!cl) { 0435 // no client yet, only store local value 0436 return; 0437 } 0438 0439 // from server point of view, "remote" cursor is the one local to the client 0440 // so the meaning in AppData struct is inverted 0441 cl->appData.useRemoteCursor = show; 0442 0443 // need to communicate this change to server or it won't stop painting cursor 0444 m_eventQueue.enqueue(new ReconfigureEvent); 0445 } 0446 0447 void VncClientThread::setQuality(RemoteView::Quality quality) 0448 { 0449 m_quality = quality; 0450 //set color depth dependent on quality 0451 switch(quality) { 0452 case RemoteView::Low: 0453 setColorDepth(bpp8); 0454 break; 0455 case RemoteView::High: 0456 setColorDepth(bpp32); 0457 break; 0458 case RemoteView::Medium: 0459 default: 0460 setColorDepth(bpp16); 0461 } 0462 } 0463 0464 void VncClientThread::setDevicePixelRatio(qreal dpr) 0465 { 0466 m_devicePixelRatio = dpr; 0467 } 0468 0469 void VncClientThread::setColorDepth(ColorDepth colorDepth) 0470 { 0471 m_colorDepth = colorDepth; 0472 } 0473 0474 RemoteView::Quality VncClientThread::quality() const 0475 { 0476 return m_quality; 0477 } 0478 0479 VncClientThread::ColorDepth VncClientThread::colorDepth() const 0480 { 0481 return m_colorDepth; 0482 } 0483 0484 void VncClientThread::setImage(const QImage &img) 0485 { 0486 QMutexLocker locker(&mutex); 0487 m_image = img; 0488 } 0489 0490 const QImage VncClientThread::image(int x, int y, int w, int h) 0491 { 0492 QMutexLocker locker(&mutex); 0493 0494 if (w == 0) // full image requested 0495 return m_image; 0496 else 0497 return m_image.copy(x, y, w, h); 0498 } 0499 0500 void VncClientThread::emitUpdated(int x, int y, int w, int h) 0501 { 0502 Q_EMIT imageUpdated(x, y, w, h); 0503 } 0504 0505 void VncClientThread::emitGotCut(const QString &text) 0506 { 0507 Q_EMIT gotCut(text); 0508 } 0509 0510 void VncClientThread::stop() 0511 { 0512 QMutexLocker locker(&mutex); 0513 m_stopped = true; 0514 } 0515 0516 void VncClientThread::run() 0517 { 0518 QMutexLocker locker(&mutex); 0519 0520 while (!m_stopped) { // try to connect as long as the server allows 0521 locker.relock(); 0522 m_passwordError = false; 0523 locker.unlock(); 0524 0525 if (clientCreate(false)) { 0526 // The initial connection attempt worked! 0527 break; 0528 } 0529 0530 locker.relock(); 0531 if (m_passwordError) { 0532 locker.unlock(); 0533 // Try again. 0534 continue; 0535 } 0536 0537 // The initial connection attempt failed, and not because of a 0538 // password problem. Bail out. 0539 m_stopped = true; 0540 locker.unlock(); 0541 } 0542 0543 locker.relock(); 0544 qCDebug(KRDC) << "--------------------- Starting main VNC event loop ---------------------"; 0545 while (!m_stopped) { 0546 locker.unlock(); 0547 const int i = WaitForMessage(cl, 500); 0548 if (m_stopped || i < 0) { 0549 break; 0550 } 0551 if (i) { 0552 if (!HandleRFBServerMessage(cl)) { 0553 if (m_keepalive.failed) { 0554 do { 0555 // Reconnect after a short delay. That way, if the 0556 // attempt fails very quickly, we don't sit in a very 0557 // tight loop. 0558 clientDestroy(); 0559 msleep(1000); 0560 clientStateChange(RemoteView::Connecting, i18n("Reconnecting.")); 0561 } while (!clientCreate(true)); 0562 continue; 0563 } 0564 qCritical(KRDC) << "HandleRFBServerMessage failed"; 0565 break; 0566 } 0567 } 0568 0569 locker.relock(); 0570 while (!m_eventQueue.isEmpty()) { 0571 ClientEvent* clientEvent = m_eventQueue.dequeue(); 0572 locker.unlock(); 0573 clientEvent->fire(cl); 0574 delete clientEvent; 0575 locker.relock(); 0576 } 0577 } 0578 0579 m_stopped = true; 0580 } 0581 0582 /** 0583 * Factor out the initialisation of the VNC client library. Notice this has 0584 * both static parts as in @see rfbClientLog and @see rfbClientErr, 0585 * as well as instance local data @see rfbGetClient(). 0586 * 0587 * On return from here, if cl is set, the connection will have been made else 0588 * cl will not be set. 0589 */ 0590 bool VncClientThread::clientCreate(bool reinitialising) 0591 { 0592 rfbClientLog = outputHandlerStatic; 0593 rfbClientErr = outputHandlerStatic; 0594 0595 //24bit color dept in 32 bits per pixel = default. Will change colordepth and bpp later if needed 0596 cl = rfbGetClient(8, 3, 4); 0597 setClientColorDepth(cl, this->colorDepth()); 0598 cl->MallocFrameBuffer = newclientStatic; 0599 cl->canHandleNewFBSize = true; 0600 cl->GetPassword = passwdHandlerStatic; 0601 cl->GetCredential = credentialHandlerStatic; 0602 cl->GotFrameBufferUpdate = updatefbStaticPartial; 0603 cl->FinishedFrameBufferUpdate = updateFbStaticFinished; 0604 cl->GotXCutText = cuttextStatic; 0605 cl->GotCursorShape = cursorShapeHandlerStatic; 0606 rfbClientSetClientData(cl, nullptr, this); 0607 0608 cl->appData.useRemoteCursor = m_showLocalCursor; 0609 0610 cl->serverHost = strdup(m_host.toUtf8().constData()); 0611 0612 cl->serverPort = m_port; 0613 0614 qCDebug(KRDC) << "--------------------- trying init ---------------------"; 0615 0616 if (!rfbInitClient(cl, nullptr, nullptr)) { 0617 if (!reinitialising) { 0618 // Don't whine on reconnection failure: presumably the network 0619 // is simply still down. 0620 qCCritical(KRDC) << "rfbInitClient failed"; 0621 } 0622 cl = nullptr; 0623 return false; 0624 } 0625 0626 if (reinitialising) { 0627 clientStateChange(RemoteView::Connected, i18n("Reconnected.")); 0628 } else { 0629 clientStateChange(RemoteView::Connected, i18n("Connected.")); 0630 } 0631 clientSetKeepalive(); 0632 return true; 0633 } 0634 0635 /** 0636 * Undo @see clientCreate(). 0637 */ 0638 void VncClientThread::clientDestroy() 0639 { 0640 0641 if (cl) { 0642 // Disconnect from vnc server & cleanup allocated resources 0643 rfbClientCleanup(cl); 0644 cl = nullptr; 0645 } 0646 } 0647 0648 /** 0649 * The VNC client library does not make use of keepalives. We go behind its 0650 * back to set it up. 0651 */ 0652 void VncClientThread::clientSetKeepalive() 0653 { 0654 // If keepalive is disabled, do nothing. 0655 m_keepalive.set = false; 0656 m_keepalive.failed = false; 0657 if (!m_keepalive.intervalSeconds) { 0658 return; 0659 } 0660 int optval; 0661 socklen_t optlen = sizeof(optval); 0662 0663 // Try to set the option active 0664 optval = 1; 0665 if (setsockopt(cl->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) { 0666 qCritical(KRDC) << "setsockopt(SO_KEEPALIVE)" << strerror(errno); 0667 return; 0668 } 0669 0670 optval = m_keepalive.intervalSeconds; 0671 if (setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) { 0672 qCritical(KRDC) << "setsockopt(TCP_KEEPIDLE)" << strerror(errno); 0673 return; 0674 } 0675 0676 optval = m_keepalive.intervalSeconds; 0677 if (setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) { 0678 qCritical(KRDC) << "setsockopt(TCP_KEEPINTVL)" << strerror(errno); 0679 return; 0680 } 0681 0682 optval = m_keepalive.failedProbes; 0683 if(setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen) < 0) { 0684 qCritical(KRDC) << "setsockopt(TCP_KEEPCNT)" << strerror(errno); 0685 return; 0686 } 0687 m_keepalive.set = true; 0688 qCDebug(KRDC) << "TCP keepalive set"; 0689 } 0690 0691 /** 0692 * The VNC client state changed. 0693 */ 0694 void VncClientThread::clientStateChange(RemoteView::RemoteStatus status, const QString &details) 0695 { 0696 qCDebug(KRDC) << status << details << m_host << ":" << m_port; 0697 Q_EMIT clientStateChanged(status, details); 0698 } 0699 0700 ClientEvent::~ClientEvent() 0701 { 0702 } 0703 0704 void ReconfigureEvent::fire(rfbClient* cl) 0705 { 0706 SetFormatAndEncodings(cl); 0707 } 0708 0709 void PointerClientEvent::fire(rfbClient* cl) 0710 { 0711 SendPointerEvent(cl, m_x, m_y, m_buttonMask); 0712 } 0713 0714 void KeyClientEvent::fire(rfbClient* cl) 0715 { 0716 SendKeyEvent(cl, m_key, m_pressed); 0717 } 0718 0719 void ClientCutEvent::fire(rfbClient* cl) 0720 { 0721 QByteArray toLatin1Converted = text.toLatin1(); 0722 SendClientCutText(cl, toLatin1Converted.data(), toLatin1Converted.length()); 0723 } 0724 0725 void VncClientThread::mouseEvent(int x, int y, int buttonMask) 0726 { 0727 QMutexLocker lock(&mutex); 0728 if (m_stopped) 0729 return; 0730 0731 m_eventQueue.enqueue(new PointerClientEvent(x, y, buttonMask)); 0732 } 0733 0734 void VncClientThread::keyEvent(int key, bool pressed) 0735 { 0736 QMutexLocker lock(&mutex); 0737 if (m_stopped) 0738 return; 0739 0740 m_eventQueue.enqueue(new KeyClientEvent(key, pressed)); 0741 } 0742 0743 void VncClientThread::clientCut(const QString &text) 0744 { 0745 QMutexLocker lock(&mutex); 0746 if (m_stopped) 0747 return; 0748 0749 m_eventQueue.enqueue(new ClientCutEvent(text)); 0750 } 0751 0752 #include "moc_vncclientthread.cpp"