📄 conn.cs
字号:
// Copyright (c) 2004-2005, 2007 Rocky Lo. 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 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.
using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using System.Threading;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
using System.Collections;
using Vnc.RfbProto;
using Vnc.Security;
using SystemEx.WindowCE.Net;
namespace Vnc.Viewer
{
/// <remarks>
/// This class represents a connection to the server.
/// It prompts a user for the connection details, connects to the server,
/// creates a display, and then handles server messages.
/// </remarks>
internal class Conn
{
/// <summary>
/// This is the version number we report to the server. At the moment we
/// "borrow" this from the UltraVNC viewer.
/// </summary>
// TODO: Have we implemented everything needed in order to say that we are
// compliant to this version?
private const byte ViewerRfbMajorVer = 3;
private const byte ViewerRfbMinorVer = 4;
// These are cleaned up upon termination because they contain initial
// values of a connection object.
private ConnOpts opts = null;
private ViewOpts viewOpts = null;
// These are cleaned up upon termination because they contain
// unmanaged resources.
private TcpClient tcpClient = null;
private NetworkStream stream = null;
private BinaryReader reader = null;
private BinaryWriter writer = null;
private NetworkConn networkConn = null;
// These are set each time a connection is run.
private ServInit servInit = null;
private string desktopName = null;
private int majorVer = -1;
private int minorVer = -1;
private View view = null;
private bool termBgThread = false;
private byte bytesPp = 0;
private byte bpp = 0;
private byte depth = 0;
private bool isBigEndian = false;
private bool isTrueColor = false;
private UInt16 redMax = 0;
private UInt16 greenMax = 0;
private UInt16 blueMax = 0;
private byte redShift = 0;
private byte greenShift = 0;
private byte blueShift = 0;
private UInt16 frameBufWidth = 0;
private UInt16 frameBufHeight = 0;
internal bool IsFmtChgPending = false;
private EventHandler closeHdr = null;
internal Conn()
{
closeHdr = new EventHandler(CloseView);
}
private void CloseView(object sender, EventArgs e)
{
// Do this in the main thread.
view.Close();
}
private void ViewClosed(object sender, EventArgs e)
{
termBgThread = true;
App.RemoveConn(this);
}
private void GetConnDetails()
{
SessDlg sessDlg;
if(viewOpts == null)
sessDlg = SessDlgFactory.Create();
else
sessDlg = SessDlgFactory.Create(viewOpts);
if(sessDlg.ShowDialog() != DialogResult.OK)
throw new QuietEx();
opts = sessDlg.ConnOpts;
}
private void Connect()
{
try
{
try
{
IPAddress ipAdr = IPAddress.Parse(opts.Host);
IPEndPoint ipEndPt = new IPEndPoint(ipAdr, opts.Port);
tcpClient = new TcpClient();
tcpClient.Connect(ipEndPt);
}
catch(FormatException)
{
tcpClient = new TcpClient(opts.Host, opts.Port);
}
stream = tcpClient.GetStream();
reader = new BinaryReader(stream, Encoding.ASCII);
writer = new BinaryWriter(stream, Encoding.ASCII);
}
catch(SocketException)
{
throw new WarnEx(App.GetStr("Unable to connect to the specified server!"));
}
}
private void Listen()
{
TcpListener listener = new TcpListener(IPAddress.Any, opts.Port);
try
{
listener.Start();
ListenDlg listenDlg = new ListenDlg(listener);
if(listenDlg.ShowDialog() != DialogResult.OK)
throw new QuietEx();
tcpClient = listener.AcceptTcpClient();
stream = tcpClient.GetStream();
reader = new BinaryReader(stream, Encoding.ASCII);
writer = new BinaryWriter(stream, Encoding.ASCII);
}
catch(SocketException)
{
throw new WarnEx(App.GetStr("Unable to get an incoming connection from the server!"));
}
finally
{
try
{
listener.Stop();
}
catch
{}
}
}
private string ReadAsciiStr(int numChars)
{
if(numChars == 0)
return String.Empty;
char[] chars = reader.ReadChars(numChars);
return new string(chars);
}
private byte ReadByte()
{
return reader.ReadByte();
}
private byte[] ReadBytes(int numBytes)
{
if(numBytes == 0)
return new byte[0];
return reader.ReadBytes(numBytes);
}
private UInt32 ReadUInt32()
{
Int32 result = reader.ReadInt32();
result = IPAddress.NetworkToHostOrder(result);
return unchecked((UInt32)result);
}
private void WriteAsciiStr(string str)
{
writer.Write(str.ToCharArray());
}
private void WriteBytes(byte[] bytes)
{
writer.Write(bytes);
}
internal void WriteBytes(byte[] bytes, RfbCliMsgType msgType)
{
WriteBytes(bytes);
}
private void NegoProtoVer()
{
string verMsg = ReadAsciiStr(RfbSize.VerMsg);
if(!RfbProtoUtil.IsValidVerMsg(verMsg))
throw new WarnEx(App.GetStr("The server is not a VNC server!"));
RfbProtoUtil.GetVerFromMsg(verMsg, out majorVer, out minorVer);
if(majorVer == 3 && minorVer < 3)
throw new WarnEx(App.GetStr("This server version is not supported!"));
else
{
majorVer = ViewerRfbMajorVer;
minorVer = ViewerRfbMinorVer;
}
verMsg = RfbProtoUtil.GetVerMsg(majorVer, minorVer);
WriteAsciiStr(verMsg);
}
private void CreateDisp()
{
view = ViewFactory.Create(this, opts, frameBufWidth, frameBufHeight);
view.Text = desktopName;
view.Closed += new EventHandler(ViewClosed);
view.Show();
}
private void Auth()
{
RfbAuthScheme authScheme = (RfbAuthScheme)ReadUInt32();
switch(authScheme)
{
case RfbAuthScheme.ConnFailed:
throw new WarnEx(App.GetStr("Connection failed at authentication!"));
case RfbAuthScheme.NoAuth:
break;
case RfbAuthScheme.VncAuth:
if(opts.Passwd == null || opts.Passwd.Length == 0)
{
AuthDlg authDlg = new AuthDlg();
if(authDlg.ShowDialog() != DialogResult.OK)
throw new QuietEx();
if(authDlg.Passwd.Length <= 0)
throw new WarnEx(App.GetStr("Empty password!"));
opts.Passwd = authDlg.Passwd;
}
byte[] challenge = ReadBytes(RfbSize.AuthChallenge);
VncAuth.EncryptBytes(challenge, opts.Passwd);
WriteBytes(challenge);
RfbAuthResult authResult = (RfbAuthResult)ReadUInt32();
switch(authResult)
{
case RfbAuthResult.Ok:
break;
case RfbAuthResult.Failed:
throw new WarnEx(App.GetStr("Authentication failed!"));
case RfbAuthResult.TooMany:
throw new WarnEx(App.GetStr("Too many!"));
default:
throw new WarnEx(App.GetStr("Authentication failed but reason unknown!"));
}
break;
default:
throw new WarnEx(App.GetStr("Authentication scheme unknown!"));
}
}
private void SendCliInit()
{
byte[] msg = RfbProtoUtil.GetCliInitMsg(opts.ViewOpts.ShareServ);
WriteBytes(msg);
}
private void ReadServInit()
{
byte[] msg = ReadBytes(RfbSize.ServInit);
servInit = new ServInit(msg);
frameBufWidth = servInit.Width;
frameBufHeight = servInit.Height;
desktopName = ReadAsciiStr((int)servInit.NameLen);
}
private void SetPixelFormat()
{
byte[] msg;
if(opts.ViewOpts.PixelSize == PixelSize.Force8Bit)
{
bpp = 8;
depth = 8;
isBigEndian = false;
isTrueColor = true;
redMax = 7;
greenMax = 7;
blueMax = 3;
redShift = 0;
greenShift = 3;
blueShift = 6;
bytesPp = 1;
}
else if(opts.ViewOpts.PixelSize == PixelSize.Force16Bit || !servInit.IsTrueColor)
{
bpp = 16;
depth = 16;
isBigEndian = false;
isTrueColor = true;
redMax = 63;
greenMax = 31;
blueMax = 31;
redShift = 0;
greenShift = 6;
blueShift = 11;
bytesPp = 2;
}
else
{
bpp = servInit.Bpp;
depth = servInit.Depth;
isBigEndian = false;
isTrueColor = servInit.IsTrueColor;
redMax = servInit.RedMax;
greenMax = servInit.GreenMax;
blueMax = servInit.BlueMax;
redShift = servInit.RedShift;
greenShift = servInit.GreenShift;
blueShift = servInit.BlueShift;
bytesPp = (byte)((bpp + 7) / 8);
}
msg = RfbProtoUtil.GetSetPixelFormatMsg(bpp, depth, isBigEndian, isTrueColor, redMax, greenMax, blueMax, redShift, greenShift, blueShift);
WriteBytes(msg, RfbCliMsgType.SetPixelFormat);
}
private void SetEncodings()
{
// We use a stack here. The least favored encoding is pushed onto the stack first.
Stack stack = new Stack();
stack.Push(RfbEncoding.Raw);
stack.Push(RfbEncoding.CopyRect);
stack.Push(RfbEncoding.Rre);
// We do support CoRRE encoding.
// However, Ultra-VNC server is broken.
// If we use CoRRE and server-side scaling is enabled, the server will
// send us frame buffer updates with number of rectangles set incorrectly.
// So the morale of the story is not to use CoRRE. If we know the server
// does not scale the buffer, then we can enable CoRRE.
// But this can all be avoided by using Hextile.
//stack.Push(RfbEncoding.CoRre);
stack.Push(RfbEncoding.Hex);
stack.Push(RfbEncoding.NewFBSize);
byte[] msg;
msg = RfbProtoUtil.GetSetEncodingsMsgHdr((UInt16)stack.Count);
WriteBytes(msg, RfbCliMsgType.SetEncodings);
RfbEncoding[] encodings = new RfbEncoding[stack.Count];
stack.ToArray().CopyTo(encodings, 0);
msg = RfbProtoUtil.GetSetEncodingsMsg(encodings);
WriteBytes(msg);
}
private void EstNetworkConn()
{
// We use the connection manager on PPCs and Smartphones.
if(App.DevCap.Lvl >= DevCapLvl.Desktop)
return;
networkConn = new NetworkConn("http://" + opts.Host + "/");
networkConn.Est();
}
private void RelNetworkConn()
{
// We use the connection manager on PPCs and Smartphones.
if(App.DevCap.Lvl >= DevCapLvl.Desktop)
return;
if(networkConn != null)
{
networkConn.Rel();
networkConn = null;
}
}
private void CleanUp()
{
// We don't cleanup majorVer, minorVer, etc. here because
// we will always read them when run is called.
if(writer != null)
{
writer.Close();
writer = null;
}
if(reader != null)
{
reader.Close();
reader = null;
}
if(stream != null)
{
stream.Close();
stream = null;
}
if(tcpClient != null)
{
tcpClient.Close();
tcpClient = null;
}
RelNetworkConn();
opts = null;
viewOpts = null;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -