blob: b07f5c356d8e4938832f365a2e538995f6d27a63 [file] [log] [blame]
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +00001/* 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
19// -=- Single-Threaded VNC Server implementation
20
21
22// Note about how sockets get closed:
23//
24// Closing sockets to clients is non-trivial because the code which calls
25// VNCServerST must explicitly know about all the sockets (so that it can block
26// on them appropriately). However, VNCServerST may want to close clients for
27// a number of reasons, and from a variety of entry points. The simplest is
28// when processSocketEvent() is called for a client, and the remote end has
29// closed its socket. A more complex reason is when processSocketEvent() is
30// called for a client which has just sent a ClientInit with the shared flag
31// set to false - in this case we want to close all other clients. Yet another
32// reason for disconnecting clients is when the desktop size has changed as a
33// result of a call to setPixelBuffer().
34//
35// The responsibility for creating and deleting sockets is entirely with the
36// calling code. When VNCServerST wants to close a connection to a client it
37// calls the VNCSConnectionST's close() method which calls shutdown() on the
38// socket. Eventually the calling code will notice that the socket has been
39// shut down and call removeSocket() so that we can delete the
40// VNCSConnectionST. Note that the socket must not be deleted by the calling
41// code until after removeSocket() has been called.
42//
43// One minor complication is that we don't allocate a VNCSConnectionST object
44// for a blacklisted host (since we want to minimise the resources used for
45// dealing with such a connection). In order to properly implement the
46// getSockets function, we must maintain a separate closingSockets list,
47// otherwise blacklisted connections might be "forgotten".
48
49
Pierre Ossman559a2e82012-01-23 15:54:11 +000050#include <assert.h>
Pierre Ossmanf99c5712009-03-13 14:41:27 +000051#include <stdlib.h>
52
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000053#include <rfb/ServerCore.h>
54#include <rfb/VNCServerST.h>
55#include <rfb/VNCSConnectionST.h>
56#include <rfb/ComparingUpdateTracker.h>
Adam Tkaca6578bf2010-04-23 14:07:41 +000057#include <rfb/Security.h>
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000058#include <rfb/KeyRemapper.h>
59#include <rfb/util.h>
60
61#include <rdr/types.h>
62
63using namespace rfb;
64
65static LogWriter slog("VNCServerST");
66LogWriter VNCServerST::connectionsLog("Connections");
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000067
Pierre Ossmanbbf955e2011-11-08 12:44:10 +000068rfb::IntParameter deferUpdateTime("DeferUpdate",
DRC4548f302011-12-22 15:57:59 +000069 "Time in milliseconds to defer updates",1);
Pierre Ossmanbbf955e2011-11-08 12:44:10 +000070
71rfb::BoolParameter alwaysSetDeferUpdateTimer("AlwaysSetDeferUpdateTimer",
72 "Always reset the defer update timer on every change",false);
73
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000074//
75// -=- VNCServerST Implementation
76//
77
78// -=- Constructors/Destructor
79
Adam Tkaca6578bf2010-04-23 14:07:41 +000080VNCServerST::VNCServerST(const char* name_, SDesktop* desktop_)
Pierre Ossman559a2e82012-01-23 15:54:11 +000081 : blHosts(&blacklist), desktop(desktop_), desktopStarted(false),
82 blockCounter(0), pb(0),
Adam Tkacd36b6262009-09-04 10:57:20 +000083 name(strDup(name_)), pointerClient(0), comparer(0),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000084 renderedCursorInvalid(false),
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000085 queryConnectionHandler(0), keyRemapper(&KeyRemapper::defInstance),
86 useEconomicTranslate(false),
Pierre Ossmanbbf955e2011-11-08 12:44:10 +000087 lastConnectionTime(0), disableclients(false),
88 deferTimer(this), deferPending(false)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +000089{
90 lastUserInputTime = lastDisconnectTime = time(0);
91 slog.debug("creating single-threaded server %s", name.buf);
92}
93
94VNCServerST::~VNCServerST()
95{
96 slog.debug("shutting down server %s", name.buf);
97
98 // Close any active clients, with appropriate logging & cleanup
99 closeClients("Server shutdown");
100
101 // Delete all the clients, and their sockets, and any closing sockets
102 // NB: Deleting a client implicitly removes it from the clients list
103 while (!clients.empty()) {
104 delete clients.front();
105 }
106
107 // Stop the desktop object if active, *only* after deleting all clients!
108 if (desktopStarted) {
109 desktopStarted = false;
110 desktop->stop();
111 }
112
113 delete comparer;
114}
115
116
117// SocketServer methods
118
119void VNCServerST::addSocket(network::Socket* sock, bool outgoing)
120{
121 // - Check the connection isn't black-marked
122 // *** do this in getSecurity instead?
123 CharArray address(sock->getPeerAddress());
124 if (blHosts->isBlackmarked(address.buf)) {
125 connectionsLog.error("blacklisted: %s", address.buf);
126 try {
127 SConnection::writeConnFailedFromScratch("Too many security failures",
128 &sock->outStream());
129 } catch (rdr::Exception&) {
130 }
131 sock->shutdown();
132 closingSockets.push_back(sock);
133 return;
134 }
135
136 if (clients.empty()) {
137 lastConnectionTime = time(0);
138 }
139
140 VNCSConnectionST* client = new VNCSConnectionST(this, sock, outgoing);
141 client->init();
142}
143
144void VNCServerST::removeSocket(network::Socket* sock) {
145 // - If the socket has resources allocated to it, delete them
146 std::list<VNCSConnectionST*>::iterator ci;
147 for (ci = clients.begin(); ci != clients.end(); ci++) {
148 if ((*ci)->getSock() == sock) {
149 // - Delete the per-Socket resources
150 delete *ci;
151
152 // - Check that the desktop object is still required
153 if (authClientCount() == 0 && desktopStarted) {
154 slog.debug("no authenticated clients - stopping desktop");
155 desktopStarted = false;
156 desktop->stop();
157 }
158 return;
159 }
160 }
161
162 // - If the Socket has no resources, it may have been a closingSocket
163 closingSockets.remove(sock);
164}
165
166void VNCServerST::processSocketEvent(network::Socket* sock)
167{
168 // - Find the appropriate VNCSConnectionST and process the event
169 std::list<VNCSConnectionST*>::iterator ci;
170 for (ci = clients.begin(); ci != clients.end(); ci++) {
171 if ((*ci)->getSock() == sock) {
172 (*ci)->processMessages();
173 return;
174 }
175 }
176 throw rdr::Exception("invalid Socket in VNCServerST");
177}
178
179int VNCServerST::checkTimeouts()
180{
181 int timeout = 0;
182 std::list<VNCSConnectionST*>::iterator ci, ci_next;
Pierre Ossman2d61deb2011-10-25 15:18:53 +0000183
184 soonestTimeout(&timeout, Timer::checkTimeouts());
185
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000186 for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
187 ci_next = ci; ci_next++;
188 soonestTimeout(&timeout, (*ci)->checkIdleTimeout());
189 }
190
191 int timeLeft;
Constantin Kaplinsky8499d0c2008-08-21 05:51:29 +0000192 time_t now = time(0);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000193
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000194 // Check MaxDisconnectionTime
195 if (rfb::Server::maxDisconnectionTime && clients.empty()) {
196 if (now < lastDisconnectTime) {
197 // Someone must have set the time backwards.
198 slog.info("Time has gone backwards - resetting lastDisconnectTime");
199 lastDisconnectTime = now;
200 }
201 timeLeft = lastDisconnectTime + rfb::Server::maxDisconnectionTime - now;
202 if (timeLeft < -60) {
203 // Someone must have set the time forwards.
204 slog.info("Time has gone forwards - resetting lastDisconnectTime");
205 lastDisconnectTime = now;
206 timeLeft = rfb::Server::maxDisconnectionTime;
207 }
208 if (timeLeft <= 0) {
209 slog.info("MaxDisconnectionTime reached, exiting");
210 exit(0);
211 }
212 soonestTimeout(&timeout, timeLeft * 1000);
213 }
214
215 // Check MaxConnectionTime
216 if (rfb::Server::maxConnectionTime && lastConnectionTime && !clients.empty()) {
217 if (now < lastConnectionTime) {
218 // Someone must have set the time backwards.
219 slog.info("Time has gone backwards - resetting lastConnectionTime");
220 lastConnectionTime = now;
221 }
222 timeLeft = lastConnectionTime + rfb::Server::maxConnectionTime - now;
223 if (timeLeft < -60) {
224 // Someone must have set the time forwards.
225 slog.info("Time has gone forwards - resetting lastConnectionTime");
226 lastConnectionTime = now;
227 timeLeft = rfb::Server::maxConnectionTime;
228 }
229 if (timeLeft <= 0) {
230 slog.info("MaxConnectionTime reached, exiting");
231 exit(0);
232 }
233 soonestTimeout(&timeout, timeLeft * 1000);
234 }
235
236
237 // Check MaxIdleTime
238 if (rfb::Server::maxIdleTime) {
239 if (now < lastUserInputTime) {
240 // Someone must have set the time backwards.
241 slog.info("Time has gone backwards - resetting lastUserInputTime");
242 lastUserInputTime = now;
243 }
244 timeLeft = lastUserInputTime + rfb::Server::maxIdleTime - now;
245 if (timeLeft < -60) {
246 // Someone must have set the time forwards.
247 slog.info("Time has gone forwards - resetting lastUserInputTime");
248 lastUserInputTime = now;
249 timeLeft = rfb::Server::maxIdleTime;
250 }
251 if (timeLeft <= 0) {
252 slog.info("MaxIdleTime reached, exiting");
253 exit(0);
254 }
255 soonestTimeout(&timeout, timeLeft * 1000);
256 }
257
258 return timeout;
259}
260
261
262// VNCServer methods
263
Pierre Ossman559a2e82012-01-23 15:54:11 +0000264void VNCServerST::blockUpdates()
265{
266 blockCounter++;
267}
268
269void VNCServerST::unblockUpdates()
270{
271 assert(blockCounter > 0);
272
273 blockCounter--;
274
275 // Flush out any updates we might have blocked
276 if (blockCounter == 0)
277 tryUpdate();
278}
279
Pierre Ossman04e62db2009-03-23 16:57:07 +0000280void VNCServerST::setPixelBuffer(PixelBuffer* pb_, const ScreenSet& layout)
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000281{
282 pb = pb_;
283 delete comparer;
284 comparer = 0;
285
Pierre Ossman04e62db2009-03-23 16:57:07 +0000286 screenLayout = layout;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000287
Pierre Ossman04e62db2009-03-23 16:57:07 +0000288 if (!pb) {
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000289 if (desktopStarted)
290 throw Exception("setPixelBuffer: null PixelBuffer when desktopStarted?");
Pierre Ossman04e62db2009-03-23 16:57:07 +0000291 return;
292 }
293
294 comparer = new ComparingUpdateTracker(pb);
295 cursor.setPF(pb->getPF());
296 renderedCursor.setPF(pb->getPF());
297
298 // Make sure that we have at least one screen
299 if (screenLayout.num_screens() == 0)
300 screenLayout.add_screen(Screen(0, 0, 0, pb->width(), pb->height(), 0));
301
302 std::list<VNCSConnectionST*>::iterator ci, ci_next;
303 for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
304 ci_next = ci; ci_next++;
305 (*ci)->pixelBufferChange();
306 // Since the new pixel buffer means an ExtendedDesktopSize needs to
307 // be sent anyway, we don't need to call screenLayoutChange.
308 }
309}
310
311void VNCServerST::setPixelBuffer(PixelBuffer* pb_)
312{
313 ScreenSet layout;
314
315 if (!pb_) {
316 if (desktopStarted)
317 throw Exception("setPixelBuffer: null PixelBuffer when desktopStarted?");
318 return;
319 }
320
321 layout = screenLayout;
322
323 // Check that the screen layout is still valid
324 if (!layout.validate(pb_->width(), pb_->height())) {
325 Rect fbRect;
326 ScreenSet::iterator iter, iter_next;
327
328 fbRect.setXYWH(0, 0, pb_->width(), pb_->height());
329
330 for (iter = layout.begin();iter != layout.end();iter = iter_next) {
331 iter_next = iter; ++iter_next;
332 if (iter->dimensions.enclosed_by(fbRect))
333 continue;
334 iter->dimensions = iter->dimensions.intersect(fbRect);
335 if (iter->dimensions.is_empty()) {
336 slog.info("Removing screen %d (%x) as it is completely outside the new framebuffer",
337 (int)iter->id, (unsigned)iter->id);
338 layout.remove_screen(iter->id);
339 }
340 }
341 }
342
343 setPixelBuffer(pb_, layout);
344}
345
346void VNCServerST::setScreenLayout(const ScreenSet& layout)
347{
348 if (!pb)
349 throw Exception("setScreenLayout: new screen layout without a PixelBuffer");
350 if (!layout.validate(pb->width(), pb->height()))
351 throw Exception("setScreenLayout: invalid screen layout");
352
Pierre Ossmandf453202009-04-02 14:26:45 +0000353 screenLayout = layout;
354
Pierre Ossman04e62db2009-03-23 16:57:07 +0000355 std::list<VNCSConnectionST*>::iterator ci, ci_next;
356 for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
357 ci_next = ci; ci_next++;
Pierre Ossmana3ac01e2011-11-07 21:13:54 +0000358 (*ci)->screenLayoutChangeOrClose(reasonServer);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000359 }
360}
361
362void VNCServerST::setColourMapEntries(int firstColour, int nColours)
363{
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)->setColourMapEntriesOrClose(firstColour, nColours);
368 }
369}
370
371void VNCServerST::bell()
372{
373 std::list<VNCSConnectionST*>::iterator ci, ci_next;
374 for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
375 ci_next = ci; ci_next++;
Pierre Ossmana3ac01e2011-11-07 21:13:54 +0000376 (*ci)->bellOrClose();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000377 }
378}
379
380void VNCServerST::serverCutText(const char* str, int len)
381{
382 std::list<VNCSConnectionST*>::iterator ci, ci_next;
383 for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
384 ci_next = ci; ci_next++;
Pierre Ossmana3ac01e2011-11-07 21:13:54 +0000385 (*ci)->serverCutTextOrClose(str, len);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000386 }
387}
388
Peter Ã…strandc39e0782009-01-15 12:21:42 +0000389void VNCServerST::setName(const char* name_)
390{
Adam Tkacd36b6262009-09-04 10:57:20 +0000391 name.replaceBuf(strDup(name_));
Peter Ã…strandc39e0782009-01-15 12:21:42 +0000392 std::list<VNCSConnectionST*>::iterator ci, ci_next;
393 for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
394 ci_next = ci; ci_next++;
Pierre Ossmana3ac01e2011-11-07 21:13:54 +0000395 (*ci)->setDesktopNameOrClose(name_);
Peter Ã…strandc39e0782009-01-15 12:21:42 +0000396 }
397}
398
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000399void VNCServerST::add_changed(const Region& region)
400{
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000401 if (comparer == NULL)
402 return;
403
404 comparer->add_changed(region);
405 startDefer();
406 tryUpdate();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000407}
408
409void VNCServerST::add_copied(const Region& dest, const Point& delta)
410{
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000411 if (comparer == NULL)
412 return;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000413
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000414 comparer->add_copied(dest, delta);
415 startDefer();
416 tryUpdate();
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000417}
418
419void VNCServerST::setCursor(int width, int height, const Point& newHotspot,
420 void* data, void* mask)
421{
422 cursor.hotspot = newHotspot;
423 cursor.setSize(width, height);
424 memcpy(cursor.data, data, cursor.dataLen());
425 memcpy(cursor.mask.buf, mask, cursor.maskLen());
426
427 cursor.crop();
428
429 renderedCursorInvalid = true;
430
431 std::list<VNCSConnectionST*>::iterator ci, ci_next;
432 for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
433 ci_next = ci; ci_next++;
434 (*ci)->renderedCursorChange();
435 (*ci)->setCursorOrClose();
436 }
437}
438
439void VNCServerST::setCursorPos(const Point& pos)
440{
441 if (!cursorPos.equals(pos)) {
442 cursorPos = pos;
443 renderedCursorInvalid = true;
444 std::list<VNCSConnectionST*>::iterator ci;
445 for (ci = clients.begin(); ci != clients.end(); ci++)
446 (*ci)->renderedCursorChange();
447 }
448}
449
450// Other public methods
451
452void VNCServerST::approveConnection(network::Socket* sock, bool accept,
453 const char* reason)
454{
455 std::list<VNCSConnectionST*>::iterator ci;
456 for (ci = clients.begin(); ci != clients.end(); ci++) {
457 if ((*ci)->getSock() == sock) {
458 (*ci)->approveConnectionOrClose(accept, reason);
459 return;
460 }
461 }
462}
463
464void VNCServerST::closeClients(const char* reason, network::Socket* except)
465{
466 std::list<VNCSConnectionST*>::iterator i, next_i;
467 for (i=clients.begin(); i!=clients.end(); i=next_i) {
468 next_i = i; next_i++;
469 if ((*i)->getSock() != except)
470 (*i)->close(reason);
471 }
472}
473
474void VNCServerST::getSockets(std::list<network::Socket*>* sockets)
475{
476 sockets->clear();
477 std::list<VNCSConnectionST*>::iterator ci;
478 for (ci = clients.begin(); ci != clients.end(); ci++) {
479 sockets->push_back((*ci)->getSock());
480 }
481 std::list<network::Socket*>::iterator si;
482 for (si = closingSockets.begin(); si != closingSockets.end(); si++) {
483 sockets->push_back(*si);
484 }
485}
486
487SConnection* VNCServerST::getSConnection(network::Socket* sock) {
488 std::list<VNCSConnectionST*>::iterator ci;
489 for (ci = clients.begin(); ci != clients.end(); ci++) {
490 if ((*ci)->getSock() == sock)
491 return *ci;
492 }
493 return 0;
494}
495
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000496bool VNCServerST::handleTimeout(Timer* t)
497{
498 if (t != &deferTimer)
499 return false;
500
501 tryUpdate();
502
503 return false;
504}
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000505
506// -=- Internal methods
507
508void VNCServerST::startDesktop()
509{
510 if (!desktopStarted) {
511 slog.debug("starting desktop");
512 desktop->start(this);
513 desktopStarted = true;
514 if (!pb)
515 throw Exception("SDesktop::start() did not set a valid PixelBuffer");
516 }
517}
518
519int VNCServerST::authClientCount() {
520 int count = 0;
521 std::list<VNCSConnectionST*>::iterator ci;
522 for (ci = clients.begin(); ci != clients.end(); ci++) {
523 if ((*ci)->authenticated())
524 count++;
525 }
526 return count;
527}
528
529inline bool VNCServerST::needRenderedCursor()
530{
531 std::list<VNCSConnectionST*>::iterator ci;
532 for (ci = clients.begin(); ci != clients.end(); ci++)
533 if ((*ci)->needRenderedCursor()) return true;
534 return false;
535}
536
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000537inline void VNCServerST::startDefer()
538{
539 if (deferUpdateTime == 0)
540 return;
541
542 if (deferPending && !alwaysSetDeferUpdateTimer)
543 return;
544
545 gettimeofday(&deferStart, NULL);
546 deferTimer.start(deferUpdateTime);
547
548 deferPending = true;
549}
550
551inline bool VNCServerST::checkDefer()
552{
553 if (!deferPending)
554 return true;
555
556 if (msSince(&deferStart) >= deferUpdateTime)
557 return true;
558
559 return false;
560}
561
562void VNCServerST::tryUpdate()
563{
564 std::list<VNCSConnectionST*>::iterator ci, ci_next;
565
Pierre Ossman559a2e82012-01-23 15:54:11 +0000566 if (blockCounter > 0)
567 return;
568
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000569 if (!checkDefer())
570 return;
571
572 for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
573 ci_next = ci; ci_next++;
574 (*ci)->writeFramebufferUpdateOrClose();
575 }
576}
577
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000578// checkUpdate() is called just before sending an update. It checks to see
579// what updates are pending and propagates them to the update tracker for each
580// client. It uses the ComparingUpdateTracker's compare() method to filter out
581// areas of the screen which haven't actually changed. It also checks the
582// state of the (server-side) rendered cursor, if necessary rendering it again
583// with the correct background.
584
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000585bool VNCServerST::checkUpdate()
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000586{
Constantin Kaplinsky604d7812007-08-31 15:50:37 +0000587 UpdateInfo ui;
588 comparer->getUpdateInfo(&ui, pb->getRect());
589
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000590 bool renderCursor = needRenderedCursor();
591
Constantin Kaplinsky604d7812007-08-31 15:50:37 +0000592 if (ui.is_empty() && !(renderCursor && renderedCursorInvalid))
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000593 return true;
594
Pierre Ossman559a2e82012-01-23 15:54:11 +0000595 // Block clients as the frame buffer cannot be safely accessed
596 if (blockCounter > 0)
597 return false;
598
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000599 // Block client from updating if we are currently deferring updates
600 if (!checkDefer())
601 return false;
602
603 deferPending = false;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000604
Pierre Ossman02e43d72009-03-05 11:57:11 +0000605 Region toCheck = ui.changed.union_(ui.copied);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000606
607 if (renderCursor) {
608 Rect clippedCursorRect
609 = cursor.getRect(cursorTL()).intersect(pb->getRect());
610
611 if (!renderedCursorInvalid && (toCheck.intersect(clippedCursorRect)
612 .is_empty())) {
613 renderCursor = false;
614 } else {
615 renderedCursorTL = clippedCursorRect.tl;
616 renderedCursor.setSize(clippedCursorRect.width(),
617 clippedCursorRect.height());
618 toCheck.assign_union(clippedCursorRect);
619 }
620 }
621
622 pb->grabRegion(toCheck);
623
Pierre Ossmanb114cec2011-11-20 15:36:11 +0000624 if (getComparerState())
625 comparer->enable();
626 else
627 comparer->disable();
628
629 if (comparer->compare())
Constantin Kaplinskyf0b3be72008-08-21 05:22:04 +0000630 comparer->getUpdateInfo(&ui, pb->getRect());
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000631
632 if (renderCursor) {
633 pb->getImage(renderedCursor.data,
634 renderedCursor.getRect(renderedCursorTL));
635 renderedCursor.maskRect(cursor.getRect(cursorTL()
636 .subtract(renderedCursorTL)),
637 cursor.data, cursor.mask.buf);
638 renderedCursorInvalid = false;
639 }
640
641 std::list<VNCSConnectionST*>::iterator ci, ci_next;
642 for (ci = clients.begin(); ci != clients.end(); ci = ci_next) {
643 ci_next = ci; ci_next++;
Constantin Kaplinsky604d7812007-08-31 15:50:37 +0000644 (*ci)->add_copied(ui.copied, ui.copy_delta);
645 (*ci)->add_changed(ui.changed);
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000646 }
647
648 comparer->clear();
Pierre Ossmanbbf955e2011-11-08 12:44:10 +0000649
650 return true;
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000651}
652
Constantin Kaplinskya2adc8d2006-05-25 05:01:55 +0000653void VNCServerST::getConnInfo(ListConnInfo * listConn)
654{
655 listConn->Clear();
656 listConn->setDisable(getDisable());
657 if (clients.empty())
658 return;
659 std::list<VNCSConnectionST*>::iterator i;
660 for (i = clients.begin(); i != clients.end(); i++)
661 listConn->addInfo((void*)(*i), (*i)->getSock()->getPeerAddress(),
662 (*i)->getStartTime(), (*i)->getStatus());
663}
664
665void VNCServerST::setConnStatus(ListConnInfo* listConn)
666{
667 setDisable(listConn->getDisable());
668 if (listConn->Empty() || clients.empty()) return;
669 for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
670 VNCSConnectionST* conn = (VNCSConnectionST*)listConn->iGetConn();
671 std::list<VNCSConnectionST*>::iterator i;
672 for (i = clients.begin(); i != clients.end(); i++) {
673 if ((*i) == conn) {
674 int status = listConn->iGetStatus();
675 if (status == 3) {
676 (*i)->close(0);
677 } else {
678 (*i)->setStatus(status);
679 }
680 break;
681 }
682 }
683 }
684}
Constantin Kaplinsky9d1fc6c2008-06-14 05:23:10 +0000685
Pierre Ossman04e62db2009-03-23 16:57:07 +0000686void VNCServerST::notifyScreenLayoutChange(VNCSConnectionST* requester)
687{
688 std::list<VNCSConnectionST*>::iterator ci, ci_next;
689 for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
690 ci_next = ci; ci_next++;
691 if ((*ci) == requester)
692 continue;
Pierre Ossmana3ac01e2011-11-07 21:13:54 +0000693 (*ci)->screenLayoutChangeOrClose(reasonOtherClient);
Pierre Ossman04e62db2009-03-23 16:57:07 +0000694 }
695}
Pierre Ossmanb114cec2011-11-20 15:36:11 +0000696
697bool VNCServerST::getComparerState()
698{
699 if (rfb::Server::compareFB == 0)
700 return false;
701 if (rfb::Server::compareFB != 2)
702 return true;
703
704 std::list<VNCSConnectionST*>::iterator ci, ci_next;
705 for (ci=clients.begin();ci!=clients.end();ci=ci_next) {
706 ci_next = ci; ci_next++;
707 if ((*ci)->getComparerState())
708 return true;
709 }
710 return false;
711}