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