From 8aa9f130cdf288ae6adf92d115a239d7f22d3a9b Mon Sep 17 00:00:00 2001 From: Heath Volmer Date: Thu, 22 Sep 2016 21:57:21 -0600 Subject: [PATCH] GenericSshClient changes for S+ module --- .../Pepperdash Core/Comm/GenericSshClient.cs | 741 ++++++++++-------- .../Comm/GenericTcpIpClient.cs | 562 ++++++------- .../Pepperdash Core/CommunicationExtras.cs | 182 +++-- .../Pepperdash Core/PepperDash_Core.csproj | 2 +- .../Pepperdash Core/bin/PepperDash_Core.clz | Bin 679066 -> 679182 bytes .../bin/PepperDash_Core.config | 4 +- .../Pepperdash Core/bin/PepperDash_Core.dll | Bin 28856 -> 28856 bytes .../Pepperdash Core/bin/manifest.info | 2 +- .../Pepperdash Core/bin/manifest.ser | Bin 651 -> 649 bytes 9 files changed, 785 insertions(+), 708 deletions(-) diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs index 9b2c36f..e5e40d1 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericSshClient.cs @@ -1,337 +1,404 @@ -using System; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; -using Crestron.SimplSharp.Ssh; -using Crestron.SimplSharp.Ssh.Common; - -namespace PepperDash.Core -{ - public class ConnectionChangeEventArgs : EventArgs - { - public bool IsConnected { get; private set; } - public GenericSshClient Client { get; private set; } - public ushort Status { get { return Client.UStatus; } } - - // S+ Constructor - public ConnectionChangeEventArgs() { } - - public ConnectionChangeEventArgs(bool isConnected, GenericSshClient client) - { - IsConnected = isConnected; - Client = client; - } - } - - //***************************************************************************************************** - //***************************************************************************************************** - - public class GenericSshClient : Device, IBasicCommunication, IAutoReconnect - { - public event EventHandler BytesReceived; - public event EventHandler TextReceived; - - public event EventHandler ConnectionChange; - //public event EventHandler DataReceive; - - public string Hostname { get; set; } - /// - /// Port on server - /// - public int Port { get; set; } - public string Username { get; set; } - public string Password { get; set; } - - public bool IsConnected - { - // returns false if no client or not connected - get { return (Client != null ? Client.IsConnected : false); } - set - { - if (value) - UStatus = 2; - OnConnectionChange(); - } - } - /// - /// Contains the familiar Simpl analog status values - /// - public ushort UStatus { get; private set; } - - /// - /// Determines whether client will attempt reconnection on failure. Default is true - /// - public bool AutoReconnect { get; set; } - - /// - /// Millisecond value, determines the timeout period in between reconnect attempts - /// - public int AutoReconnectIntervalMs { get; set; } - - SshClient Client; - ShellStream TheStream; - CTimer ReconnectTimer; - //bool ReconnectTimerRunning; - - public GenericSshClient(string key, string hostname, int port, string username, string password) : - base(key) - { - AutoReconnectIntervalMs = 5000; - AutoReconnect = true; - Hostname = hostname; - Port = port; - Username = username; - Password = password; - CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); - } - - void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) - { - if (programEventType == eProgramStatusEventType.Stopping) - { - if (Client != null) - { - Debug.Console(2, this, "Closing connection"); - Client.Disconnect(); - Client.Dispose(); - Debug.Console(2, this, "Connection closed"); - } - } - } - - /// - /// Connect to the server, using the provided properties. - /// - public void Connect() - { - Debug.Console(1, this, "attempting connect, IsConnected={0}", Client != null ? Client.IsConnected : false); - - //ReconnectTimerRunning = false; - if (ReconnectTimer != null) - { - ReconnectTimer.Stop(); - ReconnectTimer = null; - } - - if (IsConnected) - return; - - if (Hostname != null && Hostname != string.Empty && Port > 0 && - Username != null && Password != null) - { - - UStatus = 1; - IsConnected = false; - - // This handles both password and keyboard-interactive (like on OS-X, 'nixes) - KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(Username); - kauth.AuthenticationPrompt += new EventHandler(kauth_AuthenticationPrompt); - PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password); - ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth); - // always spin up new client in case parameters have changed - if (Client != null) - { - Client.Disconnect(); - Client = null; - } - Client = new SshClient(connectionInfo); - - Client.ErrorOccurred += Client_ErrorOccurred; - try - { - Client.Connect(); - if (Client.IsConnected) - { - Client.KeepAliveInterval = TimeSpan.FromSeconds(2); - Client.SendKeepAlive(); - IsConnected = true; - Debug.Console(1, this, "Connected"); - TheStream = Client.CreateShellStream("PDTShell", 100, 80, 100, 200, 65534); - TheStream.DataReceived += Stream_DataReceived; - } - return; - } - catch (SshConnectionException e) - { - var ie = e.InnerException; // The details are inside!! - string msg; - if (ie is SocketException) - msg = string.Format("'{0}' CONNECTION failure: Cannot reach host, ({1})", Key, ie.GetType()); - else if (ie is System.Net.Sockets.SocketException) - msg = string.Format("'{0}' Connection failure: Cannot reach host '{1}' on port {2}, ({3})", - Key, Hostname, Port, ie.GetType()); - else if (ie is SshAuthenticationException) - { - msg = string.Format("'{0}' Authentication failure for username '{1}', ({2})", - Username, Key, ie.GetType()); - Debug.Console(0, this, "Authentication failure for username '{0}', ({1})", - Username, ie.GetType()); - } - else - Debug.Console(0, this, "Error on connect:\r({0})", e); - } - catch (Exception e) - { - Debug.Console(0, this, "Unhandled exception on connect:\r({0})", e); - } - } - else - { - Debug.Console(0, this, "Connect failed. Check hostname, port, username and password are set or not null"); - } - - // Sucess will not make it this far - UStatus = 3; - IsConnected = false; - HandleConnectionFailure(); - } - - /// - /// Disconnect the clients and put away it's resources. - /// - public void Disconnect() - { - // Stop trying reconnects, if we are - if (ReconnectTimer != null) - { - ReconnectTimer.Stop(); - ReconnectTimer = null; - } - // Otherwise just close up - if (Client != null) // && Client.IsConnected) <-- Doesn't always report properly... - { - Debug.Console(1, this, "Disconnecting"); - Client.Disconnect(); - Cleanup(); - UStatus = 5; - IsConnected = false; - } - } - - /// - /// Anything to do with reestablishing connection on failures - /// - void HandleConnectionFailure() - { - Debug.Console(2, this, "Checking autoreconnect: {0}, {1}ms", - AutoReconnect, AutoReconnectIntervalMs); - if (AutoReconnect) - { - if (ReconnectTimer == null)// || !ReconnectTimerRunning) - { - ReconnectTimer = new CTimer(o => - { - Connect(); - ReconnectTimer = null; - }, AutoReconnectIntervalMs); - Debug.Console(1, this, "Attempting connection in {0} seconds", - (float)(AutoReconnectIntervalMs / 1000)); - } - else - { - Debug.Console(2, this, "{0} second reconnect cycle running", - (float)(AutoReconnectIntervalMs / 1000)); - } - } - } - - void Cleanup() - { - Debug.Console(2, this, "cleaning up resources"); - Client = null; - } - - /// - /// Handles the keyboard interactive authentication, should it be required. - /// - void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e) - { - foreach (AuthenticationPrompt prompt in e.Prompts) - if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1) - prompt.Response = Password; - } - - /// - /// Handler for data receive on ShellStream. Passes data across to queue for line parsing. - /// - void Stream_DataReceived(object sender, Crestron.SimplSharp.Ssh.Common.ShellDataEventArgs e) - { - var bytes = e.Data; - if (bytes.Length > 0) - { - var bytesHandler = BytesReceived; - if (bytesHandler != null) - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - var textHandler = TextReceived; - if (textHandler != null) - { - var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - } - } - } - - /// - /// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange - /// event - /// - void Client_ErrorOccurred(object sender, Crestron.SimplSharp.Ssh.Common.ExceptionEventArgs e) - { - if (!(e.Exception is SshConnectionException)) - { - Debug.Console(0, this, "SSH client error: {0}", e.Exception); - UStatus = 4; - } - Client.Disconnect(); - Client = null; - Debug.Console(1, this, "Disconnected by remote"); - IsConnected = false; - HandleConnectionFailure(); - } - - /// - /// Helper for ConnectionChange event - /// - void OnConnectionChange() - { - if(ConnectionChange != null) - ConnectionChange(this, new ConnectionChangeEventArgs(IsConnected, this)); - } - - #region IBasicCommunication Members - - public void SendText(string text) - { - try - { - TheStream.Write(text); - TheStream.Flush(); - } - catch - { - Debug.Console(1, this, "Stream write failed. Disconnected, closing"); - UStatus = 4; - IsConnected = false; - HandleConnectionFailure(); - } - } - - public void SendBytes(byte[] bytes) - { - try - { - TheStream.Write(bytes, 0, bytes.Length); - TheStream.Flush(); - } - catch - { - Debug.Console(1, this, "Stream write failed. Disconnected, closing"); - UStatus = 4; - IsConnected = false; - HandleConnectionFailure(); - } - } - - #endregion - } -} +using System; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; +using Crestron.SimplSharp.Ssh; +using Crestron.SimplSharp.Ssh.Common; + +namespace PepperDash.Core +{ + public class ConnectionChangeEventArgs : EventArgs + { + public bool IsConnected { get; private set; } + + public ushort UIsConnected { get { return (ushort)(Client.IsConnected ? 1 : 0); } } + + public GenericSshClient Client { get; private set; } + public ushort Status { get { return Client.UStatus; } } + + // S+ Constructor + public ConnectionChangeEventArgs() { } + + public ConnectionChangeEventArgs(bool isConnected, GenericSshClient client) + { + IsConnected = isConnected; + Client = client; + } + } + + //***************************************************************************************************** + //***************************************************************************************************** + + public class GenericSshClient : Device, IBasicCommunication, IAutoReconnect + { + /// + /// Event that fires when data is received. Delivers args with byte array + /// + public event EventHandler BytesReceived; + + /// + /// Event that fires when data is received. Delivered as text. + /// + public event EventHandler TextReceived; + + /// + /// Event when the connection status changes. + /// + public event EventHandler ConnectionChange; + + + public string Hostname { get; set; } + /// + /// Port on server + /// + public int Port { get; set; } + public string Username { get; set; } + public string Password { get; set; } + + public bool IsConnected + { + // returns false if no client or not connected + get { return UStatus == 2; } + } + /// + /// Contains the familiar Simpl analog status values + /// + public ushort UStatus + { + get { return _UStatus; } + private set + { + if (_UStatus == value) + return; + _UStatus = value; + OnConnectionChange(); + } + + } + ushort _UStatus; + + /// + /// Determines whether client will attempt reconnection on failure. Default is true + /// + public bool AutoReconnect { get; set; } + + /// + /// S+ helper for AutoReconnect + /// + public ushort UAutoReconnect + { + get { return (ushort)(AutoReconnect ? 1 : 0); } + set { AutoReconnect = value == 1; } + } + + /// + /// Millisecond value, determines the timeout period in between reconnect attempts. + /// Set to 5000 by default + /// + public int AutoReconnectIntervalMs { get; set; } + + SshClient Client; + ShellStream TheStream; + CTimer ReconnectTimer; + + /// + /// Typical constructor. + /// + public GenericSshClient(string key, string hostname, int port, string username, string password) : + base(key) + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + Key = key; + Hostname = hostname; + Port = port; + Username = username; + Password = password; + AutoReconnectIntervalMs = 5000; + } + + /// + /// S+ Constructor - Must set all properties before calling Connect + /// + public GenericSshClient() + : base("Uninitialized SshClient") + { + CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler); + AutoReconnectIntervalMs = 5000; + } + + /// + /// Just to help S+ set the key + /// + public void Initialize(string key) + { + Key = key; + } + + /// + /// Handles closing this up when the program shuts down + /// + void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType) + { + if (programEventType == eProgramStatusEventType.Stopping) + { + if (Client != null) + { + Debug.Console(2, this, "Program stopping. Closing connection"); + Client.Disconnect(); + Client.Dispose(); + } + } + } + + /// + /// Connect to the server, using the provided properties. + /// + public void Connect() + { + Debug.Console(1, this, "attempting connect, IsConnected={0}", Client != null ? Client.IsConnected : false); + + // Cancel reconnect if running. + if (ReconnectTimer != null) + { + ReconnectTimer.Stop(); + ReconnectTimer = null; + } + + // Don't try to connect if already + if (IsConnected) + return; + + // Don't go unless everything is here + if (string.IsNullOrEmpty(Hostname) || Port < 1 || Port > 65535 + || Username == null || Password == null) + { + Debug.Console(0, this, "Connect failed. Check hostname, port, username and password are set or not null"); + return; + } + + //You can do it! + UStatus = 1; + //IsConnected = false; + + // This handles both password and keyboard-interactive (like on OS-X, 'nixes) + KeyboardInteractiveAuthenticationMethod kauth = new KeyboardInteractiveAuthenticationMethod(Username); + kauth.AuthenticationPrompt += new EventHandler(kauth_AuthenticationPrompt); + PasswordAuthenticationMethod pauth = new PasswordAuthenticationMethod(Username, Password); + ConnectionInfo connectionInfo = new ConnectionInfo(Hostname, Port, Username, pauth, kauth); + + // always spin up new client in case parameters have changed + // **** MAY WANT TO CHANGE THIS BECAUSE OF SOCKET LEAKS **** + if (Client != null) + { + Client.Disconnect(); + Client = null; + } + Client = new SshClient(connectionInfo); + + Client.ErrorOccurred += Client_ErrorOccurred; + try + { + Client.Connect(); + if (Client.IsConnected) + { + Client.KeepAliveInterval = TimeSpan.FromSeconds(2); + Client.SendKeepAlive(); + TheStream = Client.CreateShellStream("PDTShell", 100, 80, 100, 200, 65534); + TheStream.DataReceived += Stream_DataReceived; + Debug.Console(1, this, "Connected"); + UStatus = 2; + //IsConnected = true; + } + return; + } + catch (SshConnectionException e) + { + var ie = e.InnerException; // The details are inside!! + if (ie is SocketException) + Debug.Console(0, this, "'{0}' CONNECTION failure: Cannot reach host, ({1})", Key, ie.GetType()); + else if (ie is System.Net.Sockets.SocketException) + Debug.Console(0, this, "'{0}' Connection failure: Cannot reach host '{1}' on port {2}, ({3})", + Key, Hostname, Port, ie.GetType()); + else if (ie is SshAuthenticationException) + { + Debug.Console(0, this, "Authentication failure for username '{0}', ({1})", + Username, ie.GetType()); + } + else + Debug.Console(0, this, "Error on connect:\r({0})", e); + } + catch (Exception e) + { + Debug.Console(0, this, "Unhandled exception on connect:\r({0})", e); + } + + + // Sucess will not make it this far + UStatus = 3; + //IsConnected = false; + HandleConnectionFailure(); + } + + /// + /// Disconnect the clients and put away it's resources. + /// + public void Disconnect() + { + // Stop trying reconnects, if we are + if (ReconnectTimer != null) + { + ReconnectTimer.Stop(); + ReconnectTimer = null; + } + DiscoAndCleanup(); + UStatus = 5; + //IsConnected = false; + } + + /// + /// + /// + void DiscoAndCleanup() + { + if (Client != null) + { + Client.ErrorOccurred -= Client_ErrorOccurred; + TheStream.DataReceived -= Stream_DataReceived; + Debug.Console(2, this, "Cleaning up disconnected client"); + Client.Disconnect(); + Client.Dispose(); + Client = null; + } + } + + /// + /// Anything to do with reestablishing connection on failures + /// + void HandleConnectionFailure() + { + DiscoAndCleanup(); + + Debug.Console(2, this, "Checking autoreconnect: {0}, {1}ms", + AutoReconnect, AutoReconnectIntervalMs); + if (AutoReconnect) + { + if (ReconnectTimer == null)// || !ReconnectTimerRunning) + { + ReconnectTimer = new CTimer(o => + { + Connect(); + ReconnectTimer = null; + }, AutoReconnectIntervalMs); + Debug.Console(1, this, "Attempting connection in {0} seconds", + (float)(AutoReconnectIntervalMs / 1000)); + } + else + { + Debug.Console(2, this, "{0} second reconnect cycle running", + (float)(AutoReconnectIntervalMs / 1000)); + } + } + } + + /// + /// Handles the keyboard interactive authentication, should it be required. + /// + void kauth_AuthenticationPrompt(object sender, AuthenticationPromptEventArgs e) + { + foreach (AuthenticationPrompt prompt in e.Prompts) + if (prompt.Request.IndexOf("Password:", StringComparison.InvariantCultureIgnoreCase) != -1) + prompt.Response = Password; + } + + /// + /// Handler for data receive on ShellStream. Passes data across to queue for line parsing. + /// + void Stream_DataReceived(object sender, Crestron.SimplSharp.Ssh.Common.ShellDataEventArgs e) + { + var bytes = e.Data; + if (bytes.Length > 0) + { + var bytesHandler = BytesReceived; + if (bytesHandler != null) + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + var textHandler = TextReceived; + if (textHandler != null) + { + var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } + } + } + + /// + /// Error event handler for client events - disconnect, etc. Will forward those events via ConnectionChange + /// event + /// + void Client_ErrorOccurred(object sender, Crestron.SimplSharp.Ssh.Common.ExceptionEventArgs e) + { + Debug.Console(0, this, "SSH client error: {0}", e.Exception); + if (!(e.Exception is SshConnectionException)) + { + Debug.Console(1, this, "Disconnected by remote"); + } + if (Client != null) + { + Client.Disconnect(); + Client.Dispose(); + Client = null; + } + UStatus = 4; + //IsConnected = false; + HandleConnectionFailure(); + } + + /// + /// Helper for ConnectionChange event + /// + void OnConnectionChange() + { + if(ConnectionChange != null) + ConnectionChange(this, new ConnectionChangeEventArgs(IsConnected, this)); + } + + #region IBasicCommunication Members + + /// + /// + /// + /// + public void SendText(string text) + { + try + { + TheStream.Write(text); + TheStream.Flush(); + } + catch + { + Debug.Console(1, this, "Stream write failed. Disconnected, closing"); + UStatus = 4; + //IsConnected = false; + HandleConnectionFailure(); + } + } + + public void SendBytes(byte[] bytes) + { + try + { + TheStream.Write(bytes, 0, bytes.Length); + TheStream.Flush(); + } + catch + { + Debug.Console(1, this, "Stream write failed. Disconnected, closing"); + UStatus = 4; + //IsConnected = false; + HandleConnectionFailure(); + } + } + + #endregion + } +} diff --git a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs index d5c618f..59fb3f3 100644 --- a/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs +++ b/Pepperdash Core/Pepperdash Core/Comm/GenericTcpIpClient.cs @@ -1,282 +1,282 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Text.RegularExpressions; -using Crestron.SimplSharp; -using Crestron.SimplSharp.CrestronSockets; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace PepperDash.Core -{ - public class GenericTcpIpClient : Device, IBasicCommunication, IAutoReconnect - { - /// - /// - /// - public event EventHandler BytesReceived; - - /// - /// - /// - public event EventHandler TextReceived; - - /// - /// - /// - public TCPClient Client { get; private set; } - - /// - /// - /// - public bool IsConnected { get { return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } - - /// - /// - /// - public SocketStatus ClientStatus { get { return Client.ClientStatus; } } - - /// - /// - /// - public string ClientStatusText { get { return Client.ClientStatus.ToString(); } } - - /// - /// - /// - public ushort UClientStatus { get { return (ushort)Client.ClientStatus; } } - - /// - /// - /// - public string ConnectionFailure { get { return Client.ClientStatus.ToString(); } } - - /// - /// - /// - public bool AutoReconnect { get; set; } - - /// - /// - /// - public int AutoReconnectIntervalMs { get; set; } - - /// - /// Set only when the disconnect method is called. - /// - bool DisconnectCalledByUser; - - /// - /// - /// - public bool Connected - { - get { return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } - } - - CTimer RetryTimer; - - public GenericTcpIpClient(string key, string address, int port, int bufferSize) - : base(key) - { - Client = new TCPClient(address, port, bufferSize); - } - - public override bool CustomActivate() - { - Client.SocketStatusChange += new TCPClientSocketStatusChangeEventHandler(Client_SocketStatusChange); - return true; - } - - public override bool Deactivate() - { - Client.SocketStatusChange -= this.Client_SocketStatusChange; - return true; - } - - public void Connect() - { - Client.ConnectToServerAsync(null); - DisconnectCalledByUser = false; - } - - public void Disconnnect() - { - DisconnectCalledByUser = true; - Client.DisconnectFromServer(); - } - - void ConnectToServerCallback(TCPClient c) - { - if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) - WaitAndTryReconnect(); - } - - void WaitAndTryReconnect() - { - Client.DisconnectFromServer(); - Debug.Console(2, "Attempting reconnect, status={0}", Client.ClientStatus); - RetryTimer = new CTimer(o => { Client.ConnectToServerAsync(ConnectToServerCallback); }, 1000); - } - - void Receive(TCPClient client, int numBytes) - { - if (numBytes > 0) - { - var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); - var bytesHandler = BytesReceived; - if (bytesHandler != null) - bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); - var textHandler = TextReceived; - if (textHandler != null) - { - var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); - textHandler(this, new GenericCommMethodReceiveTextArgs(str)); - } - } - Client.ReceiveDataAsync(Receive); - } - - /// - /// General send method - /// - public void SendText(string text) - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - // Check debug level before processing byte array - if (Debug.Level == 2) - Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); - Client.SendData(bytes, bytes.Length); - } - - /// - /// This is useful from console and...? - /// - public void SendEscapedText(string text) - { - var unescapedText = Regex.Replace(text, @"\\x([0-9a-fA-F][0-9a-fA-F])", s => - { - var hex = s.Groups[1].Value; - return ((char)Convert.ToByte(hex, 16)).ToString(); - }); - SendText(unescapedText); - - } - - public void SendBytes(byte[] bytes) - { - if (Debug.Level == 2) - Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); - Client.SendData(bytes, bytes.Length); - } - - - void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) - { - - Debug.Console(2, this, "Socket status change {0} ({1})", clientSocketStatus, UClientStatus); - if (client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED && !DisconnectCalledByUser) - WaitAndTryReconnect(); - - switch (clientSocketStatus) - { - case SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY: - break; - case SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY: - break; - case SocketStatus.SOCKET_STATUS_CONNECTED: - Client.ReceiveDataAsync(Receive); - DisconnectCalledByUser = false; - break; - case SocketStatus.SOCKET_STATUS_CONNECT_FAILED: - break; - case SocketStatus.SOCKET_STATUS_DNS_FAILED: - break; - case SocketStatus.SOCKET_STATUS_DNS_LOOKUP: - break; - case SocketStatus.SOCKET_STATUS_DNS_RESOLVED: - break; - case SocketStatus.SOCKET_STATUS_LINK_LOST: - break; - case SocketStatus.SOCKET_STATUS_NO_CONNECT: - break; - case SocketStatus.SOCKET_STATUS_SOCKET_NOT_EXIST: - break; - case SocketStatus.SOCKET_STATUS_WAITING: - break; - default: - break; - } - } - } - - - public class TcpSshPropertiesConfig - { - [JsonProperty(Required = Required.Always)] - public string Address { get; set; } - - [JsonProperty(Required = Required.Always)] - public int Port { get; set; } - - public string Username { get; set; } - public string Password { get; set; } - - /// - /// Defaults to 32768 - /// - public int BufferSize { get; set; } - - /// - /// Defaults to true - /// - public bool AutoReconnect { get; set; } - - /// - /// Defaults to 5000ms - /// - public int AutoReconnectIntervalMs { get; set; } - - public TcpSshPropertiesConfig() - { - BufferSize = 32768; - AutoReconnect = true; - AutoReconnectIntervalMs = 5000; - } - - } - - //public class TcpIpConfig - //{ - // [JsonProperty(Required = Required.Always)] - // public string Address { get; set; } - - // [JsonProperty(Required = Required.Always)] - // public int Port { get; set; } - - // /// - // /// Defaults to 32768 - // /// - // public int BufferSize { get; set; } - - // /// - // /// Defaults to true - // /// - // public bool AutoReconnect { get; set; } - - // /// - // /// Defaults to 5000ms - // /// - // public int AutoReconnectIntervalMs { get; set; } - - // public TcpIpConfig() - // { - // BufferSize = 32768; - // AutoReconnect = true; - // AutoReconnectIntervalMs = 5000; - // } - //} - +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Text.RegularExpressions; +using Crestron.SimplSharp; +using Crestron.SimplSharp.CrestronSockets; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace PepperDash.Core +{ + public class GenericTcpIpClient : Device, IBasicCommunication, IAutoReconnect + { + /// + /// + /// + public event EventHandler BytesReceived; + + /// + /// + /// + public event EventHandler TextReceived; + + /// + /// + /// + public TCPClient Client { get; private set; } + + /// + /// + /// + public bool IsConnected { get { return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } } + + /// + /// + /// + public SocketStatus ClientStatus { get { return Client.ClientStatus; } } + + /// + /// + /// + public string ClientStatusText { get { return Client.ClientStatus.ToString(); } } + + /// + /// + /// + public ushort UClientStatus { get { return (ushort)Client.ClientStatus; } } + + /// + /// + /// + public string ConnectionFailure { get { return Client.ClientStatus.ToString(); } } + + /// + /// + /// + public bool AutoReconnect { get; set; } + + /// + /// + /// + public int AutoReconnectIntervalMs { get; set; } + + /// + /// Set only when the disconnect method is called. + /// + bool DisconnectCalledByUser; + + /// + /// + /// + public bool Connected + { + get { return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; } + } + + CTimer RetryTimer; + + public GenericTcpIpClient(string key, string address, int port, int bufferSize) + : base(key) + { + Client = new TCPClient(address, port, bufferSize); + Client.SocketStatusChange += new TCPClientSocketStatusChangeEventHandler(Client_SocketStatusChange); + } + + //public override bool CustomActivate() + //{ + // return true; + //} + + public override bool Deactivate() + { + Client.SocketStatusChange -= this.Client_SocketStatusChange; + return true; + } + + public void Connect() + { + Client.ConnectToServerAsync(null); + DisconnectCalledByUser = false; + } + + public void Disconnnect() + { + DisconnectCalledByUser = true; + Client.DisconnectFromServer(); + } + + void ConnectToServerCallback(TCPClient c) + { + if (c.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED) + WaitAndTryReconnect(); + } + + void WaitAndTryReconnect() + { + Client.DisconnectFromServer(); + Debug.Console(2, "Attempting reconnect, status={0}", Client.ClientStatus); + RetryTimer = new CTimer(o => { Client.ConnectToServerAsync(ConnectToServerCallback); }, 1000); + } + + void Receive(TCPClient client, int numBytes) + { + if (numBytes > 0) + { + var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray(); + var bytesHandler = BytesReceived; + if (bytesHandler != null) + bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes)); + var textHandler = TextReceived; + if (textHandler != null) + { + var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length); + textHandler(this, new GenericCommMethodReceiveTextArgs(str)); + } + } + Client.ReceiveDataAsync(Receive); + } + + /// + /// General send method + /// + public void SendText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + // Check debug level before processing byte array + if (Debug.Level == 2) + Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + Client.SendData(bytes, bytes.Length); + } + + /// + /// This is useful from console and...? + /// + public void SendEscapedText(string text) + { + var unescapedText = Regex.Replace(text, @"\\x([0-9a-fA-F][0-9a-fA-F])", s => + { + var hex = s.Groups[1].Value; + return ((char)Convert.ToByte(hex, 16)).ToString(); + }); + SendText(unescapedText); + + } + + public void SendBytes(byte[] bytes) + { + if (Debug.Level == 2) + Debug.Console(2, this, "Sending {0} bytes: '{1}'", bytes.Length, ComTextHelper.GetEscapedText(bytes)); + Client.SendData(bytes, bytes.Length); + } + + + void Client_SocketStatusChange(TCPClient client, SocketStatus clientSocketStatus) + { + + Debug.Console(2, this, "Socket status change {0} ({1})", clientSocketStatus, UClientStatus); + if (client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED && !DisconnectCalledByUser) + WaitAndTryReconnect(); + + switch (clientSocketStatus) + { + case SocketStatus.SOCKET_STATUS_BROKEN_LOCALLY: + break; + case SocketStatus.SOCKET_STATUS_BROKEN_REMOTELY: + break; + case SocketStatus.SOCKET_STATUS_CONNECTED: + Client.ReceiveDataAsync(Receive); + DisconnectCalledByUser = false; + break; + case SocketStatus.SOCKET_STATUS_CONNECT_FAILED: + break; + case SocketStatus.SOCKET_STATUS_DNS_FAILED: + break; + case SocketStatus.SOCKET_STATUS_DNS_LOOKUP: + break; + case SocketStatus.SOCKET_STATUS_DNS_RESOLVED: + break; + case SocketStatus.SOCKET_STATUS_LINK_LOST: + break; + case SocketStatus.SOCKET_STATUS_NO_CONNECT: + break; + case SocketStatus.SOCKET_STATUS_SOCKET_NOT_EXIST: + break; + case SocketStatus.SOCKET_STATUS_WAITING: + break; + default: + break; + } + } + } + + + public class TcpSshPropertiesConfig + { + [JsonProperty(Required = Required.Always)] + public string Address { get; set; } + + [JsonProperty(Required = Required.Always)] + public int Port { get; set; } + + public string Username { get; set; } + public string Password { get; set; } + + /// + /// Defaults to 32768 + /// + public int BufferSize { get; set; } + + /// + /// Defaults to true + /// + public bool AutoReconnect { get; set; } + + /// + /// Defaults to 5000ms + /// + public int AutoReconnectIntervalMs { get; set; } + + public TcpSshPropertiesConfig() + { + BufferSize = 32768; + AutoReconnect = true; + AutoReconnectIntervalMs = 5000; + } + + } + + //public class TcpIpConfig + //{ + // [JsonProperty(Required = Required.Always)] + // public string Address { get; set; } + + // [JsonProperty(Required = Required.Always)] + // public int Port { get; set; } + + // /// + // /// Defaults to 32768 + // /// + // public int BufferSize { get; set; } + + // /// + // /// Defaults to true + // /// + // public bool AutoReconnect { get; set; } + + // /// + // /// Defaults to 5000ms + // /// + // public int AutoReconnectIntervalMs { get; set; } + + // public TcpIpConfig() + // { + // BufferSize = 32768; + // AutoReconnect = true; + // AutoReconnectIntervalMs = 5000; + // } + //} + } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/CommunicationExtras.cs b/Pepperdash Core/Pepperdash Core/CommunicationExtras.cs index fc50f0f..910d277 100644 --- a/Pepperdash Core/Pepperdash Core/CommunicationExtras.cs +++ b/Pepperdash Core/Pepperdash Core/CommunicationExtras.cs @@ -1,87 +1,97 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using Crestron.SimplSharp; - -using Newtonsoft.Json; -using Newtonsoft.Json.Linq; - -namespace PepperDash.Core -{ - /// - /// Represents a device that uses basic connection - /// - public interface IBasicCommunication : IKeyed - { - event EventHandler BytesReceived; - event EventHandler TextReceived; - - bool IsConnected { get; } - void SendText(string text); - void SendBytes(byte[] bytes); - void Connect(); - } - - public interface IAutoReconnect - { - bool AutoReconnect { get; set; } - int AutoReconnectIntervalMs { get; set; } - } - - /// - /// - /// - public enum eGenericCommMethodStatusChangeType - { - Connected, Disconnected - } - - /// - /// This delegate defines handler for IBasicCommunication status changes - /// - /// Device firing the status change - /// - public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status); - - /// - /// - /// - public class GenericCommMethodReceiveBytesArgs : EventArgs - { - public byte[] Bytes { get; private set; } - public GenericCommMethodReceiveBytesArgs(byte[] bytes) - { - Bytes = bytes; - } - } - - /// - /// - /// - public class GenericCommMethodReceiveTextArgs : EventArgs - { - public string Text { get; private set; } - public GenericCommMethodReceiveTextArgs(string text) - { - Text = text; - } - } - - /// - /// - /// - public class ComTextHelper - { - public static string GetEscapedText(byte[] bytes) - { - return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); - } - - public static string GetEscapedText(string text) - { - var bytes = Encoding.GetEncoding(28591).GetBytes(text); - return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); - } - } +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Crestron.SimplSharp; + +using Newtonsoft.Json; +using Newtonsoft.Json.Linq; + +namespace PepperDash.Core +{ + /// + /// Represents a device that uses basic connection + /// + public interface IBasicCommunication : IKeyed + { + event EventHandler BytesReceived; + event EventHandler TextReceived; + + bool IsConnected { get; } + void SendText(string text); + void SendBytes(byte[] bytes); + void Connect(); + } + + public interface IAutoReconnect + { + bool AutoReconnect { get; set; } + int AutoReconnectIntervalMs { get; set; } + } + + /// + /// + /// + public enum eGenericCommMethodStatusChangeType + { + Connected, Disconnected + } + + /// + /// This delegate defines handler for IBasicCommunication status changes + /// + /// Device firing the status change + /// + public delegate void GenericCommMethodStatusHandler(IBasicCommunication comm, eGenericCommMethodStatusChangeType status); + + /// + /// + /// + public class GenericCommMethodReceiveBytesArgs : EventArgs + { + public byte[] Bytes { get; private set; } + public GenericCommMethodReceiveBytesArgs(byte[] bytes) + { + Bytes = bytes; + } + + /// + /// Stupid S+ Constructor + /// + public GenericCommMethodReceiveBytesArgs() { } + } + + /// + /// + /// + public class GenericCommMethodReceiveTextArgs : EventArgs + { + public string Text { get; private set; } + public GenericCommMethodReceiveTextArgs(string text) + { + Text = text; + } + + /// + /// Stupid S+ Constructor + /// + public GenericCommMethodReceiveTextArgs() { } + } + + /// + /// + /// + public class ComTextHelper + { + public static string GetEscapedText(byte[] bytes) + { + return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); + } + + public static string GetEscapedText(string text) + { + var bytes = Encoding.GetEncoding(28591).GetBytes(text); + return String.Concat(bytes.Select(b => string.Format(@"[{0:X2}]", (int)b)).ToArray()); + } + } } \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj index b3f1dba..71d09a4 100644 --- a/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj +++ b/Pepperdash Core/Pepperdash Core/PepperDash_Core.csproj @@ -85,7 +85,7 @@ C:\Users\hvolm\Desktop\working\pepperdash-simplsharp-core\Pepperdash Core\Pepperdash Core\bin\PepperDash_Core.clz 1.007.0017 - 9/20/2016 2:09:33 PM + 9/22/2016 9:42:40 PM False diff --git a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.clz b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.clz index 31f23384de82459bbde03d8f5caf651aaae08550..2f42194a7436fd45db56b5c3ca2c64e3b9106a67 100644 GIT binary patch delta 14159 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 delta 14055 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 - 9/20/2016 2:09:33 PM - 1.0.0.23686 + 9/22/2016 9:42:40 PM + 1.0.0.37279 \ No newline at end of file diff --git a/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.dll b/Pepperdash Core/Pepperdash Core/bin/PepperDash_Core.dll index 41a5609a345be56c5ca5fca9b9a4bc469b7d65ff..3216370601a5c0d53222ec5210a334649f112378 100644 GIT binary patch delta 12954 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%0A_X~}l2{(((pMx>Najl% zAL9JQGTrRv=Wyv5iHjvRPj^W!7c@&emdEK+68A?qeN5shi4>JNF)1UF;+#%N920jw z88Y$8Rbq`;FK!i^#7p8$u|(aWzN&trey!$cU9}xro3>Z`llFzyQy-y^(EyF3l<7Ne1V$QBduI3)3* ztn^=07FD(NK)2cjjdMae-lfw-Ki8V>=k&EQeZ53ia+#l1XUpdXdMNnqFTnEU0oK!3 z;zYmAibez&$4i_pal4p}3J(Sr0DGBxfwN7PdDT3F^mLrfxgQIGZj;Z2>X3dp#4>M( zxcSpEoo&Qn+2jp5EYoQ^UxHlQm*uc^7c2PjIz-@wWjCOLuPUD^a*E-8KVFDv$mfCJ zG95VVjKku zbC9zYBk9L+J&gPuj3~B$pr39-SsvYvFW#DBlm#Rh^AIfrr7+$CFF}$h?Ew^cuTh9} zFNu8-V+3)eQK&z6&8B{M;FTnLCGc}aG17xEaRjz5#vzzI3JnDcT>N_=Jsc=#1QaSX zQsQXzSjf51JjO#*kNm^HduSj2G0zcCi4TOX_EjHJpHYu!F|C=8 zJp5^0C?B-kd39uu#Fv=Q9VKr5FX=tq5u?gWOSRHCXGJmWNxB>R)(Op_542y=%esRv zQTxPEy@a#*ilyzJUNKX3(qlI||2}r6Q$0QDr*W(5>l)XuagL3Rw{IC2Qhc*#t*cwN zzRB4*zNI}hAxAN58ynU&)U9gxMtyt1#IFo1GyF?EeIjua|YjVuk-p1qf}w|+5?NOQv#ZgYx)$QvwHCoV<&=+2s^)6 zyt2X|H5@J~Ld*$=yA}CJV^&n;Go#JliZ(wGZGJ4;{Nrfz;jlBaZl@}`6*;Ht6765r z6)3qPj0hG8`+aJpC0}%FA9&+~N;Urbe=biho_@RW{h|e5yb`)**7#YC-aWj^xbevJb8j^2J-=7>r}j;&?pE#l7Thwn_P2jIem?Js!NY%W#iv{PRbAgN#|ZRp zo!t6=a}-6bplZ{N&I3#Y1;(J^lQ-zX^hxrDr@vdV_u#iD_h>vDZHlZqRcZcu IrR%f*0_n8*KmY&$ diff --git a/Pepperdash Core/Pepperdash Core/bin/manifest.info b/Pepperdash Core/Pepperdash Core/bin/manifest.info index 99454ee..523e5f6 100644 --- a/Pepperdash Core/Pepperdash Core/bin/manifest.info +++ b/Pepperdash Core/Pepperdash Core/bin/manifest.info @@ -1,4 +1,4 @@ -MainAssembly=PepperDash_Core.dll:d21b9348a9ff127c20006e8d8b9a166c +MainAssembly=PepperDash_Core.dll:022f5296f4c24102c3cb64cd3a10fa41 MainAssemblyMinFirmwareVersion=1.007.0017 ü DependencySource=Newtonsoft.Json.Compact.dll:ea996aa2ec65aa1878e7c9d09e37a896 diff --git a/Pepperdash Core/Pepperdash Core/bin/manifest.ser b/Pepperdash Core/Pepperdash Core/bin/manifest.ser index 05d9635becc2579caceda182c0e142278d854f7a..245249ef1119eea5bc5f22e6db587f235ce27fad 100644 GIT binary patch delta 472 zcmV;}0Vn>81&IZayMOl{>^*o0kj1iCtQXIUdU2K2xqQF#fd0Sx0AD}7|80UqAMfn# zo!{Sk`04rnbZ>umXK#9MI{9>eI=h$c?wn`)!2NZ#uBXG;zs%bC;Fr&-sn@BFeV7r*cC`!sLfw$h`fahi_QZEMHEGy!q(S_Y9Hmg+zXlU$xb;sm|N+cbaNB zKB*R~Y}zUeN3}eA`0&##+smh)-p{h#g9iusgXzQB&cpoPgY4kpr#{s-!<1(41$mg@ zk2d$!os5@tb$?N3i>Fze{l35NNu4)sT@e9aKmEOa-`{sLqz*N|Kl|4=3-rLuscpTPEbnbod OOa33d+Mav`1^@tAB^0*+ delta 474 zcmV<00VV#41&alcyMKH4K0WvpAd6+OSTCLx_2Me4bNPPf0sVjX0lt2E|JwwKKA!FE zP9EOdKgb@QpYQHHnC|WD?0lLZ%nl|Gv)xZWol@i1)w-SzWB)R1=YwB9ucle4ElwW& zzQ6BR4I%vd{=W0es$BfOzwgt$dD~X2-}m>us_M7J^5XaXeScRBWkyi8n_{sln|W5R zwxX+G@|>S?~pm$Q61E%N50N8d9mVFdWtL?BT;tvurP)etJL4b`KsLJSoh_bbZT9>Az9)6wv~@)UeEszI`h9=j&5%0O{Ql^pS9!xD;Xi-L z$k2B`r0;9Y>1)jC$+~H)#c|u##bn*)&DpZe>+@`C=F3s!;dFnpKii+)-+egw^#1+q z{2?*%r}=D}?ae;@bn?)r_3hzz>3)k|Hqia{{l3o}+*2Ovt>@$Z(0qJ5FKJZ6vykPp z2YdNsC*OT||Ng`5-ueAcAM6}V@&}*p@86$IXYpBxL+#T37O-zc`*?3(kK%DyH_^HG Q!7urL0L1jaY6S)W06