blob: 4ee44e0440a4dac964d8932054366546b1834963 [file] [log] [blame]
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +00001/* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
2 * Copyright (C) 2004-2006 Constantin Kaplinsky. All Rights Reserved.
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +00003 *
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 */
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000019
20// FIXME: Check cases when screen width/height is not a multiply of 32.
21// e.g. 800x600.
22
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000023#include <strings.h>
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000024#include <sys/types.h>
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000025#include <sys/stat.h>
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000026#include <unistd.h>
27#include <errno.h>
28#include <rfb/Logger_stdio.h>
29#include <rfb/LogWriter.h>
30#include <rfb/VNCServerST.h>
31#include <rfb/Configuration.h>
32#include <rfb/SSecurityFactoryStandard.h>
Constantin Kaplinsky478f22c2006-04-19 06:13:06 +000033#include <rfb/Timer.h>
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000034#include <network/TcpSocket.h>
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +000035#include <tx/TXWindow.h>
36
Constantin Kaplinsky3f6ad6b2006-04-17 14:06:41 +000037#include <vncconfig_unix/QueryConnectDialog.h>
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000038
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000039#include <signal.h>
40#include <X11/X.h>
41#include <X11/Xlib.h>
42#include <X11/Xutil.h>
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000043#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000044#include <X11/extensions/XTest.h>
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000045#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000046
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000047#include <x0vncserver/Image.h>
48#include <x0vncserver/PollingManager.h>
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000049#include <x0vncserver/PollingScheduler.h>
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000050
Constantin Kaplinskya6866902006-03-02 12:03:30 +000051// XXX Lynx/OS 2.3: protos for select(), bzero()
52#ifdef Lynx
53#include <sys/proto.h>
54#endif
55
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000056using namespace rfb;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000057using namespace network;
58
59LogWriter vlog("main");
60
Constantin Kaplinsky602f34d2005-09-14 16:11:41 +000061IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
62 "cycle; actual interval may be dynamically "
Constantin Kaplinskyef7ac9b2006-02-10 12:26:54 +000063 "adjusted to satisfy MaxProcessorUsage setting", 30);
Constantin Kaplinsky602f34d2005-09-14 16:11:41 +000064IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of "
65 "CPU time to be consumed", 35);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000066BoolParameter useShm("UseSHM", "Use MIT-SHM extension if available", true);
67BoolParameter useOverlay("OverlayMode", "Use overlay mode under "
68 "IRIX or Solaris", true);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000069StringParameter displayname("display", "The X display", "");
70IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +000071IntParameter queryConnectTimeout("QueryConnectTimeout",
72 "Number of seconds to show the Accept Connection dialog before "
73 "rejecting the connection",
74 10);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000075StringParameter hostsFile("HostsFile", "File with IP access control rules", "");
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000076
77static void CleanupSignalHandler(int sig)
78{
79 // CleanupSignalHandler allows C++ object cleanup to happen because it calls
80 // exit() rather than the default which is to abort.
81 fprintf(stderr,"CleanupSignalHandler called\n");
82 exit(1);
83}
84
85
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +000086class QueryConnHandler : public VNCServerST::QueryConnectionHandler,
87 public QueryResultCallback {
88public:
89 QueryConnHandler(Display* dpy, VNCServerST* vs)
90 : display(dpy), server(vs), queryConnectDialog(0), queryConnectSock(0) {}
91 ~QueryConnHandler() { delete queryConnectDialog; }
92
93 // -=- VNCServerST::QueryConnectionHandler interface
94 virtual VNCServerST::queryResult queryConnection(network::Socket* sock,
95 const char* userName,
96 char** reason) {
97 if (queryConnectSock) {
98 *reason = strDup("Another connection is currently being queried.");
99 return VNCServerST::REJECT;
100 }
101 if (!userName) userName = "(anonymous)";
102 queryConnectSock = sock;
103 CharArray address(sock->getPeerAddress());
104 delete queryConnectDialog;
105 queryConnectDialog = new QueryConnectDialog(display, address.buf,
106 userName, queryConnectTimeout,
107 this);
108 queryConnectDialog->map();
109 return VNCServerST::PENDING;
110 }
111
112 // -=- QueryResultCallback interface
113 virtual void queryApproved() {
114 server->approveConnection(queryConnectSock, true, 0);
115 queryConnectSock = 0;
116 }
117 virtual void queryRejected() {
118 server->approveConnection(queryConnectSock, false,
119 "Connection rejected by local user");
120 queryConnectSock = 0;
121 }
122private:
123 Display* display;
124 VNCServerST* server;
125 QueryConnectDialog* queryConnectDialog;
126 network::Socket* queryConnectSock;
127};
128
129
130class XDesktop : public SDesktop, public ColourMap
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000131{
132public:
133 XDesktop(Display* dpy_)
Constantin Kaplinsky49476542006-04-18 09:22:53 +0000134 : dpy(dpy_), pb(0), server(0), image(0), pollmgr(0),
135 oldButtonMask(0), haveXtest(false), maxButtons(0), running(false)
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000136 {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000137#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000138 int xtestEventBase;
139 int xtestErrorBase;
140 int major, minor;
141
142 if (XTestQueryExtension(dpy, &xtestEventBase,
143 &xtestErrorBase, &major, &minor)) {
144 XTestGrabControl(dpy, True);
145 vlog.info("XTest extension present - version %d.%d",major,minor);
146 haveXtest = true;
147 } else {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000148#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000149 vlog.info("XTest extension not present");
150 vlog.info("unable to inject events or display while server is grabbed");
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000151#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000152 }
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000153#endif
154
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000155 }
156 virtual ~XDesktop() {
157 stop();
158 }
159
160 // -=- SDesktop interface
161
162 virtual void start(VNCServer* vs) {
163
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000164 // Determine actual number of buttons of the X pointer device.
165 unsigned char btnMap[8];
166 int numButtons = XGetPointerMapping(dpy, btnMap, 8);
167 maxButtons = (numButtons > 8) ? 8 : numButtons;
168 vlog.info("Enabling %d button%s of X pointer device",
169 maxButtons, (maxButtons != 1) ? "s" : "");
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000170
171 int dpyWidth = DisplayWidth(dpy, DefaultScreen(dpy));
172 int dpyHeight = DisplayHeight(dpy, DefaultScreen(dpy));
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000173
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000174 ImageFactory factory((bool)useShm, (bool)useOverlay);
175 image = factory.newImage(dpy, dpyWidth, dpyHeight);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000176 image->get(DefaultRootWindow(dpy));
177
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000178 pollmgr = new PollingManager(dpy, image, &factory);
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000179 pollmgr->setVNCServer(vs);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000180
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000181 pf.bpp = image->xim->bits_per_pixel;
182 pf.depth = image->xim->depth;
183 pf.bigEndian = (image->xim->byte_order == MSBFirst);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000184 pf.trueColour = image->isTrueColor();
185 pf.redShift = ffs(image->xim->red_mask) - 1;
186 pf.greenShift = ffs(image->xim->green_mask) - 1;
187 pf.blueShift = ffs(image->xim->blue_mask) - 1;
188 pf.redMax = image->xim->red_mask >> pf.redShift;
189 pf.greenMax = image->xim->green_mask >> pf.greenShift;
190 pf.blueMax = image->xim->blue_mask >> pf.blueShift;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000191
192 pb = new FullFramePixelBuffer(pf, dpyWidth, dpyHeight,
193 (rdr::U8*)image->xim->data, this);
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000194 server = vs;
195 server->setPixelBuffer(pb);
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000196
197 running = true;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000198 }
199
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000200 virtual void stop() {
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000201 running = false;
202
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000203 delete pb;
204 delete pollmgr;
Constantin Kaplinsky93c3f892006-04-19 10:32:33 +0000205 delete image;
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000206
207 pb = 0;
208 pollmgr = 0;
Constantin Kaplinsky93c3f892006-04-19 10:32:33 +0000209 image = 0;
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000210 }
211
212 inline bool isRunning() {
213 return running;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000214 }
215
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000216 inline void poll() {
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000217 if (pollmgr)
218 pollmgr->poll();
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000219 }
220
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000221 virtual void pointerEvent(const Point& pos, int buttonMask) {
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000222 pollmgr->setPointerPos(pos);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000223#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000224 if (!haveXtest) return;
225 XTestFakeMotionEvent(dpy, DefaultScreen(dpy), pos.x, pos.y, CurrentTime);
226 if (buttonMask != oldButtonMask) {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000227 for (int i = 0; i < maxButtons; i++) {
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000228 if ((buttonMask ^ oldButtonMask) & (1<<i)) {
229 if (buttonMask & (1<<i)) {
230 XTestFakeButtonEvent(dpy, i+1, True, CurrentTime);
231 } else {
232 XTestFakeButtonEvent(dpy, i+1, False, CurrentTime);
233 }
234 }
235 }
236 }
237 oldButtonMask = buttonMask;
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000238#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000239 }
240
241 virtual void keyEvent(rdr::U32 key, bool down) {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000242#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000243 if (!haveXtest) return;
244 int keycode = XKeysymToKeycode(dpy, key);
245 if (keycode)
246 XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000247#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000248 }
249
250 virtual void clientCutText(const char* str, int len) {
251 }
252
253 virtual Point getFbSize() {
254 return Point(pb->width(), pb->height());
255 }
256
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000257 // -=- ColourMap callbacks
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000258 virtual void lookup(int index, int* r, int* g, int* b) {
259 XColor xc;
260 xc.pixel = index;
261 if (index < DisplayCells(dpy,DefaultScreen(dpy))) {
262 XQueryColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), &xc);
263 } else {
264 xc.red = xc.green = xc.blue = 0;
265 }
266 *r = xc.red;
267 *g = xc.green;
268 *b = xc.blue;
269 }
270
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000271protected:
272 Display* dpy;
273 PixelFormat pf;
274 PixelBuffer* pb;
275 VNCServer* server;
276 Image* image;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000277 PollingManager* pollmgr;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000278 int oldButtonMask;
279 bool haveXtest;
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000280 int maxButtons;
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000281 bool running;
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000282};
283
284
285class FileTcpFilter : public TcpFilter
286{
287
288public:
289
290 FileTcpFilter(const char *fname)
291 : TcpFilter("-"), fileName(NULL), lastModTime(0)
292 {
293 if (fname != NULL)
294 fileName = strdup((char *)fname);
295 }
296
297 virtual ~FileTcpFilter()
298 {
299 if (fileName != NULL)
300 free(fileName);
301 }
302
303 virtual bool verifyConnection(Socket* s)
304 {
305 if (!reloadRules()) {
306 vlog.error("Could not read IP filtering rules: rejecting all clients");
307 filter.clear();
308 filter.push_back(parsePattern("-"));
309 return false;
310 }
311
312 return TcpFilter::verifyConnection(s);
313 }
314
315protected:
316
317 bool reloadRules()
318 {
319 if (fileName == NULL)
320 return true;
321
322 struct stat st;
323 if (stat(fileName, &st) != 0)
324 return false;
325
326 if (st.st_mtime != lastModTime) {
327 // Actually reload only if the file was modified
328 FILE *fp = fopen(fileName, "r");
329 if (fp == NULL)
330 return false;
331
332 // Remove all the rules from the parent class
333 filter.clear();
334
335 // Parse the file contents adding rules to the parent class
336 char buf[32];
337 while (readLine(buf, 32, fp)) {
338 if (buf[0] && strchr("+-?", buf[0])) {
339 filter.push_back(parsePattern(buf));
340 }
341 }
342
343 fclose(fp);
344 lastModTime = st.st_mtime;
345 }
346 return true;
347 }
348
349protected:
350
351 char *fileName;
352 time_t lastModTime;
353
354private:
355
356 //
357 // NOTE: we silently truncate long lines in this function.
358 //
359
360 bool readLine(char *buf, int bufSize, FILE *fp)
361 {
362 if (fp == NULL || buf == NULL || bufSize == 0)
363 return false;
364
365 if (fgets(buf, bufSize, fp) == NULL)
366 return false;
367
368 char *ptr = strchr(buf, '\n');
369 if (ptr != NULL) {
370 *ptr = '\0'; // remove newline at the end
371 } else {
372 if (!feof(fp)) {
373 int c;
374 do { // skip the rest of a long line
375 c = getc(fp);
376 } while (c != '\n' && c != EOF);
377 }
378 }
379 return true;
380 }
381
382};
383
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000384char* programName;
385
386static void usage()
387{
388 fprintf(stderr, "\nusage: %s [<parameters>]\n", programName);
389 fprintf(stderr,"\n"
390 "Parameters can be turned on with -<param> or off with -<param>=0\n"
391 "Parameters which take a value can be specified as "
392 "-<param> <value>\n"
393 "Other valid forms are <param>=<value> -<param>=<value> "
394 "--<param>=<value>\n"
395 "Parameter names are case-insensitive. The parameters are:\n\n");
396 Configuration::listParams(79, 14);
397 exit(1);
398}
399
400int main(int argc, char** argv)
401{
402 initStdIOLoggers();
403 LogWriter::setLogParams("*:stderr:30");
404
405 programName = argv[0];
406 Display* dpy;
407
408 for (int i = 1; i < argc; i++) {
409 if (Configuration::setParam(argv[i]))
410 continue;
411
412 if (argv[i][0] == '-') {
413 if (i+1 < argc) {
414 if (Configuration::setParam(&argv[i][1], argv[i+1])) {
415 i++;
416 continue;
417 }
418 }
419 usage();
420 }
421
422 usage();
423 }
424
425 CharArray dpyStr(displayname.getData());
426 if (!(dpy = XOpenDisplay(dpyStr.buf[0] ? dpyStr.buf : 0))) {
427 fprintf(stderr,"%s: unable to open display \"%s\"\r\n",
428 programName, XDisplayName(displayname.getData()));
429 exit(1);
430 }
431
432 signal(SIGHUP, CleanupSignalHandler);
433 signal(SIGINT, CleanupSignalHandler);
434 signal(SIGTERM, CleanupSignalHandler);
435
436 try {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000437 TXWindow::init(dpy,"x0vncserver");
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000438 XDesktop desktop(dpy);
439 VNCServerST server("x0vncserver", &desktop);
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000440 QueryConnHandler qcHandler(dpy, &server);
441 server.setQueryConnectionHandler(&qcHandler);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000442
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000443 TcpListener listener((int)rfbport);
444 vlog.info("Listening on port %d", (int)rfbport);
445
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000446 FileTcpFilter fileTcpFilter(hostsFile.getData());
447 if (strlen(hostsFile.getData()) != 0)
448 listener.setFilter(&fileTcpFilter);
449
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000450 PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage);
Constantin Kaplinsky602f34d2005-09-14 16:11:41 +0000451
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000452 while (true) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000453 struct timeval tv;
454 fd_set rfds;
455 std::list<Socket*> sockets;
456 std::list<Socket*>::iterator i;
457
458 // Process any incoming X events
459 TXWindow::handleXEvents(dpy);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000460
461 FD_ZERO(&rfds);
462 FD_SET(listener.getFd(), &rfds);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000463 server.getSockets(&sockets);
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000464 int clients_connected = 0;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000465 for (i = sockets.begin(); i != sockets.end(); i++) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000466 if ((*i)->isShutdown()) {
467 server.removeSocket(*i);
468 delete (*i);
469 } else {
470 FD_SET((*i)->getFd(), &rfds);
471 clients_connected++;
472 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000473 }
474
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000475 if (clients_connected) {
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000476 int wait_ms = sched.millisRemaining();
477 if (wait_ms > 500) {
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000478 wait_ms = 500;
479 }
480 tv.tv_usec = wait_ms * 1000;
481#ifdef DEBUG
Constantin Kaplinsky6a34ca52006-02-17 11:29:17 +0000482 // fprintf(stderr, "[%d]\t", wait_ms);
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000483#endif
484 } else {
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000485 sched.reset();
486 tv.tv_usec = 100000;
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000487 }
488 tv.tv_sec = 0;
489
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000490 // Do the wait...
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000491 sched.sleepStarted();
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000492 int n = select(FD_SETSIZE, &rfds, 0, 0, &tv);
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000493 sched.sleepFinished();
494
Constantin Kaplinsky659e9002005-09-09 08:32:02 +0000495 if (n < 0) {
496 if (errno == EINTR) {
497 vlog.debug("interrupted select() system call");
498 continue;
499 } else {
500 throw rdr::SystemException("select", errno);
501 }
502 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000503
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000504 // Accept new VNC connections
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000505 if (FD_ISSET(listener.getFd(), &rfds)) {
506 Socket* sock = listener.accept();
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000507 if (sock) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000508 server.addSocket(sock);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000509 } else {
510 vlog.status("Client connection rejected");
511 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000512 }
513
Constantin Kaplinsky478f22c2006-04-19 06:13:06 +0000514 Timer::checkTimeouts();
515 server.checkTimeouts();
516
517 // Client list could have been changed.
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000518 server.getSockets(&sockets);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000519
520 // Nothing more to do if there are no client connections.
521 if (sockets.empty())
522 continue;
523
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000524 // Process events on existing VNC connections
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000525 for (i = sockets.begin(); i != sockets.end(); i++) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000526 if (FD_ISSET((*i)->getFd(), &rfds))
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000527 server.processSocketEvent(*i);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000528 }
529
Constantin Kaplinsky478f22c2006-04-19 06:13:06 +0000530 if (desktop.isRunning() && sched.goodTimeToPoll()) {
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000531 sched.newPass();
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000532 desktop.poll();
533 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000534 }
535
536 } catch (rdr::Exception &e) {
537 vlog.error(e.str());
538 };
539
540 return 0;
541}