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 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. // -=- Single-Threaded VNC Server implementation
  19. // Note about how sockets get closed:
  20. //
  21. // Closing sockets to clients is non-trivial because the code which calls
  22. // VNCServerST must explicitly know about all the sockets (so that it can block
  23. // on them appropriately). However, VNCServerST may want to close clients for
  24. // a number of reasons, and from a variety of entry points. The simplest is
  25. // when processSocketEvent() is called for a client, and the remote end has
  26. // closed its socket. A more complex reason is when processSocketEvent() is
  27. // called for a client which has just sent a ClientInit with the shared flag
  28. // set to false - in this case we want to close all other clients. Yet another
  29. // reason for disconnecting clients is when the desktop size has changed as a
  30. // result of a call to setPixelBuffer().
  31. //
  32. // The responsibility for creating and deleting sockets is entirely with the
  33. // calling code. When VNCServerST wants to close a connection to a client it
  34. // calls the VNCSConnectionST's close() method which calls shutdown() on the
  35. // socket. Eventually the calling code will notice that the socket has been
  36. // shut down and call removeSocket() so that we can delete the
  37. // VNCSConnectionST. Note that the socket must not be deleted by the calling
  38. // code until after removeSocket() has been called.
  39. //
  40. // One minor complication is that we don't allocate a VNCSConnectionST object
  41. // for a blacklisted host (since we want to minimise the resources used for
  42. // dealing with such a connection). In order to properly implement the
  43. // getSockets function, we must maintain a separate closingSockets list,
  44. // otherwise blacklisted connections might be "forgotten".
  45. #include <stdlib.h>
  46. #include <rfb/ServerCore.h>
  47. #include <rfb/VNCServerST.h>
  48. #include <rfb/VNCSConnectionST.h>
  49. #include <rfb/ComparingUpdateTracker.h>
  50. #include <rfb/SSecurityFactoryStandard.h>
  51. #include <rfb/KeyRemapper.h>
  52. #include <rfb/util.h>
  53. #include <rdr/types.h>
  54. using namespace rfb;
  55. static LogWriter slog("VNCServerST");
  56. LogWriter VNCServerST::connectionsLog("Connections");
  57. static SSecurityFactoryStandard defaultSecurityFactory;
  58. //
  59. // -=- VNCServerST Implementation
  60. //
  61. // -=- Constructors/Destructor
  62. VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_,
  63. SSecurityFactory* sf)
  64. : blHosts(&blacklist), desktop(desktop_), desktopStarted(false), pb(0),
  65. name(strDup(name_)), pointerClient(0), comparer(0),
  66. renderedCursorInvalid(false),
  67. securityFactory(sf ? sf : &defaultSecurityFactory),
  68. queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
  69. useEconomicTranslate(false),
  70. lastConnectionTime(0), disableclients(false)
  71. {
  72. lastUserInputTime = lastDisconnectTime = time(0);
  73. slog.debug("creating single-threaded server %s", name.buf);
  74. }
  75. VNCServerST::~VNCServerST()
  76. {
  77. slog.debug("shutting down server %s", name.buf);
  78. // Close any active clients, with appropriate logging & cleanup
  79. closeClients("Server shutdown");
  80. // Delete all the clients, and their sockets, and any closing sockets
  81. // NB: Deleting a client implicitly removes it from the clients list
  82. while (!clients.empty()) {
  83. delete clients.front();
  84. }
  85. // Stop the desktop object if active, *only* after deleting all clients!
  86. if (desktopStarted) {
  87. desktopStarted = false;
  88. desktop->stop();
  89. }
  90. delete comparer;
  91. }
  92. // SocketServer methods
  93. void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
  94. {
  95. // - Check the connection isn't black-marked
  96. // *** do this in getSecurity instead?
  97. CharArray address(sock->getPeerAddress());
  98. if (blHosts->isBlackmarked(address.buf)) {
  99. connectionsLog.error("blacklisted: %s", address.buf);
  100. try {
  101. SConnection::writeConnFailedFromScratch("Too many security failures",
  102. &sock->outStream());
  103. } catch (rdr::Exception&) {
  104. }
  105. sock->shutdown();
  106. closingSockets.push_back(sock);
  107. return;
  108. }
  109. if (clients.empty()) {
  110. lastConnectionTime = time(0);
  111. }
  112. VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
  113. client->init();
  114. }
  115. void VNCServerST::removeSocket(network::Socket* sock) {
  116. // - If the socket has resources allocated to it, delete them
  117. std::list<VNCSConnectionST*>::iterator ci;
  118. for (ci = clients.begin(); ci != clients.end(); ci++) {
  119. if ((*ci)->getSock() == sock) {
  120. // - Delete the per-Socket resources
  121. delete *ci;
  122. // - Check that the desktop object is still required
  123. if (authClientCount() == 0 && desktopStarted) {
  124. slog.debug("no authenticated clients - stopping desktop");
  125. desktopStarted = false;
  126. desktop->stop();
  127. }
  128. return;
  129. }
  130. }
  131. // - If the Socket has no resources, it may have been a closingSocket
  132. closingSockets.remove(sock);
  133. }
  134. void VNCServerST::processSocketEvent(network::Socket* sock)
  135. {
  136. // - Find the appropriate VNCSConnectionST and process the event
  137. std::list<VNCSConnectionST*>::iterator ci;
  138. for (ci = clients.begin(); ci != clients.end(); ci++) {
  139. if ((*ci)->getSock() == sock) {
  140. (*ci)->processMessages();
  141. return;
  142. }
  143. }
  144. throw rdr::Exception("invalid Socket in VNCServerST");
  145. }
  146. int VNCServerST::checkTimeouts()
  147. {
  148. int timeout = 0;
  149. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  150. for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
  151. ci_next = ci; ci_next++;
  152. soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
  153. }
  154. int timeLeft;
  155. time_t now = time(0);
  156. // Check MaxDisconnectionTime
  157. if (rfb::Server::maxDisconnectionTime && clients.empty()) {
  158. if (now < lastDisconnectTime) {
  159. // Someone must have set the time backwards.
  160. slog.info("Time has gone backwards - resetting lastDisconnectTime");
  161. lastDisconnectTime = now;
  162. }
  163. timeLeft = lastDisconnectTime + rfb::Server::maxDisconnectionTime - now;
  164. if (timeLeft < -60) {
  165. // Someone must have set the time forwards.
  166. slog.info("Time has gone forwards - resetting lastDisconnectTime");
  167. lastDisconnectTime = now;
  168. timeLeft = rfb::Server::maxDisconnectionTime;
  169. }
  170. if (timeLeft <= 0) {
  171. slog.info("MaxDisconnectionTime reached, exiting");
  172. exit(0);
  173. }
  174. soonestTimeout(&timeout, timeLeft * 1000);
  175. }
  176. // Check MaxConnectionTime
  177. if (rfb::Server::maxConnectionTime && lastConnectionTime && !clients.empty()) {
  178. if (now < lastConnectionTime) {
  179. // Someone must have set the time backwards.
  180. slog.info("Time has gone backwards - resetting lastConnectionTime");
  181. lastConnectionTime = now;
  182. }
  183. timeLeft = lastConnectionTime + rfb::Server::maxConnectionTime - now;
  184. if (timeLeft < -60) {
  185. // Someone must have set the time forwards.
  186. slog.info("Time has gone forwards - resetting lastConnectionTime");
  187. lastConnectionTime = now;
  188. timeLeft = rfb::Server::maxConnectionTime;
  189. }
  190. if (timeLeft <= 0) {
  191. slog.info("MaxConnectionTime reached, exiting");
  192. exit(0);
  193. }
  194. soonestTimeout(&timeout, timeLeft * 1000);
  195. }
  196. // Check MaxIdleTime
  197. if (rfb::Server::maxIdleTime) {
  198. if (now < lastUserInputTime) {
  199. // Someone must have set the time backwards.
  200. slog.info("Time has gone backwards - resetting lastUserInputTime");
  201. lastUserInputTime = now;
  202. }
  203. timeLeft = lastUserInputTime + rfb::Server::maxIdleTime - now;
  204. if (timeLeft < -60) {
  205. // Someone must have set the time forwards.
  206. slog.info("Time has gone forwards - resetting lastUserInputTime");
  207. lastUserInputTime = now;
  208. timeLeft = rfb::Server::maxIdleTime;
  209. }
  210. if (timeLeft <= 0) {
  211. slog.info("MaxIdleTime reached, exiting");
  212. exit(0);
  213. }
  214. soonestTimeout(&timeout, timeLeft * 1000);
  215. }
  216. return timeout;
  217. }
  218. // VNCServer methods
  219. void VNCServerST::setPixelBuffer(PixelBuffer* pb_)
  220. {
  221. pb = pb_;
  222. delete comparer;
  223. comparer = 0;
  224. if (pb) {
  225. comparer = new ComparingUpdateTracker(pb);
  226. cursor.setPF(pb->getPF());
  227. renderedCursor.setPF(pb->getPF());
  228. if (screenLayout.num_screens() == 0) {
  229. // Boot strap the screen layout
  230. screenLayout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0));
  231. } else {
  232. // Check that the screen layout is still valid
  233. if (!screenLayout.validate(pb->width(), pb->height())) {
  234. Rect fbRect;
  235. ScreenSet::iterator iter, iter_next;
  236. fbRect.setXYWH(0, 0, pb->width(), pb->height());
  237. for (iter = screenLayout.begin();iter != screenLayout.end();iter = iter_next) {
  238. iter_next = iter; ++iter_next;
  239. if (iter->dimensions.enclosed_by(fbRect))
  240. continue;
  241. iter->dimensions = iter->dimensions.intersect(fbRect);
  242. if (iter->dimensions.is_empty()) {
  243. slog.info("Removing screen %d (%x) as it is completely outside the new framebuffer",
  244. (int)iter->id, (unsigned)iter->id);
  245. screenLayout.remove_screen(iter->id);
  246. }
  247. }
  248. }
  249. }
  250. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  251. for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
  252. ci_next = ci; ci_next++;
  253. (*ci)->pixelBufferChange();
  254. }
  255. } else {
  256. if (desktopStarted)
  257. throw Exception("setPixelBuffer: null PixelBuffer when desktopStarted?");
  258. }
  259. }
  260. void VNCServerST::setColourMapEntries(int firstColour, int nColours)
  261. {
  262. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  263. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  264. ci_next = ci; ci_next++;
  265. (*ci)->setColourMapEntriesOrClose(firstColour, nColours);
  266. }
  267. }
  268. void VNCServerST::bell()
  269. {
  270. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  271. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  272. ci_next = ci; ci_next++;
  273. (*ci)->bell();
  274. }
  275. }
  276. void VNCServerST::serverCutText(const char* str, int len)
  277. {
  278. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  279. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  280. ci_next = ci; ci_next++;
  281. (*ci)->serverCutText(str, len);
  282. }
  283. }
  284. void VNCServerST::setName(const char* name_)
  285. {
  286. name.replaceBuf(strDup(name_));
  287. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  288. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  289. ci_next = ci; ci_next++;
  290. (*ci)->setDesktopName(name_);
  291. }
  292. }
  293. void VNCServerST::add_changed(const Region& region)
  294. {
  295. if (comparer != 0) {
  296. comparer->add_changed(region);
  297. }
  298. }
  299. void VNCServerST::add_copied(const Region& dest, const Point& delta)
  300. {
  301. if (comparer != 0) {
  302. comparer->add_copied(dest, delta);
  303. }
  304. }
  305. bool VNCServerST::clientsReadyForUpdate()
  306. {
  307. std::list<VNCSConnectionST*>::iterator ci;
  308. for (ci = clients.begin(); ci != clients.end(); ci++) {
  309. if ((*ci)->readyForUpdate())
  310. return true;
  311. }
  312. return false;
  313. }
  314. void VNCServerST::tryUpdate()
  315. {
  316. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  317. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  318. ci_next = ci; ci_next++;
  319. (*ci)->writeFramebufferUpdateOrClose();
  320. }
  321. }
  322. void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
  323. void* data, void* mask)
  324. {
  325. cursor.hotspot = newHotspot;
  326. cursor.setSize(width, height);
  327. memcpy(cursor.data, data, cursor.dataLen());
  328. memcpy(cursor.mask.buf, mask, cursor.maskLen());
  329. cursor.crop();
  330. renderedCursorInvalid = true;
  331. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  332. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  333. ci_next = ci; ci_next++;
  334. (*ci)->renderedCursorChange();
  335. (*ci)->setCursorOrClose();
  336. }
  337. }
  338. void VNCServerST::setCursorPos(const Point& pos)
  339. {
  340. if (!cursorPos.equals(pos)) {
  341. cursorPos = pos;
  342. renderedCursorInvalid = true;
  343. std::list<VNCSConnectionST*>::iterator ci;
  344. for (ci = clients.begin(); ci != clients.end(); ci++)
  345. (*ci)->renderedCursorChange();
  346. }
  347. }
  348. // Other public methods
  349. void VNCServerST::approveConnection(network::Socket* sock, bool accept,
  350. const char* reason)
  351. {
  352. std::list<VNCSConnectionST*>::iterator ci;
  353. for (ci = clients.begin(); ci != clients.end(); ci++) {
  354. if ((*ci)->getSock() == sock) {
  355. (*ci)->approveConnectionOrClose(accept, reason);
  356. return;
  357. }
  358. }
  359. }
  360. void VNCServerST::closeClients(const char* reason, network::Socket* except)
  361. {
  362. std::list<VNCSConnectionST*>::iterator i, next_i;
  363. for (i=clients.begin(); i!=clients.end(); i=next_i) {
  364. next_i = i; next_i++;
  365. if ((*i)->getSock() != except)
  366. (*i)->close(reason);
  367. }
  368. }
  369. void VNCServerST::getSockets(std::list<network::Socket*>* sockets)
  370. {
  371. sockets->clear();
  372. std::list<VNCSConnectionST*>::iterator ci;
  373. for (ci = clients.begin(); ci != clients.end(); ci++) {
  374. sockets->push_back((*ci)->getSock());
  375. }
  376. std::list<network::Socket*>::iterator si;
  377. for (si = closingSockets.begin(); si != closingSockets.end(); si++) {
  378. sockets->push_back(*si);
  379. }
  380. }
  381. SConnection* VNCServerST::getSConnection(network::Socket* sock) {
  382. std::list<VNCSConnectionST*>::iterator ci;
  383. for (ci = clients.begin(); ci != clients.end(); ci++) {
  384. if ((*ci)->getSock() == sock)
  385. return *ci;
  386. }
  387. return 0;
  388. }
  389. // -=- Internal methods
  390. void VNCServerST::startDesktop()
  391. {
  392. if (!desktopStarted) {
  393. slog.debug("starting desktop");
  394. desktop->start(this);
  395. desktopStarted = true;
  396. if (!pb)
  397. throw Exception("SDesktop::start() did not set a valid PixelBuffer");
  398. }
  399. }
  400. int VNCServerST::authClientCount() {
  401. int count = 0;
  402. std::list<VNCSConnectionST*>::iterator ci;
  403. for (ci = clients.begin(); ci != clients.end(); ci++) {
  404. if ((*ci)->authenticated())
  405. count++;
  406. }
  407. return count;
  408. }
  409. inline bool VNCServerST::needRenderedCursor()
  410. {
  411. std::list<VNCSConnectionST*>::iterator ci;
  412. for (ci = clients.begin(); ci != clients.end(); ci++)
  413. if ((*ci)->needRenderedCursor()) return true;
  414. return false;
  415. }
  416. // checkUpdate() is called just before sending an update. It checks to see
  417. // what updates are pending and propagates them to the update tracker for each
  418. // client. It uses the ComparingUpdateTracker's compare() method to filter out
  419. // areas of the screen which haven't actually changed. It also checks the
  420. // state of the (server-side) rendered cursor, if necessary rendering it again
  421. // with the correct background.
  422. void VNCServerST::checkUpdate()
  423. {
  424. UpdateInfo ui;
  425. comparer->getUpdateInfo(&ui, pb->getRect());
  426. bool renderCursor = needRenderedCursor();
  427. if (ui.is_empty() && !(renderCursor && renderedCursorInvalid))
  428. return;
  429. Region toCheck = ui.changed.union_(ui.copied);
  430. if (renderCursor) {
  431. Rect clippedCursorRect
  432. = cursor.getRect(cursorTL()).intersect(pb->getRect());
  433. if (!renderedCursorInvalid && (toCheck.intersect(clippedCursorRect)
  434. .is_empty())) {
  435. renderCursor = false;
  436. } else {
  437. renderedCursorTL = clippedCursorRect.tl;
  438. renderedCursor.setSize(clippedCursorRect.width(),
  439. clippedCursorRect.height());
  440. toCheck.assign_union(clippedCursorRect);
  441. }
  442. }
  443. pb->grabRegion(toCheck);
  444. if (rfb::Server::compareFB) {
  445. comparer->compare();
  446. comparer->getUpdateInfo(&ui, pb->getRect());
  447. }
  448. if (renderCursor) {
  449. pb->getImage(renderedCursor.data,
  450. renderedCursor.getRect(renderedCursorTL));
  451. renderedCursor.maskRect(cursor.getRect(cursorTL()
  452. .subtract(renderedCursorTL)),
  453. cursor.data, cursor.mask.buf);
  454. renderedCursorInvalid = false;
  455. }
  456. std::list<VNCSConnectionST*>::iterator ci, ci_next;
  457. for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
  458. ci_next = ci; ci_next++;
  459. (*ci)->add_copied(ui.copied, ui.copy_delta);
  460. (*ci)->add_changed(ui.changed);
  461. }
  462. comparer->clear();
  463. }
  464. void VNCServerST::getConnInfo(ListConnInfo * listConn)
  465. {
  466. listConn->Clear();
  467. listConn->setDisable(getDisable());
  468. if (clients.empty())
  469. return;
  470. std::list<VNCSConnectionST*>::iterator i;
  471. for (i = clients.begin(); i != clients.end(); i++)
  472. listConn->addInfo((void*)(*i), (*i)->getSock()->getPeerAddress(),
  473. (*i)->getStartTime(), (*i)->getStatus());
  474. }
  475. void VNCServerST::setConnStatus(ListConnInfo* listConn)
  476. {
  477. setDisable(listConn->getDisable());
  478. if (listConn->Empty() || clients.empty()) return;
  479. for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
  480. VNCSConnectionST* conn = (VNCSConnectionST*)listConn->iGetConn();
  481. std::list<VNCSConnectionST*>::iterator i;
  482. for (i = clients.begin(); i != clients.end(); i++) {
  483. if ((*i) == conn) {
  484. int status = listConn->iGetStatus();
  485. if (status == 3) {
  486. (*i)->close(0);
  487. } else {
  488. (*i)->setStatus(status);
  489. }
  490. break;
  491. }
  492. }
  493. }
  494. }