📄 vncclient.cpp
字号:
// Copyright (C) 2006 Teamviewer GmbH. All Rights Reserved.
// Copyright (C) 2002 Ultr@VNC Team Members. All Rights Reserved.
// Copyright (C) 2000-2002 Const Kaplinsky. All Rights Reserved.
// Copyright (C) 2002 RealVNC Ltd. All Rights Reserved.
// Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved.
//
// This file is part of TeamViewer.
//
// TeamViewer 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 TeamViewer is not available from the place
// whence you received this file, check http://www.teamviewer.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 "rores/resource.h"
// Custom
#include "../../vncviewer/vncviewer.h"
#include "vncServer.h"
#include "VSocket.h"
#include "vncDesktop.h"
#include "vncBuffer.h"
#include "vncService.h"
#include "vncPasswd.h"
#include "vncAcceptDialog.h"
#include "vncKeymap.h"
#include "vncMenu.h"
#include "HideDesktop.h"
#include "updateDialog.h"
// Header f黵 Viewer
#include "..\..\vncviewer\VNCviewerApp32.h"
#include "vncClientControl.h"
#include "roGateway.h"
#include "localization.h" // Act : add localization on messages
#include "Global.h"
#include "FileTransferLog.h"
#include "FileOperationDialog.h"
#include "../../vncviewer/SessionDialog.h"
#include "../../vncviewer/connectionlog.h"
typedef BOOL (WINAPI *PGETDISKFREESPACEEX)(LPCSTR,PULARGE_INTEGER, PULARGE_INTEGER, PULARGE_INTEGER);
const UINT ShowPointerMessage = RegisterWindowMessage("TeamViewer.ShowPointerMessage");
extern vncMenu *menu;
extern BOOL g_impersonating_user;
// vncClient update thread class
using namespace std;
class 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);
void get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec);
// The main thread function
virtual void *run_undetached(void *arg);
protected:
virtual ~vncClientUpdateThread();
// Fields
protected:
vncClient *m_client;
omni_condition *m_signal;
omni_condition *m_sync_sig;
BOOL m_active;
BOOL m_enable;
};
// Modif cs@2005
#ifdef DSHOW
class MutexAutoLock
{
public:
MutexAutoLock(HANDLE* phMutex)
{
m_phMutex = phMutex;
if(WAIT_OBJECT_0 != WaitForSingleObject(*phMutex, INFINITE))
{
vnclog.Print(LL_INTERR, VNCLOG("Could not get access to the mutex"));
}
}
~MutexAutoLock()
{
ReleaseMutex(*m_phMutex);
}
HANDLE* m_phMutex;
};
#endif
BOOL
vncClientUpdateThread::Init(vncClient *client)
{
vnclog.Print(LL_INTINFO, VNCLOG("init update thread"));
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"));
m_client->m_updatethread=NULL;
}
void
vncClientUpdateThread::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();
}
}
void
vncClientUpdateThread::Kill()
{
vnclog.Print(LL_INTINFO, VNCLOG("kill update thread"));
omni_mutex_lock l(m_client->GetUpdateLock());
m_active=FALSE;
m_signal->signal();
}
void
vncClientUpdateThread::get_time_now(unsigned long* abs_sec, unsigned long* abs_nsec)
{
static int days_in_preceding_months[12]
= { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
static int days_in_preceding_months_leap[12]
= { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
SYSTEMTIME st;
GetSystemTime(&st);
*abs_nsec = st.wMilliseconds * 1000000;
// this formula should work until 1st March 2100
DWORD days = ((st.wYear - 1970) * 365 + (st.wYear - 1969) / 4
+ ((st.wYear % 4)
? days_in_preceding_months[st.wMonth - 1]
: days_in_preceding_months_leap[st.wMonth - 1])
+ st.wDay - 1);
*abs_sec = st.wSecond + 60 * (st.wMinute + 60 * (st.wHour + 24 * days));
}
void
vncClientUpdateThread::EnableUpdates(BOOL enable)
{
// ALWAYS call this with the UpdateLock held!
if (enable) {
vnclog.Print(LL_INTINFO, VNCLOG("enable update thread"));
} else {
vnclog.Print(LL_INTINFO, VNCLOG("disable update thread"));
}
m_enable = enable;
m_signal->signal();
unsigned long now_sec, now_nsec;
get_time_now(&now_sec, &now_nsec);
m_sync_sig->wait();
/*if (m_sync_sig->timedwait(now_sec+1,0)==0)
{
// m_signal->signal();
vnclog.Print(LL_INTINFO, VNCLOG("thread timeout"));
} */
vnclog.Print(LL_INTINFO, VNCLOG("enable/disable synced"));
}
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"));
// Set client update threads to high priority
// *** set_priority(omni_thread::PRIORITY_HIGH);
#ifndef _DEBUG
try
{
#endif
while (1)
{
// Block waiting for an update to send
{
//vnclog.Print(0, VNCLOG("vncClientUpdateThread while(1)"));
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.
if (updates_sent < 1)
{
while (m_active && (
m_client->m_fFileTransferStarted ||
!m_enable ||
m_client->IsConnectionPaused() || (
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_update_tracker.get_cached_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();
}
}
else
{
while (m_active && (
m_client->m_fFileTransferStarted ||
!m_enable ||
m_client->IsConnectionPaused() || (
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_update_tracker.get_cached_region().intersect(m_client->m_incr_rgn).is_empty() &&
!m_client->m_encodemgr.IsCursorUpdatePending() &&
!m_client->m_clipboard_text &&
!m_client->m_NewSWUpdateWaiting)))
{
// 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();
}
}
omni_mutex_lock l2(m_client->GetUpdateLock());
// If the thread is being killed then quit
if (!m_active) break;
//vnclog.Print(0, VNCLOG("vncClientUpdateThread SEND"));
// 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.
// Modif sf@2002 - FileTransfer - Don't send anything if a file transfer is running !
// if (m_client->m_fFileTransferRunning) return 0;
// if (m_client->m_pTextChat->m_fTextChatRunning) return 0;
// sf@2002
// New scale requested, we do it before sending the next Update
if (m_client->fNewScale)
{
// Send the new framebuffer size to the client
rfb::Rect ViewerSize = m_client->m_encodemgr.m_buffer->GetViewerSize();
// Copyright (C) 2001 - Harakan software
if (m_client->m_fPalmVNCScaling)
{
rfb::Rect ScreenSize = m_client->m_encodemgr.m_buffer->GetSize();
rfbPalmVNCReSizeFrameBufferMsg rsfb;
rsfb.type = rfbPalmVNCReSizeFrameBuffer;
rsfb.desktop_w = Swap16IfLE(ScreenSize.br.x);
rsfb.desktop_h = Swap16IfLE(ScreenSize.br.y);
rsfb.buffer_w = Swap16IfLE(ViewerSize.br.x);
rsfb.buffer_h = Swap16IfLE(ViewerSize.br.y);
m_client->m_socket->SendExact((char*)&rsfb,
sz_rfbPalmVNCReSizeFrameBufferMsg,
rfbPalmVNCReSizeFrameBuffer);
}
else // eSVNC-UltraVNC Scaling
{
rfbResizeFrameBufferMsg rsmsg;
rsmsg.type = rfbResizeFrameBuffer;
rsmsg.framebufferWidth = Swap16IfLE(ViewerSize.br.x);
rsmsg.framebufferHeigth = Swap16IfLE(ViewerSize.br.y);
m_client->m_socket->SendExact((char*)&rsmsg,
sz_rfbResizeFrameBufferMsg,
rfbResizeFrameBuffer);
}
m_client->m_encodemgr.m_buffer->ClearCache();
m_client->fNewScale = false;
m_client->m_fPalmVNCScaling = false;
// return 0;
}
// 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);
//if (!m_client->m_encodemgr.m_buffer->m_desktop->IsVideoDriverEnabled())
//TEST if (!m_client->m_encodemgr.m_buffer->m_desktop->m_hookdriver)
{
// Render the mouse if required
if (updates_sent > 1 ) m_client->m_cursor_update_pending = m_client->m_encodemgr.WasCursorUpdatePending();
if (updates_sent == 1 ) m_client->m_cursor_update_pending = true;
if (!m_client->m_cursor_update_sent && !m_client->m_cursor_update_pending)
{
if (m_client->m_mousemoved)
{
// Re-render its old location
m_client->m_oldmousepos =
m_client->m_oldmousepos.intersect(m_client->m_ScaledScreen); // sf@2002
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_ScaledScreen);
if (!m_client->m_oldmousepos.is_empty())
update.add_changed(m_client->m_oldmousepos);
m_client->m_mousemoved = FALSE;
}
}
}
}
// SEND THE CLIPBOARD
// If there is clipboard text to be sent then send it
// Also allow in loopbackmode
// Loopback mode with winvncviewer will cause a loping
// But ssh is back working
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.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -