You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

VNCSConnectionST.cxx 33KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2009-2019 Pierre Ossman for Cendio AB
  3. * Copyright 2018 Peter Astrand for Cendio AB
  4. *
  5. * This is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This software is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this software; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  18. * USA.
  19. */
  20. #include <network/TcpSocket.h>
  21. #include <rfb/ComparingUpdateTracker.h>
  22. #include <rfb/Encoder.h>
  23. #include <rfb/KeyRemapper.h>
  24. #include <rfb/LogWriter.h>
  25. #include <rfb/Security.h>
  26. #include <rfb/ServerCore.h>
  27. #include <rfb/SMsgWriter.h>
  28. #include <rfb/VNCServerST.h>
  29. #include <rfb/VNCSConnectionST.h>
  30. #include <rfb/screenTypes.h>
  31. #include <rfb/fenceTypes.h>
  32. #include <rfb/ledStates.h>
  33. #define XK_LATIN1
  34. #define XK_MISCELLANY
  35. #define XK_XKB_KEYS
  36. #include <rfb/keysymdef.h>
  37. using namespace rfb;
  38. static LogWriter vlog("VNCSConnST");
  39. static Cursor emptyCursor(0, 0, Point(0, 0), NULL);
  40. VNCSConnectionST::VNCSConnectionST(VNCServerST* server_, network::Socket *s,
  41. bool reverse)
  42. : sock(s), reverseConnection(reverse),
  43. inProcessMessages(false),
  44. pendingSyncFence(false), syncFence(false), fenceFlags(0),
  45. fenceDataLen(0), fenceData(NULL), congestionTimer(this),
  46. losslessTimer(this), server(server_),
  47. updateRenderedCursor(false), removeRenderedCursor(false),
  48. continuousUpdates(false), encodeManager(this), idleTimer(this),
  49. pointerEventTime(0), clientHasCursor(false),
  50. authFailureTimer(this)
  51. {
  52. setStreams(&sock->inStream(), &sock->outStream());
  53. peerEndpoint.buf = sock->getPeerEndpoint();
  54. // Configure the socket
  55. setSocketTimeouts();
  56. // Kick off the idle timer
  57. if (rfb::Server::idleTimeout) {
  58. // minimum of 15 seconds while authenticating
  59. if (rfb::Server::idleTimeout < 15)
  60. idleTimer.start(secsToMillis(15));
  61. else
  62. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  63. }
  64. }
  65. VNCSConnectionST::~VNCSConnectionST()
  66. {
  67. // If we reach here then VNCServerST is deleting us!
  68. if (closeReason.buf)
  69. vlog.info("closing %s: %s", peerEndpoint.buf, closeReason.buf);
  70. // Release any keys the client still had pressed
  71. while (!pressedKeys.empty()) {
  72. rdr::U32 keysym, keycode;
  73. keysym = pressedKeys.begin()->second;
  74. keycode = pressedKeys.begin()->first;
  75. pressedKeys.erase(pressedKeys.begin());
  76. vlog.debug("Releasing key 0x%x / 0x%x on client disconnect",
  77. keysym, keycode);
  78. server->keyEvent(keysym, keycode, false);
  79. }
  80. delete [] fenceData;
  81. }
  82. // SConnection methods
  83. bool VNCSConnectionST::accessCheck(AccessRights ar) const
  84. {
  85. // Reverse connections are user initiated, so they are implicitly
  86. // allowed to bypass the query
  87. if (reverseConnection)
  88. ar &= ~AccessNoQuery;
  89. return SConnection::accessCheck(ar);
  90. }
  91. void VNCSConnectionST::close(const char* reason)
  92. {
  93. // Log the reason for the close
  94. if (!closeReason.buf)
  95. closeReason.buf = strDup(reason);
  96. else
  97. vlog.debug("second close: %s (%s)", peerEndpoint.buf, reason);
  98. // Just shutdown the socket and mark our state as closing. Eventually the
  99. // calling code will call VNCServerST's removeSocket() method causing us to
  100. // be deleted.
  101. sock->shutdown();
  102. SConnection::close(reason);
  103. }
  104. // Methods called from VNCServerST
  105. bool VNCSConnectionST::init()
  106. {
  107. try {
  108. initialiseProtocol();
  109. } catch (rdr::Exception& e) {
  110. close(e.str());
  111. return false;
  112. }
  113. return true;
  114. }
  115. void VNCSConnectionST::processMessages()
  116. {
  117. if (state() == RFBSTATE_CLOSING) return;
  118. try {
  119. // - Now set appropriate socket timeouts and process data
  120. setSocketTimeouts();
  121. inProcessMessages = true;
  122. // Get the underlying TCP layer to build large packets if we send
  123. // multiple small responses.
  124. sock->cork(true);
  125. while (getInStream()->checkNoWait(1)) {
  126. // Silently drop any data if we are currently delaying an
  127. // authentication failure response as otherwise we would close
  128. // the connection on unexpected data, and an attacker could use
  129. // that to detect our delayed state.
  130. if (state() == RFBSTATE_SECURITY_FAILURE) {
  131. getInStream()->skip(1);
  132. continue;
  133. }
  134. if (pendingSyncFence) {
  135. syncFence = true;
  136. pendingSyncFence = false;
  137. }
  138. processMsg();
  139. if (syncFence) {
  140. writer()->writeFence(fenceFlags, fenceDataLen, fenceData);
  141. syncFence = false;
  142. }
  143. }
  144. // Flush out everything in case we go idle after this.
  145. sock->cork(false);
  146. inProcessMessages = false;
  147. // If there were anything requiring an update, try to send it here.
  148. // We wait until now with this to aggregate responses and to give
  149. // higher priority to user actions such as keyboard and pointer events.
  150. writeFramebufferUpdate();
  151. } catch (rdr::EndOfStream&) {
  152. close("Clean disconnection");
  153. } catch (rdr::Exception &e) {
  154. close(e.str());
  155. }
  156. }
  157. void VNCSConnectionST::flushSocket()
  158. {
  159. if (state() == RFBSTATE_CLOSING) return;
  160. try {
  161. setSocketTimeouts();
  162. sock->outStream().flush();
  163. // Flushing the socket might release an update that was previously
  164. // delayed because of congestion.
  165. if (sock->outStream().bufferUsage() == 0)
  166. writeFramebufferUpdate();
  167. } catch (rdr::Exception &e) {
  168. close(e.str());
  169. }
  170. }
  171. void VNCSConnectionST::pixelBufferChange()
  172. {
  173. try {
  174. if (!authenticated()) return;
  175. if (client.width() && client.height() &&
  176. (server->getPixelBuffer()->width() != client.width() ||
  177. server->getPixelBuffer()->height() != client.height()))
  178. {
  179. // We need to clip the next update to the new size, but also add any
  180. // extra bits if it's bigger. If we wanted to do this exactly, something
  181. // like the code below would do it, but at the moment we just update the
  182. // entire new size. However, we do need to clip the damagedCursorRegion
  183. // because that might be added to updates in writeFramebufferUpdate().
  184. //updates.intersect(server->pb->getRect());
  185. //
  186. //if (server->pb->width() > client.width())
  187. // updates.add_changed(Rect(client.width(), 0, server->pb->width(),
  188. // server->pb->height()));
  189. //if (server->pb->height() > client.height())
  190. // updates.add_changed(Rect(0, client.height(), client.width(),
  191. // server->pb->height()));
  192. damagedCursorRegion.assign_intersect(server->getPixelBuffer()->getRect());
  193. client.setDimensions(server->getPixelBuffer()->width(),
  194. server->getPixelBuffer()->height(),
  195. server->getScreenLayout());
  196. if (state() == RFBSTATE_NORMAL) {
  197. if (!client.supportsDesktopSize()) {
  198. close("Client does not support desktop resize");
  199. return;
  200. }
  201. writer()->writeDesktopSize(reasonServer);
  202. }
  203. // Drop any lossy tracking that is now outside the framebuffer
  204. encodeManager.pruneLosslessRefresh(Region(server->getPixelBuffer()->getRect()));
  205. }
  206. // Just update the whole screen at the moment because we're too lazy to
  207. // work out what's actually changed.
  208. updates.clear();
  209. updates.add_changed(server->getPixelBuffer()->getRect());
  210. writeFramebufferUpdate();
  211. } catch(rdr::Exception &e) {
  212. close(e.str());
  213. }
  214. }
  215. void VNCSConnectionST::writeFramebufferUpdateOrClose()
  216. {
  217. try {
  218. writeFramebufferUpdate();
  219. } catch(rdr::Exception &e) {
  220. close(e.str());
  221. }
  222. }
  223. void VNCSConnectionST::screenLayoutChangeOrClose(rdr::U16 reason)
  224. {
  225. try {
  226. screenLayoutChange(reason);
  227. writeFramebufferUpdate();
  228. } catch(rdr::Exception &e) {
  229. close(e.str());
  230. }
  231. }
  232. void VNCSConnectionST::bellOrClose()
  233. {
  234. try {
  235. if (state() == RFBSTATE_NORMAL) writer()->writeBell();
  236. } catch(rdr::Exception& e) {
  237. close(e.str());
  238. }
  239. }
  240. void VNCSConnectionST::setDesktopNameOrClose(const char *name)
  241. {
  242. try {
  243. setDesktopName(name);
  244. writeFramebufferUpdate();
  245. } catch(rdr::Exception& e) {
  246. close(e.str());
  247. }
  248. }
  249. void VNCSConnectionST::setCursorOrClose()
  250. {
  251. try {
  252. setCursor();
  253. writeFramebufferUpdate();
  254. } catch(rdr::Exception& e) {
  255. close(e.str());
  256. }
  257. }
  258. void VNCSConnectionST::setLEDStateOrClose(unsigned int state)
  259. {
  260. try {
  261. setLEDState(state);
  262. writeFramebufferUpdate();
  263. } catch(rdr::Exception& e) {
  264. close(e.str());
  265. }
  266. }
  267. void VNCSConnectionST::requestClipboardOrClose()
  268. {
  269. try {
  270. if (!accessCheck(AccessCutText)) return;
  271. if (!rfb::Server::acceptCutText) return;
  272. if (state() != RFBSTATE_NORMAL) return;
  273. requestClipboard();
  274. } catch(rdr::Exception& e) {
  275. close(e.str());
  276. }
  277. }
  278. void VNCSConnectionST::announceClipboardOrClose(bool available)
  279. {
  280. try {
  281. if (!accessCheck(AccessCutText)) return;
  282. if (!rfb::Server::sendCutText) return;
  283. if (state() != RFBSTATE_NORMAL) return;
  284. announceClipboard(available);
  285. } catch(rdr::Exception& e) {
  286. close(e.str());
  287. }
  288. }
  289. void VNCSConnectionST::sendClipboardDataOrClose(const char* data)
  290. {
  291. try {
  292. if (!accessCheck(AccessCutText)) return;
  293. if (!rfb::Server::sendCutText) return;
  294. if (state() != RFBSTATE_NORMAL) return;
  295. sendClipboardData(data);
  296. } catch(rdr::Exception& e) {
  297. close(e.str());
  298. }
  299. }
  300. bool VNCSConnectionST::getComparerState()
  301. {
  302. // We interpret a low compression level as an indication that the client
  303. // wants to prioritise CPU usage over bandwidth, and hence disable the
  304. // comparing update tracker.
  305. return (client.compressLevel == -1) || (client.compressLevel > 1);
  306. }
  307. // renderedCursorChange() is called whenever the server-side rendered cursor
  308. // changes shape or position. It ensures that the next update will clean up
  309. // the old rendered cursor and if necessary draw the new rendered cursor.
  310. void VNCSConnectionST::renderedCursorChange()
  311. {
  312. if (state() != RFBSTATE_NORMAL) return;
  313. // Are we switching between client-side and server-side cursor?
  314. if (clientHasCursor == needRenderedCursor())
  315. setCursorOrClose();
  316. bool hasRenderedCursor = !damagedCursorRegion.is_empty();
  317. if (hasRenderedCursor)
  318. removeRenderedCursor = true;
  319. if (needRenderedCursor()) {
  320. updateRenderedCursor = true;
  321. writeFramebufferUpdateOrClose();
  322. }
  323. }
  324. // needRenderedCursor() returns true if this client needs the server-side
  325. // rendered cursor. This may be because it does not support local cursor or
  326. // because the current cursor position has not been set by this client.
  327. // Unfortunately we can't know for sure when the current cursor position has
  328. // been set by this client. We guess that this is the case when the current
  329. // cursor position is the same as the last pointer event from this client, or
  330. // if it is a very short time since this client's last pointer event (up to a
  331. // second). [ Ideally we should do finer-grained timing here and make the time
  332. // configurable, but I don't think it's that important. ]
  333. bool VNCSConnectionST::needRenderedCursor()
  334. {
  335. if (state() != RFBSTATE_NORMAL)
  336. return false;
  337. if (!client.supportsLocalCursor())
  338. return true;
  339. if (!server->getCursorPos().equals(pointerEventPos) &&
  340. (time(0) - pointerEventTime) > 0)
  341. return true;
  342. return false;
  343. }
  344. void VNCSConnectionST::approveConnectionOrClose(bool accept,
  345. const char* reason)
  346. {
  347. try {
  348. approveConnection(accept, reason);
  349. } catch (rdr::Exception& e) {
  350. close(e.str());
  351. }
  352. }
  353. // -=- Callbacks from SConnection
  354. void VNCSConnectionST::authSuccess()
  355. {
  356. if (rfb::Server::idleTimeout)
  357. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  358. // - Set the connection parameters appropriately
  359. client.setDimensions(server->getPixelBuffer()->width(),
  360. server->getPixelBuffer()->height(),
  361. server->getScreenLayout());
  362. client.setName(server->getName());
  363. client.setLEDState(server->getLEDState());
  364. // - Set the default pixel format
  365. client.setPF(server->getPixelBuffer()->getPF());
  366. char buffer[256];
  367. client.pf().print(buffer, 256);
  368. vlog.info("Server default pixel format %s", buffer);
  369. // - Mark the entire display as "dirty"
  370. updates.add_changed(server->getPixelBuffer()->getRect());
  371. }
  372. void VNCSConnectionST::authFailure(const char* reason)
  373. {
  374. // Introduce a slight delay of the authentication failure response
  375. // to make it difficult to brute force a password
  376. authFailureMsg.replaceBuf(strDup(reason));
  377. authFailureTimer.start(100);
  378. }
  379. void VNCSConnectionST::queryConnection(const char* userName)
  380. {
  381. server->queryConnection(this, userName);
  382. }
  383. void VNCSConnectionST::clientInit(bool shared)
  384. {
  385. if (rfb::Server::idleTimeout)
  386. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  387. if (rfb::Server::alwaysShared || reverseConnection) shared = true;
  388. if (!accessCheck(AccessNonShared)) shared = true;
  389. if (rfb::Server::neverShared) shared = false;
  390. SConnection::clientInit(shared);
  391. server->clientReady(this, shared);
  392. }
  393. void VNCSConnectionST::setPixelFormat(const PixelFormat& pf)
  394. {
  395. SConnection::setPixelFormat(pf);
  396. char buffer[256];
  397. pf.print(buffer, 256);
  398. vlog.info("Client pixel format %s", buffer);
  399. setCursor();
  400. }
  401. void VNCSConnectionST::pointerEvent(const Point& pos, int buttonMask)
  402. {
  403. if (rfb::Server::idleTimeout)
  404. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  405. pointerEventTime = time(0);
  406. if (!accessCheck(AccessPtrEvents)) return;
  407. if (!rfb::Server::acceptPointerEvents) return;
  408. pointerEventPos = pos;
  409. server->pointerEvent(this, pointerEventPos, buttonMask);
  410. }
  411. class VNCSConnectionSTShiftPresser {
  412. public:
  413. VNCSConnectionSTShiftPresser(VNCServerST* server_)
  414. : server(server_), pressed(false) {}
  415. ~VNCSConnectionSTShiftPresser() {
  416. if (pressed) {
  417. vlog.debug("Releasing fake Shift_L");
  418. server->keyEvent(XK_Shift_L, 0, false);
  419. }
  420. }
  421. void press() {
  422. vlog.debug("Pressing fake Shift_L");
  423. server->keyEvent(XK_Shift_L, 0, true);
  424. pressed = true;
  425. }
  426. VNCServerST* server;
  427. bool pressed;
  428. };
  429. // keyEvent() - record in the pressedKeys which keys were pressed. Allow
  430. // multiple down events (for autorepeat), but only allow a single up event.
  431. void VNCSConnectionST::keyEvent(rdr::U32 keysym, rdr::U32 keycode, bool down) {
  432. rdr::U32 lookup;
  433. if (rfb::Server::idleTimeout)
  434. idleTimer.start(secsToMillis(rfb::Server::idleTimeout));
  435. if (!accessCheck(AccessKeyEvents)) return;
  436. if (!rfb::Server::acceptKeyEvents) return;
  437. if (down)
  438. vlog.debug("Key pressed: 0x%x / 0x%x", keysym, keycode);
  439. else
  440. vlog.debug("Key released: 0x%x / 0x%x", keysym, keycode);
  441. // Avoid lock keys if we don't know the server state
  442. if ((server->getLEDState() == ledUnknown) &&
  443. ((keysym == XK_Caps_Lock) ||
  444. (keysym == XK_Num_Lock) ||
  445. (keysym == XK_Scroll_Lock))) {
  446. vlog.debug("Ignoring lock key (e.g. caps lock)");
  447. return;
  448. }
  449. // Lock key heuristics
  450. // (only for clients that do not support the LED state extension)
  451. if (!client.supportsLEDState()) {
  452. // Always ignore ScrollLock as we don't have a heuristic
  453. // for that
  454. if (keysym == XK_Scroll_Lock) {
  455. vlog.debug("Ignoring lock key (e.g. caps lock)");
  456. return;
  457. }
  458. if (down && (server->getLEDState() != ledUnknown)) {
  459. // CapsLock synchronisation heuristic
  460. // (this assumes standard interaction between CapsLock the Shift
  461. // keys and normal characters)
  462. if (((keysym >= XK_A) && (keysym <= XK_Z)) ||
  463. ((keysym >= XK_a) && (keysym <= XK_z))) {
  464. bool uppercase, shift, lock;
  465. uppercase = (keysym >= XK_A) && (keysym <= XK_Z);
  466. shift = isShiftPressed();
  467. lock = server->getLEDState() & ledCapsLock;
  468. if (lock == (uppercase == shift)) {
  469. vlog.debug("Inserting fake CapsLock to get in sync with client");
  470. server->keyEvent(XK_Caps_Lock, 0, true);
  471. server->keyEvent(XK_Caps_Lock, 0, false);
  472. }
  473. }
  474. // NumLock synchronisation heuristic
  475. // (this is more cautious because of the differences between Unix,
  476. // Windows and macOS)
  477. if (((keysym >= XK_KP_Home) && (keysym <= XK_KP_Delete)) ||
  478. ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  479. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal)) {
  480. bool number, shift, lock;
  481. number = ((keysym >= XK_KP_0) && (keysym <= XK_KP_9)) ||
  482. (keysym == XK_KP_Separator) || (keysym == XK_KP_Decimal);
  483. shift = isShiftPressed();
  484. lock = server->getLEDState() & ledNumLock;
  485. if (shift) {
  486. // We don't know the appropriate NumLock state for when Shift
  487. // is pressed as it could be one of:
  488. //
  489. // a) A Unix client where Shift negates NumLock
  490. //
  491. // b) A Windows client where Shift only cancels NumLock
  492. //
  493. // c) A macOS client where Shift doesn't have any effect
  494. //
  495. } else if (lock == (number == shift)) {
  496. vlog.debug("Inserting fake NumLock to get in sync with client");
  497. server->keyEvent(XK_Num_Lock, 0, true);
  498. server->keyEvent(XK_Num_Lock, 0, false);
  499. }
  500. }
  501. }
  502. }
  503. // Turn ISO_Left_Tab into shifted Tab.
  504. VNCSConnectionSTShiftPresser shiftPresser(server);
  505. if (keysym == XK_ISO_Left_Tab) {
  506. if (!isShiftPressed())
  507. shiftPresser.press();
  508. keysym = XK_Tab;
  509. }
  510. // We need to be able to track keys, so generate a fake index when we
  511. // aren't given a keycode
  512. if (keycode == 0)
  513. lookup = 0x80000000 | keysym;
  514. else
  515. lookup = keycode;
  516. // We force the same keysym for an already down key for the
  517. // sake of sanity
  518. if (pressedKeys.find(lookup) != pressedKeys.end())
  519. keysym = pressedKeys[lookup];
  520. if (down) {
  521. pressedKeys[lookup] = keysym;
  522. } else {
  523. if (!pressedKeys.erase(lookup))
  524. return;
  525. }
  526. server->keyEvent(keysym, keycode, down);
  527. }
  528. void VNCSConnectionST::framebufferUpdateRequest(const Rect& r,bool incremental)
  529. {
  530. Rect safeRect;
  531. if (!accessCheck(AccessView)) return;
  532. SConnection::framebufferUpdateRequest(r, incremental);
  533. // Check that the client isn't sending crappy requests
  534. if (!r.enclosed_by(Rect(0, 0, client.width(), client.height()))) {
  535. vlog.error("FramebufferUpdateRequest %dx%d at %d,%d exceeds framebuffer %dx%d",
  536. r.width(), r.height(), r.tl.x, r.tl.y,
  537. client.width(), client.height());
  538. safeRect = r.intersect(Rect(0, 0, client.width(), client.height()));
  539. } else {
  540. safeRect = r;
  541. }
  542. // Just update the requested region.
  543. // Framebuffer update will be sent a bit later, see processMessages().
  544. Region reqRgn(r);
  545. if (!incremental || !continuousUpdates)
  546. requested.assign_union(reqRgn);
  547. if (!incremental) {
  548. // Non-incremental update - treat as if area requested has changed
  549. updates.add_changed(reqRgn);
  550. // And send the screen layout to the client (which, unlike the
  551. // framebuffer dimensions, the client doesn't get during init)
  552. if (client.supportsEncoding(pseudoEncodingExtendedDesktopSize))
  553. writer()->writeDesktopSize(reasonServer);
  554. // We do not send a DesktopSize since it only contains the
  555. // framebuffer size (which the client already should know) and
  556. // because some clients don't handle extra DesktopSize events
  557. // very well.
  558. }
  559. }
  560. void VNCSConnectionST::setDesktopSize(int fb_width, int fb_height,
  561. const ScreenSet& layout)
  562. {
  563. unsigned int result;
  564. if (!accessCheck(AccessSetDesktopSize)) return;
  565. if (!rfb::Server::acceptSetDesktopSize) return;
  566. result = server->setDesktopSize(this, fb_width, fb_height, layout);
  567. writer()->writeDesktopSize(reasonClient, result);
  568. }
  569. void VNCSConnectionST::fence(rdr::U32 flags, unsigned len, const char data[])
  570. {
  571. rdr::U8 type;
  572. if (flags & fenceFlagRequest) {
  573. if (flags & fenceFlagSyncNext) {
  574. pendingSyncFence = true;
  575. fenceFlags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter | fenceFlagSyncNext);
  576. fenceDataLen = len;
  577. delete [] fenceData;
  578. fenceData = NULL;
  579. if (len > 0) {
  580. fenceData = new char[len];
  581. memcpy(fenceData, data, len);
  582. }
  583. return;
  584. }
  585. // We handle everything synchronously so we trivially honor these modes
  586. flags = flags & (fenceFlagBlockBefore | fenceFlagBlockAfter);
  587. writer()->writeFence(flags, len, data);
  588. return;
  589. }
  590. if (len < 1)
  591. vlog.error("Fence response of unexpected size received");
  592. type = data[0];
  593. switch (type) {
  594. case 0:
  595. // Initial dummy fence;
  596. break;
  597. case 1:
  598. congestion.gotPong();
  599. break;
  600. default:
  601. vlog.error("Fence response of unexpected type received");
  602. }
  603. }
  604. void VNCSConnectionST::enableContinuousUpdates(bool enable,
  605. int x, int y, int w, int h)
  606. {
  607. Rect rect;
  608. if (!client.supportsFence() || !client.supportsContinuousUpdates())
  609. throw Exception("Client tried to enable continuous updates when not allowed");
  610. continuousUpdates = enable;
  611. rect.setXYWH(x, y, w, h);
  612. cuRegion.reset(rect);
  613. if (enable) {
  614. requested.clear();
  615. } else {
  616. writer()->writeEndOfContinuousUpdates();
  617. }
  618. }
  619. void VNCSConnectionST::handleClipboardRequest()
  620. {
  621. if (!accessCheck(AccessCutText)) return;
  622. server->handleClipboardRequest(this);
  623. }
  624. void VNCSConnectionST::handleClipboardAnnounce(bool available)
  625. {
  626. if (!accessCheck(AccessCutText)) return;
  627. if (!rfb::Server::acceptCutText) return;
  628. server->handleClipboardAnnounce(this, available);
  629. }
  630. void VNCSConnectionST::handleClipboardData(const char* data)
  631. {
  632. if (!accessCheck(AccessCutText)) return;
  633. if (!rfb::Server::acceptCutText) return;
  634. server->handleClipboardData(this, data);
  635. }
  636. // supportsLocalCursor() is called whenever the status of
  637. // client.supportsLocalCursor() has changed. If the client does now support local
  638. // cursor, we make sure that the old server-side rendered cursor is cleaned up
  639. // and the cursor is sent to the client.
  640. void VNCSConnectionST::supportsLocalCursor()
  641. {
  642. bool hasRenderedCursor = !damagedCursorRegion.is_empty();
  643. if (hasRenderedCursor && !needRenderedCursor())
  644. removeRenderedCursor = true;
  645. setCursor();
  646. }
  647. void VNCSConnectionST::supportsFence()
  648. {
  649. char type = 0;
  650. writer()->writeFence(fenceFlagRequest, sizeof(type), &type);
  651. }
  652. void VNCSConnectionST::supportsContinuousUpdates()
  653. {
  654. // We refuse to use continuous updates if we cannot monitor the buffer
  655. // usage using fences.
  656. if (!client.supportsFence())
  657. return;
  658. writer()->writeEndOfContinuousUpdates();
  659. }
  660. void VNCSConnectionST::supportsLEDState()
  661. {
  662. if (client.ledState() == ledUnknown)
  663. return;
  664. writer()->writeLEDState();
  665. }
  666. bool VNCSConnectionST::handleTimeout(Timer* t)
  667. {
  668. try {
  669. if ((t == &congestionTimer) ||
  670. (t == &losslessTimer))
  671. writeFramebufferUpdate();
  672. else if (t == &authFailureTimer)
  673. SConnection::authFailure(authFailureMsg.buf);
  674. } catch (rdr::Exception& e) {
  675. close(e.str());
  676. }
  677. if (t == &idleTimer)
  678. close("Idle timeout");
  679. return false;
  680. }
  681. bool VNCSConnectionST::isShiftPressed()
  682. {
  683. std::map<rdr::U32, rdr::U32>::const_iterator iter;
  684. for (iter = pressedKeys.begin(); iter != pressedKeys.end(); ++iter) {
  685. if (iter->second == XK_Shift_L)
  686. return true;
  687. if (iter->second == XK_Shift_R)
  688. return true;
  689. }
  690. return false;
  691. }
  692. void VNCSConnectionST::writeRTTPing()
  693. {
  694. char type;
  695. if (!client.supportsFence())
  696. return;
  697. congestion.updatePosition(sock->outStream().length());
  698. // We need to make sure any old update are already processed by the
  699. // time we get the response back. This allows us to reliably throttle
  700. // back on client overload, as well as network overload.
  701. type = 1;
  702. writer()->writeFence(fenceFlagRequest | fenceFlagBlockBefore,
  703. sizeof(type), &type);
  704. congestion.sentPing();
  705. }
  706. bool VNCSConnectionST::isCongested()
  707. {
  708. int eta;
  709. congestionTimer.stop();
  710. // Stuff still waiting in the send buffer?
  711. sock->outStream().flush();
  712. congestion.debugTrace("congestion-trace.csv", sock->getFd());
  713. if (sock->outStream().bufferUsage() > 0)
  714. return true;
  715. if (!client.supportsFence())
  716. return false;
  717. congestion.updatePosition(sock->outStream().length());
  718. if (!congestion.isCongested())
  719. return false;
  720. eta = congestion.getUncongestedETA();
  721. if (eta >= 0)
  722. congestionTimer.start(eta);
  723. return true;
  724. }
  725. void VNCSConnectionST::writeFramebufferUpdate()
  726. {
  727. congestion.updatePosition(sock->outStream().length());
  728. // We're in the middle of processing a command that's supposed to be
  729. // synchronised. Allowing an update to slip out right now might violate
  730. // that synchronisation.
  731. if (syncFence)
  732. return;
  733. // We try to aggregate responses, so don't send out anything whilst we
  734. // still have incoming messages. processMessages() will give us another
  735. // chance to run once things are idle.
  736. if (inProcessMessages)
  737. return;
  738. if (state() != RFBSTATE_NORMAL)
  739. return;
  740. if (requested.is_empty() && !continuousUpdates)
  741. return;
  742. // Check that we actually have some space on the link and retry in a
  743. // bit if things are congested.
  744. if (isCongested())
  745. return;
  746. // Updates often consists of many small writes, and in continuous
  747. // mode, we will also have small fence messages around the update. We
  748. // need to aggregate these in order to not clog up TCP's congestion
  749. // window.
  750. sock->cork(true);
  751. // First take care of any updates that cannot contain framebuffer data
  752. // changes.
  753. writeNoDataUpdate();
  754. // Then real data (if possible)
  755. writeDataUpdate();
  756. sock->cork(false);
  757. congestion.updatePosition(sock->outStream().length());
  758. }
  759. void VNCSConnectionST::writeNoDataUpdate()
  760. {
  761. if (!writer()->needNoDataUpdate())
  762. return;
  763. writer()->writeNoDataUpdate();
  764. // Make sure no data update is sent until next request
  765. requested.clear();
  766. }
  767. void VNCSConnectionST::writeDataUpdate()
  768. {
  769. Region req;
  770. UpdateInfo ui;
  771. bool needNewUpdateInfo;
  772. const RenderedCursor *cursor;
  773. // See what the client has requested (if anything)
  774. if (continuousUpdates)
  775. req = cuRegion.union_(requested);
  776. else
  777. req = requested;
  778. if (req.is_empty())
  779. return;
  780. // Get the lists of updates. Prior to exporting the data to the `ui' object,
  781. // getUpdateInfo() will normalize the `updates' object such way that its
  782. // `changed' and `copied' regions would not intersect.
  783. updates.getUpdateInfo(&ui, req);
  784. needNewUpdateInfo = false;
  785. // If the previous position of the rendered cursor overlaps the source of the
  786. // copy, then when the copy happens the corresponding rectangle in the
  787. // destination will be wrong, so add it to the changed region.
  788. if (!ui.copied.is_empty() && !damagedCursorRegion.is_empty()) {
  789. Region bogusCopiedCursor;
  790. bogusCopiedCursor = damagedCursorRegion;
  791. bogusCopiedCursor.translate(ui.copy_delta);
  792. bogusCopiedCursor.assign_intersect(server->getPixelBuffer()->getRect());
  793. if (!ui.copied.intersect(bogusCopiedCursor).is_empty()) {
  794. updates.add_changed(bogusCopiedCursor);
  795. needNewUpdateInfo = true;
  796. }
  797. }
  798. // If we need to remove the old rendered cursor, just add the region to
  799. // the changed region.
  800. if (removeRenderedCursor) {
  801. updates.add_changed(damagedCursorRegion);
  802. needNewUpdateInfo = true;
  803. damagedCursorRegion.clear();
  804. removeRenderedCursor = false;
  805. }
  806. // If we need a full cursor update then make sure its entire region
  807. // is marked as changed.
  808. if (updateRenderedCursor) {
  809. updates.add_changed(server->getRenderedCursor()->getEffectiveRect());
  810. needNewUpdateInfo = true;
  811. updateRenderedCursor = false;
  812. }
  813. // The `updates' object could change, make sure we have valid update info.
  814. if (needNewUpdateInfo)
  815. updates.getUpdateInfo(&ui, req);
  816. // If there are queued updates then we cannot safely send an update
  817. // without risking a partially updated screen
  818. if (!server->getPendingRegion().is_empty()) {
  819. req.clear();
  820. ui.changed.clear();
  821. ui.copied.clear();
  822. }
  823. // Does the client need a server-side rendered cursor?
  824. cursor = NULL;
  825. if (needRenderedCursor()) {
  826. Rect renderedCursorRect;
  827. cursor = server->getRenderedCursor();
  828. renderedCursorRect = cursor->getEffectiveRect();
  829. // Check that we don't try to copy over the cursor area, and
  830. // if that happens we need to treat it as changed so that we can
  831. // re-render it
  832. if (!ui.copied.intersect(renderedCursorRect).is_empty()) {
  833. ui.changed.assign_union(ui.copied.intersect(renderedCursorRect));
  834. ui.copied.assign_subtract(renderedCursorRect);
  835. }
  836. // Track where we've rendered the cursor
  837. damagedCursorRegion.assign_union(ui.changed.intersect(renderedCursorRect));
  838. }
  839. // If we don't have a normal update, then try a lossless refresh
  840. if (ui.is_empty() && !writer()->needFakeUpdate()) {
  841. writeLosslessRefresh();
  842. return;
  843. }
  844. // We have something to send, so let's get to it
  845. writeRTTPing();
  846. encodeManager.writeUpdate(ui, server->getPixelBuffer(), cursor);
  847. writeRTTPing();
  848. // The request might be for just part of the screen, so we cannot
  849. // just clear the entire update tracker.
  850. updates.subtract(req);
  851. requested.clear();
  852. }
  853. void VNCSConnectionST::writeLosslessRefresh()
  854. {
  855. Region req, pending;
  856. const RenderedCursor *cursor;
  857. int nextRefresh, nextUpdate;
  858. size_t bandwidth, maxUpdateSize;
  859. if (continuousUpdates)
  860. req = cuRegion.union_(requested);
  861. else
  862. req = requested;
  863. // If there are queued updates then we could not safely send an
  864. // update without risking a partially updated screen, however we
  865. // might still be able to send a lossless refresh
  866. pending = server->getPendingRegion();
  867. if (!pending.is_empty()) {
  868. UpdateInfo ui;
  869. // Don't touch the updates pending in the server core
  870. req.assign_subtract(pending);
  871. // Or any updates pending just for this connection
  872. updates.getUpdateInfo(&ui, req);
  873. req.assign_subtract(ui.changed);
  874. req.assign_subtract(ui.copied);
  875. }
  876. // Any lossy area we can refresh?
  877. if (!encodeManager.needsLosslessRefresh(req))
  878. return;
  879. // Right away? Or later?
  880. nextRefresh = encodeManager.getNextLosslessRefresh(req);
  881. if (nextRefresh > 0) {
  882. losslessTimer.start(nextRefresh);
  883. return;
  884. }
  885. // Prepare the cursor in case it overlaps with a region getting
  886. // refreshed
  887. cursor = NULL;
  888. if (needRenderedCursor())
  889. cursor = server->getRenderedCursor();
  890. // FIXME: If continuous updates aren't used then the client might
  891. // be slower than frameRate in its requests and we could
  892. // afford a larger update size
  893. nextUpdate = server->msToNextUpdate();
  894. // Don't bother if we're about to send a real update
  895. if (nextUpdate == 0)
  896. return;
  897. // FIXME: Bandwidth estimation without congestion control
  898. bandwidth = congestion.getBandwidth();
  899. // FIXME: Hard coded value for maximum CPU throughput
  900. if (bandwidth > 5000000)
  901. bandwidth = 5000000;
  902. maxUpdateSize = bandwidth * nextUpdate / 1000;
  903. writeRTTPing();
  904. encodeManager.writeLosslessRefresh(req, server->getPixelBuffer(),
  905. cursor, maxUpdateSize);
  906. writeRTTPing();
  907. requested.clear();
  908. }
  909. void VNCSConnectionST::screenLayoutChange(rdr::U16 reason)
  910. {
  911. if (!authenticated())
  912. return;
  913. client.setDimensions(client.width(), client.height(),
  914. server->getScreenLayout());
  915. if (state() != RFBSTATE_NORMAL)
  916. return;
  917. writer()->writeDesktopSize(reason);
  918. }
  919. // setCursor() is called whenever the cursor has changed shape or pixel format.
  920. // If the client supports local cursor then it will arrange for the cursor to
  921. // be sent to the client.
  922. void VNCSConnectionST::setCursor()
  923. {
  924. if (state() != RFBSTATE_NORMAL)
  925. return;
  926. // We need to blank out the client's cursor or there will be two
  927. if (needRenderedCursor()) {
  928. client.setCursor(emptyCursor);
  929. clientHasCursor = false;
  930. } else {
  931. client.setCursor(*server->getCursor());
  932. clientHasCursor = true;
  933. }
  934. if (client.supportsLocalCursor())
  935. writer()->writeCursor();
  936. }
  937. void VNCSConnectionST::setDesktopName(const char *name)
  938. {
  939. client.setName(name);
  940. if (state() != RFBSTATE_NORMAL)
  941. return;
  942. if (client.supportsEncoding(pseudoEncodingDesktopName))
  943. writer()->writeSetDesktopName();
  944. }
  945. void VNCSConnectionST::setLEDState(unsigned int ledstate)
  946. {
  947. if (state() != RFBSTATE_NORMAL)
  948. return;
  949. client.setLEDState(ledstate);
  950. if (client.supportsLEDState())
  951. writer()->writeLEDState();
  952. }
  953. void VNCSConnectionST::setSocketTimeouts()
  954. {
  955. int timeoutms = rfb::Server::clientWaitTimeMillis;
  956. if (timeoutms == 0)
  957. timeoutms = -1;
  958. sock->inStream().setTimeout(timeoutms);
  959. sock->outStream().setTimeout(timeoutms);
  960. }