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.

VNCServerWin32.cxx 12KB

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 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. // -=- WinVNC Version 4.0 Main Routine
  19. #include <winvnc/VNCServerWin32.h>
  20. #include <winvnc/resource.h>
  21. #include <winvnc/ListConnInfo.h>
  22. #include <winvnc/STrayIcon.h>
  23. #include <os/Mutex.h>
  24. #include <rfb_win32/ComputerName.h>
  25. #include <rfb_win32/CurrentUser.h>
  26. #include <rfb_win32/Service.h>
  27. #include <rfb/Hostname.h>
  28. #include <rfb/LogWriter.h>
  29. using namespace rfb;
  30. using namespace win32;
  31. using namespace winvnc;
  32. using namespace network;
  33. static LogWriter vlog("VNCServerWin32");
  34. const TCHAR* winvnc::VNCServerWin32::RegConfigPath = _T("Software\\TigerVNC\\WinVNC4");
  35. static IntParameter port_number("PortNumber",
  36. "TCP/IP port on which the server will accept connections", 5900);
  37. static StringParameter hosts("Hosts",
  38. "Filter describing which hosts are allowed access to this server", "+");
  39. static BoolParameter localHost("LocalHost",
  40. "Only accept connections from via the local loop-back network interface", false);
  41. static BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
  42. "Only prompt for a local user to accept incoming connections if there is a user logged on", false);
  43. static BoolParameter showTrayIcon("ShowTrayIcon",
  44. "Show the configuration applet in the system tray icon", true);
  45. VNCServerWin32::VNCServerWin32()
  46. : command(NoCommand),
  47. commandEvent(CreateEvent(0, TRUE, FALSE, 0)),
  48. sessionEvent(isServiceProcess() ?
  49. CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNC") : 0),
  50. vncServer(CStr(ComputerName().buf), &desktop),
  51. thread_id(-1), runServer(false), isDesktopStarted(false),
  52. config(&sockMgr), rfbSock(&sockMgr), trayIcon(0),
  53. queryConnectDialog(0)
  54. {
  55. commandLock = new os::Mutex;
  56. commandSig = new os::Condition(commandLock);
  57. runLock = new os::Mutex;
  58. // Initialise the desktop
  59. desktop.setStatusLocation(&isDesktopStarted);
  60. desktop.setQueryConnectionHandler(this);
  61. // Register the desktop's event to be handled
  62. sockMgr.addEvent(desktop.getUpdateEvent(), &desktop);
  63. sockMgr.addEvent(desktop.getTerminateEvent(), this);
  64. // Register the queued command event to be handled
  65. sockMgr.addEvent(commandEvent, this);
  66. if (sessionEvent)
  67. sockMgr.addEvent(sessionEvent, this);
  68. }
  69. VNCServerWin32::~VNCServerWin32() {
  70. delete trayIcon;
  71. // Stop the SDisplay from updating our state
  72. desktop.setStatusLocation(0);
  73. // Join the Accept/Reject dialog thread
  74. if (queryConnectDialog) {
  75. queryConnectDialog->wait();
  76. delete queryConnectDialog;
  77. }
  78. delete runLock;
  79. delete commandSig;
  80. delete commandLock;
  81. }
  82. void VNCServerWin32::processAddressChange() {
  83. if (!trayIcon)
  84. return;
  85. // Tool-tip prefix depends on server mode
  86. const TCHAR* prefix = _T("VNC Server (User):");
  87. if (isServiceProcess())
  88. prefix = _T("VNC Server (Service):");
  89. // Fetch the list of addresses
  90. std::list<char*> addrs;
  91. if (rfbSock.isListening())
  92. TcpListener::getMyAddresses(&addrs);
  93. else
  94. addrs.push_front(strDup("Not accepting connections"));
  95. // Allocate space for the new tip
  96. std::list<char*>::iterator i, next_i;
  97. int length = _tcslen(prefix)+1;
  98. for (i=addrs.begin(); i!= addrs.end(); i++)
  99. length += strlen(*i) + 1;
  100. // Build the new tip
  101. TCharArray toolTip(length);
  102. _tcscpy(toolTip.buf, prefix);
  103. for (i=addrs.begin(); i!= addrs.end(); i=next_i) {
  104. next_i = i; next_i ++;
  105. TCharArray addr(*i); // Assumes ownership of string
  106. _tcscat(toolTip.buf, addr.buf);
  107. if (next_i != addrs.end())
  108. _tcscat(toolTip.buf, _T(","));
  109. }
  110. // Pass the new tip to the tray icon
  111. vlog.info("Refreshing tray icon");
  112. trayIcon->setToolTip(toolTip.buf);
  113. }
  114. void VNCServerWin32::regConfigChanged() {
  115. // -=- Make sure we're listening on the right ports.
  116. rfbSock.setServer(&vncServer);
  117. rfbSock.setPort(port_number, localHost);
  118. // -=- Update the TCP address filter for both ports, if open.
  119. CharArray pattern(hosts.getData());
  120. rfbSock.setFilter(pattern.buf);
  121. // -=- Update the tray icon tooltip text with IP addresses
  122. processAddressChange();
  123. }
  124. int VNCServerWin32::run() {
  125. {
  126. os::AutoMutex a(runLock);
  127. thread_id = GetCurrentThreadId();
  128. runServer = true;
  129. }
  130. // - Create the tray icon (if possible)
  131. if (showTrayIcon)
  132. trayIcon = new STrayIconThread(*this, IDI_ICON, IDI_CONNECTED,
  133. IDI_ICON_DISABLE, IDI_CONNECTED_DISABLE,
  134. IDR_TRAY);
  135. // - Register for notification of configuration changes
  136. config.setCallback(this);
  137. if (isServiceProcess())
  138. config.setKey(HKEY_LOCAL_MACHINE, RegConfigPath);
  139. else
  140. config.setKey(HKEY_CURRENT_USER, RegConfigPath);
  141. // - Set the address-changed handler for the RFB socket
  142. rfbSock.setAddressChangeNotifier(this);
  143. DWORD result = 0;
  144. try {
  145. vlog.debug("Entering message loop");
  146. // - Run the server until we're told to quit
  147. MSG msg;
  148. int result = 0;
  149. while (runServer) {
  150. result = sockMgr.getMessage(&msg, NULL, 0, 0);
  151. if (result < 0)
  152. throw rdr::SystemException("getMessage", GetLastError());
  153. if (!isServiceProcess() && (result == 0))
  154. break;
  155. TranslateMessage(&msg);
  156. DispatchMessage(&msg);
  157. }
  158. vlog.debug("Server exited cleanly");
  159. } catch (rdr::SystemException &s) {
  160. vlog.error("%s", s.str());
  161. result = s.err;
  162. } catch (rdr::Exception &e) {
  163. vlog.error("%s", e.str());
  164. }
  165. {
  166. os::AutoMutex a(runLock);
  167. runServer = false;
  168. thread_id = (DWORD)-1;
  169. }
  170. return result;
  171. }
  172. void VNCServerWin32::stop() {
  173. os::AutoMutex a(runLock);
  174. runServer = false;
  175. if (thread_id != (DWORD)-1)
  176. PostThreadMessage(thread_id, WM_QUIT, 0, 0);
  177. }
  178. bool VNCServerWin32::disconnectClients(const char* reason) {
  179. return queueCommand(DisconnectClients, reason, 0);
  180. }
  181. bool VNCServerWin32::addNewClient(const char* client) {
  182. TcpSocket* sock = 0;
  183. try {
  184. CharArray hostname;
  185. int port;
  186. getHostAndPort(client, &hostname.buf, &port, 5500);
  187. vlog.error("port=%d", port);
  188. sock = new TcpSocket(hostname.buf, port);
  189. if (queueCommand(AddClient, sock, 0))
  190. return true;
  191. delete sock;
  192. } catch (...) {
  193. delete sock;
  194. }
  195. return false;
  196. }
  197. bool VNCServerWin32::getClientsInfo(ListConnInfo* LCInfo) {
  198. return queueCommand(GetClientsInfo, LCInfo, 0);
  199. }
  200. bool VNCServerWin32::setClientsStatus(ListConnInfo* LCInfo) {
  201. return queueCommand(SetClientsStatus, LCInfo, 0);
  202. }
  203. void VNCServerWin32::queryConnection(network::Socket* sock,
  204. const char* userName)
  205. {
  206. if (queryOnlyIfLoggedOn && CurrentUserToken().noUserLoggedOn()) {
  207. vncServer.approveConnection(sock, true, NULL);
  208. return;
  209. }
  210. if (queryConnectDialog) {
  211. vncServer.approveConnection(sock, false, "Another connection is currently being queried.");
  212. return;
  213. }
  214. queryConnectDialog = new QueryConnectDialog(sock, userName, this);
  215. queryConnectDialog->startDialog();
  216. }
  217. void VNCServerWin32::queryConnectionComplete() {
  218. queueCommand(QueryConnectionComplete, 0, 0, false);
  219. }
  220. bool VNCServerWin32::queueCommand(Command cmd, const void* data, int len, bool wait) {
  221. os::AutoMutex a(commandLock);
  222. while (command != NoCommand)
  223. commandSig->wait();
  224. command = cmd;
  225. commandData = data;
  226. commandDataLen = len;
  227. SetEvent(commandEvent);
  228. if (wait) {
  229. while (command != NoCommand)
  230. commandSig->wait();
  231. commandSig->signal();
  232. }
  233. return true;
  234. }
  235. void VNCServerWin32::processEvent(HANDLE event_) {
  236. ResetEvent(event_);
  237. if (event_ == commandEvent.h) {
  238. // If there is no command queued then return immediately
  239. {
  240. os::AutoMutex a(commandLock);
  241. if (command == NoCommand)
  242. return;
  243. }
  244. // Perform the required command
  245. switch (command) {
  246. case DisconnectClients:
  247. // Disconnect all currently active VNC Viewers
  248. vncServer.closeClients((const char*)commandData);
  249. break;
  250. case AddClient:
  251. // Make a reverse connection to a VNC Viewer
  252. sockMgr.addSocket((network::Socket*)commandData, &vncServer);
  253. break;
  254. case GetClientsInfo:
  255. getConnInfo((ListConnInfo*)commandData);
  256. break;
  257. case SetClientsStatus:
  258. setConnStatus((ListConnInfo*)commandData);
  259. break;
  260. case QueryConnectionComplete:
  261. // The Accept/Reject dialog has completed
  262. // Get the result, then clean it up
  263. vncServer.approveConnection(queryConnectDialog->getSock(),
  264. queryConnectDialog->isAccepted(),
  265. "Connection rejected by user");
  266. queryConnectDialog->wait();
  267. delete queryConnectDialog;
  268. queryConnectDialog = 0;
  269. break;
  270. default:
  271. vlog.error("unknown command %d queued", command);
  272. };
  273. // Clear the command and signal completion
  274. {
  275. os::AutoMutex a(commandLock);
  276. command = NoCommand;
  277. commandSig->signal();
  278. }
  279. } else if ((event_ == sessionEvent.h) ||
  280. (event_ == desktop.getTerminateEvent())) {
  281. stop();
  282. }
  283. }
  284. void VNCServerWin32::getConnInfo(ListConnInfo * listConn)
  285. {
  286. std::list<network::Socket*> sockets;
  287. std::list<network::Socket*>::iterator i;
  288. listConn->Clear();
  289. listConn->setDisable(sockMgr.getDisable(&vncServer));
  290. vncServer.getSockets(&sockets);
  291. for (i = sockets.begin(); i != sockets.end(); i++) {
  292. rfb::SConnection* conn;
  293. int status;
  294. conn = vncServer.getConnection(*i);
  295. if (!conn)
  296. continue;
  297. if (conn->accessCheck(rfb::SConnection::AccessPtrEvents |
  298. rfb::SConnection::AccessKeyEvents |
  299. rfb::SConnection::AccessView))
  300. status = 0;
  301. else if (conn->accessCheck(rfb::SConnection::AccessView))
  302. status = 1;
  303. else
  304. status = 2;
  305. listConn->addInfo((void*)(*i), (*i)->getPeerAddress(), status);
  306. }
  307. }
  308. void VNCServerWin32::setConnStatus(ListConnInfo* listConn)
  309. {
  310. sockMgr.setDisable(&vncServer, listConn->getDisable());
  311. if (listConn->Empty())
  312. return;
  313. for (listConn->iBegin(); !listConn->iEnd(); listConn->iNext()) {
  314. network::Socket* sock;
  315. rfb::SConnection* conn;
  316. int status;
  317. sock = (network::Socket*)listConn->iGetConn();
  318. conn = vncServer.getConnection(sock);
  319. if (!conn)
  320. continue;
  321. status = listConn->iGetStatus();
  322. if (status == 3) {
  323. conn->close(0);
  324. } else {
  325. rfb::SConnection::AccessRights ar;
  326. ar = rfb::SConnection::AccessDefault;
  327. switch (status) {
  328. case 0:
  329. ar |= rfb::SConnection::AccessPtrEvents |
  330. rfb::SConnection::AccessKeyEvents |
  331. rfb::SConnection::AccessView;
  332. break;
  333. case 1:
  334. ar |= rfb::SConnection::AccessView;
  335. ar &= ~(rfb::SConnection::AccessPtrEvents |
  336. rfb::SConnection::AccessKeyEvents);
  337. break;
  338. case 2:
  339. ar &= ~(rfb::SConnection::AccessPtrEvents |
  340. rfb::SConnection::AccessKeyEvents |
  341. rfb::SConnection::AccessView);
  342. break;
  343. }
  344. conn->setAccessRights(ar);
  345. conn->framebufferUpdateRequest(vncServer.getPixelBuffer()->getRect(), false);
  346. }
  347. }
  348. }