Removed old work, this would be commit with just updates to TCP Client, and EventArgs.cs. After this adding back in classes for secure client and secure and unsecure server classes after this commit. Using the tested separated classes that were created for a project as dynamic modules.

This commit is contained in:
Joshua Gutenplan
2017-03-18 10:14:03 -07:00
parent 45049e415c
commit 6caff913ca
4 changed files with 0 additions and 1244 deletions

Binary file not shown.

View File

@@ -1,371 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core;
namespace PepperDash.Core
{
public class DynamicTcpClient : Device, ISocketStatus, IAutoReconnect
{
#region Events
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
#endregion
#region Properties & Variables
/// <summary>
/// Address of server
/// </summary>
public string Hostname { get; set; }
/// <summary>
/// Port on server
/// </summary>
public int Port { get; set; }
/// <summary>
/// S+ helper
/// </summary>
public ushort UPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
/// <summary>
/// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class
/// </summary>
public bool RequiresPresharedKey { get; set; }
/// <summary>
/// S+ helper for requires shared key bool
/// </summary>
public ushort uRequiresPresharedKey
{
set
{
if (value == 1)
RequiresPresharedKey = true;
else
RequiresPresharedKey = false;
}
}
/// <summary>
/// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module
/// </summary>
public string SharedKey { get; set; }
/// <summary>
/// flag to show the client is waiting for the server to send the shared key
/// </summary>
private bool WaitingForSharedKeyResponse { get; set; }
/// <summary>
/// Defaults to 2000
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsConnected
{
get { return Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
}
/// <summary>
/// S+ helper for IsConnected
/// </summary>
public ushort UIsConnected
{
get { return (ushort)(IsConnected ? 1 : 0); }
}
/// <summary>
/// Client socket status Read only
/// </summary>
public SocketStatus ClientStatus
{
get
{
if (Client == null)
return SocketStatus.SOCKET_STATUS_NO_CONNECT;
return Client.ClientStatus;
}
}
/// <summary>
/// Contains the familiar Simpl analog status values. This drives the ConnectionChange event
/// and IsConnected would be true when this == 2.
/// </summary>
public ushort UStatus
{
get { return (ushort)ClientStatus; }
}
/// <summary>
/// Status text shows the message associated with socket status
/// </summary>
public string ClientStatusText { get { return ClientStatus.ToString(); } }
/// <summary>
/// bool to track if auto reconnect should be set on the socket
/// </summary>
public bool AutoReconnect { get; set; }
/// <summary>
/// S+ helper for AutoReconnect
/// </summary>
public ushort UAutoReconnect
{
get { return (ushort)(AutoReconnect ? 1 : 0); }
set { AutoReconnect = value == 1; }
}
/// <summary>
/// Milliseconds to wait before attempting to reconnect. Defaults to 5000
/// </summary>
public int AutoReconnectIntervalMs { get; set; }
/// <summary>
/// Flag Set only when the disconnect method is called.
/// </summary>
bool DisconnectCalledByUser;
/// <summary>
/// Connected bool
/// </summary>
public bool Connected
{
get { return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
}
CTimer RetryTimer; //private Timer for auto reconnect
public SecureTCPClient Client; //Secure Client Class
#endregion
#region Constructors
//Base class constructor
public DynamicTcpClient(string key, string address, int port, int bufferSize)
: base(key)
{
Hostname = address;
Port = port;
BufferSize = bufferSize;
AutoReconnectIntervalMs = 5000;
}
//base class constructor
public DynamicTcpClient()
: base("Uninitialized SecureTcpClient")
{
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
AutoReconnectIntervalMs = 5000;
BufferSize = 2000;
}
#endregion
#region Methods
/// <summary>
/// Just to help S+ set the key
/// </summary>
public void Initialize(string key)
{
Key = key;
}
/// <summary>
/// Handles closing this up when the program shuts down
/// </summary>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
{
if (Client != null)
{
Debug.Console(1, this, "Program stopping. Closing connection");
Client.DisconnectFromServer();
Client.Dispose();
}
}
}
/// <summary>
/// Deactivate the client. Unregisters the socket status change event and returns true.
/// </summary>
/// <returns></returns>
public override bool Deactivate()
{
if(Client != null)
Client.SocketStatusChange -= this.Client_SocketStatusChange;
return true;
}
/// <summary>
/// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name.
/// </summary>
public void Connect()
{
if (IsConnected)
return;
if (string.IsNullOrEmpty(Hostname))
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No address set", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No address set", Key));
return;
}
if (Port < 1 || Port > 65535)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': Invalid port", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': Invalid port", Key));
return;
}
if (string.IsNullOrEmpty(SharedKey) && RequiresPresharedKey)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No Shared Key set", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No Shared Key set", Key));
return;
}
Client = new SecureTCPClient(Hostname, Port, BufferSize);
Client.SocketStatusChange += Client_SocketStatusChange;
try
{
DisconnectCalledByUser = false;
if(RequiresPresharedKey)
WaitingForSharedKeyResponse = true;
SocketErrorCodes error = Client.ConnectToServer();
}
catch (Exception ex)
{
CrestronConsole.PrintLine("Secure Client could not connect. Error: {0}", ex.Message);
}
}
/// <summary>
/// Disconnect client. Does not dispose.
/// </summary>
public void Disconnect()
{
DisconnectCalledByUser = true;
Client.DisconnectFromServer();
}
/// <summary>
/// callback after connection made
/// </summary>
/// <param name="o"></param>
void ConnectToServerCallback(object o)
{
Client.ConnectToServer();
if (Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED)
WaitAndTryReconnect();
}
/// <summary>
/// Called from Socket Status change if auto reconnect and socket disconnected (Not disconnected by user)
/// </summary>
void WaitAndTryReconnect()
{
Client.DisconnectFromServer();
Debug.Console(2, "Attempting reconnect, status={0}", Client.ClientStatus);
RetryTimer = new CTimer(ConnectToServerCallback, AutoReconnectIntervalMs);
}
/// <summary>
/// Receive callback
/// </summary>
/// <param name="client"></param>
/// <param name="numBytes"></param>
void Receive(SecureTCPClient client, int numBytes)
{
if (numBytes > 0)
{
var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray();
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
if (WaitingForSharedKeyResponse && RequiresPresharedKey)
{
if (str != (SharedKey + "\n"))
{
WaitingForSharedKeyResponse = false;
Client.DisconnectFromServer();
CrestronConsole.PrintLine("Client {0} was disconnected from server because the server did not respond with a matching shared key after connection", Key);
ErrorLog.Error("Client {0} was disconnected from server because the server did not respond with a matching shared key after connection", Key);
return;
}
else
{
WaitingForSharedKeyResponse = false;
CrestronConsole.PrintLine("Client {0} successfully connected to the server and received the Shared Key. Ready for communication", Key);
}
}
else
{
var bytesHandler = BytesReceived;
if (bytesHandler != null)
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
var textHandler = TextReceived;
if (textHandler != null)
{
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
}
}
}
Client.ReceiveDataAsync(Receive);
}
/// <summary>
/// General send method
/// </summary>
public void SendText(string text)
{
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
Client.SendData(bytes, bytes.Length);
}
public void SendBytes(byte[] bytes)
{
Client.SendData(bytes, bytes.Length);
}
/// <summary>
/// SocketStatusChange Callback
/// </summary>
/// <param name="client"></param>
/// <param name="clientSocketStatus"></param>
void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus)
{
Debug.Console(2, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText);
if (client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED && !DisconnectCalledByUser && AutoReconnect)
WaitAndTryReconnect();
// Probably doesn't need to be a switch since all other cases were eliminated
switch (clientSocketStatus)
{
case SocketStatus.SOCKET_STATUS_CONNECTED:
Client.ReceiveDataAsync(Receive);
SendText(SharedKey + "\n");
DisconnectCalledByUser = false;
break;
}
var handler = ConnectionChange;
if (handler != null)
ConnectionChange(this, new GenericSocketStatusChageEventArgs(this));
}
#endregion
}
}

View File

@@ -1,501 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core;
namespace PepperDash.Core
{
public class DynamicTCPServer : Device
{
#region Events
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
public event EventHandler<DynamicTCPServerSocketStatusChangeEventArgs> ClientConnectionChange;
public event EventHandler<DynamicTCPServerStateChangedEventArgs> ServerStateChange;
#endregion
#region Properties/Variables
/// <summary>
/// Secure or unsecure TCP server. Defaults to Unsecure or standard TCP server without SSL
/// </summary>
public bool Secure { get; set; }
/// <summary>
/// S+ Helper for Secure bool. Parameter in SIMPL+ so there is no get, one way set from simpl+ Param to property in func main of SIMPL+
/// </summary>
public ushort uSecure
{
set
{
if (value == 1)
Secure = true;
else if (value == 0)
Secure = false;
}
}
public string status
{
get
{
if (Secure ? SecureServer != null : UnsecureServer != null)
return Secure ? SecureServer.State.ToString() : UnsecureServer.State.ToString();
else
return "";
}
}
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsConnected
{
get { return (Secure ? SecureServer != null : UnsecureServer != null) &&
(Secure ? SecureServer.State == ServerState.SERVER_CONNECTED : UnsecureServer.State == ServerState.SERVER_CONNECTED); }
}
/// <summary>
/// S+ helper for IsConnected
/// </summary>
public ushort uIsConnected
{
get { return (ushort)(IsConnected ? 1 : 0); }
}
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsListening
{
get { return (Secure ? SecureServer != null : UnsecureServer != null) &&
(Secure ? SecureServer.State == ServerState.SERVER_LISTENING : UnsecureServer.State == ServerState.SERVER_LISTENING); }
}
/// <summary>
/// S+ helper for IsConnected
/// </summary>
public ushort uIsListening
{
get { return (ushort)(IsListening ? 1 : 0); }
}
public ushort MaxClients { get; set; } // should be set by parameter in SIMPL+ in the MAIN method, Should not ever need to be configurable
/// <summary>
/// Number of clients currently connected.
/// </summary>
public ushort NumberOfClientsConnected
{
get
{
if (Secure ? SecureServer != null : UnsecureServer != null)
return Secure ? (ushort)SecureServer.NumberOfClientsConnected : (ushort)UnsecureServer.NumberOfClientsConnected;
return 0;
}
}
/// <summary>
/// Port on server
/// </summary>
public int Port { get; set; }
/// <summary>
/// S+ helper
/// </summary>
public ushort uPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
/// <summary>
/// Bool to show whether the server requires a preshared key. Must be set the same in the client, and if true shared keys must be identical on server/client
/// </summary>
public bool RequiresPresharedKey { get; set; }
/// <summary>
/// S+ helper for requires shared key bool
/// </summary>
public ushort uRequiresPresharedKey
{
set
{
if (value == 1)
RequiresPresharedKey = true;
else
RequiresPresharedKey = false;
}
}
/// <summary>
/// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module.
/// If SharedKey changes while server is listening or clients are connected, disconnect and stop listening will be called
/// </summary>
public string SharedKey { get; set; }
/// <summary>
/// flags to show the secure server is waiting for client at index to send the shared key
/// </summary>
public List<uint> WaitingForSharedKey = new List<uint>();
/// <summary>
/// Store the connected client indexes
/// </summary>
public List<uint> ConnectedClientsIndexes = new List<uint>();
/// <summary>
/// Defaults to 2000
/// </summary>
public int BufferSize { get; set; }
public string OnlyAcceptConnectionFromAddress { get; set; }
private bool ServerStopped { get; set; }
SecureTCPServer SecureServer;
TCPServer UnsecureServer;
#endregion
#region Constructors
//base class constructor
public DynamicTCPServer()
: base("Uninitialized Dynamic TCP Server")
{
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
BufferSize = 2000;
Secure = false;
}
#endregion
#region Methods - Server Actions
public void Initialize(string key)
{
Key = key;
}
public void Listen()
{
try
{
if (Port < 1 || Port > 65535)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': Invalid port", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': Invalid port", Key));
return;
}
if (string.IsNullOrEmpty(SharedKey) && RequiresPresharedKey)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No Shared Key set", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No Shared Key set", Key));
return;
}
if (IsListening)
return;
if (Secure)
{
SecureServer = new SecureTCPServer(Port, MaxClients);
SecureServer.SocketStatusChange += new SecureTCPServerSocketStatusChangeEventHandler(SecureServer_SocketStatusChange);
ServerStopped = false;
if (!string.IsNullOrEmpty(OnlyAcceptConnectionFromAddress))
SecureServer.WaitForConnectionAsync(OnlyAcceptConnectionFromAddress, SecureConnectCallback);
else
SecureServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback);
onServerStateChange();
Debug.Console(2, "Secure Server Status: {0}, Socket Status: {1}\r\n", SecureServer.State.ToString(), SecureServer.ServerSocketStatus);
}
else
{
UnsecureServer = new TCPServer(Port, MaxClients);
UnsecureServer.SocketStatusChange += new TCPServerSocketStatusChangeEventHandler(UnsecureServer_SocketStatusChange);
ServerStopped = false;
if (!string.IsNullOrEmpty(OnlyAcceptConnectionFromAddress))
UnsecureServer.WaitForConnectionAsync(OnlyAcceptConnectionFromAddress, UnsecureConnectCallback);
else
UnsecureServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
onServerStateChange();
Debug.Console(2, "Unsecure Server Status: {0}, Socket Status: {1}\r\n", UnsecureServer.State.ToString(), UnsecureServer.ServerSocketStatus);
}
}
catch (Exception ex)
{
ErrorLog.Error("Error with Dynamic Server: {0}", ex.ToString());
}
}
public void StopListening()
{
Debug.Console(2, "Stopping Listener");
if (SecureServer != null)
SecureServer.Stop();
if (UnsecureServer != null)
UnsecureServer.Stop();
ServerStopped = true;
onServerStateChange();
}
public void DisconnectAllClients()
{
Debug.Console(2, "Disconnecting All Clients");
if (SecureServer != null)
SecureServer.DisconnectAll();
if (UnsecureServer != null)
UnsecureServer.DisconnectAll();
onConnectionChange();
onServerStateChange(); //State shows both listening and connected
}
public void BroadcastText(string text)
{
if (ConnectedClientsIndexes.Count > 0)
{
if (Secure)
{
foreach (uint i in ConnectedClientsIndexes)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
SecureServer.SendDataAsync(i, b, b.Length, SecureSendDataAsyncCallback);
}
}
else
{
foreach (uint i in ConnectedClientsIndexes)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
UnsecureServer.SendDataAsync(i, b, b.Length, UnsecureSendDataAsyncCallback);
}
}
}
}
/// <summary>
/// Not sure this is useful in library, maybe Pro??
/// </summary>
/// <param name="text"></param>
/// <param name="clientIndex"></param>
public void SendTextToClient(string text, uint clientIndex)
{
if (Secure)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
SecureServer.SendDataAsync(clientIndex, b, b.Length, SecureSendDataAsyncCallback);
}
else
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(text);
UnsecureServer.SendDataAsync(clientIndex, b, b.Length, UnsecureSendDataAsyncCallback);
}
}
#endregion
#region Methods - Socket Status Changed Callbacks
void SecureServer_SocketStatusChange(SecureTCPServer mySecureTCPServer, uint clientIndex, SocketStatus serverSocketStatus)
{
Debug.Console(2, "Client at {0} ServerSocketStatus {1}",
mySecureTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), serverSocketStatus.ToString());
if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
{
if (RequiresPresharedKey && !WaitingForSharedKey.Contains(clientIndex))
WaitingForSharedKey.Add(clientIndex);
if (!ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Add(clientIndex);
}
if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) != SocketStatus.SOCKET_STATUS_CONNECTED && ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Remove(clientIndex);
onConnectionChange();//Go to simpl and send the server and whether it is secure or not. Could check secure from Simpl+ but better to use the passed
//variable in case we need to use this in Pro. Simpl+ won't use arguments, will just check the uIsConnected Property. Currently Simpl+ is just going to report
//connected not reporting by client
}
void UnsecureServer_SocketStatusChange(TCPServer mySecureTCPServer, uint clientIndex, SocketStatus serverSocketStatus)
{
Debug.Console(2, "Client at {0} ServerSocketStatus {1}",
mySecureTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex), serverSocketStatus.ToString());
if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
{
if (RequiresPresharedKey && !WaitingForSharedKey.Contains(clientIndex))
WaitingForSharedKey.Add(clientIndex);
if (!ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Add(clientIndex);
}
if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) != SocketStatus.SOCKET_STATUS_CONNECTED && ConnectedClientsIndexes.Contains(clientIndex))
ConnectedClientsIndexes.Remove(clientIndex);
onConnectionChange();
}
#endregion
#region Methods Connected Callbacks
void SecureConnectCallback(SecureTCPServer mySecureTCPServer, uint clientIndex)
{
if (mySecureTCPServer.ClientConnected(clientIndex))
{
if (RequiresPresharedKey)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(SharedKey + "\n");
mySecureTCPServer.SendDataAsync(clientIndex, b, b.Length, SecureSendDataAsyncCallback);
Debug.Console(2, "Sent Shared Key to client at {0}", mySecureTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex));
}
mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedCallback);
if (mySecureTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
mySecureTCPServer.WaitForConnectionAsync(IPAddress.Any, SecureConnectCallback);
}
}
void UnsecureConnectCallback(TCPServer myTCPServer, uint clientIndex)
{
if (myTCPServer.ClientConnected(clientIndex))
{
if (RequiresPresharedKey)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes(SharedKey + "\n");
myTCPServer.SendDataAsync(clientIndex, b, b.Length, UnsecureSendDataAsyncCallback);
Debug.Console(2, "Sent Shared Key to client at {0}", myTCPServer.GetAddressServerAcceptedConnectionFromForSpecificClient(clientIndex));
}
myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedCallback);
if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
}
if (myTCPServer.State != ServerState.SERVER_LISTENING && MaxClients > 1 && !ServerStopped)
myTCPServer.WaitForConnectionAsync(IPAddress.Any, UnsecureConnectCallback);
}
#endregion
#region Methods - Send/Receive Callbacks
void SecureSendDataAsyncCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesSent)
{
//Seems there is nothing to do here
}
void UnsecureSendDataAsyncCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesSent)
{
//Seems there is nothing to do here
}
void SecureReceivedCallback(SecureTCPServer mySecureTCPServer, uint clientIndex, int numberOfBytesReceived)
{
if (numberOfBytesReceived > 0)
{
string received = "Nothing";
byte[] bytes = mySecureTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex);
received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived);
if (WaitingForSharedKey.Contains(clientIndex))
{
received = received.Replace("\r", "");
received = received.Replace("\n", "");
if (received != SharedKey)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting");
Debug.Console(2, "Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
ErrorLog.Error("Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
mySecureTCPServer.SendDataAsync(clientIndex, b, b.Length, null);
mySecureTCPServer.Disconnect(clientIndex);
}
if (mySecureTCPServer.NumberOfClientsConnected > 0)
mySecureTCPServer.ReceiveDataAsync(SecureReceivedCallback);
WaitingForSharedKey.Remove(clientIndex);
byte[] skResponse = Encoding.GetEncoding(28591).GetBytes("Shared Key Match, Connected and ready for communication");
mySecureTCPServer.SendDataAsync(clientIndex, skResponse, skResponse.Length, null);
mySecureTCPServer.ReceiveDataAsync(SecureReceivedCallback);
}
else
{
mySecureTCPServer.ReceiveDataAsync(SecureReceivedCallback);
Debug.Console(2, "Secure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n",
mySecureTCPServer.PortNumber, mySecureTCPServer.AddressServerAcceptedConnectionFrom, numberOfBytesReceived, received);
onTextReceived(received);
}
}
if (mySecureTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
mySecureTCPServer.ReceiveDataAsync(clientIndex, SecureReceivedCallback);
}
void UnsecureReceivedCallback(TCPServer myTCPServer, uint clientIndex, int numberOfBytesReceived)
{
if (numberOfBytesReceived > 0)
{
string received = "Nothing";
byte[] bytes = myTCPServer.GetIncomingDataBufferForSpecificClient(clientIndex);
received = System.Text.Encoding.GetEncoding(28591).GetString(bytes, 0, numberOfBytesReceived);
if (WaitingForSharedKey.Contains(clientIndex))
{
received = received.Replace("\r", "");
received = received.Replace("\n", "");
if (received != SharedKey)
{
byte[] b = Encoding.GetEncoding(28591).GetBytes("Shared key did not match server. Disconnecting");
Debug.Console(2, "Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
ErrorLog.Error("Client at index {0} Shared key did not match the server, disconnecting client", clientIndex);
myTCPServer.SendDataAsync(clientIndex, b, b.Length, null);
myTCPServer.Disconnect(clientIndex);
}
if (myTCPServer.NumberOfClientsConnected > 0)
myTCPServer.ReceiveDataAsync(UnsecureReceivedCallback);
WaitingForSharedKey.Remove(clientIndex);
byte[] skResponse = Encoding.GetEncoding(28591).GetBytes("Shared Key Match, Connected and ready for communication");
myTCPServer.SendDataAsync(clientIndex, skResponse, skResponse.Length, null);
myTCPServer.ReceiveDataAsync(UnsecureReceivedCallback);
}
else
{
myTCPServer.ReceiveDataAsync(UnsecureReceivedCallback);
Debug.Console(2, "Secure Server Listening on Port: {0}, client IP: {1}, NumberOfBytesReceived: {2}, Received: {3}\r\n",
myTCPServer.PortNumber, myTCPServer.AddressServerAcceptedConnectionFrom, numberOfBytesReceived, received);
onTextReceived(received);
}
}
if (myTCPServer.GetServerSocketStatusForSpecificClient(clientIndex) == SocketStatus.SOCKET_STATUS_CONNECTED)
myTCPServer.ReceiveDataAsync(clientIndex, UnsecureReceivedCallback);
}
#endregion
#region Methods - EventHelpers/Callbacks
void onConnectionChange()
{
var handler = ClientConnectionChange;
if (handler != null)
{
if (Secure)
handler(this, new DynamicTCPServerSocketStatusChangeEventArgs(SecureServer, Secure));
else
handler(this, new DynamicTCPServerSocketStatusChangeEventArgs(UnsecureServer, Secure));
}
}
void onTextReceived(string text)
{
var handler = TextReceived;
if (handler != null)
handler(this, new GenericCommMethodReceiveTextArgs(text));
}
void onServerStateChange()
{
var handler = ServerStateChange;
if(handler != null)
{
if(Secure)
handler(this, new DynamicTCPServerStateChangedEventArgs(SecureServer, Secure));
else
handler(this, new DynamicTCPServerStateChangedEventArgs(UnsecureServer, Secure));
}
}
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
{
Debug.Console(1, this, "Program stopping. Closing server");
DisconnectAllClients();
StopListening();
}
}
#endregion
}
}

View File

@@ -1,372 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using Crestron.SimplSharp;
using Crestron.SimplSharp.CrestronSockets;
using PepperDash.Core;
namespace PepperDash.Core
{
public class GenericSecureTcpClient : Device, ISocketStatus, IAutoReconnect
{
#region Events
public event EventHandler<GenericCommMethodReceiveBytesArgs> BytesReceived;
public event EventHandler<GenericCommMethodReceiveTextArgs> TextReceived;
public event EventHandler<GenericSocketStatusChageEventArgs> ConnectionChange;
#endregion
#region Properties & Variables
/// <summary>
/// Address of server
/// </summary>
public string Hostname { get; set; }
/// <summary>
/// Port on server
/// </summary>
public int Port { get; set; }
/// <summary>
/// S+ helper
/// </summary>
public ushort UPort
{
get { return Convert.ToUInt16(Port); }
set { Port = Convert.ToInt32(value); }
}
/// <summary>
/// Bool to show whether the server requires a preshared key. This is used in the DynamicTCPServer class
/// </summary>
public bool RequiresPresharedKey { get; set; }
/// <summary>
/// S+ helper for requires shared key bool
/// </summary>
public ushort URequiresPresharedKey
{
set
{
if (value == 1)
RequiresPresharedKey = true;
else
RequiresPresharedKey = false;
}
}
/// <summary>
/// SharedKey is sent for varification to the server. Shared key can be any text (255 char limit in SIMPL+ Module), but must match the Shared Key on the Server module
/// </summary>
public string SharedKey { get; set; }
/// <summary>
/// flag to show the client is waiting for the server to send the shared key
/// </summary>
private bool WaitingForSharedKeyResponse { get; set; }
/// <summary>
/// Defaults to 2000
/// </summary>
public int BufferSize { get; set; }
/// <summary>
/// Bool showing if socket is connected
/// </summary>
public bool IsConnected
{
get { return Client != null && Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
}
/// <summary>
/// S+ helper for IsConnected
/// </summary>
public ushort UIsConnected
{
get { return (ushort)(IsConnected ? 1 : 0); }
}
/// <summary>
/// Client socket status Read only
/// </summary>
public SocketStatus ClientStatus
{
get
{
if (Client == null)
return SocketStatus.SOCKET_STATUS_NO_CONNECT;
return Client.ClientStatus;
}
}
/// <summary>
/// Contains the familiar Simpl analog status values. This drives the ConnectionChange event
/// and IsConnected would be true when this == 2.
/// </summary>
public ushort UStatus
{
get { return (ushort)ClientStatus; }
}
/// <summary>
/// Status text shows the message associated with socket status
/// </summary>
public string ClientStatusText { get { return ClientStatus.ToString(); } }
/// <summary>
/// bool to track if auto reconnect should be set on the socket
/// </summary>
public bool AutoReconnect { get; set; }
/// <summary>
/// S+ helper for AutoReconnect
/// </summary>
public ushort UAutoReconnect
{
get { return (ushort)(AutoReconnect ? 1 : 0); }
set { AutoReconnect = value == 1; }
}
/// <summary>
/// Milliseconds to wait before attempting to reconnect. Defaults to 5000
/// </summary>
public int AutoReconnectIntervalMs { get; set; }
/// <summary>
/// Flag Set only when the disconnect method is called.
/// </summary>
bool DisconnectCalledByUser;
/// <summary>
/// Connected bool
/// </summary>
public bool Connected
{
get { return Client.ClientStatus == SocketStatus.SOCKET_STATUS_CONNECTED; }
}
CTimer RetryTimer; //private Timer for auto reconnect
public SecureTCPClient Client; //Secure Client Class
#endregion
#region Constructors
//Base class constructor
public GenericSecureTcpClient(string key, string address, int port, int bufferSize)
: base(key)
{
Hostname = address;
Port = port;
BufferSize = bufferSize;
AutoReconnectIntervalMs = 5000;
}
//base class constructor
public GenericSecureTcpClient()
: base("Uninitialized SecureTcpClient")
{
CrestronEnvironment.ProgramStatusEventHandler += new ProgramStatusEventHandler(CrestronEnvironment_ProgramStatusEventHandler);
AutoReconnectIntervalMs = 5000;
BufferSize = 2000;
}
#endregion
#region Methods
/// <summary>
/// Just to help S+ set the key
/// </summary>
public void Initialize(string key)
{
Key = key;
}
/// <summary>
/// Handles closing this up when the program shuts down
/// </summary>
void CrestronEnvironment_ProgramStatusEventHandler(eProgramStatusEventType programEventType)
{
if (programEventType == eProgramStatusEventType.Stopping)
{
if (Client != null)
{
Debug.Console(1, this, "Program stopping. Closing connection");
Client.DisconnectFromServer();
Client.Dispose();
}
}
}
/// <summary>
/// Deactivate the client. Unregisters the socket status change event and returns true.
/// </summary>
/// <returns></returns>
public override bool Deactivate()
{
if(Client != null)
Client.SocketStatusChange -= this.Client_SocketStatusChange;
return true;
}
/// <summary>
/// Connect Method. Will return if already connected. Will write errors if missing address, port, or unique key/name.
/// </summary>
public void Connect()
{
if (IsConnected)
return;
if (string.IsNullOrEmpty(Hostname))
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No address set", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No address set", Key));
return;
}
if (Port < 1 || Port > 65535)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': Invalid port", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': Invalid port", Key));
return;
}
if (string.IsNullOrEmpty(SharedKey) && RequiresPresharedKey)
{
Debug.Console(1, Debug.ErrorLogLevel.Warning, "GenericSecureTcpClient '{0}': No Shared Key set", Key);
ErrorLog.Warn(string.Format("GenericSecureTcpClient '{0}': No Shared Key set", Key));
return;
}
Client = new SecureTCPClient(Hostname, Port, BufferSize);
Client.SocketStatusChange += Client_SocketStatusChange;
try
{
DisconnectCalledByUser = false;
if(RequiresPresharedKey)
WaitingForSharedKeyResponse = true;
SocketErrorCodes error = Client.ConnectToServer();
}
catch (Exception ex)
{
CrestronConsole.PrintLine("Secure Client could not connect. Error: {0}", ex.Message);
}
}
/// <summary>
/// Disconnect client. Does not dispose.
/// </summary>
public void Disconnect()
{
DisconnectCalledByUser = true;
Client.DisconnectFromServer();
}
/// <summary>
/// callback after connection made
/// </summary>
/// <param name="o"></param>
void ConnectToServerCallback(object o)
{
Client.ConnectToServer();
if (Client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED)
WaitAndTryReconnect();
}
/// <summary>
/// Called from Socket Status change if auto reconnect and socket disconnected (Not disconnected by user)
/// </summary>
void WaitAndTryReconnect()
{
Client.DisconnectFromServer();
Debug.Console(2, "Attempting reconnect, status={0}", Client.ClientStatus);
if(!DisconnectCalledByUser)
RetryTimer = new CTimer(ConnectToServerCallback, AutoReconnectIntervalMs);
}
/// <summary>
/// Receive callback
/// </summary>
/// <param name="client"></param>
/// <param name="numBytes"></param>
void Receive(SecureTCPClient client, int numBytes)
{
if (numBytes > 0)
{
var bytes = client.IncomingDataBuffer.Take(numBytes).ToArray();
var str = Encoding.GetEncoding(28591).GetString(bytes, 0, bytes.Length);
if (WaitingForSharedKeyResponse && RequiresPresharedKey)
{
if (str != (SharedKey + "\n"))
{
WaitingForSharedKeyResponse = false;
Client.DisconnectFromServer();
CrestronConsole.PrintLine("Client {0} was disconnected from server because the server did not respond with a matching shared key after connection", Key);
ErrorLog.Error("Client {0} was disconnected from server because the server did not respond with a matching shared key after connection", Key);
return;
}
else
{
WaitingForSharedKeyResponse = false;
CrestronConsole.PrintLine("Client {0} successfully connected to the server and received the Shared Key. Ready for communication", Key);
}
}
else
{
var bytesHandler = BytesReceived;
if (bytesHandler != null)
bytesHandler(this, new GenericCommMethodReceiveBytesArgs(bytes));
var textHandler = TextReceived;
if (textHandler != null)
{
textHandler(this, new GenericCommMethodReceiveTextArgs(str));
}
}
}
Client.ReceiveDataAsync(Receive);
}
/// <summary>
/// General send method
/// </summary>
public void SendText(string text)
{
var bytes = Encoding.GetEncoding(28591).GetBytes(text);
Client.SendData(bytes, bytes.Length);
}
public void SendBytes(byte[] bytes)
{
Client.SendData(bytes, bytes.Length);
}
/// <summary>
/// SocketStatusChange Callback
/// </summary>
/// <param name="client"></param>
/// <param name="clientSocketStatus"></param>
void Client_SocketStatusChange(SecureTCPClient client, SocketStatus clientSocketStatus)
{
Debug.Console(2, this, "Socket status change {0} ({1})", clientSocketStatus, ClientStatusText);
if (client.ClientStatus != SocketStatus.SOCKET_STATUS_CONNECTED && !DisconnectCalledByUser && AutoReconnect)
WaitAndTryReconnect();
// Probably doesn't need to be a switch since all other cases were eliminated
switch (clientSocketStatus)
{
case SocketStatus.SOCKET_STATUS_CONNECTED:
Client.ReceiveDataAsync(Receive);
SendText(SharedKey + "\n");
DisconnectCalledByUser = false;
break;
}
var handler = ConnectionChange;
if (handler != null)
ConnectionChange(this, new GenericSocketStatusChageEventArgs(this));
}
#endregion
}
}