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> 
   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);
 
  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()
 
  146     if (INTEL_AMT_KVM_STRING == cl->desktopName) {
 
  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);
 
  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)
 
  219     kDebug(5011) << cutText;
 
  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);
 
  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.");
 
  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(); 
 
  343     QTimer *outputErrorMessagesCheckTimer = 
new QTimer(
this);
 
  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)
 
  396         setColorDepth(
bpp32);
 
  400         setColorDepth(
bpp16);
 
  404 void VncClientThread::setColorDepth(ColorDepth colorDepth)
 
  432         return m_image.
copy(x, y, w, h);
 
  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);
 
  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());
 
  685 #include "moc_vncclientthread.cpp" 
void setInterval(int msec)
 
void mouseEvent(int x, int y, int buttonMask)
 
RemoteStatus
State of the connection. 
 
QString & vsprintf(const char *cformat, va_list ap)
 
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)
 
QImage copy(const QRect &rectangle) const
 
RemoteView::Quality quality() const 
 
void gotCut(const QString &text)
 
void setLocalData(T data)
 
void imageUpdated(int x, int y, int w, int h)
 
void passwordRequest(bool includingUsername=false)
 
QString fromUtf8(const char *str, int size)
 
static const QString INTEL_AMT_KVM_STRING
 
void emitGotCut(const QString &text)
 
const char * constData() const
 
void outputErrorMessage(const QString &message)
 
const QString username() const 
 
bool contains(QChar ch, Qt::CaseSensitivity cs) 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)
 
bool wait(unsigned long time)
 
void setColorTable(const QVector< QRgb > colors)
 
void setImage(const QImage &img)
 
bool connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
 
virtual void fire(rfbClient *)=0
 
void msleep(unsigned long msecs)
 
QByteArray toUtf8() const