27 #include <netinet/in.h>
28 #include <netinet/tcp.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <QMutexLocker>
32 #include <QThreadStorage>
37 static QThreadStorage<VncClientThread **>
instances;
40 rfbBool VncClientThread::newclientStatic(rfbClient *cl)
45 return t->newclient();
49 void VncClientThread::updatefbStatic(rfbClient *cl,
int x,
int y,
int w,
int h)
54 return t->updatefb(x, y, w, h);
58 void VncClientThread::cuttextStatic(rfbClient *cl,
const char *text,
int textlen)
63 t->cuttext(text, textlen);
67 char *VncClientThread::passwdHandlerStatic(rfbClient *cl)
72 return t->passwdHandler();
76 rfbCredential *VncClientThread::credentialHandlerStatic(rfbClient *cl,
int credentialType)
81 return t->credentialHandler(credentialType);
85 void VncClientThread::outputHandlerStatic(
const char *format, ...)
90 va_start(args, format);
91 (*t)->outputHandler(format, args);
99 if (m_colorTable.isEmpty()) {
100 m_colorTable.resize(256);
102 for (
int i = 0; i < 256; ++i) {
108 m_colorTable[i] = qRgb(r, g, b);
111 cl->format.depth = 8;
112 cl->format.bitsPerPixel = 8;
113 cl->format.redShift = 0;
114 cl->format.greenShift = 3;
115 cl->format.blueShift = 6;
116 cl->format.redMax = 7;
117 cl->format.greenMax = 7;
118 cl->format.blueMax = 3;
121 cl->format.depth = 16;
122 cl->format.bitsPerPixel = 16;
123 cl->format.redShift = 11;
124 cl->format.greenShift = 5;
125 cl->format.blueShift = 0;
126 cl->format.redMax = 0x1f;
127 cl->format.greenMax = 0x3f;
128 cl->format.blueMax = 0x1f;
132 cl->format.depth = 24;
133 cl->format.bitsPerPixel = 32;
134 cl->format.redShift = 16;
135 cl->format.greenShift = 8;
136 cl->format.blueShift = 0;
137 cl->format.redMax = 0xff;
138 cl->format.greenMax = 0xff;
139 cl->format.blueMax = 0xff;
143 rfbBool VncClientThread::newclient()
147 kDebug(5011) <<
"Intel(R) AMT KVM: switching to 8 bit color depth (workaround, recent libvncserver needed)";
152 const int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel;
153 const int size = width * height * (depth / 8);
158 memset(cl->frameBuffer,
'\0', size);
162 cl->appData.encodingsString =
"copyrect zlib hextile raw";
163 cl->appData.compressLevel = 0;
164 cl->appData.qualityLevel = 9;
167 cl->appData.encodingsString =
"copyrect tight zrle ultra zlib hextile corre rre raw";
168 cl->appData.compressLevel = 5;
169 cl->appData.qualityLevel = 7;
174 cl->appData.encodingsString =
"copyrect tight zrle ultra zlib hextile corre rre raw";
175 cl->appData.compressLevel = 9;
176 cl->appData.qualityLevel = 1;
179 SetFormatAndEncodings(cl);
180 kDebug(5011) <<
"Client created";
184 void VncClientThread::updatefb(
int x,
int y,
int w,
int h)
188 const int width = cl->width, height = cl->height;
192 img = QImage(cl->frameBuffer, width, height, QImage::Format_Indexed8);
193 img.setColorTable(m_colorTable);
196 img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB16);
199 img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB32);
204 kDebug(5011) <<
"image not loaded";
216 void VncClientThread::cuttext(
const char *text,
int textlen)
218 const QString cutText = QString::fromUtf8(text, textlen);
219 kDebug(5011) << cutText;
221 if (!cutText.isEmpty()) {
226 char *VncClientThread::passwdHandler()
228 kDebug(5011) <<
"password request";
231 if (!m_keepalive.failed) {
233 m_passwordError =
true;
235 return strdup(m_password.toUtf8());
238 rfbCredential *VncClientThread::credentialHandler(
int credentialType)
240 kDebug(5011) <<
"credential request" << credentialType;
242 rfbCredential *cred = 0;
244 switch (credentialType) {
245 case rfbCredentialTypeUser:
247 m_passwordError =
true;
249 cred =
new rfbCredential;
250 cred->userCredential.username = strdup(
username().toUtf8());
251 cred->userCredential.password = strdup(
password().toUtf8());
254 kError(5011) <<
"credential request failed, unspported credentialType:" << credentialType;
261 void VncClientThread::outputHandler(
const char *format, ...)
264 va_start(args, format);
267 message.vsprintf(format, args);
271 message = message.trimmed();
273 kDebug(5011) << message;
275 if ((message.contains(
"Couldn't convert ")) ||
276 (message.contains(
"Unable to connect to VNC server"))) {
279 QString tmp = i18n(
"Server not found.");
280 if (m_keepalive.set && !m_password.isNull()) {
281 m_keepalive.failed =
true;
282 if (m_previousDetails != tmp) {
283 m_previousDetails = tmp;
287 outputErrorMessageString = tmp;
294 if (message.contains(
"VNC connection failed: Authentication failed")) {
295 m_keepalive.failed =
false;
296 outputErrorMessageString = i18n(
"VNC authentication failed.");
298 if ((message.contains(
"VNC connection failed: Authentication failed, too many tries")) ||
299 (message.contains(
"VNC connection failed: Too many authentication failures"))) {
300 m_keepalive.failed =
false;
301 outputErrorMessageString = i18n(
"VNC authentication failed because of too many authentication tries.");
304 if (message.contains(
"VNC server closed connection"))
305 outputErrorMessageString = i18n(
"VNC server closed connection.");
309 if (message.contains(
"read (")) {
312 QString tmp = i18n(
"Disconnected: %1.", message);
313 if (m_keepalive.set && !m_password.isNull()) {
314 m_keepalive.failed =
true;
317 outputErrorMessageString = tmp;
322 if (message.contains(
"VNC server supports protocol version 3.889"))
323 outputErrorMessageString =
"INTERNAL:APPLE_VNC_COMPATIBILTY";
335 m_keepalive.intervalSeconds = 1;
336 m_keepalive.failedProbes = 3;
337 m_keepalive.set =
false;
338 m_keepalive.failed =
false;
339 m_previousDetails = QString::null;
340 outputErrorMessageString.clear();
341 QMutexLocker locker(&mutex);
343 QTimer *outputErrorMessagesCheckTimer =
new QTimer(
this);
344 outputErrorMessagesCheckTimer->setInterval(500);
345 connect(outputErrorMessagesCheckTimer, SIGNAL(timeout()),
this, SLOT(checkOutputErrorMessage()));
346 outputErrorMessagesCheckTimer->start();
354 const bool quitSuccess = wait(1000);
355 kDebug(5011) <<
"Attempting to stop in deconstructor, will crash if this fails:" << quitSuccess;
363 void VncClientThread::checkOutputErrorMessage()
365 if (!outputErrorMessageString.isEmpty()) {
366 kDebug(5011) << outputErrorMessageString;
367 QString errorMessage = outputErrorMessageString;
368 outputErrorMessageString.clear();
370 if ((errorMessage != i18n(
"VNC authentication failed.")) || m_passwordError)
377 QMutexLocker locker(&mutex);
383 QMutexLocker locker(&mutex);
396 setColorDepth(
bpp32);
400 setColorDepth(
bpp16);
404 void VncClientThread::setColorDepth(ColorDepth colorDepth)
421 QMutexLocker locker(&mutex);
427 QMutexLocker locker(&mutex);
432 return m_image.copy(x, y, w, h);
447 QMutexLocker locker(&mutex);
453 QMutexLocker locker(&mutex);
460 m_passwordError =
false;
463 if (clientCreate(
false)) {
469 if (m_passwordError) {
482 kDebug(5011) <<
"--------------------- Starting main VNC event loop ---------------------";
485 const int i = WaitForMessage(cl, 500);
486 if (m_stopped || i < 0) {
490 if (!HandleRFBServerMessage(cl)) {
491 if (m_keepalive.failed) {
499 }
while (!clientCreate(
true));
502 kError(5011) <<
"HandleRFBServerMessage failed";
508 while (!m_eventQueue.isEmpty()) {
511 clientEvent->
fire(cl);
528 bool VncClientThread::clientCreate(
bool reinitialising)
530 rfbClientLog = outputHandlerStatic;
531 rfbClientErr = outputHandlerStatic;
534 cl = rfbGetClient(8, 3, 4);
536 cl->MallocFrameBuffer = newclientStatic;
537 cl->canHandleNewFBSize =
true;
538 cl->GetPassword = passwdHandlerStatic;
539 cl->GetCredential = credentialHandlerStatic;
540 cl->GotFrameBufferUpdate = updatefbStatic;
541 cl->GotXCutText = cuttextStatic;
542 rfbClientSetClientData(cl, 0,
this);
544 cl->serverHost = strdup(m_host.toUtf8().constData());
546 if (m_port < 0 || !m_port)
549 if (m_port >= 0 && m_port < 100)
551 cl->serverPort = m_port;
553 kDebug(5011) <<
"--------------------- trying init ---------------------";
555 if (!rfbInitClient(cl, 0, 0)) {
556 if (!reinitialising) {
559 kError(5011) <<
"rfbInitClient failed";
565 if (reinitialising) {
570 clientSetKeepalive();
577 void VncClientThread::clientDestroy()
582 rfbClientCleanup(cl);
591 void VncClientThread::clientSetKeepalive()
594 m_keepalive.set =
false;
595 m_keepalive.failed =
false;
596 if (!m_keepalive.intervalSeconds) {
600 socklen_t optlen =
sizeof(optval);
604 if (setsockopt(cl->sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen) < 0) {
605 kError(5011) <<
"setsockopt(SO_KEEPALIVE)" << strerror(errno);
609 optval = m_keepalive.intervalSeconds;
610 if (setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPIDLE, &optval, optlen) < 0) {
611 kError(5011) <<
"setsockopt(TCP_KEEPIDLE)" << strerror(errno);
615 optval = m_keepalive.intervalSeconds;
616 if (setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPINTVL, &optval, optlen) < 0) {
617 kError(5011) <<
"setsockopt(TCP_KEEPINTVL)" << strerror(errno);
621 optval = m_keepalive.failedProbes;
622 if(setsockopt(cl->sock, IPPROTO_TCP, TCP_KEEPCNT, &optval, optlen) < 0) {
623 kError(5011) <<
"setsockopt(TCP_KEEPCNT)" << strerror(errno);
626 m_keepalive.set =
true;
627 kDebug(5011) <<
"TCP keepalive set";
635 kDebug(5011) << status << details << m_host <<
":" << m_port;
645 SendPointerEvent(cl, m_x, m_y, m_buttonMask);
650 SendKeyEvent(cl, m_key, m_pressed);
655 SendClientCutText(cl, text.toUtf8().data(), text.size());
660 QMutexLocker lock(&mutex);
669 QMutexLocker lock(&mutex);
678 QMutexLocker lock(&mutex);
685 #include "moc_vncclientthread.cpp"
void mouseEvent(int x, int y, int buttonMask)
RemoteStatus
State of the connection.
void setQuality(RemoteView::Quality quality)
const QString password() const
ColorDepth colorDepth() const
void clientStateChanged(RemoteView::RemoteStatus status, const QString &details)
When we connect/disconnect/reconnect/etc., this signal will be emitted.
void keyEvent(int key, bool pressed)
RemoteView::Quality quality() const
void gotCut(const QString &text)
void imageUpdated(int x, int y, int w, int h)
void passwordRequest(bool includingUsername=false)
static const QString INTEL_AMT_KVM_STRING
void emitGotCut(const QString &text)
void outputErrorMessage(const QString &message)
const QString username() const
void setHost(const QString &host)
const QImage image(int x=0, int y=0, int w=0, int h=0)
VncClientThread(QObject *parent=0)
void emitUpdated(int x, int y, int w, int h)
static QThreadStorage< VncClientThread ** > instances
void clientCut(const QString &text)
void setImage(const QImage &img)
virtual void fire(rfbClient *)=0