blob: 70a5361b7cc5f43d827bd441fee0acc61e25af1a [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 Kaplinsky44e99642006-05-20 12:58:38 +000047#include <x0vncserver/Geometry.h>
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +000048#include <x0vncserver/Image.h>
49#include <x0vncserver/PollingManager.h>
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +000050#include <x0vncserver/PollingScheduler.h>
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000051
Constantin Kaplinskya6866902006-03-02 12:03:30 +000052// XXX Lynx/OS 2.3: protos for select(), bzero()
53#ifdef Lynx
54#include <sys/proto.h>
55#endif
56
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000057using namespace rfb;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000058using namespace network;
59
60LogWriter vlog("main");
61
Constantin Kaplinsky602f34d2005-09-14 16:11:41 +000062IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
63 "cycle; actual interval may be dynamically "
Constantin Kaplinskyef7ac9b2006-02-10 12:26:54 +000064 "adjusted to satisfy MaxProcessorUsage setting", 30);
Constantin Kaplinsky602f34d2005-09-14 16:11:41 +000065IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of "
66 "CPU time to be consumed", 35);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000067BoolParameter useShm("UseSHM", "Use MIT-SHM extension if available", true);
68BoolParameter useOverlay("OverlayMode", "Use overlay mode under "
69 "IRIX or Solaris", true);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000070StringParameter displayname("display", "The X display", "");
71IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +000072IntParameter queryConnectTimeout("QueryConnectTimeout",
73 "Number of seconds to show the Accept Connection dialog before "
74 "rejecting the connection",
75 10);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +000076StringParameter hostsFile("HostsFile", "File with IP access control rules", "");
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +000077
78static void CleanupSignalHandler(int sig)
79{
80 // CleanupSignalHandler allows C++ object cleanup to happen because it calls
81 // exit() rather than the default which is to abort.
82 fprintf(stderr,"CleanupSignalHandler called\n");
83 exit(1);
84}
85
86
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +000087class QueryConnHandler : public VNCServerST::QueryConnectionHandler,
88 public QueryResultCallback {
89public:
90 QueryConnHandler(Display* dpy, VNCServerST* vs)
91 : display(dpy), server(vs), queryConnectDialog(0), queryConnectSock(0) {}
92 ~QueryConnHandler() { delete queryConnectDialog; }
93
94 // -=- VNCServerST::QueryConnectionHandler interface
95 virtual VNCServerST::queryResult queryConnection(network::Socket* sock,
96 const char* userName,
97 char** reason) {
98 if (queryConnectSock) {
99 *reason = strDup("Another connection is currently being queried.");
100 return VNCServerST::REJECT;
101 }
102 if (!userName) userName = "(anonymous)";
103 queryConnectSock = sock;
104 CharArray address(sock->getPeerAddress());
105 delete queryConnectDialog;
106 queryConnectDialog = new QueryConnectDialog(display, address.buf,
107 userName, queryConnectTimeout,
108 this);
109 queryConnectDialog->map();
110 return VNCServerST::PENDING;
111 }
112
113 // -=- QueryResultCallback interface
114 virtual void queryApproved() {
115 server->approveConnection(queryConnectSock, true, 0);
116 queryConnectSock = 0;
117 }
118 virtual void queryRejected() {
119 server->approveConnection(queryConnectSock, false,
120 "Connection rejected by local user");
121 queryConnectSock = 0;
122 }
123private:
124 Display* display;
125 VNCServerST* server;
126 QueryConnectDialog* queryConnectDialog;
127 network::Socket* queryConnectSock;
128};
129
130
131class XDesktop : public SDesktop, public ColourMap
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000132{
133public:
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000134 XDesktop(Display* dpy_, Geometry *geometry_)
135 : dpy(dpy_), geometry(geometry_), pb(0), server(0), image(0), pollmgr(0),
Constantin Kaplinsky49476542006-04-18 09:22:53 +0000136 oldButtonMask(0), haveXtest(false), maxButtons(0), running(false)
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000137 {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000138#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000139 int xtestEventBase;
140 int xtestErrorBase;
141 int major, minor;
142
143 if (XTestQueryExtension(dpy, &xtestEventBase,
144 &xtestErrorBase, &major, &minor)) {
145 XTestGrabControl(dpy, True);
146 vlog.info("XTest extension present - version %d.%d",major,minor);
147 haveXtest = true;
148 } else {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000149#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000150 vlog.info("XTest extension not present");
151 vlog.info("unable to inject events or display while server is grabbed");
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000152#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000153 }
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000154#endif
155
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000156 }
157 virtual ~XDesktop() {
158 stop();
159 }
160
161 // -=- SDesktop interface
162
163 virtual void start(VNCServer* vs) {
164
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000165 // Determine actual number of buttons of the X pointer device.
166 unsigned char btnMap[8];
167 int numButtons = XGetPointerMapping(dpy, btnMap, 8);
168 maxButtons = (numButtons > 8) ? 8 : numButtons;
169 vlog.info("Enabling %d button%s of X pointer device",
170 maxButtons, (maxButtons != 1) ? "s" : "");
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000171
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000172 ImageFactory factory((bool)useShm, (bool)useOverlay);
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000173 image = factory.newImage(dpy, geometry->width(), geometry->height());
174 image->get(DefaultRootWindow(dpy),
175 geometry->offsetLeft(), geometry->offsetTop());
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000176
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000177 // FIXME: Duplication in using offsets above and here:
178 pollmgr = new PollingManager(dpy, image, &factory,
179 geometry->offsetLeft(),
180 geometry->offsetTop());
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000181 pollmgr->setVNCServer(vs);
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000182
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000183 pf.bpp = image->xim->bits_per_pixel;
184 pf.depth = image->xim->depth;
185 pf.bigEndian = (image->xim->byte_order == MSBFirst);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000186 pf.trueColour = image->isTrueColor();
187 pf.redShift = ffs(image->xim->red_mask) - 1;
188 pf.greenShift = ffs(image->xim->green_mask) - 1;
189 pf.blueShift = ffs(image->xim->blue_mask) - 1;
190 pf.redMax = image->xim->red_mask >> pf.redShift;
191 pf.greenMax = image->xim->green_mask >> pf.greenShift;
192 pf.blueMax = image->xim->blue_mask >> pf.blueShift;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000193
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000194 pb = new FullFramePixelBuffer(pf, geometry->width(), geometry->height(),
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000195 (rdr::U8*)image->xim->data, this);
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000196 server = vs;
197 server->setPixelBuffer(pb);
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000198
199 running = true;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000200 }
201
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000202 virtual void stop() {
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000203 running = false;
204
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000205 delete pb;
206 delete pollmgr;
Constantin Kaplinsky93c3f892006-04-19 10:32:33 +0000207 delete image;
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000208
209 pb = 0;
210 pollmgr = 0;
Constantin Kaplinsky93c3f892006-04-19 10:32:33 +0000211 image = 0;
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000212 }
213
214 inline bool isRunning() {
215 return running;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000216 }
217
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000218 inline void poll() {
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000219 if (pollmgr)
220 pollmgr->poll();
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000221 }
222
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000223 virtual void pointerEvent(const Point& pos, int buttonMask) {
Constantin Kaplinskyce676c62006-02-08 13:36:58 +0000224 pollmgr->setPointerPos(pos);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000225#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000226 if (!haveXtest) return;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000227 XTestFakeMotionEvent(dpy, DefaultScreen(dpy),
228 geometry->offsetLeft() + pos.x,
229 geometry->offsetTop() + pos.y,
230 CurrentTime);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000231 if (buttonMask != oldButtonMask) {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000232 for (int i = 0; i < maxButtons; i++) {
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000233 if ((buttonMask ^ oldButtonMask) & (1<<i)) {
234 if (buttonMask & (1<<i)) {
235 XTestFakeButtonEvent(dpy, i+1, True, CurrentTime);
236 } else {
237 XTestFakeButtonEvent(dpy, i+1, False, CurrentTime);
238 }
239 }
240 }
241 }
242 oldButtonMask = buttonMask;
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000243#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000244 }
245
246 virtual void keyEvent(rdr::U32 key, bool down) {
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000247#ifdef HAVE_XTEST
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000248 if (!haveXtest) return;
249 int keycode = XKeysymToKeycode(dpy, key);
250 if (keycode)
251 XTestFakeKeyEvent(dpy, keycode, down, CurrentTime);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000252#endif
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000253 }
254
255 virtual void clientCutText(const char* str, int len) {
256 }
257
258 virtual Point getFbSize() {
259 return Point(pb->width(), pb->height());
260 }
261
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000262 // -=- ColourMap callbacks
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000263 virtual void lookup(int index, int* r, int* g, int* b) {
264 XColor xc;
265 xc.pixel = index;
266 if (index < DisplayCells(dpy,DefaultScreen(dpy))) {
267 XQueryColor(dpy, DefaultColormap(dpy,DefaultScreen(dpy)), &xc);
268 } else {
269 xc.red = xc.green = xc.blue = 0;
270 }
271 *r = xc.red;
272 *g = xc.green;
273 *b = xc.blue;
274 }
275
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000276protected:
277 Display* dpy;
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000278 Geometry* geometry;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000279 PixelFormat pf;
280 PixelBuffer* pb;
281 VNCServer* server;
282 Image* image;
Constantin Kaplinskyaf1891c2005-09-29 06:18:28 +0000283 PollingManager* pollmgr;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000284 int oldButtonMask;
285 bool haveXtest;
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000286 int maxButtons;
Constantin Kaplinskyb38ceeb2006-04-18 08:57:17 +0000287 bool running;
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000288};
289
290
291class FileTcpFilter : public TcpFilter
292{
293
294public:
295
296 FileTcpFilter(const char *fname)
297 : TcpFilter("-"), fileName(NULL), lastModTime(0)
298 {
299 if (fname != NULL)
300 fileName = strdup((char *)fname);
301 }
302
303 virtual ~FileTcpFilter()
304 {
305 if (fileName != NULL)
306 free(fileName);
307 }
308
309 virtual bool verifyConnection(Socket* s)
310 {
311 if (!reloadRules()) {
312 vlog.error("Could not read IP filtering rules: rejecting all clients");
313 filter.clear();
314 filter.push_back(parsePattern("-"));
315 return false;
316 }
317
318 return TcpFilter::verifyConnection(s);
319 }
320
321protected:
322
323 bool reloadRules()
324 {
325 if (fileName == NULL)
326 return true;
327
328 struct stat st;
329 if (stat(fileName, &st) != 0)
330 return false;
331
332 if (st.st_mtime != lastModTime) {
333 // Actually reload only if the file was modified
334 FILE *fp = fopen(fileName, "r");
335 if (fp == NULL)
336 return false;
337
338 // Remove all the rules from the parent class
339 filter.clear();
340
341 // Parse the file contents adding rules to the parent class
342 char buf[32];
343 while (readLine(buf, 32, fp)) {
344 if (buf[0] && strchr("+-?", buf[0])) {
345 filter.push_back(parsePattern(buf));
346 }
347 }
348
349 fclose(fp);
350 lastModTime = st.st_mtime;
351 }
352 return true;
353 }
354
355protected:
356
357 char *fileName;
358 time_t lastModTime;
359
360private:
361
362 //
363 // NOTE: we silently truncate long lines in this function.
364 //
365
366 bool readLine(char *buf, int bufSize, FILE *fp)
367 {
368 if (fp == NULL || buf == NULL || bufSize == 0)
369 return false;
370
371 if (fgets(buf, bufSize, fp) == NULL)
372 return false;
373
374 char *ptr = strchr(buf, '\n');
375 if (ptr != NULL) {
376 *ptr = '\0'; // remove newline at the end
377 } else {
378 if (!feof(fp)) {
379 int c;
380 do { // skip the rest of a long line
381 c = getc(fp);
382 } while (c != '\n' && c != EOF);
383 }
384 }
385 return true;
386 }
387
388};
389
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000390char* programName;
391
392static void usage()
393{
394 fprintf(stderr, "\nusage: %s [<parameters>]\n", programName);
395 fprintf(stderr,"\n"
396 "Parameters can be turned on with -<param> or off with -<param>=0\n"
397 "Parameters which take a value can be specified as "
398 "-<param> <value>\n"
399 "Other valid forms are <param>=<value> -<param>=<value> "
400 "--<param>=<value>\n"
401 "Parameter names are case-insensitive. The parameters are:\n\n");
402 Configuration::listParams(79, 14);
403 exit(1);
404}
405
406int main(int argc, char** argv)
407{
408 initStdIOLoggers();
409 LogWriter::setLogParams("*:stderr:30");
410
411 programName = argv[0];
412 Display* dpy;
413
414 for (int i = 1; i < argc; i++) {
415 if (Configuration::setParam(argv[i]))
416 continue;
417
418 if (argv[i][0] == '-') {
419 if (i+1 < argc) {
420 if (Configuration::setParam(&argv[i][1], argv[i+1])) {
421 i++;
422 continue;
423 }
424 }
425 usage();
426 }
427
428 usage();
429 }
430
431 CharArray dpyStr(displayname.getData());
432 if (!(dpy = XOpenDisplay(dpyStr.buf[0] ? dpyStr.buf : 0))) {
433 fprintf(stderr,"%s: unable to open display \"%s\"\r\n",
434 programName, XDisplayName(displayname.getData()));
435 exit(1);
436 }
437
438 signal(SIGHUP, CleanupSignalHandler);
439 signal(SIGINT, CleanupSignalHandler);
440 signal(SIGTERM, CleanupSignalHandler);
441
442 try {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000443 TXWindow::init(dpy,"x0vncserver");
Constantin Kaplinsky44e99642006-05-20 12:58:38 +0000444 Geometry geo(DisplayWidth(dpy, DefaultScreen(dpy)),
445 DisplayHeight(dpy, DefaultScreen(dpy)));
446 XDesktop desktop(dpy, &geo);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000447 VNCServerST server("x0vncserver", &desktop);
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000448 QueryConnHandler qcHandler(dpy, &server);
449 server.setQueryConnectionHandler(&qcHandler);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000450
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000451 TcpListener listener((int)rfbport);
452 vlog.info("Listening on port %d", (int)rfbport);
453
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000454 FileTcpFilter fileTcpFilter(hostsFile.getData());
455 if (strlen(hostsFile.getData()) != 0)
456 listener.setFilter(&fileTcpFilter);
457
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000458 PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage);
Constantin Kaplinsky602f34d2005-09-14 16:11:41 +0000459
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000460 while (true) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000461 struct timeval tv;
462 fd_set rfds;
463 std::list<Socket*> sockets;
464 std::list<Socket*>::iterator i;
465
466 // Process any incoming X events
467 TXWindow::handleXEvents(dpy);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000468
469 FD_ZERO(&rfds);
470 FD_SET(listener.getFd(), &rfds);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000471 server.getSockets(&sockets);
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000472 int clients_connected = 0;
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000473 for (i = sockets.begin(); i != sockets.end(); i++) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000474 if ((*i)->isShutdown()) {
475 server.removeSocket(*i);
476 delete (*i);
477 } else {
478 FD_SET((*i)->getFd(), &rfds);
479 clients_connected++;
480 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000481 }
482
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000483 if (clients_connected) {
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000484 int wait_ms = sched.millisRemaining();
485 if (wait_ms > 500) {
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000486 wait_ms = 500;
487 }
488 tv.tv_usec = wait_ms * 1000;
489#ifdef DEBUG
Constantin Kaplinsky6a34ca52006-02-17 11:29:17 +0000490 // fprintf(stderr, "[%d]\t", wait_ms);
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000491#endif
492 } else {
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000493 sched.reset();
494 tv.tv_usec = 100000;
Constantin Kaplinsky3f56fa72006-02-16 11:50:25 +0000495 }
496 tv.tv_sec = 0;
497
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000498 // Do the wait...
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000499 sched.sleepStarted();
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000500 int n = select(FD_SETSIZE, &rfds, 0, 0, &tv);
Constantin Kaplinskye179b5a2006-02-17 09:30:21 +0000501 sched.sleepFinished();
502
Constantin Kaplinsky659e9002005-09-09 08:32:02 +0000503 if (n < 0) {
504 if (errno == EINTR) {
505 vlog.debug("interrupted select() system call");
506 continue;
507 } else {
508 throw rdr::SystemException("select", errno);
509 }
510 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000511
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000512 // Accept new VNC connections
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000513 if (FD_ISSET(listener.getFd(), &rfds)) {
514 Socket* sock = listener.accept();
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000515 if (sock) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000516 server.addSocket(sock);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000517 } else {
518 vlog.status("Client connection rejected");
519 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000520 }
521
Constantin Kaplinsky478f22c2006-04-19 06:13:06 +0000522 Timer::checkTimeouts();
523 server.checkTimeouts();
524
525 // Client list could have been changed.
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000526 server.getSockets(&sockets);
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000527
528 // Nothing more to do if there are no client connections.
529 if (sockets.empty())
530 continue;
531
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000532 // Process events on existing VNC connections
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000533 for (i = sockets.begin(); i != sockets.end(); i++) {
Constantin Kaplinskya1d2cef2006-04-17 08:46:22 +0000534 if (FD_ISSET((*i)->getFd(), &rfds))
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000535 server.processSocketEvent(*i);
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000536 }
537
Constantin Kaplinsky478f22c2006-04-19 06:13:06 +0000538 if (desktop.isRunning() && sched.goodTimeToPoll()) {
Constantin Kaplinsky0cbad332006-02-16 14:51:11 +0000539 sched.newPass();
Constantin Kaplinskyd31fd312005-09-08 19:29:02 +0000540 desktop.poll();
541 }
Constantin Kaplinsky47ed8d32004-10-08 09:43:57 +0000542 }
543
544 } catch (rdr::Exception &e) {
545 vlog.error(e.str());
546 };
547
548 return 0;
549}