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 9.5KB

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
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  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/STrayIcon.h>
  22. #include <os/Mutex.h>
  23. #include <rfb_win32/ComputerName.h>
  24. #include <rfb_win32/CurrentUser.h>
  25. #include <rfb_win32/Service.h>
  26. #include <rfb/Hostname.h>
  27. #include <rfb/LogWriter.h>
  28. using namespace rfb;
  29. using namespace win32;
  30. using namespace winvnc;
  31. using namespace network;
  32. static LogWriter vlog("VNCServerWin32");
  33. const TCHAR* winvnc::VNCServerWin32::RegConfigPath = _T("Software\\TigerVNC\\WinVNC4");
  34. static IntParameter port_number("PortNumber",
  35. "TCP/IP port on which the server will accept connections", 5900);
  36. static StringParameter hosts("Hosts",
  37. "Filter describing which hosts are allowed access to this server", "+");
  38. static BoolParameter localHost("LocalHost",
  39. "Only accept connections from via the local loop-back network interface", false);
  40. static BoolParameter queryOnlyIfLoggedOn("QueryOnlyIfLoggedOn",
  41. "Only prompt for a local user to accept incoming connections if there is a user logged on", false);
  42. static BoolParameter showTrayIcon("ShowTrayIcon",
  43. "Show the configuration applet in the system tray icon", true);
  44. VNCServerWin32::VNCServerWin32()
  45. : command(NoCommand),
  46. commandEvent(CreateEvent(0, TRUE, FALSE, 0)),
  47. sessionEvent(isServiceProcess() ?
  48. CreateEvent(0, FALSE, FALSE, "Global\\SessionEventTigerVNC") : 0),
  49. vncServer(CStr(ComputerName().buf), &desktop),
  50. thread_id(-1), runServer(false), isDesktopStarted(false),
  51. config(&sockMgr), rfbSock(&sockMgr), trayIcon(0),
  52. queryConnectDialog(0)
  53. {
  54. commandLock = new os::Mutex;
  55. commandSig = new os::Condition(commandLock);
  56. runLock = new os::Mutex;
  57. // Initialise the desktop
  58. desktop.setStatusLocation(&isDesktopStarted);
  59. // Initialise the VNC server
  60. vncServer.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(rfb::ListConnInfo* LCInfo) {
  197. return queueCommand(GetClientsInfo, LCInfo, 0);
  198. }
  199. bool VNCServerWin32::setClientsStatus(rfb::ListConnInfo* LCInfo) {
  200. return queueCommand(SetClientsStatus, LCInfo, 0);
  201. }
  202. VNCServerST::queryResult VNCServerWin32::queryConnection(network::Socket* sock,
  203. const char* userName,
  204. char** reason)
  205. {
  206. if (queryOnlyIfLoggedOn && CurrentUserToken().noUserLoggedOn())
  207. return VNCServerST::ACCEPT;
  208. if (queryConnectDialog) {
  209. *reason = rfb::strDup("Another connection is currently being queried.");
  210. return VNCServerST::REJECT;
  211. }
  212. queryConnectDialog = new QueryConnectDialog(sock, userName, this);
  213. queryConnectDialog->startDialog();
  214. return VNCServerST::PENDING;
  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. vncServer.getConnInfo((ListConnInfo*)commandData);
  255. break;
  256. case SetClientsStatus:
  257. vncServer.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. }