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.

VNCServerST.cxx 21KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright 2009-2018 Pierre Ossman for Cendio AB
  3. *
  4. * This is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 2 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This software is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this software; if not, write to the Free Software
  16. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  17. * USA.
  18. */
  19. // -=- Single-Threaded VNC Server implementation
  20. // Note about how sockets get closed:
  21. //
  22. // Closing sockets to clients is non-trivial because the code which calls
  23. // VNCServerST must explicitly know about all the sockets (so that it can block
  24. // on them appropriately). However, VNCServerST may want to close clients for
  25. // a number of reasons, and from a variety of entry points. The simplest is
  26. // when processSocketEvent() is called for a client, and the remote end has
  27. // closed its socket. A more complex reason is when processSocketEvent() is
  28. // called for a client which has just sent a ClientInit with the shared flag
  29. // set to false - in this case we want to close all other clients. Yet another
  30. // reason for disconnecting clients is when the desktop size has changed as a
  31. // result of a call to setPixelBuffer().
  32. //
  33. // The responsibility for creating and deleting sockets is entirely with the
  34. // calling code. When VNCServerST wants to close a connection to a client it
  35. // calls the VNCSConnectionST's close() method which calls shutdown() on the
  36. // socket. Eventually the calling code will notice that the socket has been
  37. // shut down and call removeSocket() so that we can delete the
  38. // VNCSConnectionST. Note that the socket must not be deleted by the calling
  39. // code until after removeSocket() has been called.
  40. //
  41. // One minor complication is that we don't allocate a VNCSConnectionST object
  42. // for a blacklisted host (since we want to minimise the resources used for
  43. // dealing with such a connection). In order to properly implement the
  44. // getSockets function, we must maintain a separate closingSockets list,
  45. // otherwise blacklisted connections might be "forgotten".
  46. #include <assert.h>
  47. #include <stdlib.h>
  48. #include <rfb/ComparingUpdateTracker.h>
  49. #include <rfb/KeyRemapper.h>
  50. #include <rfb/ListConnInfo.h>
  51. #include <rfb/Security.h>
  52. #include <rfb/ServerCore.h>
  53. #include <rfb/VNCServerST.h>
  54. #include <rfb/VNCSConnectionST.h>
  55. #include <rfb/util.h>
  56. #include <rfb/ledStates.h>
  57. #include <rdr/types.h>
  58. using namespace rfb;
  59. static LogWriter slog("VNCServerST");
  60. LogWriter VNCServerST::connectionsLog("Connections");
  61. //
  62. // -=- VNCServerST Implementation
  63. //
  64. // -=- Constructors/Destructor
  65. VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
  66. : blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
  67. blockCounter(0), pb(0), ledState(ledUnknown),
  68. name(strDup(name_)), pointerClient(0), comparer(0),
  69. cursor(new Cursor(0, 0, Point(), NULL)),
  70. renderedCursorInvalid(false),
  71. queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
  72. lastConnectionTime(0), disableclients(false),
  73. frameTimer(this)
  74. {
  75. lastUserInputTime = lastDisconnectTime = time(0);
  76. slog.debug("creating single-threaded server %s", name.buf);
  77. }
  78. VNCServerST::~VNCServerST()
  79. {
  80. slog.debug("shutting down server %s", name.buf);
  81. // Close any active clients, with appropriate logging & cleanup
  82. closeClients("Server shutdown");
  83. // Stop trying to render things
  84. stopFrameClock();
  85. // Delete all the clients, and their sockets, and any closing sockets
  86. // NB: Deleting a client implicitly removes it from the clients list
  87. while (!clients.empty()) {
  88. delete clients.front();
  89. }
  90. // Stop the desktop object if active, *only* after deleting all clients!
  91. stopDesktop();
  92. if (comparer)
  93. comparer->logStats();
  94. delete comparer;
  95. delete cursor;
  96. }
  97. // SocketServer methods
  98. void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
  99. {
  100. // - Check the connection isn't black-marked
  101. // *** do this in getSecurity instead?
  102. CharArray address(sock->getPeerAddress());
  103. if (blHosts->isBlackmarked(address.buf)) {
  104. connectionsLog.error("blacklisted: %s", address.buf);
  105. try {
  106. SConnection::writeConnFailedFromScratch("Too many security failures",
  107. &sock->outStream());
  108. } catch (rdr::Exception&) {
  109. }
  110. sock->shutdown();
  111. closingSockets.push_back(sock);
  112. return;
  113. }
  114. if (clients.empty()) {
  115. lastConnectionTime = time(0);
  116. }
  117. VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
  118. client->init();
  119. }
  120. void VNCServerST::removeSocket(network::Socket* sock) {
  121. // - If the socket has resources allocated to it, delete them
  122. std::list<VNCSConnectionST*>::iterator ci;
  123. for (ci = clients.begin(); ci != clients.end(); ci++) {
  124. if ((*ci)->getSock() == sock) {
  125. // - Delete the per-Socket resources
  126. delete *ci;
  127. // - Check that the desktop object is still required
  128. if (authClientCount() == 0)
  129. stopDesktop();
  130. if (comparer)
  131. comparer->logStats();
  132. return;
  133. }
  134. }
  135. // - If the Socket has no resources, it may have been a closingSocket
  136. closingSockets.remove(sock);
  137. }
  138. void VNCServerST::processSocketReadEvent(network::Socket* sock)
  139. {
  140. // - Find the appropriate VNCSConnectionST and process the event
  141. std::list<VNCSConnectionST*>::iterator ci;
  142. for (ci = clients.begin(); ci != clients.end(); ci++) {
  143. if ((*ci)->getSock() == sock) {
  144. (*ci)->processMessages();
  145. return;
  146. }
  147. }
  148. throw rdr::Exception("invalid Socket in VNCServerST");
  149. }
  150. void VNCServerST::processSocketWriteEvent(network::Socket* sock)
  151. {
  152. // - Find the appropriate VNCSConnectionST and process the event
  153. std::list<VNCSConnectionST*>::iterator ci;
  154. for (ci = clients.begin(); ci != clients.end(); ci++) {
  155. if ((*ci)->getSock() == sock) {
  156. (*ci)->flushSocket();
  157. return;
  158. }
  159. }
  160. throw rdr::Exception("invalid Socket in VNCServerST");
  161. }
  162. int VNCServerST::checkTimeouts()
  163. {
  164. int timeout = 0;
  165. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  166. soonestTimeout(&timeout, Timer::checkTimeouts());
  167. for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
  168. ci_next = ci; ci_next++;
  169. soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
  170. }
  171. int timeLeft;
  172. time_t now = time(0);
  173. // Check MaxDisconnectionTime
  174. if (rfb::Server::maxDisconnectionTime && clients.empty()) {
  175. if (now < lastDisconnectTime) {
  176. // Someone must have set the time backwards.
  177. slog.info("Time has gone backwards - resetting lastDisconnectTime");
  178. lastDisconnectTime = now;
  179. }
  180. timeLeft = lastDisconnectTime + rfb::Server::maxDisconnectionTime - now;
  181. if (timeLeft < -60) {
  182. // Someone must have set the time forwards.
  183. slog.info("Time has gone forwards - resetting lastDisconnectTime");
  184. lastDisconnectTime = now;
  185. timeLeft = rfb::Server::maxDisconnectionTime;
  186. }
  187. if (timeLeft <= 0) {
  188. slog.info("MaxDisconnectionTime reached, exiting");
  189. exit(0);
  190. }
  191. soonestTimeout(&timeout, timeLeft * 1000);
  192. }
  193. // Check MaxConnectionTime
  194. if (rfb::Server::maxConnectionTime && lastConnectionTime && !clients.empty()) {
  195. if (now < lastConnectionTime) {
  196. // Someone must have set the time backwards.
  197. slog.info("Time has gone backwards - resetting lastConnectionTime");
  198. lastConnectionTime = now;
  199. }
  200. timeLeft = lastConnectionTime + rfb::Server::maxConnectionTime - now;
  201. if (timeLeft < -60) {
  202. // Someone must have set the time forwards.
  203. slog.info("Time has gone forwards - resetting lastConnectionTime");
  204. lastConnectionTime = now;
  205. timeLeft = rfb::Server::maxConnectionTime;
  206. }
  207. if (timeLeft <= 0) {
  208. slog.info("MaxConnectionTime reached, exiting");
  209. exit(0);
  210. }
  211. soonestTimeout(&timeout, timeLeft * 1000);
  212. }
  213. // Check MaxIdleTime
  214. if (rfb::Server::maxIdleTime) {
  215. if (now < lastUserInputTime) {
  216. // Someone must have set the time backwards.
  217. slog.info("Time has gone backwards - resetting lastUserInputTime");
  218. lastUserInputTime = now;
  219. }
  220. timeLeft = lastUserInputTime + rfb::Server::maxIdleTime - now;
  221. if (timeLeft < -60) {
  222. // Someone must have set the time forwards.
  223. slog.info("Time has gone forwards - resetting lastUserInputTime");
  224. lastUserInputTime = now;
  225. timeLeft = rfb::Server::maxIdleTime;
  226. }
  227. if (timeLeft <= 0) {
  228. slog.info("MaxIdleTime reached, exiting");
  229. exit(0);
  230. }
  231. soonestTimeout(&timeout, timeLeft * 1000);
  232. }
  233. return timeout;
  234. }
  235. // VNCServer methods
  236. void VNCServerST::blockUpdates()
  237. {
  238. blockCounter++;
  239. stopFrameClock();
  240. }
  241. void VNCServerST::unblockUpdates()
  242. {
  243. assert(blockCounter > 0);
  244. blockCounter--;
  245. // Restart the frame clock if we have updates
  246. if (blockCounter == 0) {
  247. if (!comparer->is_empty())
  248. startFrameClock();
  249. }
  250. }
  251. void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout)
  252. {
  253. if (comparer)
  254. comparer->logStats();
  255. pb = pb_;
  256. delete comparer;
  257. comparer = 0;
  258. if (!pb) {
  259. screenLayout = ScreenSet();
  260. if (desktopStarted)
  261. throw Exception("setPixelBuffer: null PixelBuffer when desktopStarted?");
  262. return;
  263. }
  264. if (!layout.validate(pb->width(), pb->height()))
  265. throw Exception("setPixelBuffer: invalid screen layout");
  266. screenLayout = layout;
  267. // Assume the framebuffer contents wasn't saved and reset everything
  268. // that tracks its contents
  269. comparer = new ComparingUpdateTracker(pb);
  270. renderedCursorInvalid = true;
  271. add_changed(pb->getRect());
  272. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  273. for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
  274. ci_next = ci; ci_next++;
  275. (*ci)->pixelBufferChange();
  276. // Since the new pixel buffer means an ExtendedDesktopSize needs to
  277. // be sent anyway, we don't need to call screenLayoutChange.
  278. }
  279. }
  280. void VNCServerST::setPixelBuffer(PixelBuffer* pb_)
  281. {
  282. ScreenSet layout = screenLayout;
  283. // Check that the screen layout is still valid
  284. if (pb_ && !layout.validate(pb_->width(), pb_->height())) {
  285. Rect fbRect;
  286. ScreenSet::iterator iter, iter_next;
  287. fbRect.setXYWH(0, 0, pb_->width(), pb_->height());
  288. for (iter = layout.begin();iter != layout.end();iter = iter_next) {
  289. iter_next = iter; ++iter_next;
  290. if (iter->dimensions.enclosed_by(fbRect))
  291. continue;
  292. iter->dimensions = iter->dimensions.intersect(fbRect);
  293. if (iter->dimensions.is_empty()) {
  294. slog.info("Removing screen %d (%x) as it is completely outside the new framebuffer",
  295. (int)iter->id, (unsigned)iter->id);
  296. layout.remove_screen(iter->id);
  297. }
  298. }
  299. }
  300. // Make sure that we have at least one screen
  301. if (layout.num_screens() == 0)
  302. layout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0));
  303. setPixelBuffer(pb_, layout);
  304. }
  305. void VNCServerST::setScreenLayout(const ScreenSet& layout)
  306. {
  307. if (!pb)
  308. throw Exception("setScreenLayout: new screen layout without a PixelBuffer");
  309. if (!layout.validate(pb->width(), pb->height()))
  310. throw Exception("setScreenLayout: invalid screen layout");
  311. screenLayout = layout;
  312. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  313. for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
  314. ci_next = ci; ci_next++;
  315. (*ci)->screenLayoutChangeOrClose(reasonServer);
  316. }
  317. }
  318. void VNCServerST::bell()
  319. {
  320. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  321. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  322. ci_next = ci; ci_next++;
  323. (*ci)->bellOrClose();
  324. }
  325. }
  326. void VNCServerST::serverCutText(const char* str, int len)
  327. {
  328. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  329. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  330. ci_next = ci; ci_next++;
  331. (*ci)->serverCutTextOrClose(str, len);
  332. }
  333. }
  334. void VNCServerST::setName(const char* name_)
  335. {
  336. name.replaceBuf(strDup(name_));
  337. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  338. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  339. ci_next = ci; ci_next++;
  340. (*ci)->setDesktopNameOrClose(name_);
  341. }
  342. }
  343. void VNCServerST::add_changed(const Region& region)
  344. {
  345. if (comparer == NULL)
  346. return;
  347. comparer->add_changed(region);
  348. startFrameClock();
  349. }
  350. void VNCServerST::add_copied(const Region& dest, const Point& delta)
  351. {
  352. if (comparer == NULL)
  353. return;
  354. comparer->add_copied(dest, delta);
  355. startFrameClock();
  356. }
  357. void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
  358. const rdr::U8* data)
  359. {
  360. delete cursor;
  361. cursor = new Cursor(width, height, newHotspot, data);
  362. cursor->crop();
  363. renderedCursorInvalid = true;
  364. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  365. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  366. ci_next = ci; ci_next++;
  367. (*ci)->renderedCursorChange();
  368. (*ci)->setCursorOrClose();
  369. }
  370. }
  371. void VNCServerST::setCursorPos(const Point& pos)
  372. {
  373. if (!cursorPos.equals(pos)) {
  374. cursorPos = pos;
  375. renderedCursorInvalid = true;
  376. std::list<VNCSConnectionST*>::iterator ci;
  377. for (ci = clients.begin(); ci != clients.end(); ci++)
  378. (*ci)->renderedCursorChange();
  379. }
  380. }
  381. void VNCServerST::setLEDState(unsigned int state)
  382. {
  383. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  384. if (state == ledState)
  385. return;
  386. ledState = state;
  387. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  388. ci_next = ci; ci_next++;
  389. (*ci)->setLEDStateOrClose(state);
  390. }
  391. }
  392. // Other public methods
  393. void VNCServerST::approveConnection(network::Socket* sock, bool accept,
  394. const char* reason)
  395. {
  396. std::list<VNCSConnectionST*>::iterator ci;
  397. for (ci = clients.begin(); ci != clients.end(); ci++) {
  398. if ((*ci)->getSock() == sock) {
  399. (*ci)->approveConnectionOrClose(accept, reason);
  400. return;
  401. }
  402. }
  403. }
  404. void VNCServerST::closeClients(const char* reason, network::Socket* except)
  405. {
  406. std::list<VNCSConnectionST*>::iterator i, next_i;
  407. for (i=clients.begin(); i!=clients.end(); i=next_i) {
  408. next_i = i; next_i++;
  409. if ((*i)->getSock() != except)
  410. (*i)->close(reason);
  411. }
  412. }
  413. void VNCServerST::getSockets(std::list<network::Socket*>* sockets)
  414. {
  415. sockets->clear();
  416. std::list<VNCSConnectionST*>::iterator ci;
  417. for (ci = clients.begin(); ci != clients.end(); ci++) {
  418. sockets->push_back((*ci)->getSock());
  419. }
  420. std::list<network::Socket*>::iterator si;
  421. for (si = closingSockets.begin(); si != closingSockets.end(); si++) {
  422. sockets->push_back(*si);
  423. }
  424. }
  425. SConnection* VNCServerST::getSConnection(network::Socket* sock) {
  426. std::list<VNCSConnectionST*>::iterator ci;
  427. for (ci = clients.begin(); ci != clients.end(); ci++) {
  428. if ((*ci)->getSock() == sock)
  429. return *ci;
  430. }
  431. return 0;
  432. }
  433. bool VNCServerST::handleTimeout(Timer* t)
  434. {
  435. if (t == &frameTimer) {
  436. // We keep running until we go a full interval without any updates
  437. if (comparer->is_empty())
  438. return false;
  439. writeUpdate();
  440. // If this is the first iteration then we need to adjust the timeout
  441. if (frameTimer.getTimeoutMs() != 1000/rfb::Server::frameRate) {
  442. frameTimer.start(1000/rfb::Server::frameRate);
  443. return false;
  444. }
  445. return true;
  446. }
  447. return false;
  448. }
  449. // -=- Internal methods
  450. void VNCServerST::startDesktop()
  451. {
  452. if (!desktopStarted) {
  453. slog.debug("starting desktop");
  454. desktop->start(this);
  455. if (!pb)
  456. throw Exception("SDesktop::start() did not set a valid PixelBuffer");
  457. desktopStarted = true;
  458. // The tracker might have accumulated changes whilst we were
  459. // stopped, so flush those out
  460. if (!comparer->is_empty())
  461. writeUpdate();
  462. }
  463. }
  464. void VNCServerST::stopDesktop()
  465. {
  466. if (desktopStarted) {
  467. slog.debug("stopping desktop");
  468. desktopStarted = false;
  469. desktop->stop();
  470. stopFrameClock();
  471. }
  472. }
  473. int VNCServerST::authClientCount() {
  474. int count = 0;
  475. std::list<VNCSConnectionST*>::iterator ci;
  476. for (ci = clients.begin(); ci != clients.end(); ci++) {
  477. if ((*ci)->authenticated())
  478. count++;
  479. }
  480. return count;
  481. }
  482. inline bool VNCServerST::needRenderedCursor()
  483. {
  484. std::list<VNCSConnectionST*>::iterator ci;
  485. for (ci = clients.begin(); ci != clients.end(); ci++)
  486. if ((*ci)->needRenderedCursor()) return true;
  487. return false;
  488. }
  489. void VNCServerST::startFrameClock()
  490. {
  491. if (frameTimer.isStarted())
  492. return;
  493. if (blockCounter > 0)
  494. return;
  495. if (!desktopStarted)
  496. return;
  497. // The first iteration will be just half a frame as we get a very
  498. // unstable update rate if we happen to be perfectly in sync with
  499. // the application's update rate
  500. frameTimer.start(1000/rfb::Server::frameRate/2);
  501. }
  502. void VNCServerST::stopFrameClock()
  503. {
  504. frameTimer.stop();
  505. }
  506. int VNCServerST::msToNextUpdate()
  507. {
  508. // FIXME: If the application is updating slower than frameRate then
  509. // we could allow the clients more time here
  510. if (!frameTimer.isStarted())
  511. return 1000/rfb::Server::frameRate/2;
  512. else
  513. return frameTimer.getRemainingMs();
  514. }
  515. // writeUpdate() is called on a regular interval in order to see what
  516. // updates are pending and propagates them to the update tracker for
  517. // each client. It uses the ComparingUpdateTracker's compare() method
  518. // to filter out areas of the screen which haven't actually changed. It
  519. // also checks the state of the (server-side) rendered cursor, if
  520. // necessary rendering it again with the correct background.
  521. void VNCServerST::writeUpdate()
  522. {
  523. UpdateInfo ui;
  524. Region toCheck;
  525. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  526. assert(blockCounter == 0);
  527. assert(desktopStarted);
  528. comparer->getUpdateInfo(&ui, pb->getRect());
  529. toCheck = ui.changed.union_(ui.copied);
  530. if (needRenderedCursor()) {
  531. Rect clippedCursorRect = Rect(0, 0, cursor->width(), cursor->height())
  532. .translate(cursorPos.subtract(cursor->hotspot()))
  533. .intersect(pb->getRect());
  534. if (!toCheck.intersect(clippedCursorRect).is_empty())
  535. renderedCursorInvalid = true;
  536. }
  537. pb->grabRegion(toCheck);
  538. if (getComparerState())
  539. comparer->enable();
  540. else
  541. comparer->disable();
  542. if (comparer->compare())
  543. comparer->getUpdateInfo(&ui, pb->getRect());
  544. comparer->clear();
  545. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  546. ci_next = ci; ci_next++;
  547. (*ci)->add_copied(ui.copied, ui.copy_delta);
  548. (*ci)->add_changed(ui.changed);
  549. (*ci)->writeFramebufferUpdateOrClose();
  550. }
  551. }
  552. // checkUpdate() is called by clients to see if it is safe to read from
  553. // the framebuffer at this time.
  554. Region VNCServerST::getPendingRegion()
  555. {
  556. UpdateInfo ui;
  557. // Block clients as the frame buffer cannot be safely accessed
  558. if (blockCounter > 0)
  559. return pb->getRect();
  560. // Block client from updating if there are pending updates
  561. if (comparer->is_empty())
  562. return Region();
  563. comparer->getUpdateInfo(&ui, pb->getRect());
  564. return ui.changed.union_(ui.copied);
  565. }
  566. const RenderedCursor* VNCServerST::getRenderedCursor()
  567. {
  568. if (renderedCursorInvalid) {
  569. renderedCursor.update(pb, cursor, cursorPos);
  570. renderedCursorInvalid = false;
  571. }
  572. return &renderedCursor;
  573. }
  574. void VNCServerST::getConnInfo(ListConnInfo * listConn)
  575. {
  576. listConn->Clear();
  577. listConn->setDisable(getDisable());
  578. if (clients.empty())
  579. return;
  580. std::list<VNCSConnectionST*>::iterator i;
  581. for (i = clients.begin(); i != clients.end(); i++)
  582. listConn->addInfo((void*)(*i), (*i)->getSock()->getPeerAddress(),
  583. (*i)->getStartTime(), (*i)->getStatus());
  584. }
  585. void VNCServerST::setConnStatus(ListConnInfo* listConn)
  586. {
  587. setDisable(listConn->getDisable());
  588. if (listConn->Empty() || clients.empty()) return;
  589. for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
  590. VNCSConnectionST* conn = (VNCSConnectionST*)listConn->iGetConn();
  591. std::list<VNCSConnectionST*>::iterator i;
  592. for (i = clients.begin(); i != clients.end(); i++) {
  593. if ((*i) == conn) {
  594. int status = listConn->iGetStatus();
  595. if (status == 3) {
  596. (*i)->close(0);
  597. } else {
  598. (*i)->setStatus(status);
  599. }
  600. break;
  601. }
  602. }
  603. }
  604. }
  605. void VNCServerST::notifyScreenLayoutChange(VNCSConnectionST* requester)
  606. {
  607. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  608. for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
  609. ci_next = ci; ci_next++;
  610. if ((*ci) == requester)
  611. continue;
  612. (*ci)->screenLayoutChangeOrClose(reasonOtherClient);
  613. }
  614. }
  615. bool VNCServerST::getComparerState()
  616. {
  617. if (rfb::Server::compareFB == 0)
  618. return false;
  619. if (rfb::Server::compareFB != 2)
  620. return true;
  621. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  622. for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
  623. ci_next = ci; ci_next++;
  624. if ((*ci)->getComparerState())
  625. return true;
  626. }
  627. return false;
  628. }