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.

x0vncserver.cxx 10KB

Rebrand the source as TigerVNC. It is my hope that this patch is minimal but still complete. The rebranding was done using a script: find trunk -name .svn -prune -o -type f -exec rep.sh \{\} \; pushd trunk svn revert doc/TODO doc/registered-codes.txt doc/ft-protocol-problems.txt doc/rfbtight.tex perl -pi -e 's|tightvnc|tigervnc|g' unix/configure.ac win/configure.ac unix/README With rep.sh looking like: perl -pi -e 's|TightVNC|TigerVNC|g' "$@" perl -pi -e 's|www\.tightvnc\.com/bugs\.html|www\.tigervnc\.org|g' "$@" perl -pi -e 's|www\.tightvnc\.com|www\.tigervnc\.org|g' "$@" perl -pi -e 's|devteam\@tightvnc\.com|tigervnc-devel\@lists\.sourceforge\.net|g' "$@" perl -pi -e 's|TigerVNC Team|TightVNC Team|g' "$@" perl -pi -e 's|TigerVNC Group|TightVNC Group|g' "$@" perl -pi -e 's|TigerVNC protocol|TightVNC protocol|g' "$@" perl -pi -e 's|TigerVNC-specific|TightVNC-specific|g' "$@" perl -pi -e 's|Vendor signatures: standard VNC/RealVNC, TridiaVNC, and TigerVNC|Vendor signatures: standard VNC/RealVNC, TridiaVNC, and TightVNC|g' "$@" perl -pi -e 's|TigerVNC vendor|TightVNC vendor|g' "$@" perl -pi -e 's|TigerVNC extension|TightVNC extension|g' "$@" perl -pi -e 's|protocolTigerVNC|protocolTightVNC|g' "$@" perl -pi -e 's|TigerVNC additions were|TightVNC additions were|g' "$@" perl -pi -e 's|TigerVNC 1\.2|TightVNC 1\.2|g' "$@" perl -pi -e 's|TigerVNC authentication type|TightVNC authentication type|g' "$@" git-svn-id: svn://svn.code.sf.net/p/tigervnc/code/trunk@3621 3789f03b-4d11-0410-bbf8-ca57d06f2519
15 년 전
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401
  1. /* Copyright (C) 2002-2005 RealVNC Ltd. All Rights Reserved.
  2. * Copyright (C) 2004-2008 Constantin Kaplinsky. All Rights Reserved.
  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. // FIXME: Check cases when screen width/height is not a multiply of 32.
  20. // e.g. 800x600.
  21. #include <strings.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include <unistd.h>
  25. #include <errno.h>
  26. #include <rfb/Logger_stdio.h>
  27. #include <rfb/LogWriter.h>
  28. #include <rfb/VNCServerST.h>
  29. #include <rfb/Configuration.h>
  30. #include <rfb/Timer.h>
  31. #include <network/TcpSocket.h>
  32. #include <network/UnixSocket.h>
  33. #include <signal.h>
  34. #include <X11/X.h>
  35. #include <X11/Xlib.h>
  36. #include <X11/Xutil.h>
  37. #include <x0vncserver/XDesktop.h>
  38. #include <x0vncserver/Geometry.h>
  39. #include <x0vncserver/Image.h>
  40. #include <x0vncserver/PollingScheduler.h>
  41. extern char buildtime[];
  42. using namespace rfb;
  43. using namespace network;
  44. static LogWriter vlog("Main");
  45. IntParameter pollingCycle("PollingCycle", "Milliseconds per one polling "
  46. "cycle; actual interval may be dynamically "
  47. "adjusted to satisfy MaxProcessorUsage setting", 30);
  48. IntParameter maxProcessorUsage("MaxProcessorUsage", "Maximum percentage of "
  49. "CPU time to be consumed", 35);
  50. StringParameter displayname("display", "The X display", "");
  51. IntParameter rfbport("rfbport", "TCP port to listen for RFB protocol",5900);
  52. StringParameter rfbunixpath("rfbunixpath", "Unix socket to listen for RFB protocol", "");
  53. IntParameter rfbunixmode("rfbunixmode", "Unix socket access mode", 0600);
  54. StringParameter hostsFile("HostsFile", "File with IP access control rules", "");
  55. BoolParameter localhostOnly("localhost",
  56. "Only allow connections from localhost",
  57. false);
  58. //
  59. // Allow the main loop terminate itself gracefully on receiving a signal.
  60. //
  61. static bool caughtSignal = false;
  62. static void CleanupSignalHandler(int sig)
  63. {
  64. caughtSignal = true;
  65. }
  66. class FileTcpFilter : public TcpFilter
  67. {
  68. public:
  69. FileTcpFilter(const char *fname)
  70. : TcpFilter("-"), fileName(NULL), lastModTime(0)
  71. {
  72. if (fname != NULL)
  73. fileName = strdup((char *)fname);
  74. }
  75. virtual ~FileTcpFilter()
  76. {
  77. if (fileName != NULL)
  78. free(fileName);
  79. }
  80. virtual bool verifyConnection(Socket* s)
  81. {
  82. if (!reloadRules()) {
  83. vlog.error("Could not read IP filtering rules: rejecting all clients");
  84. filter.clear();
  85. filter.push_back(parsePattern("-"));
  86. return false;
  87. }
  88. return TcpFilter::verifyConnection(s);
  89. }
  90. protected:
  91. bool reloadRules()
  92. {
  93. if (fileName == NULL)
  94. return true;
  95. struct stat st;
  96. if (stat(fileName, &st) != 0)
  97. return false;
  98. if (st.st_mtime != lastModTime) {
  99. // Actually reload only if the file was modified
  100. FILE *fp = fopen(fileName, "r");
  101. if (fp == NULL)
  102. return false;
  103. // Remove all the rules from the parent class
  104. filter.clear();
  105. // Parse the file contents adding rules to the parent class
  106. char buf[32];
  107. while (readLine(buf, 32, fp)) {
  108. if (buf[0] && strchr("+-?", buf[0])) {
  109. filter.push_back(parsePattern(buf));
  110. }
  111. }
  112. fclose(fp);
  113. lastModTime = st.st_mtime;
  114. }
  115. return true;
  116. }
  117. protected:
  118. char *fileName;
  119. time_t lastModTime;
  120. private:
  121. //
  122. // NOTE: we silently truncate long lines in this function.
  123. //
  124. bool readLine(char *buf, int bufSize, FILE *fp)
  125. {
  126. if (fp == NULL || buf == NULL || bufSize == 0)
  127. return false;
  128. if (fgets(buf, bufSize, fp) == NULL)
  129. return false;
  130. char *ptr = strchr(buf, '\n');
  131. if (ptr != NULL) {
  132. *ptr = '\0'; // remove newline at the end
  133. } else {
  134. if (!feof(fp)) {
  135. int c;
  136. do { // skip the rest of a long line
  137. c = getc(fp);
  138. } while (c != '\n' && c != EOF);
  139. }
  140. }
  141. return true;
  142. }
  143. };
  144. char* programName;
  145. static void printVersion(FILE *fp)
  146. {
  147. fprintf(fp, "TigerVNC Server version %s, built %s\n",
  148. PACKAGE_VERSION, buildtime);
  149. }
  150. static void usage()
  151. {
  152. printVersion(stderr);
  153. fprintf(stderr, "\nUsage: %s [<parameters>]\n", programName);
  154. fprintf(stderr, " %s --version\n", programName);
  155. fprintf(stderr,"\n"
  156. "Parameters can be turned on with -<param> or off with -<param>=0\n"
  157. "Parameters which take a value can be specified as "
  158. "-<param> <value>\n"
  159. "Other valid forms are <param>=<value> -<param>=<value> "
  160. "--<param>=<value>\n"
  161. "Parameter names are case-insensitive. The parameters are:\n\n");
  162. Configuration::listParams(79, 14);
  163. exit(1);
  164. }
  165. int main(int argc, char** argv)
  166. {
  167. initStdIOLoggers();
  168. LogWriter::setLogParams("*:stderr:30");
  169. programName = argv[0];
  170. Display* dpy;
  171. Configuration::enableServerParams();
  172. for (int i = 1; i < argc; i++) {
  173. if (Configuration::setParam(argv[i]))
  174. continue;
  175. if (argv[i][0] == '-') {
  176. if (i+1 < argc) {
  177. if (Configuration::setParam(&argv[i][1], argv[i+1])) {
  178. i++;
  179. continue;
  180. }
  181. }
  182. if (strcmp(argv[i], "-v") == 0 ||
  183. strcmp(argv[i], "-version") == 0 ||
  184. strcmp(argv[i], "--version") == 0) {
  185. printVersion(stdout);
  186. return 0;
  187. }
  188. usage();
  189. }
  190. usage();
  191. }
  192. CharArray dpyStr(displayname.getData());
  193. if (!(dpy = XOpenDisplay(dpyStr.buf[0] ? dpyStr.buf : 0))) {
  194. // FIXME: Why not vlog.error(...)?
  195. fprintf(stderr,"%s: unable to open display \"%s\"\r\n",
  196. programName, XDisplayName(dpyStr.buf));
  197. exit(1);
  198. }
  199. signal(SIGHUP, CleanupSignalHandler);
  200. signal(SIGINT, CleanupSignalHandler);
  201. signal(SIGTERM, CleanupSignalHandler);
  202. std::list<SocketListener*> listeners;
  203. try {
  204. TXWindow::init(dpy,"x0vncserver");
  205. Geometry geo(DisplayWidth(dpy, DefaultScreen(dpy)),
  206. DisplayHeight(dpy, DefaultScreen(dpy)));
  207. if (geo.getRect().is_empty()) {
  208. vlog.error("Exiting with error");
  209. return 1;
  210. }
  211. XDesktop desktop(dpy, &geo);
  212. VNCServerST server("x0vncserver", &desktop);
  213. if (rfbunixpath.getValueStr()[0] != '\0') {
  214. listeners.push_back(new network::UnixListener(rfbunixpath, rfbunixmode));
  215. vlog.info("Listening on %s (mode %04o)", (const char*)rfbunixpath, (int)rfbunixmode);
  216. } else {
  217. if (localhostOnly)
  218. createLocalTcpListeners(&listeners, (int)rfbport);
  219. else
  220. createTcpListeners(&listeners, 0, (int)rfbport);
  221. vlog.info("Listening on port %d", (int)rfbport);
  222. }
  223. const char *hostsData = hostsFile.getData();
  224. FileTcpFilter fileTcpFilter(hostsData);
  225. if (strlen(hostsData) != 0)
  226. for (std::list<SocketListener*>::iterator i = listeners.begin();
  227. i != listeners.end();
  228. i++)
  229. (*i)->setFilter(&fileTcpFilter);
  230. delete[] hostsData;
  231. PollingScheduler sched((int)pollingCycle, (int)maxProcessorUsage);
  232. while (!caughtSignal) {
  233. int wait_ms;
  234. struct timeval tv;
  235. fd_set rfds, wfds;
  236. std::list<Socket*> sockets;
  237. std::list<Socket*>::iterator i;
  238. // Process any incoming X events
  239. TXWindow::handleXEvents(dpy);
  240. FD_ZERO(&rfds);
  241. FD_ZERO(&wfds);
  242. FD_SET(ConnectionNumber(dpy), &rfds);
  243. for (std::list<SocketListener*>::iterator i = listeners.begin();
  244. i != listeners.end();
  245. i++)
  246. FD_SET((*i)->getFd(), &rfds);
  247. server.getSockets(&sockets);
  248. int clients_connected = 0;
  249. for (i = sockets.begin(); i != sockets.end(); i++) {
  250. if ((*i)->isShutdown()) {
  251. server.removeSocket(*i);
  252. delete (*i);
  253. } else {
  254. FD_SET((*i)->getFd(), &rfds);
  255. if ((*i)->outStream().hasBufferedData())
  256. FD_SET((*i)->getFd(), &wfds);
  257. clients_connected++;
  258. }
  259. }
  260. if (!clients_connected)
  261. sched.reset();
  262. wait_ms = 0;
  263. if (sched.isRunning()) {
  264. wait_ms = sched.millisRemaining();
  265. if (wait_ms > 500) {
  266. wait_ms = 500;
  267. }
  268. }
  269. soonestTimeout(&wait_ms, Timer::checkTimeouts());
  270. tv.tv_sec = wait_ms / 1000;
  271. tv.tv_usec = (wait_ms % 1000) * 1000;
  272. // Do the wait...
  273. sched.sleepStarted();
  274. int n = select(FD_SETSIZE, &rfds, &wfds, 0,
  275. wait_ms ? &tv : NULL);
  276. sched.sleepFinished();
  277. if (n < 0) {
  278. if (errno == EINTR) {
  279. vlog.debug("Interrupted select() system call");
  280. continue;
  281. } else {
  282. throw rdr::SystemException("select", errno);
  283. }
  284. }
  285. // Accept new VNC connections
  286. for (std::list<SocketListener*>::iterator i = listeners.begin();
  287. i != listeners.end();
  288. i++) {
  289. if (FD_ISSET((*i)->getFd(), &rfds)) {
  290. Socket* sock = (*i)->accept();
  291. if (sock) {
  292. server.addSocket(sock);
  293. } else {
  294. vlog.status("Client connection rejected");
  295. }
  296. }
  297. }
  298. Timer::checkTimeouts();
  299. // Client list could have been changed.
  300. server.getSockets(&sockets);
  301. // Nothing more to do if there are no client connections.
  302. if (sockets.empty())
  303. continue;
  304. // Process events on existing VNC connections
  305. for (i = sockets.begin(); i != sockets.end(); i++) {
  306. if (FD_ISSET((*i)->getFd(), &rfds))
  307. server.processSocketReadEvent(*i);
  308. if (FD_ISSET((*i)->getFd(), &wfds))
  309. server.processSocketWriteEvent(*i);
  310. }
  311. if (desktop.isRunning() && sched.goodTimeToPoll()) {
  312. sched.newPass();
  313. desktop.poll();
  314. }
  315. }
  316. } catch (rdr::Exception &e) {
  317. vlog.error("%s", e.str());
  318. return 1;
  319. }
  320. TXWindow::handleXEvents(dpy);
  321. // Run listener destructors; remove UNIX sockets etc
  322. for (std::list<SocketListener*>::iterator i = listeners.begin();
  323. i != listeners.end();
  324. i++) {
  325. delete *i;
  326. }
  327. vlog.info("Terminated");
  328. return 0;
  329. }