📄 vncclient.cpp
字号:
// Copyright (C) 2002-2003 RealVNC Ltd. 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.//// 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.// vncClient.cpp// The per-client object. This object takes care of all per-client stuff,// such as socket input and buffering of updates.// vncClient class handles the following functions:// - Recieves requests from the connected client and// handles them// - Handles incoming updates properly, using a vncBuffer// object to keep track of screen changes// It uses a vncBuffer and is passed the vncDesktop and// vncServer to communicate with.// Includes#include "stdhdrs.h"#include <omnithread.h>#include "resource.h"// Custom#include "vncServer.h"#include "vncClient.h"#include "VSocket.h"#include "vncDesktop.h"#include "rfbRegion.h"#include "vncBuffer.h"#include "vncService.h"#include "vncPasswd.h"#include "vncAcceptDialog.h"#include "vncKeymap.h"// #include "rfb.h"// vncClient update thread classclass vncClientUpdateThread : public omni_thread{public: // Init BOOL Init(vncClient *client); // Kick the thread to send an update void Trigger(); // Kill the thread void Kill(); // Disable/enable updates void EnableUpdates(BOOL enable); // The main thread function virtual void *run_undetached(void *arg);protected: virtual ~vncClientUpdateThread(); // Fieldsprotected: vncClient *m_client; omni_condition *m_signal; omni_condition *m_sync_sig; BOOL m_active; BOOL m_enable;};BOOLvncClientUpdateThread::Init(vncClient *client){ vnclog.Print(LL_INTINFO, VNCLOG("init update thread\n")); m_client = client; omni_mutex_lock l(m_client->GetUpdateLock()); m_signal = new omni_condition(&m_client->GetUpdateLock()); m_sync_sig = new omni_condition(&m_client->GetUpdateLock()); m_active = TRUE; m_enable = m_client->m_disable_protocol == 0; if (m_signal && m_sync_sig) { start_undetached(); return TRUE; } return FALSE;}vncClientUpdateThread::~vncClientUpdateThread(){ if (m_signal) delete m_signal; if (m_sync_sig) delete m_sync_sig; vnclog.Print(LL_INTINFO, VNCLOG("update thread gone\n"));}voidvncClientUpdateThread::Trigger(){ // ALWAYS lock client UpdateLock before calling this! // Only trigger an update if protocol is enabled if (m_client->m_disable_protocol == 0) { m_signal->signal(); }}voidvncClientUpdateThread::Kill(){ vnclog.Print(LL_INTINFO, VNCLOG("kill update thread\n")); omni_mutex_lock l(m_client->GetUpdateLock()); m_active=FALSE; m_signal->signal();}voidvncClientUpdateThread::EnableUpdates(BOOL enable){ // ALWAYS call this with the UpdateLock held! if (enable) { vnclog.Print(LL_INTINFO, VNCLOG("enable update thread\n")); } else { vnclog.Print(LL_INTINFO, VNCLOG("disable update thread\n")); } m_enable = enable; m_signal->signal(); m_sync_sig->wait(); vnclog.Print(LL_INTINFO, VNCLOG("enable/disable synced\n"));}void*vncClientUpdateThread::run_undetached(void *arg){ rfb::SimpleUpdateTracker update; rfb::Region2D clipregion; char *clipboard_text = 0; update.enable_copyrect(true); BOOL send_palette = FALSE; unsigned long updates_sent=0; vnclog.Print(LL_INTINFO, VNCLOG("starting update thread\n")); // Set client update threads to high priority // *** set_priority(omni_thread::PRIORITY_HIGH); while (1) { // Block waiting for an update to send { omni_mutex_lock l(m_client->GetUpdateLock()); m_client->m_incr_rgn = m_client->m_incr_rgn.union_(clipregion); // We block as long as updates are disabled, or the client // isn't interested in them, unless this thread is killed. while (m_active && ( !m_enable || ( m_client->m_update_tracker.get_changed_region().intersect(m_client->m_incr_rgn).is_empty() && m_client->m_update_tracker.get_copied_region().intersect(m_client->m_incr_rgn).is_empty() && !m_client->m_clipboard_text ) ) ) { // Issue the synchronisation signal, to tell other threads // where we have got to m_sync_sig->broadcast(); // Wait to be kicked into action m_signal->wait(); } // If the thread is being killed then quit if (!m_active) break; // SEND AN UPDATE! // The thread is active, updates are enabled, and the // client is expecting an update - let's see if there // is anything to send. // Has the palette changed? send_palette = m_client->m_palettechanged; m_client->m_palettechanged = FALSE; // Fetch the incremental region clipregion = m_client->m_incr_rgn; m_client->m_incr_rgn.clear(); // Get the clipboard data, if any if (m_client->m_clipboard_text) { clipboard_text = m_client->m_clipboard_text; m_client->m_clipboard_text = 0; } // Get the update details from the update tracker m_client->m_update_tracker.flush_update(update, clipregion); // Render the mouse if required if (m_client->m_mousemoved) { // Re-render its old location m_client->m_oldmousepos = m_client->m_oldmousepos.intersect(m_client->m_fullscreen); if (!m_client->m_oldmousepos.is_empty()) update.add_changed(m_client->m_oldmousepos); // And render its new one m_client->m_encodemgr.m_buffer->GetMousePos(m_client->m_oldmousepos); m_client->m_oldmousepos = m_client->m_oldmousepos.intersect(m_client->m_fullscreen); if (!m_client->m_oldmousepos.is_empty()) update.add_changed(m_client->m_oldmousepos); m_client->m_mousemoved = FALSE; } // Get the encode manager to update the client back buffer m_client->m_encodemgr.GrabRegion(update.get_changed_region()); } // SEND THE CLIPBOARD // If there is clipboard text to be sent then send it if (clipboard_text) { rfbServerCutTextMsg message; message.length = Swap32IfLE(strlen(clipboard_text)); if (!m_client->SendRFBMsg(rfbServerCutText, (BYTE *) &message, sizeof(message))) { m_client->m_socket->Close(); } if (!m_client->m_socket->SendExact(clipboard_text, strlen(clipboard_text))) { m_client->m_socket->Close(); } free(clipboard_text); clipboard_text = 0; } // SEND AN UPDATE // We do this without holding locks, to avoid network problems // stalling the server. // Update the client palette if necessary if (send_palette) { m_client->SendPalette(); } // Send updates to the client - this implicitly clears // the supplied update tracker if (m_client->SendUpdate(update)) { updates_sent++; clipregion.clear(); } } vnclog.Print(LL_INTINFO, VNCLOG("stopping update thread\n")); vnclog.Print(LL_INTERR, "client sent %lu updates\n", updates_sent); return 0;}// vncClient thread classclass vncClientThread : public omni_thread{public: // Init virtual BOOL Init(vncClient *client, vncServer *server, VSocket *socket, BOOL auth, BOOL shared); // Sub-Init routines virtual BOOL InitVersion(); virtual BOOL InitAuthenticate(); // The main thread function virtual void run(void *arg);protected: virtual ~vncClientThread(); // Fieldsprotected: VSocket *m_socket; vncServer *m_server; vncClient *m_client; BOOL m_auth; BOOL m_shared;};vncClientThread::~vncClientThread(){ // If we have a client object then delete it if (m_client != NULL) delete m_client;}BOOLvncClientThread::Init(vncClient *client, vncServer *server, VSocket *socket, BOOL auth, BOOL shared){ // Save the server pointer and window handle m_server = server; m_socket = socket; m_client = client; m_auth = auth; m_shared = shared; // Start the thread start(); return TRUE;}BOOLvncClientThread::InitVersion(){ // Generate the server's protocol version rfbProtocolVersionMsg protocolMsg; sprintf((char *)protocolMsg, rfbProtocolVersionFormat, rfbProtocolMajorVersion, rfbProtocolMinorVersion); // Send the protocol message if (!m_socket->SendExact((char *)&protocolMsg, sz_rfbProtocolVersionMsg)) return FALSE; // Now, get the client's protocol version rfbProtocolVersionMsg protocol_ver; protocol_ver[12] = 0; if (!m_socket->ReadExact((char *)&protocol_ver, sz_rfbProtocolVersionMsg)) return FALSE; // Check the protocol version int major, minor; sscanf((char *)&protocol_ver, rfbProtocolVersionFormat, &major, &minor); if (major != rfbProtocolMajorVersion) return FALSE; return TRUE;}BOOLvncClientThread::InitAuthenticate(){ // Retrieve the local password char password[MAXPWLEN]; m_server->GetPassword(password); vncPasswd::ToText plain(password); // Verify the peer host name against the AuthHosts string vncServer::AcceptQueryReject verified; if (m_auth) { verified = vncServer::aqrAccept; } else { verified = m_server->VerifyHost(m_socket->GetPeerName()); } // If necessary, query the connection with a timed dialog if (verified == vncServer::aqrQuery) { vncAcceptDialog *acceptDlg = new vncAcceptDialog(m_server->QueryTimeout(), m_socket->GetPeerName()); if ((acceptDlg == 0) || (!(acceptDlg->DoDialog()))) verified = vncServer::aqrReject; } if (verified == vncServer::aqrReject) { CARD32 auth_val = Swap32IfLE(rfbConnFailed); char *errmsg = "Your connection has been rejected."; CARD32 errlen = Swap32IfLE(strlen(errmsg)); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; if (!m_socket->SendExact((char *)&errlen, sizeof(errlen))) return FALSE; m_socket->SendExact(errmsg, strlen(errmsg)); return FALSE; } // By default we disallow passwordless workstations! if ((strlen(plain) == 0) && m_server->AuthRequired()) { vnclog.Print(LL_CONNERR, VNCLOG("no password specified for server - client rejected\n")); // Send an error message to the client CARD32 auth_val = Swap32IfLE(rfbConnFailed); char *errmsg = "This server does not have a valid password enabled. " "Until a password is set, incoming connections cannot be accepted."; CARD32 errlen = Swap32IfLE(strlen(errmsg)); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; if (!m_socket->SendExact((char *)&errlen, sizeof(errlen))) return FALSE; m_socket->SendExact(errmsg, strlen(errmsg)); return FALSE; } // By default we filter out local loop connections, because they're pointless if (!m_server->LoopbackOk()) { char *localname = strdup(m_socket->GetSockName()); char *remotename = strdup(m_socket->GetPeerName()); // Check that the local & remote names are different! if ((localname != NULL) && (remotename != NULL)) { BOOL ok = strcmp(localname, remotename) != 0; if (localname != NULL) free(localname); if (remotename != NULL) free(remotename); if (!ok) { vnclog.Print(LL_CONNERR, VNCLOG("loopback connection attempted - client rejected\n")); // Send an error message to the client CARD32 auth_val = Swap32IfLE(rfbConnFailed); char *errmsg = "Local loop-back connections are disabled."; CARD32 errlen = Swap32IfLE(strlen(errmsg)); if (!m_socket->SendExact((char *)&auth_val, sizeof(auth_val))) return FALSE; if (!m_socket->SendExact((char *)&errlen, sizeof(errlen))) return FALSE; m_socket->SendExact(errmsg, strlen(errmsg)); return FALSE; } } } // Authenticate the connection, if required if (m_auth || (strlen(plain) == 0))
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -