您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

VNCServerWin32.cxx 11KB

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