diff --git a/CHANGELOG.md b/CHANGELOG.md index 37fcd554..a30bbd08 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ### Fixed - #1595: Unhandled exception when trying to browse through non existent multi ssh history with keyboard key strokes - #1337: Unhandled exception after closing mRemoteNG +- #359: Making a VNC connection to an unreachable host causes the application to not respond for 20-30 seconds ## [1.77.1] - 2019-09-02 ### Added diff --git a/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs b/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs index be25d5b9..89cc45f3 100644 --- a/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs +++ b/mRemoteV1/Connection/Protocol/VNC/Connection.Protocol.VNC.cs @@ -1,316 +1,362 @@ -using System; -using System.ComponentModel; -using mRemoteNG.App; -using mRemoteNG.Tools; -using mRemoteNG.UI.Forms; - -// ReSharper disable ArrangeAccessorOwnerBody - - -namespace mRemoteNG.Connection.Protocol.VNC -{ - public class ProtocolVNC : ProtocolBase, ISupportsViewOnly - { - #region Properties - - public bool SmartSize - { - get { return _VNC.Scaled; } - set { _VNC.Scaled = value; } - } - - public bool ViewOnly - { - get { return _VNC.ViewOnly; } - set { _VNC.ViewOnly = value; } - } - - #endregion - - #region Private Declarations - - private VncSharp.RemoteDesktop _VNC; - private ConnectionInfo Info; - - #endregion - - #region Public Methods - - public ProtocolVNC() - { - Control = new VncSharp.RemoteDesktop(); - } - - public override bool Initialize() - { - base.Initialize(); - - try - { - _VNC = (VncSharp.RemoteDesktop)Control; - - Info = InterfaceControl.Info; - - _VNC.VncPort = Info.Port; - - return true; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strVncSetPropsFailed + Environment.NewLine + ex.Message, - true); - return false; - } - } - - public override bool Connect() - { - SetEventHandlers(); - - try - { - _VNC.Connect(Info.Hostname, Info.VNCViewOnly, Info.VNCSmartSizeMode != SmartSizeMode.SmartSNo); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strConnectionOpenFailed + Environment.NewLine + - ex.Message); - return false; - } - - return true; - } - - public override void Disconnect() - { - try - { - _VNC.Disconnect(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strVncConnectionDisconnectFailed + Environment.NewLine + - ex.Message, true); - } - } - - public void SendSpecialKeys(SpecialKeys Keys) - { - try - { - // ReSharper disable once SwitchStatementMissingSomeCases - switch (Keys) - { - case SpecialKeys.CtrlAltDel: - _VNC.SendSpecialKeys(VncSharp.SpecialKeys.CtrlAltDel); - break; - case SpecialKeys.CtrlEsc: - _VNC.SendSpecialKeys(VncSharp.SpecialKeys.CtrlEsc); - break; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strVncSendSpecialKeysFailed + Environment.NewLine + - ex.Message, true); - } - } - - public void ToggleSmartSize() - { - try - { - SmartSize = !SmartSize; - RefreshScreen(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strVncToggleSmartSizeFailed + Environment.NewLine + - ex.Message, true); - } - } - - public void ToggleViewOnly() - { - try - { - ViewOnly = !ViewOnly; - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strVncToggleViewOnlyFailed + Environment.NewLine + - ex.Message, true); - } - } - - - public void StartChat() - { - throw new NotImplementedException(); - } - - public void StartFileTransfer() - { - throw new NotImplementedException(); - } - - public void RefreshScreen() - { - try - { - _VNC.FullScreenUpdate(); - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strVncRefreshFailed + Environment.NewLine + ex.Message, - true); - } - } - - #endregion - - #region Private Methods - - private void SetEventHandlers() - { - try - { - _VNC.ConnectComplete += VNCEvent_Connected; - _VNC.ConnectionLost += VNCEvent_Disconnected; - FrmMain.ClipboardChanged += VNCEvent_ClipboardChanged; - if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials) && Info?.Password?.Length > 0) - { - _VNC.GetPassword = VNCEvent_Authenticate; - } - } - catch (Exception ex) - { - Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, - Language.strVncSetEventHandlersFailed + Environment.NewLine + - ex.Message, true); - } - } - - #endregion - - #region Private Events & Handlers - - private void VNCEvent_Connected(object sender, EventArgs e) - { - Event_Connected(this); - _VNC.AutoScroll = Info.VNCSmartSizeMode == SmartSizeMode.SmartSNo; - } - - private void VNCEvent_Disconnected(object sender, EventArgs e) - { - FrmMain.ClipboardChanged -= VNCEvent_ClipboardChanged; - Event_Disconnected(sender, @"VncSharp Disconnected.", null); - Close(); - } - - private void VNCEvent_ClipboardChanged() - { - _VNC.FillServerClipboard(); - } - - private string VNCEvent_Authenticate() - { - return Info.Password; - } - - #endregion - - #region Enums - - public enum Defaults - { - Port = 5900 - } - - public enum SpecialKeys - { - CtrlAltDel, - CtrlEsc - } - - public enum Compression - { - [LocalizedAttributes.LocalizedDescription("strNoCompression")] - CompNone = 99, - [Description("0")] Comp0 = 0, - [Description("1")] Comp1 = 1, - [Description("2")] Comp2 = 2, - [Description("3")] Comp3 = 3, - [Description("4")] Comp4 = 4, - [Description("5")] Comp5 = 5, - [Description("6")] Comp6 = 6, - [Description("7")] Comp7 = 7, - [Description("8")] Comp8 = 8, - [Description("9")] Comp9 = 9 - } - - public enum Encoding - { - [Description("Raw")] EncRaw, - [Description("RRE")] EncRRE, - [Description("CoRRE")] EncCorre, - [Description("Hextile")] EncHextile, - [Description("Zlib")] EncZlib, - [Description("Tight")] EncTight, - [Description("ZlibHex")] EncZLibHex, - [Description("ZRLE")] EncZRLE - } - - public enum AuthMode - { - [LocalizedAttributes.LocalizedDescription("VNC")] - AuthVNC, - - [LocalizedAttributes.LocalizedDescription("Windows")] - AuthWin - } - - public enum ProxyType - { - [LocalizedAttributes.LocalizedDescription("strNone")] - ProxyNone, - - [LocalizedAttributes.LocalizedDescription("strHttp")] - ProxyHTTP, - - [LocalizedAttributes.LocalizedDescription("strSocks5")] - ProxySocks5, - - [LocalizedAttributes.LocalizedDescription("strUltraVncRepeater")] - ProxyUltra - } - - public enum Colors - { - [LocalizedAttributes.LocalizedDescription("strNormal")] - ColNormal, - [Description("8-bit")] Col8Bit - } - - public enum SmartSizeMode - { - [LocalizedAttributes.LocalizedDescription("strNoSmartSize")] - SmartSNo, - - [LocalizedAttributes.LocalizedDescription("strFree")] - SmartSFree, - - [LocalizedAttributes.LocalizedDescription("strAspect")] - SmartSAspect - } - - #endregion - } -} \ No newline at end of file +using System; +using System.Threading; +using System.ComponentModel; +using System.Net.Sockets; +using mRemoteNG.App; +using mRemoteNG.Tools; +using mRemoteNG.UI.Forms; + +// ReSharper disable ArrangeAccessorOwnerBody + + +namespace mRemoteNG.Connection.Protocol.VNC +{ + public class ProtocolVNC : ProtocolBase, ISupportsViewOnly + { + #region Properties + + public bool SmartSize + { + get { return _vnc.Scaled; } + set { _vnc.Scaled = value; } + } + + public bool ViewOnly + { + get { return _vnc.ViewOnly; } + set { _vnc.ViewOnly = value; } + } + + #endregion + + #region Private Declarations + + private VncSharp.RemoteDesktop _vnc; + private ConnectionInfo _info; + private static bool _isConnectionSuccessful; + private static Exception _socketexception; + private static readonly ManualResetEvent TimeoutObject = new ManualResetEvent(false); + + #endregion + + #region Public Methods + + public ProtocolVNC() + { + Control = new VncSharp.RemoteDesktop(); + } + + public override bool Initialize() + { + base.Initialize(); + + try + { + _vnc = (VncSharp.RemoteDesktop)Control; + _info = InterfaceControl.Info; + _vnc.VncPort = _info.Port; + + return true; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncSetPropsFailed + Environment.NewLine + ex.Message, + true); + return false; + } + } + + public override bool Connect() + { + SetEventHandlers(); + try + { + if (TestConnect(_info.Hostname, _info.Port, 500)) + _vnc.Connect(_info.Hostname, _info.VNCViewOnly, _info.VNCSmartSizeMode != SmartSizeMode.SmartSNo); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strConnectionOpenFailed + Environment.NewLine + + ex.Message); + return false; + } + + return true; + } + + public override void Disconnect() + { + try + { + _vnc.Disconnect(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncConnectionDisconnectFailed + Environment.NewLine + + ex.Message, true); + } + } + + public void SendSpecialKeys(SpecialKeys Keys) + { + try + { + // ReSharper disable once SwitchStatementMissingSomeCases + switch (Keys) + { + case SpecialKeys.CtrlAltDel: + _vnc.SendSpecialKeys(VncSharp.SpecialKeys.CtrlAltDel); + break; + case SpecialKeys.CtrlEsc: + _vnc.SendSpecialKeys(VncSharp.SpecialKeys.CtrlEsc); + break; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncSendSpecialKeysFailed + Environment.NewLine + + ex.Message, true); + } + } + + public void ToggleSmartSize() + { + try + { + SmartSize = !SmartSize; + RefreshScreen(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncToggleSmartSizeFailed + Environment.NewLine + + ex.Message, true); + } + } + + public void ToggleViewOnly() + { + try + { + ViewOnly = !ViewOnly; + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncToggleViewOnlyFailed + Environment.NewLine + + ex.Message, true); + } + } + + + public void StartChat() + { + throw new NotImplementedException(); + } + + public void StartFileTransfer() + { + throw new NotImplementedException(); + } + + public void RefreshScreen() + { + try + { + _vnc.FullScreenUpdate(); + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncRefreshFailed + Environment.NewLine + ex.Message, + true); + } + } + + #endregion + + #region Private Methods + + private void SetEventHandlers() + { + try + { + _vnc.ConnectComplete += VNCEvent_Connected; + _vnc.ConnectionLost += VNCEvent_Disconnected; + FrmMain.ClipboardChanged += VNCEvent_ClipboardChanged; + if (!Force.HasFlag(ConnectionInfo.Force.NoCredentials) && _info?.Password?.Length > 0) + { + _vnc.GetPassword = VNCEvent_Authenticate; + } + } + catch (Exception ex) + { + Runtime.MessageCollector.AddMessage(Messages.MessageClass.ErrorMsg, + Language.strVncSetEventHandlersFailed + Environment.NewLine + + ex.Message, true); + } + } + + private static bool TestConnect(string hostName, int port, int timeoutMSec) + { + var tcpclient = new TcpClient(); + + TimeoutObject.Reset(); + tcpclient.BeginConnect(hostName, port, CallBackMethod, tcpclient); + + if (TimeoutObject.WaitOne(timeoutMSec, false)) + { + if (_isConnectionSuccessful) return true; + } + else + { + tcpclient.Close(); + throw new TimeoutException($"Connection timed out to host " + hostName + " on port " + port); + } + + return false; + } + + private static void CallBackMethod(IAsyncResult asyncresult) + { + try + { + _isConnectionSuccessful = false; + var tcpclient = asyncresult.AsyncState as TcpClient; + + if (tcpclient?.Client == null) return; + + tcpclient.EndConnect(asyncresult); + _isConnectionSuccessful = true; + } + catch (Exception ex) + { + _isConnectionSuccessful = false; + _socketexception = ex; + } + finally + { + TimeoutObject.Set(); + } + } + + #endregion + + #region Private Events & Handlers + + private void VNCEvent_Connected(object sender, EventArgs e) + { + Event_Connected(this); + _vnc.AutoScroll = _info.VNCSmartSizeMode == SmartSizeMode.SmartSNo; + } + + private void VNCEvent_Disconnected(object sender, EventArgs e) + { + FrmMain.ClipboardChanged -= VNCEvent_ClipboardChanged; + Event_Disconnected(sender, @"VncSharp Disconnected.", null); + Close(); + } + + private void VNCEvent_ClipboardChanged() + { + _vnc.FillServerClipboard(); + } + + private string VNCEvent_Authenticate() + { + return _info.Password; + } + + #endregion + + #region Enums + + public enum Defaults + { + Port = 5900 + } + + public enum SpecialKeys + { + CtrlAltDel, + CtrlEsc + } + + public enum Compression + { + [LocalizedAttributes.LocalizedDescription("strNoCompression")] + CompNone = 99, + [Description("0")] Comp0 = 0, + [Description("1")] Comp1 = 1, + [Description("2")] Comp2 = 2, + [Description("3")] Comp3 = 3, + [Description("4")] Comp4 = 4, + [Description("5")] Comp5 = 5, + [Description("6")] Comp6 = 6, + [Description("7")] Comp7 = 7, + [Description("8")] Comp8 = 8, + [Description("9")] Comp9 = 9 + } + + public enum Encoding + { + [Description("Raw")] EncRaw, + [Description("RRE")] EncRRE, + [Description("CoRRE")] EncCorre, + [Description("Hextile")] EncHextile, + [Description("Zlib")] EncZlib, + [Description("Tight")] EncTight, + [Description("ZlibHex")] EncZLibHex, + [Description("ZRLE")] EncZRLE + } + + public enum AuthMode + { + [LocalizedAttributes.LocalizedDescription("VNC")] + AuthVNC, + + [LocalizedAttributes.LocalizedDescription("Windows")] + AuthWin + } + + public enum ProxyType + { + [LocalizedAttributes.LocalizedDescription("strNone")] + ProxyNone, + + [LocalizedAttributes.LocalizedDescription("strHttp")] + ProxyHTTP, + + [LocalizedAttributes.LocalizedDescription("strSocks5")] + ProxySocks5, + + [LocalizedAttributes.LocalizedDescription("strUltraVncRepeater")] + ProxyUltra + } + + public enum Colors + { + [LocalizedAttributes.LocalizedDescription("strNormal")] + ColNormal, + [Description("8-bit")] Col8Bit + } + + public enum SmartSizeMode + { + [LocalizedAttributes.LocalizedDescription("strNoSmartSize")] + SmartSNo, + + [LocalizedAttributes.LocalizedDescription("strFree")] + SmartSFree, + + [LocalizedAttributes.LocalizedDescription("strAspect")] + SmartSAspect + } + + #endregion + } +}