PageRenderTime 26ms CodeModel.GetById 10ms RepoModel.GetById 0ms app.codeStats 0ms

/kdenetwork-4.8.97/krdc/vnc/vncclientthread.cpp

#
C++ | 454 lines | 348 code | 74 blank | 32 comment | 36 complexity | 8f7b5c1627d116f9f5d3b49fe2b5f161 MD5 | raw file
Possible License(s): BSD-3-Clause, LGPL-2.0, GPL-2.0, CC-BY-SA-3.0, LGPL-2.1, GPL-3.0
  1. /****************************************************************************
  2. **
  3. ** Copyright (C) 2007-2008 Urs Wolfer <uwolfer @ kde.org>
  4. **
  5. ** This file is part of KDE.
  6. **
  7. ** This program is free software; you can redistribute it and/or modify
  8. ** it under the terms of the GNU General Public License as published by
  9. ** the Free Software Foundation; either version 2 of the License, or
  10. ** (at your option) any later version.
  11. **
  12. ** This program is distributed in the hope that it will be useful,
  13. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. ** GNU General Public License for more details.
  16. **
  17. ** You should have received a copy of the GNU General Public License
  18. ** along with this program; see the file COPYING. If not, write to
  19. ** the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  20. ** Boston, MA 02110-1301, USA.
  21. **
  22. ****************************************************************************/
  23. #include "vncclientthread.h"
  24. #include <QMutexLocker>
  25. #include <QTimer>
  26. //for detecting intel AMT KVM vnc server
  27. static const QString INTEL_AMT_KVM_STRING= "Intel(r) AMT KVM";
  28. static QString outputErrorMessageString;
  29. QVector<QRgb> VncClientThread::m_colorTable;
  30. void VncClientThread::setClientColorDepth(rfbClient* cl, VncClientThread::ColorDepth cd)
  31. {
  32. switch(cd) {
  33. case bpp8:
  34. if (m_colorTable.isEmpty()) {
  35. m_colorTable.resize(256);
  36. int r,g,b;
  37. for (int i = 0; i < 256; ++i) {
  38. //pick out the red (3 bits), green (3 bits) and blue (2 bits) bits and make them maximum significant in 8bits
  39. //this gives a colortable for 8bit true colors
  40. r= (i & 0x07) << 5;
  41. g= (i & 0x38) << 2;
  42. b= i & 0xc0;
  43. m_colorTable[i] = qRgb(r, g, b);
  44. }
  45. }
  46. cl->format.depth = 8;
  47. cl->format.bitsPerPixel = 8;
  48. cl->format.redShift = 0;
  49. cl->format.greenShift = 3;
  50. cl->format.blueShift = 6;
  51. cl->format.redMax = 7;
  52. cl->format.greenMax = 7;
  53. cl->format.blueMax = 3;
  54. break;
  55. case bpp16:
  56. cl->format.depth = 16;
  57. cl->format.bitsPerPixel = 16;
  58. cl->format.redShift = 11;
  59. cl->format.greenShift = 5;
  60. cl->format.blueShift = 0;
  61. cl->format.redMax = 0x1f;
  62. cl->format.greenMax = 0x3f;
  63. cl->format.blueMax = 0x1f;
  64. break;
  65. case bpp32:
  66. default:
  67. cl->format.depth = 24;
  68. cl->format.bitsPerPixel = 32;
  69. cl->format.redShift = 16;
  70. cl->format.greenShift = 8;
  71. cl->format.blueShift = 0;
  72. cl->format.redMax = 0xff;
  73. cl->format.greenMax = 0xff;
  74. cl->format.blueMax = 0xff;
  75. }
  76. }
  77. rfbBool VncClientThread::newclient(rfbClient *cl)
  78. {
  79. VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
  80. Q_ASSERT(t);
  81. //8bit color hack for Intel(r) AMT KVM "classic vnc" = vnc server built in in Intel Vpro chipsets.
  82. if (INTEL_AMT_KVM_STRING == cl->desktopName) {
  83. kDebug(5011) << "Intel(R) AMT KVM: switching to 8 bit color depth (workaround, recent libvncserver needed)";
  84. t->setColorDepth(bpp8);
  85. }
  86. setClientColorDepth(cl, t->colorDepth());
  87. const int width = cl->width, height = cl->height, depth = cl->format.bitsPerPixel;
  88. const int size = width * height * (depth / 8);
  89. if (t->frameBuffer)
  90. delete [] t->frameBuffer; // do not leak if we get a new framebuffer size
  91. t->frameBuffer = new uint8_t[size];
  92. cl->frameBuffer = t->frameBuffer;
  93. memset(cl->frameBuffer, '\0', size);
  94. switch (t->quality()) {
  95. case RemoteView::High:
  96. cl->appData.encodingsString = "copyrect zlib hextile raw";
  97. cl->appData.compressLevel = 0;
  98. cl->appData.qualityLevel = 9;
  99. break;
  100. case RemoteView::Medium:
  101. cl->appData.encodingsString = "copyrect tight zrle ultra zlib hextile corre rre raw";
  102. cl->appData.compressLevel = 5;
  103. cl->appData.qualityLevel = 7;
  104. break;
  105. case RemoteView::Low:
  106. case RemoteView::Unknown:
  107. default:
  108. cl->appData.encodingsString = "copyrect tight zrle ultra zlib hextile corre rre raw";
  109. cl->appData.compressLevel = 9;
  110. cl->appData.qualityLevel = 1;
  111. }
  112. SetFormatAndEncodings(cl);
  113. kDebug(5011) << "Client created";
  114. return true;
  115. }
  116. void VncClientThread::updatefb(rfbClient* cl, int x, int y, int w, int h)
  117. {
  118. // kDebug(5011) << "updated client: x: " << x << ", y: " << y << ", w: " << w << ", h: " << h;
  119. VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
  120. Q_ASSERT(t);
  121. const int width = cl->width, height = cl->height;
  122. QImage img;
  123. switch(t->colorDepth()) {
  124. case bpp8:
  125. img = QImage(cl->frameBuffer, width, height, QImage::Format_Indexed8);
  126. img.setColorTable(m_colorTable);
  127. break;
  128. case bpp16:
  129. img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB16);
  130. break;
  131. case bpp32:
  132. img = QImage(cl->frameBuffer, width, height, QImage::Format_RGB32);
  133. break;
  134. }
  135. if (img.isNull()) {
  136. kDebug(5011) << "image not loaded";
  137. }
  138. t->setImage(img);
  139. t->emitUpdated(x, y, w, h);
  140. }
  141. void VncClientThread::cuttext(rfbClient* cl, const char *text, int textlen)
  142. {
  143. const QString cutText = QString::fromUtf8(text, textlen);
  144. kDebug(5011) << cutText;
  145. if (!cutText.isEmpty()) {
  146. VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
  147. Q_ASSERT(t);
  148. t->emitGotCut(cutText);
  149. }
  150. }
  151. char *VncClientThread::passwdHandler(rfbClient *cl)
  152. {
  153. kDebug(5011) << "password request" << kBacktrace();
  154. VncClientThread *t = (VncClientThread*)rfbClientGetClientData(cl, 0);
  155. Q_ASSERT(t);
  156. t->passwordRequest();
  157. t->m_passwordError = true;
  158. return strdup(t->password().toLocal8Bit());
  159. }
  160. void VncClientThread::outputHandler(const char *format, ...)
  161. {
  162. va_list args;
  163. va_start(args, format);
  164. QString message;
  165. message.vsprintf(format, args);
  166. va_end(args);
  167. message = message.trimmed();
  168. kDebug(5011) << message;
  169. if ((message.contains("Couldn't convert ")) ||
  170. (message.contains("Unable to connect to VNC server")))
  171. outputErrorMessageString = i18n("Server not found.");
  172. if ((message.contains("VNC connection failed: Authentication failed, too many tries")) ||
  173. (message.contains("VNC connection failed: Too many authentication failures")))
  174. outputErrorMessageString = i18n("VNC authentication failed because of too many authentication tries.");
  175. if (message.contains("VNC connection failed: Authentication failed"))
  176. outputErrorMessageString = i18n("VNC authentication failed.");
  177. if (message.contains("VNC server closed connection"))
  178. outputErrorMessageString = i18n("VNC server closed connection.");
  179. // internal messages, not displayed to user
  180. if (message.contains("VNC server supports protocol version 3.889")) // see http://bugs.kde.org/162640
  181. outputErrorMessageString = "INTERNAL:APPLE_VNC_COMPATIBILTY";
  182. }
  183. VncClientThread::VncClientThread(QObject *parent)
  184. : QThread(parent)
  185. , frameBuffer(0)
  186. , cl(0)
  187. , m_stopped(false)
  188. {
  189. QMutexLocker locker(&mutex);
  190. QTimer *outputErrorMessagesCheckTimer = new QTimer(this);
  191. outputErrorMessagesCheckTimer->setInterval(500);
  192. connect(outputErrorMessagesCheckTimer, SIGNAL(timeout()), this, SLOT(checkOutputErrorMessage()));
  193. outputErrorMessagesCheckTimer->start();
  194. }
  195. VncClientThread::~VncClientThread()
  196. {
  197. if(isRunning()) {
  198. stop();
  199. terminate();
  200. const bool quitSuccess = wait(1000);
  201. kDebug(5011) << "Attempting to stop in deconstructor, will crash if this fails:" << quitSuccess;
  202. }
  203. if (cl) {
  204. // Disconnect from vnc server & cleanup allocated resources
  205. rfbClientCleanup(cl);
  206. }
  207. delete [] frameBuffer;
  208. }
  209. void VncClientThread::checkOutputErrorMessage()
  210. {
  211. if (!outputErrorMessageString.isEmpty()) {
  212. kDebug(5011) << outputErrorMessageString;
  213. QString errorMessage = outputErrorMessageString;
  214. outputErrorMessageString.clear();
  215. // show authentication failure error only after the 3rd unsuccessful try
  216. if ((errorMessage != i18n("VNC authentication failed.")) || m_passwordError)
  217. outputErrorMessage(errorMessage);
  218. }
  219. }
  220. void VncClientThread::setHost(const QString &host)
  221. {
  222. QMutexLocker locker(&mutex);
  223. m_host = host;
  224. }
  225. void VncClientThread::setPort(int port)
  226. {
  227. QMutexLocker locker(&mutex);
  228. m_port = port;
  229. }
  230. void VncClientThread::setQuality(RemoteView::Quality quality)
  231. {
  232. m_quality = quality;
  233. //set color depth dependent on quality
  234. switch(quality) {
  235. case RemoteView::Low:
  236. setColorDepth(bpp8);
  237. break;
  238. case RemoteView::High:
  239. setColorDepth(bpp32);
  240. break;
  241. case RemoteView::Medium:
  242. default:
  243. setColorDepth(bpp16);
  244. }
  245. }
  246. void VncClientThread::setColorDepth(ColorDepth colorDepth)
  247. {
  248. m_colorDepth= colorDepth;
  249. }
  250. RemoteView::Quality VncClientThread::quality() const
  251. {
  252. return m_quality;
  253. }
  254. VncClientThread::ColorDepth VncClientThread::colorDepth() const
  255. {
  256. return m_colorDepth;
  257. }
  258. void VncClientThread::setImage(const QImage &img)
  259. {
  260. QMutexLocker locker(&mutex);
  261. m_image = img;
  262. }
  263. const QImage VncClientThread::image(int x, int y, int w, int h)
  264. {
  265. QMutexLocker locker(&mutex);
  266. if (w == 0) // full image requested
  267. return m_image;
  268. else
  269. return m_image.copy(x, y, w, h);
  270. }
  271. void VncClientThread::emitUpdated(int x, int y, int w, int h)
  272. {
  273. emit imageUpdated(x, y, w, h);
  274. }
  275. void VncClientThread::emitGotCut(const QString &text)
  276. {
  277. emit gotCut(text);
  278. }
  279. void VncClientThread::stop()
  280. {
  281. QMutexLocker locker(&mutex);
  282. m_stopped = true;
  283. }
  284. void VncClientThread::run()
  285. {
  286. QMutexLocker locker(&mutex);
  287. while (!m_stopped) { // try to connect as long as the server allows
  288. locker.relock();
  289. m_passwordError = false;
  290. locker.unlock();
  291. rfbClientLog = outputHandler;
  292. rfbClientErr = outputHandler;
  293. //24bit color dept in 32 bits per pixel = default. Will change colordepth and bpp later if needed
  294. cl = rfbGetClient(8, 3, 4);
  295. setClientColorDepth(cl, this->colorDepth());
  296. cl->MallocFrameBuffer = newclient;
  297. cl->canHandleNewFBSize = true;
  298. cl->GetPassword = passwdHandler;
  299. cl->GotFrameBufferUpdate = updatefb;
  300. cl->GotXCutText = cuttext;
  301. rfbClientSetClientData(cl, 0, this);
  302. locker.relock();
  303. cl->serverHost = strdup(m_host.toUtf8().constData());
  304. if (m_port < 0 || !m_port) // port is invalid or empty...
  305. m_port = 5900; // fallback: try an often used VNC port
  306. if (m_port >= 0 && m_port < 100) // the user most likely used the short form (e.g. :1)
  307. m_port += 5900;
  308. cl->serverPort = m_port;
  309. locker.unlock();
  310. kDebug(5011) << "--------------------- trying init ---------------------";
  311. if (rfbInitClient(cl, 0, 0))
  312. break;
  313. else
  314. cl = 0;
  315. locker.relock();
  316. if (m_passwordError)
  317. continue;
  318. return;
  319. }
  320. locker.relock();
  321. kDebug(5011) << "--------------------- Starting main VNC event loop ---------------------";
  322. while (!m_stopped) {
  323. locker.unlock();
  324. const int i = WaitForMessage(cl, 500);
  325. if (i < 0) {
  326. break;
  327. }
  328. if (i) {
  329. if (!HandleRFBServerMessage(cl)) {
  330. break;
  331. }
  332. }
  333. locker.relock();
  334. while (!m_eventQueue.isEmpty()) {
  335. ClientEvent* clientEvent = m_eventQueue.dequeue();
  336. locker.unlock();
  337. clientEvent->fire(cl);
  338. delete clientEvent;
  339. locker.relock();
  340. }
  341. }
  342. m_stopped = true;
  343. }
  344. ClientEvent::~ClientEvent()
  345. {
  346. }
  347. void PointerClientEvent::fire(rfbClient* cl)
  348. {
  349. SendPointerEvent(cl, m_x, m_y, m_buttonMask);
  350. }
  351. void KeyClientEvent::fire(rfbClient* cl)
  352. {
  353. SendKeyEvent(cl, m_key, m_pressed);
  354. }
  355. void ClientCutEvent::fire(rfbClient* cl)
  356. {
  357. SendClientCutText(cl, text.toUtf8().data(), text.size());
  358. }
  359. void VncClientThread::mouseEvent(int x, int y, int buttonMask)
  360. {
  361. QMutexLocker lock(&mutex);
  362. if (m_stopped)
  363. return;
  364. m_eventQueue.enqueue(new PointerClientEvent(x, y, buttonMask));
  365. }
  366. void VncClientThread::keyEvent(int key, bool pressed)
  367. {
  368. QMutexLocker lock(&mutex);
  369. if (m_stopped)
  370. return;
  371. m_eventQueue.enqueue(new KeyClientEvent(key, pressed));
  372. }
  373. void VncClientThread::clientCut(const QString &text)
  374. {
  375. QMutexLocker lock(&mutex);
  376. if (m_stopped)
  377. return;
  378. m_eventQueue.enqueue(new ClientCutEvent(text));
  379. }
  380. #include "moc_vncclientthread.cpp"