📄 vncserver.cpp
字号:
// Copyright (C) 2000 Tridia Corporation. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This file is part of the VNC system.
//
// The VNC system is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
// USA.
//
// TightVNC distribution homepage on the Web: http://www.tightvnc.com/
//
// If the source code for the VNC system is not available from the place
// whence you received this file, check http://www.uk.research.att.com/vnc or contact
// the authors on vnc@uk.research.att.com for information on obtaining it.
// vncServer.cpp
// vncServer class implementation
// Includes
#include "stdhdrs.h"
#include <omnithread.h>
#include <string.h>
#include <lmcons.h>
// Custom
#include "WinVNC.h"
#include "vncServer.h"
#include "vncSockConnect.h"
#include "vncCorbaConnect.h"
#include "vncClient.h"
#include "vncService.h"
// Constructor/destructor
vncServer::vncServer()
{
ResetPasswordsValidityInfo();
// Initialise some important stuffs...
m_socketConn = NULL;
m_corbaConn = NULL;
m_httpConn = NULL;
m_desktop = NULL;
m_name = NULL;
m_port = DISPLAY_TO_PORT(0);
m_port_http = DISPLAY_TO_HPORT(0);
m_autoportselect = TRUE;
m_passwd_required = TRUE;
m_beepConnect = FALSE;
m_beepDisconnect = FALSE;
m_auth_hosts = 0;
m_blacklist = 0;
{
vncPasswd::FromClear clearPWD;
memcpy(m_password, clearPWD, MAXPWLEN);
m_password_set = FALSE;
memcpy(m_password_viewonly, clearPWD, MAXPWLEN);
m_password_viewonly_set = FALSE;
}
m_querysetting = 2;
m_querytimeout = 10;
m_queryaccept = FALSE;
m_queryallownopass = FALSE;
// Autolock settings
m_lock_on_exit = 0;
// Set the polling mode options
m_poll_fullscreen = FALSE;
m_poll_foreground = FALSE;
m_poll_undercursor = TRUE;
m_poll_oneventonly = FALSE;
m_poll_consoleonly = TRUE;
m_dont_set_hooks = FALSE;
m_dont_use_driver = FALSE;
m_driver_direct_access_en = TRUE;
// General options
m_loopbackOnly = FALSE;
m_disableTrayIcon = FALSE;
m_loopback_allowed = FALSE;
m_httpd_enabled = TRUE;
m_httpd_params_enabled = FALSE;
m_lock_on_exit = 0;
m_connect_pri = 0;
// Set the input options
m_enable_remote_inputs = TRUE;
m_disable_local_inputs = FALSE;
// Clear the client mapping table
for (int x=0; x<MAX_CLIENTS; x++)
m_clientmap[x] = NULL;
m_nextid = 0;
// Signal set when a client quits
m_clientquitsig = new omni_condition(&m_clientsLock);
m_clients_disabled = FALSE;
m_local_input_priority = FALSE;
m_full_screen = TRUE;
m_WindowShared= FALSE;
m_hwndShared = NULL;
m_screen_area = FALSE;
m_primary_display_only_shared = FALSE;
m_disable_time = 3;
SetSharedRect(GetScreenRect());
SetPollingCycle(300);
PollingCycleChanged(false);
m_cursor_pos.x = 0;
m_cursor_pos.y = 0;
// initialize
m_enable_file_transfers = FALSE;
m_remove_wallpaper = FALSE;
m_blank_screen = FALSE;
#ifdef HORIZONLIVE
m_full_screen = FALSE;
m_WindowShared= TRUE;
m_local_input_priority = TRUE;
m_remote_mouse = 1;
m_remote_keyboard = 1;
#endif
m_wallpaper_wait = FALSE;
}
vncServer::~vncServer()
{
vnclog.Print(LL_STATE, VNCLOG("shutting down server object\n"));
// If there is a socket_conn object then delete it
if (m_socketConn != NULL)
{
delete m_socketConn;
m_socketConn = NULL;
}
if (m_corbaConn != NULL)
{
delete m_corbaConn;
m_corbaConn = NULL;
}
if (m_httpConn != NULL)
{
delete m_httpConn;
m_httpConn = NULL;
}
// Remove any active clients!
KillAuthClients();
KillUnauthClients();
// Wait for all the clients to die
WaitUntilAuthEmpty();
WaitUntilUnauthEmpty();
// Don't free the desktop until no KillClient is likely to free it
{ omni_mutex_lock l(m_desktopLock);
if (m_desktop != NULL)
{
delete m_desktop;
m_desktop = NULL;
}
}
// Don't free the authhosts string until no more connections are possible
if (m_auth_hosts != 0)
{
free(m_auth_hosts);
m_auth_hosts = 0;
}
if (m_name != NULL)
{
free(m_name);
m_name = NULL;
}
if (m_clientquitsig != NULL)
{
delete m_clientquitsig;
m_clientquitsig = NULL;
}
vnclog.Print(LL_STATE, VNCLOG("shutting down server object(4)\n"));
}
// Client handling functions
void
vncServer::DisableClients(BOOL state)
{
m_clients_disabled = state;
}
BOOL
vncServer::ClientsDisabled()
{
return m_clients_disabled;
}
vncClientId
vncServer::AddClient(VSocket *socket, BOOL reverse, BOOL shared)
{
return AddClient(socket, reverse, shared, TRUE, TRUE);
}
vncClientId
vncServer::AddClient(VSocket *socket, BOOL reverse, BOOL shared,
BOOL keysenabled, BOOL ptrenabled)
{
vncClient *client;
omni_mutex_lock l(m_clientsLock);
// Try to allocate a client id...
vncClientId clientid = m_nextid;
do
{
clientid = (clientid+1) % MAX_CLIENTS;
if (clientid == m_nextid)
{
vnclog.Print(LL_CONNERR, VNCLOG("too many clients already connected\n"));
delete socket;
return -1;
}
}
while (m_clientmap[clientid] != NULL);
// Create a new client and add it to the relevant client list
client = new vncClient();
if (client == NULL) {
vnclog.Print(LL_CONNERR, VNCLOG("failed to allocate client object\n"));
delete socket;
return -1;
}
// Set the client's settings
client->EnableKeyboard(keysenabled && m_enable_remote_inputs);
client->EnablePointer(ptrenabled && m_enable_remote_inputs);
// Start the client
if (!client->Init(this, socket, reverse, shared, clientid))
{
// The client will delete the socket for us...
vnclog.Print(LL_CONNERR, VNCLOG("failed to initialize client object\n"));
delete client;
return -1;
}
m_clientmap[clientid] = client;
// Add the client to unauth the client list
m_unauthClients.push_back(clientid);
// Notify anyone interested about this event
DoNotify(WM_SRV_CLIENT_CONNECT, 0, 0);
vnclog.Print(LL_INTINFO, VNCLOG("AddClient() done\n"));
return clientid;
}
BOOL
vncServer::Authenticated(vncClientId clientid)
{
vncClientList::iterator i;
BOOL authok = TRUE;
omni_mutex_lock l1(m_desktopLock);
omni_mutex_lock l2(m_clientsLock);
// Search the unauthenticated client list
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
vncClient *client = GetClient(clientid);
// Yes, so remove the client and add it to the auth list
m_unauthClients.erase(i);
// Create the screen handler if necessary
if (m_desktop == NULL)
{
if (RemoveWallpaperEnabled()) {
m_wallpaper_wait = TRUE;
DoNotify(WM_SRV_CLIENT_HIDEWALLPAPER, 0, 0);
}
m_desktop = new vncDesktop();
if (m_desktop == NULL)
{
vnclog.Print(LL_CONNERR, VNCLOG("failed to allocate desktop object\n"));
client->Kill();
authok = FALSE;
break;
}
if (!m_desktop->Init(this))
{
vnclog.Print(LL_CONNERR, VNCLOG("failed to initialize desktop object\n"));
client->Kill();
authok = FALSE;
delete m_desktop;
m_desktop = NULL;
break;
}
}
// Create a buffer object for this client
vncBuffer *buffer = new vncBuffer(m_desktop);
if (buffer == NULL)
{
vnclog.Print(LL_CONNERR, VNCLOG("failed to allocate buffer object\n"));
client->Kill();
authok = FALSE;
break;
}
// Tell the client about this new buffer
client->SetBuffer(buffer);
// Add the client to the auth list
m_authClients.push_back(clientid);
break;
}
}
// Notify anyone interested of this event
DoNotify(WM_SRV_CLIENT_AUTHENTICATED, 0, 0);
vnclog.Print(LL_INTINFO, VNCLOG("Authenticated() done\n"));
// If so configured, beep to indicate the new connection is
// present.
if (authok && GetBeepConnect())
{
MessageBeep(MB_OK);
}
return authok;
}
void
vncServer::KillClient(vncClientId clientid)
{
vncClientList::iterator i;
BOOL done = FALSE;
omni_mutex_lock l(m_clientsLock);
// Find the client in one of the two lists
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
vnclog.Print(LL_INTINFO, VNCLOG("killing unauth client\n"));
// Ask the client to die
vncClient *client = GetClient(clientid);
client->Kill();
done = TRUE;
break;
}
}
if (!done)
{
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
vnclog.Print(LL_INTINFO, VNCLOG("killing auth client\n"));
// Yes, so kill it
vncClient *client = GetClient(clientid);
client->Kill();
done = TRUE;
break;
}
}
}
vnclog.Print(LL_INTINFO, VNCLOG("KillClient() done\n"));
}
void
vncServer::KillAuthClients()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Tell all the authorised clients to die!
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
vnclog.Print(LL_INTINFO, VNCLOG("killing auth client\n"));
// Kill the client
GetClient(*i)->Kill();
}
vnclog.Print(LL_INTINFO, VNCLOG("KillAuthClients() done\n"));
}
void
vncServer::KillUnauthClients()
{
vncClientList::iterator i;
omni_mutex_lock l(m_clientsLock);
// Tell all the authorised clients to die!
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
vnclog.Print(LL_INTINFO, VNCLOG("killing unauth client\n"));
// Kill the client
GetClient(*i)->Kill();
}
vnclog.Print(LL_INTINFO, VNCLOG("KillUnauthClients() done\n"));
}
UINT
vncServer::AuthClientCount()
{
omni_mutex_lock l(m_clientsLock);
return m_authClients.size();
}
UINT
vncServer::UnauthClientCount()
{
omni_mutex_lock l(m_clientsLock);
return m_unauthClients.size();
}
void
vncServer::WaitUntilAuthEmpty()
{
omni_mutex_lock l(m_clientsLock);
// Wait for all the clients to exit
while (!m_authClients.empty())
{
// Wait for a client to quit
m_clientquitsig->wait();
}
}
void
vncServer::WaitUntilUnauthEmpty()
{
omni_mutex_lock l(m_clientsLock);
// Wait for all the clients to exit
while (!m_unauthClients.empty())
{
// Wait for a client to quit
m_clientquitsig->wait();
}
}
BOOL
vncServer::RemoteEventReceived()
{
vncClientList::iterator i;
BOOL result = FALSE;
omni_mutex_lock l(m_clientsLock);
// Iterate over the authorised clients
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
result = result || GetClient(*i)->RemoteEventReceived();
}
return result;
}
// Client info retrieval/setup
vncClient*
vncServer::GetClient(vncClientId clientid)
{
if ((clientid >= 0) && (clientid < MAX_CLIENTS))
return m_clientmap[clientid];
return NULL;
}
vncClientList
vncServer::ClientList()
{
vncClientList clients;
omni_mutex_lock l(m_clientsLock);
clients = m_authClients;
return clients;
}
void
vncServer::BlockRemoteInput(BOOL block)
{
omni_mutex_lock l(m_clientsLock);
vncClientList::iterator i;
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
GetClient(*i)->BlockInput(block);
}
const char*
vncServer::GetClientName(vncClientId clientid)
{
omni_mutex_lock l(m_clientsLock);
vncClient *client = GetClient(clientid);
if (client != NULL)
return client->GetClientName();
return NULL;
}
// RemoveClient should ONLY EVER be used by the client to remove itself.
void
vncServer::RemoveClient(vncClientId clientid)
{
vncClientList::iterator i;
BOOL done = FALSE;
omni_mutex_lock l1(m_desktopLock);
{ omni_mutex_lock l2(m_clientsLock);
// Find the client in one of the two lists
for (i = m_unauthClients.begin(); i != m_unauthClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
vnclog.Print(LL_INTINFO, VNCLOG("removing unauthorised client\n"));
// Yes, so remove the client and kill it
m_unauthClients.erase(i);
m_clientmap[clientid] = NULL;
done = TRUE;
break;
}
}
if (!done)
{
for (i = m_authClients.begin(); i != m_authClients.end(); i++)
{
// Is this the right client?
if ((*i) == clientid)
{
vnclog.Print(LL_INTINFO, VNCLOG("removing authorised client\n"));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -