📄 clientconnection.cpp
字号:
// Copyright (C) 2003-2006 Constantin Kaplinsky. All Rights Reserved.
// 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.
// Many thanks to Randy Brown <rgb@inven.com> for providing the 3-button
// emulation code.
// This is the main source for a ClientConnection object.
// It handles almost everything to do with a connection to a server.
// The decoding of specific rectangle encodings is done in separate files.
#include "stdhdrs.h"
#include "vncviewer.h"
#ifdef UNDER_CE
#include "omnithreadce.h"
#define SD_BOTH 0x02
#else
#include "omnithread.h"
#endif
#include "ClientConnection.h"
#include "SessionDialog.h"
#include "LoginAuthDialog.h"
#include "AboutBox.h"
#include "FileTransfer.h"
#include "commctrl.h"
#include "Exception.h"
extern "C" {
#include "vncauth.h"
#include "d3des.h"
}
#define INITIALNETBUFSIZE 4096
#define MAX_ENCODINGS 20
#define VWR_WND_CLASS_NAME _T("VNCviewer")
/*
* Macro to compare pixel formats.
*/
#define PF_EQ(x,y) \
((x.bitsPerPixel == y.bitsPerPixel) && \
(x.depth == y.depth) && \
((x.bigEndian == y.bigEndian) || (x.bitsPerPixel == 8)) && \
(x.trueColour == y.trueColour) && \
(!x.trueColour || ((x.redMax == y.redMax) && \
(x.greenMax == y.greenMax) && \
(x.blueMax == y.blueMax) && \
(x.redShift == y.redShift) && \
(x.greenShift == y.greenShift) && \
(x.blueShift == y.blueShift))))
const rfbPixelFormat vnc8bitFormat = {8, 8, 0, 1, 7,7,3, 0,3,6,0,0};
const rfbPixelFormat vnc16bitFormat = {16, 16, 0, 1, 63, 31, 31, 0,6,11,0,0};
// *************************************************************************
// A Client connection involves two threads - the main one which sets up
// connections and processes window messages and inputs, and a
// client-specific one which receives, decodes and draws output data
// from the remote server.
// This first section contains bits which are generally called by the main
// program thread.
// *************************************************************************
ClientConnection::ClientConnection(VNCviewerApp *pApp)
{
Init(pApp);
}
ClientConnection::ClientConnection(VNCviewerApp *pApp, SOCKET sock)
{
Init(pApp);
m_sock = sock;
m_serverInitiated = true;
struct sockaddr_in svraddr;
int sasize = sizeof(svraddr);
if (getpeername(sock, (struct sockaddr *) &svraddr,
&sasize) != SOCKET_ERROR) {
_stprintf(m_host, _T("%d.%d.%d.%d"),
svraddr.sin_addr.S_un.S_un_b.s_b1,
svraddr.sin_addr.S_un.S_un_b.s_b2,
svraddr.sin_addr.S_un.S_un_b.s_b3,
svraddr.sin_addr.S_un.S_un_b.s_b4);
m_port = svraddr.sin_port;
} else {
_tcscpy(m_host,_T("(unknown)"));
m_port = 0;
};
}
ClientConnection::ClientConnection(VNCviewerApp *pApp, LPTSTR host, int port)
{
Init(pApp);
_tcsncpy(m_host, host, MAX_HOST_NAME_LEN);
m_port = port;
}
void ClientConnection::Init(VNCviewerApp *pApp)
{
m_hwnd = NULL;
m_hwnd1 = NULL;
m_hwndscroll = NULL;
m_hToolbar = NULL;
m_desktopName = NULL;
m_port = -1;
m_serverInitiated = false;
m_netbuf = NULL;
m_netbufsize = 0;
m_zlibbuf = NULL;
m_zlibbufsize = 0;
m_hwndNextViewer = NULL;
m_pApp = pApp;
m_dormant = false;
m_hBitmapDC = NULL;
m_hBitmap = NULL;
m_hPalette = NULL;
m_encPasswd[0] = '\0';
m_connDlg = NULL;
m_enableFileTransfers = false;
m_fileTransferDialogShown = false;
m_pFileTransfer = new FileTransfer(this, m_pApp);
// We take the initial conn options from the application defaults
m_opts = m_pApp->m_options;
m_sock = INVALID_SOCKET;
m_bKillThread = false;
m_threadStarted = true;
m_running = false;
m_pendingFormatChange = false;
m_hScrollPos = 0; m_vScrollPos = 0;
m_waitingOnEmulateTimer = false;
m_emulatingMiddleButton = false;
m_decompStreamInited = false;
m_decompStreamRaw.total_in = ZLIBHEX_DECOMP_UNINITED;
m_decompStreamEncoded.total_in = ZLIBHEX_DECOMP_UNINITED;
for (int i = 0; i < 4; i++)
m_tightZlibStreamActive[i] = false;
prevCursorSet = false;
rcCursorX = 0;
rcCursorY = 0;
// Create a buffer for various network operations
CheckBufferSize(INITIALNETBUFSIZE);
m_pApp->RegisterConnection(this);
}
void ClientConnection::InitCapabilities()
{
// Supported authentication methods
m_authCaps.Add(rfbAuthNone, rfbStandardVendor, sig_rfbAuthNone,
"No authentication");
m_authCaps.Add(rfbAuthVNC, rfbStandardVendor, sig_rfbAuthVNC,
"Standard VNC password authentication");
// Known server->client message types
m_serverMsgCaps.Add(rfbFileListData, rfbTightVncVendor,
sig_rfbFileListData, "File list data");
m_serverMsgCaps.Add(rfbFileDownloadData, rfbTightVncVendor,
sig_rfbFileDownloadData, "File download data");
m_serverMsgCaps.Add(rfbFileUploadCancel, rfbTightVncVendor,
sig_rfbFileUploadCancel, "File upload cancel request");
m_serverMsgCaps.Add(rfbFileDownloadFailed, rfbTightVncVendor,
sig_rfbFileDownloadFailed, "File download failure notification");
// Known client->server message types
m_clientMsgCaps.Add(rfbFileListRequest, rfbTightVncVendor,
sig_rfbFileListRequest, "File list request");
m_clientMsgCaps.Add(rfbFileDownloadRequest, rfbTightVncVendor,
sig_rfbFileDownloadRequest, "File download request");
m_clientMsgCaps.Add(rfbFileUploadRequest, rfbTightVncVendor,
sig_rfbFileUploadRequest, "File upload request");
m_clientMsgCaps.Add(rfbFileUploadData, rfbTightVncVendor,
sig_rfbFileUploadData, "File upload data");
m_clientMsgCaps.Add(rfbFileDownloadCancel, rfbTightVncVendor,
sig_rfbFileDownloadCancel, "File download cancel request");
m_clientMsgCaps.Add(rfbFileUploadFailed, rfbTightVncVendor,
sig_rfbFileUploadFailed, "File upload failure notification");
// Supported encoding types
m_encodingCaps.Add(rfbEncodingCopyRect, rfbStandardVendor,
sig_rfbEncodingCopyRect, "Standard CopyRect encoding");
m_encodingCaps.Add(rfbEncodingRRE, rfbStandardVendor,
sig_rfbEncodingRRE, "Standard RRE encoding");
m_encodingCaps.Add(rfbEncodingCoRRE, rfbStandardVendor,
sig_rfbEncodingCoRRE, "Standard CoRRE encoding");
m_encodingCaps.Add(rfbEncodingHextile, rfbStandardVendor,
sig_rfbEncodingHextile, "Standard Hextile encoding");
m_encodingCaps.Add(rfbEncodingZlib, rfbTridiaVncVendor,
sig_rfbEncodingZlib, "Zlib encoding from TridiaVNC");
m_encodingCaps.Add(rfbEncodingZlibHex, rfbTridiaVncVendor,
sig_rfbEncodingZlibHex, "ZlibHex encoding from TridiaVNC");
m_encodingCaps.Add(rfbEncodingTight, rfbTightVncVendor,
sig_rfbEncodingTight, "Tight encoding by Constantin Kaplinsky");
// Supported "fake" encoding types
m_encodingCaps.Add(rfbEncodingCompressLevel0, rfbTightVncVendor,
sig_rfbEncodingCompressLevel0, "Compression level");
m_encodingCaps.Add(rfbEncodingQualityLevel0, rfbTightVncVendor,
sig_rfbEncodingQualityLevel0, "JPEG quality level");
m_encodingCaps.Add(rfbEncodingXCursor, rfbTightVncVendor,
sig_rfbEncodingXCursor, "X-style cursor shape update");
m_encodingCaps.Add(rfbEncodingRichCursor, rfbTightVncVendor,
sig_rfbEncodingRichCursor, "Rich-color cursor shape update");
m_encodingCaps.Add(rfbEncodingPointerPos, rfbTightVncVendor,
sig_rfbEncodingPointerPos, "Pointer position update");
m_encodingCaps.Add(rfbEncodingLastRect, rfbTightVncVendor,
sig_rfbEncodingLastRect, "LastRect protocol extension");
m_encodingCaps.Add(rfbEncodingNewFBSize, rfbTightVncVendor,
sig_rfbEncodingNewFBSize, "Framebuffer size change");
}
//
// Run() creates the connection if necessary, does the initial negotiations
// and then starts the thread running which does the output (update) processing.
// If Run throws an Exception, the caller must delete the ClientConnection object.
//
void ClientConnection::Run()
{
// Get the host name and port if we haven't got it
if (m_port == -1) {
GetConnectDetails();
} else {
if (m_pApp->m_options.m_listening) {
m_opts.LoadOpt(m_opts.m_display,
KEY_VNCVIEWER_HISTORI);
}
}
// Show the "Connecting..." dialog box
m_connDlg = new ConnectingDialog(m_pApp->m_instance, m_opts.m_display);
// Connect if we're not already connected
if (m_sock == INVALID_SOCKET)
Connect();
SetSocketOptions();
NegotiateProtocolVersion();
PerformAuthentication();
// Set up windows etc
CreateDisplay();
SendClientInit();
ReadServerInit();
// Only for protocol version 3.7t
if (m_tightVncProtocol) {
// Determine which protocol messages and encodings are supported.
ReadInteractionCaps();
// Enable file transfers only if the server supports that.
m_enableFileTransfers = false;
if ( m_clientMsgCaps.IsEnabled(rfbFileListRequest) &&
m_serverMsgCaps.IsEnabled(rfbFileListData) ) {
m_enableFileTransfers = true;
}
}
// Close the "Connecting..." dialog box if not closed yet.
if (m_connDlg != NULL) {
delete m_connDlg;
m_connDlg = NULL;
}
EnableFullControlOptions();
CreateLocalFramebuffer();
SetupPixelFormat();
SetFormatAndEncodings();
// This starts the worker thread.
// The rest of the processing continues in run_undetached.
start_undetached();
}
static WNDCLASS wndclass; // FIXME!
void ClientConnection::CreateDisplay()
{
// Create the window
WNDCLASS wndclass;
wndclass.style = 0;
wndclass.lpfnWndProc = ClientConnection::Proc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = m_pApp->m_instance;
wndclass.hIcon = (HICON)LoadIcon(m_pApp->m_instance,
MAKEINTRESOURCE(IDI_MAINICON));
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetSysColorBrush(COLOR_BTNFACE);
wndclass.lpszMenuName = (LPCTSTR)NULL;
wndclass.lpszClassName = VWR_WND_CLASS_NAME;
RegisterClass(&wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = ClientConnection::ScrollProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = m_pApp->m_instance;
wndclass.hIcon = NULL;
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = (LPCTSTR)NULL;
wndclass.lpszClassName = "ScrollClass";
RegisterClass(&wndclass);
wndclass.style = 0;
wndclass.lpfnWndProc = ClientConnection::Proc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = m_pApp->m_instance;
wndclass.hIcon = NULL;
switch (m_pApp->m_options.m_localCursor) {
case NOCURSOR:
wndclass.hCursor = LoadCursor(m_pApp->m_instance,
MAKEINTRESOURCE(IDC_NOCURSOR));
break;
case SMALLCURSOR:
wndclass.hCursor = LoadCursor(m_pApp->m_instance,
MAKEINTRESOURCE(IDC_SMALLDOT));
break;
case NORMALCURSOR:
wndclass.hCursor =LoadCursor(NULL,IDC_ARROW);
break;
case DOTCURSOR:
default:
wndclass.hCursor = LoadCursor(m_pApp->m_instance,
MAKEINTRESOURCE(IDC_DOTCURSOR));
}
wndclass.hbrBackground = (HBRUSH) GetStockObject(BLACK_BRUSH);
wndclass.lpszMenuName = (LPCTSTR)NULL;
wndclass.lpszClassName = "ChildClass";
RegisterClass(&wndclass);
m_hwnd1 = CreateWindow(VWR_WND_CLASS_NAME,
_T("VNCviewer"),
WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_SIZEBOX|
WS_MINIMIZEBOX|WS_MAXIMIZEBOX|
WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT, // x-size
CW_USEDEFAULT, // y-size
NULL, // Parent handle
NULL, // Menu handle
m_pApp->m_instance,
NULL);
SetWindowLong(m_hwnd1, GWL_USERDATA, (LONG) this);
SetWindowLong(m_hwnd1, GWL_WNDPROC, (LONG)ClientConnection::WndProc1);
ShowWindow(m_hwnd1, SW_HIDE);
m_hwndscroll = CreateWindow("ScrollClass",
NULL,
WS_CHILD | WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_BORDER,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT, // x-size
CW_USEDEFAULT, // y-size
m_hwnd1, // Parent handle
NULL, // Menu handle
m_pApp->m_instance,
NULL);
SetWindowLong(m_hwndscroll, GWL_USERDATA, (LONG) this);
ShowWindow(m_hwndscroll, SW_HIDE);
// Create a memory DC which we'll use for drawing to
// the local framebuffer
m_hBitmapDC = CreateCompatibleDC(NULL);
// Set a suitable palette up
if (GetDeviceCaps(m_hBitmapDC, RASTERCAPS) & RC_PALETTE) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -