//******************************************************************************************************// ClientConnection.cs - Gbtc//// Copyright © 2010, Grid Protection Alliance. All Rights Reserved.//// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See// the NOTICE file distributed with this work for additional information regarding copyright ownership.// The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may// not use this file except in compliance with the License. You may obtain a copy of the License at://// http://www.opensource.org/licenses/eclipse-1.0.php//// Unless agreed to in writing, the subject software distributed under the License is distributed on an// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the// License for the specific language governing permissions and limitations.//// Code Modification History:// ----------------------------------------------------------------------------------------------------// 06/24/2011 - Ritchie// Generated original version of source code.////****************************************************************************************************** using GSF.Communication;//using GSF.Security.Cryptography;using System;using System.Collections.Generic;using System.IO;using System.Net;using System.Net.Sockets;using System.Security.Cryptography;using System.Text; namespace GSF.TimeSeries.Transport{ /// <summary> /// Represents a <see cref="DataSubscriber"/> client connection to the <see cref="DataPublisher"/>. /// </summary> public class ClientConnection : IProvideStatus, IDisposable { #region [ Members ] // Constants private const int EvenKey = 0; // Even key/IV index private const int OddKey = 1; // Odd key/IV index private const int KeyIndex = 0; // Index of cipher key component in keyIV array private const int IVIndex = 1; // Index of initialization vector component in keyIV array // Fields private DataPublisher m_parent; private Guid m_clientID; private Guid m_subscriberID; private string m_connectionID; private string m_hostName; private string m_subscriberAcronym; private string m_subscriberName; private string m_sharedSecret; private string m_subscriberInfo; private IClientSubscription m_subscription; private volatile bool m_authenticated; private volatile byte[][][] m_keyIVs; private volatile int m_cipherIndex; private IPAddress m_ipAddress; private TcpServer m_commandChannel; private UdpServer m_dataChannel; private string m_configurationString; private bool m_connectionEstablished; private bool m_isSubscribed; private Ticks m_lastCipherKeyUpdateTime; private System.Timers.Timer m_pingTimer; private System.Timers.Timer m_reconnectTimer; private OperationalModes m_operationalModes; private Encoding m_encoding; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="ClientConnection"/> instance. /// </summary> /// <param name="parent">Parent data publisher.</param> /// <param name="clientID">Client ID of associated connection.</param> /// <param name="commandChannel"><see cref="TcpServer"/> command channel used to lookup connection information.</param> public ClientConnection(DataPublisher parent, Guid clientID, TcpServer commandChannel) { m_parent = parent; m_clientID = clientID; m_commandChannel = commandChannel; m_subscriberID = clientID; m_keyIVs = null; m_cipherIndex = 0; // Setup ping timer m_pingTimer = new System.Timers.Timer(); m_pingTimer.Interval = 5000.0D; m_pingTimer.AutoReset = true; m_pingTimer.Elapsed += m_pingTimer_Elapsed; m_pingTimer.Start(); // Setup reconnect timer m_reconnectTimer = new System.Timers.Timer(); m_reconnectTimer.Interval = 1000.0D; m_reconnectTimer.AutoReset = false; m_reconnectTimer.Elapsed += m_reconnectTimer_Elapsed; // Attempt to lookup remote connection identification for logging purposes try { TransportProvider<Socket> client; IPEndPoint remoteEndPoint = null; if ((object)commandChannel != null && commandChannel.TryGetClient(clientID, out client)) remoteEndPoint = client.Provider.RemoteEndPoint as IPEndPoint; if ((object)remoteEndPoint != null) { m_ipAddress = remoteEndPoint.Address; if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) m_connectionID = "[" + m_ipAddress + "]:" + remoteEndPoint.Port; else m_connectionID = m_ipAddress + ":" + remoteEndPoint.Port; try { IPHostEntry ipHost = Dns.GetHostEntry(remoteEndPoint.Address); if (!ipHost.HostName.IsNullOrWhiteSpace()) { m_hostName = ipHost.HostName; m_connectionID = m_hostName + " (" + m_connectionID + ")"; } } catch { // Just ignoring possible DNS lookup failures... } } } catch { // At worst we'll just use the client GUID for identification m_connectionID = (m_subscriberID == Guid.Empty ? clientID.ToString() : m_subscriberID.ToString()); } if (m_connectionID.IsNullOrWhiteSpace()) m_connectionID = "unavailable"; if (m_hostName.IsNullOrWhiteSpace()) { if (m_ipAddress != null) m_hostName = m_ipAddress.ToString(); else m_hostName = m_connectionID; } if (m_ipAddress == null) m_ipAddress = System.Net.IPAddress.None; } /// <summary> /// Releases the unmanaged resources before the <see cref="ClientConnection"/> object is reclaimed by <see cref="GC"/>. /// </summary> ~ClientConnection() { Dispose(false); } #endregion #region [ Properties ] /// <summary> /// Gets client ID of this <see cref="ClientConnection"/>. /// </summary> public Guid ClientID { get { return m_clientID; } } /// <summary> /// Gets or sets reference to <see cref="UdpServer"/> data channel, attaching to or detaching from events as needed, associated with this <see cref="ClientConnection"/>. /// </summary> public UdpServer DataChannel { get { return m_dataChannel; } set { m_connectionEstablished = (value != null); if (m_dataChannel != null) { // Detach from events on existing data channel reference m_dataChannel.SendClientDataException -= m_dataChannel_SendClientDataException; m_dataChannel.ServerStarted -= m_dataChannel_ServerStarted; m_dataChannel.ServerStopped -= m_dataChannel_ServerStopped; if (m_dataChannel != value) m_dataChannel.Dispose(); } // Assign new data channel reference m_dataChannel = value; if (m_dataChannel != null) { // Save UDP settings so channel can be reestablished if needed m_configurationString = m_dataChannel.ConfigurationString; // Attach to events on new data channel reference m_dataChannel.SendClientDataException += m_dataChannel_SendClientDataException; m_dataChannel.ServerStarted += m_dataChannel_ServerStarted; m_dataChannel.ServerStopped += m_dataChannel_ServerStopped; } } } /// <summary> /// Gets <see cref="IServer"/> publication channel - that is, data channel if defined otherwise command channel. /// </summary> public IServer PublishChannel { get { return ((object)m_dataChannel == null ? (IServer)m_commandChannel : (IServer)m_dataChannel); } } /// <summary> /// Gets connected state of the associated client socket. /// </summary> public bool IsConnected { get { TransportProvider<Socket> client; bool isConnected = false; try { if ((object)m_commandChannel != null && m_commandChannel.TryGetClient(m_clientID, out client)) isConnected = client.Provider.Connected; } catch { isConnected = false; } return isConnected; } } /// <summary> /// Gets or sets IsSubscribed state. /// </summary> public bool IsSubscribed { get { return m_isSubscribed; } set { m_isSubscribed = value; } } /// <summary> /// Gets or sets the <see cref="Guid"/> based subscriber ID of this <see cref="ClientConnection"/>. /// </summary> public Guid SubscriberID { get { return m_subscriberID; } set { m_subscriberID = value; } } /// <summary> /// Gets or sets the subscriber acronym of this <see cref="ClientConnection"/>. /// </summary> public string SubscriberAcronym { get { return m_subscriberAcronym; } set { m_subscriberAcronym = value; } } /// <summary> /// Gets or sets the subscriber name of this <see cref="ClientConnection"/>. /// </summary> public string SubscriberName { get { return m_subscriberName; } set { m_subscriberName = value; } } /// <summary> /// Gets or sets subscriber info for this <see cref="ClientConnection"/>. /// </summary> public string SubscriberInfo { get { if (m_subscriberInfo.IsNullOrWhiteSpace()) return m_subscriberName; return m_subscriberInfo; } set { if (value.IsNullOrWhiteSpace()) { m_subscriberInfo = null; } else { Dictionary<string, string> settings = value.ParseKeyValuePairs(); string source, version, buildDate; settings.TryGetValue("source", out source); settings.TryGetValue("version", out version); settings.TryGetValue("buildDate", out buildDate); m_subscriberInfo = string.Format("{0} version {1} built on {2}", source.ToNonNullNorWhiteSpace("unknown source"), version.ToNonNullNorWhiteSpace("?.?.?.?"), buildDate.ToNonNullNorWhiteSpace("undefined date")); } } } /// <summary> /// Gets the connection identification of this <see cref="ClientConnection"/>. /// </summary> public string ConnectionID { get { return m_connectionID; } } /// <summary> /// Gets or sets authenticated state of this <see cref="ClientConnection"/>. /// </summary> public bool Authenticated { get { return m_authenticated; } set { m_authenticated = value; } } /// <summary> /// Gets or sets shared secret used to lookup cipher keys only known to client and server. /// </summary> public string SharedSecret { get { return m_sharedSecret; } set { m_sharedSecret = value; } } /// <summary> /// Gets active and standby keys and initialization vectors. /// </summary> public byte[][][] KeyIVs { get { return m_keyIVs; } } /// <summary> /// Gets current cipher index. /// </summary> public int CipherIndex { get { return m_cipherIndex; } } /// <summary> /// Gets time of last cipher key update. /// </summary> public Ticks LastCipherKeyUpdateTime { get { return m_lastCipherKeyUpdateTime; } } /// <summary> /// Gets the IP address of the remote client connection. /// </summary> public IPAddress IPAddress { get { return m_ipAddress; } } /// <summary> /// Gets or sets subscription associated with this <see cref="ClientConnection"/>. /// </summary> public IClientSubscription Subscription { get { return m_subscription; } set { m_subscription = value; if (m_subscription != null) m_subscription.HostName = m_hostName; } } /// <summary> /// Gets the subscriber name of this <see cref="ClientConnection"/>. /// </summary> public string Name { get { return SubscriberName; } } /// <summary> /// Gets or sets a set of flags that define ways in /// which the subscriber and publisher communicate. /// </summary> public OperationalModes OperationalModes { get { return m_operationalModes; } set { m_operationalModes = value; switch ((OperationalEncoding)(value & Transport.OperationalModes.EncodingMask)) { case OperationalEncoding.Unicode: m_encoding = Encoding.Unicode; break; case OperationalEncoding.BigEndianUnicode: m_encoding = Encoding.BigEndianUnicode; break; case OperationalEncoding.UTF8: m_encoding = Encoding.UTF8; break; case OperationalEncoding.ANSI: m_encoding = Encoding.Default; break; default: throw new InvalidOperationException(string.Format("Unsupported encoding detected: {0}", value)); } } } Lines 1–500 of 768. Load more
//****************************************************************************************************** // ClientConnection.cs - Gbtc // // Copyright © 2010, Grid Protection Alliance. All Rights Reserved. // // Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See // the NOTICE file distributed with this work for additional information regarding copyright ownership. // The GPA licenses this file to you under the Eclipse Public License -v 1.0 (the "License"); you may // not use this file except in compliance with the License. You may obtain a copy of the License at: // // http://www.opensource.org/licenses/eclipse-1.0.php // // Unless agreed to in writing, the subject software distributed under the License is distributed on an // "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the // License for the specific language governing permissions and limitations. // // Code Modification History: // ---------------------------------------------------------------------------------------------------- // 06/24/2011 - Ritchie // Generated original version of source code. // //****************************************************************************************************** using GSF.Communication; //using GSF.Security.Cryptography; using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Security.Cryptography; using System.Text; namespace GSF.TimeSeries.Transport { /// <summary> /// Represents a <see cref="DataSubscriber"/> client connection to the <see cref="DataPublisher"/>. /// </summary> public class ClientConnection : IProvideStatus, IDisposable { #region [ Members ] // Constants private const int EvenKey = 0; // Even key/IV index private const int OddKey = 1; // Odd key/IV index private const int KeyIndex = 0; // Index of cipher key component in keyIV array private const int IVIndex = 1; // Index of initialization vector component in keyIV array // Fields private DataPublisher m_parent; private Guid m_clientID; private Guid m_subscriberID; private string m_connectionID; private string m_hostName; private string m_subscriberAcronym; private string m_subscriberName; private string m_sharedSecret; private string m_subscriberInfo; private IClientSubscription m_subscription; private volatile bool m_authenticated; private volatile byte[][][] m_keyIVs; private volatile int m_cipherIndex; private IPAddress m_ipAddress; private TcpServer m_commandChannel; private UdpServer m_dataChannel; private string m_configurationString; private bool m_connectionEstablished; private bool m_isSubscribed; private Ticks m_lastCipherKeyUpdateTime; private System.Timers.Timer m_pingTimer; private System.Timers.Timer m_reconnectTimer; private OperationalModes m_operationalModes; private Encoding m_encoding; private bool m_disposed; #endregion #region [ Constructors ] /// <summary> /// Creates a new <see cref="ClientConnection"/> instance. /// </summary> /// <param name="parent">Parent data publisher.</param> /// <param name="clientID">Client ID of associated connection.</param> /// <param name="commandChannel"><see cref="TcpServer"/> command channel used to lookup connection information.</param> public ClientConnection(DataPublisher parent, Guid clientID, TcpServer commandChannel) { m_parent = parent; m_clientID = clientID; m_commandChannel = commandChannel; m_subscriberID = clientID; m_keyIVs = null; m_cipherIndex = 0; // Setup ping timer m_pingTimer = new System.Timers.Timer(); m_pingTimer.Interval = 5000.0D; m_pingTimer.AutoReset = true; m_pingTimer.Elapsed += m_pingTimer_Elapsed; m_pingTimer.Start(); // Setup reconnect timer m_reconnectTimer = new System.Timers.Timer(); m_reconnectTimer.Interval = 1000.0D; m_reconnectTimer.AutoReset = false; m_reconnectTimer.Elapsed += m_reconnectTimer_Elapsed; // Attempt to lookup remote connection identification for logging purposes try { TransportProvider<Socket> client; IPEndPoint remoteEndPoint = null; if ((object)commandChannel != null && commandChannel.TryGetClient(clientID, out client)) remoteEndPoint = client.Provider.RemoteEndPoint as IPEndPoint; if ((object)remoteEndPoint != null) { m_ipAddress = remoteEndPoint.Address; if (remoteEndPoint.AddressFamily == AddressFamily.InterNetworkV6) m_connectionID = "[" + m_ipAddress + "]:" + remoteEndPoint.Port; else m_connectionID = m_ipAddress + ":" + remoteEndPoint.Port; try { IPHostEntry ipHost = Dns.GetHostEntry(remoteEndPoint.Address); if (!ipHost.HostName.IsNullOrWhiteSpace()) { m_hostName = ipHost.HostName; m_connectionID = m_hostName + " (" + m_connectionID + ")"; } } catch { // Just ignoring possible DNS lookup failures... } } } catch { // At worst we'll just use the client GUID for identification m_connectionID = (m_subscriberID == Guid.Empty ? clientID.ToString() : m_subscriberID.ToString()); } if (m_connectionID.IsNullOrWhiteSpace()) m_connectionID = "unavailable"; if (m_hostName.IsNullOrWhiteSpace()) { if (m_ipAddress != null) m_hostName = m_ipAddress.ToString(); else m_hostName = m_connectionID; } if (m_ipAddress == null) m_ipAddress = System.Net.IPAddress.None; } /// <summary> /// Releases the unmanaged resources before the <see cref="ClientConnection"/> object is reclaimed by <see cref="GC"/>. /// </summary> ~ClientConnection() { Dispose(false); } #endregion #region [ Properties ] /// <summary> /// Gets client ID of this <see cref="ClientConnection"/>. /// </summary> public Guid ClientID { get { return m_clientID; } } /// <summary> /// Gets or sets reference to <see cref="UdpServer"/> data channel, attaching to or detaching from events as needed, associated with this <see cref="ClientConnection"/>. /// </summary> public UdpServer DataChannel { get { return m_dataChannel; } set { m_connectionEstablished = (value != null); if (m_dataChannel != null) { // Detach from events on existing data channel reference m_dataChannel.SendClientDataException -= m_dataChannel_SendClientDataException; m_dataChannel.ServerStarted -= m_dataChannel_ServerStarted; m_dataChannel.ServerStopped -= m_dataChannel_ServerStopped; if (m_dataChannel != value) m_dataChannel.Dispose(); } // Assign new data channel reference m_dataChannel = value; if (m_dataChannel != null) { // Save UDP settings so channel can be reestablished if needed m_configurationString = m_dataChannel.ConfigurationString; // Attach to events on new data channel reference m_dataChannel.SendClientDataException += m_dataChannel_SendClientDataException; m_dataChannel.ServerStarted += m_dataChannel_ServerStarted; m_dataChannel.ServerStopped += m_dataChannel_ServerStopped; } } } /// <summary> /// Gets <see cref="IServer"/> publication channel - that is, data channel if defined otherwise command channel. /// </summary> public IServer PublishChannel { get { return ((object)m_dataChannel == null ? (IServer)m_commandChannel : (IServer)m_dataChannel); } } /// <summary> /// Gets connected state of the associated client socket. /// </summary> public bool IsConnected { get { TransportProvider<Socket> client; bool isConnected = false; try { if ((object)m_commandChannel != null && m_commandChannel.TryGetClient(m_clientID, out client)) isConnected = client.Provider.Connected; } catch { isConnected = false; } return isConnected; } } /// <summary> /// Gets or sets IsSubscribed state. /// </summary> public bool IsSubscribed { get { return m_isSubscribed; } set { m_isSubscribed = value; } } /// <summary> /// Gets or sets the <see cref="Guid"/> based subscriber ID of this <see cref="ClientConnection"/>. /// </summary> public Guid SubscriberID { get { return m_subscriberID; } set { m_subscriberID = value; } } /// <summary> /// Gets or sets the subscriber acronym of this <see cref="ClientConnection"/>. /// </summary> public string SubscriberAcronym { get { return m_subscriberAcronym; } set { m_subscriberAcronym = value; } } /// <summary> /// Gets or sets the subscriber name of this <see cref="ClientConnection"/>. /// </summary> public string SubscriberName { get { return m_subscriberName; } set { m_subscriberName = value; } } /// <summary> /// Gets or sets subscriber info for this <see cref="ClientConnection"/>. /// </summary> public string SubscriberInfo { get { if (m_subscriberInfo.IsNullOrWhiteSpace()) return m_subscriberName; return m_subscriberInfo; } set { if (value.IsNullOrWhiteSpace()) { m_subscriberInfo = null; } else { Dictionary<string, string> settings = value.ParseKeyValuePairs(); string source, version, buildDate; settings.TryGetValue("source", out source); settings.TryGetValue("version", out version); settings.TryGetValue("buildDate", out buildDate); m_subscriberInfo = string.Format("{0} version {1} built on {2}", source.ToNonNullNorWhiteSpace("unknown source"), version.ToNonNullNorWhiteSpace("?.?.?.?"), buildDate.ToNonNullNorWhiteSpace("undefined date")); } } } /// <summary> /// Gets the connection identification of this <see cref="ClientConnection"/>. /// </summary> public string ConnectionID { get { return m_connectionID; } } /// <summary> /// Gets or sets authenticated state of this <see cref="ClientConnection"/>. /// </summary> public bool Authenticated { get { return m_authenticated; } set { m_authenticated = value; } } /// <summary> /// Gets or sets shared secret used to lookup cipher keys only known to client and server. /// </summary> public string SharedSecret { get { return m_sharedSecret; } set { m_sharedSecret = value; } } /// <summary> /// Gets active and standby keys and initialization vectors. /// </summary> public byte[][][] KeyIVs { get { return m_keyIVs; } } /// <summary> /// Gets current cipher index. /// </summary> public int CipherIndex { get { return m_cipherIndex; } } /// <summary> /// Gets time of last cipher key update. /// </summary> public Ticks LastCipherKeyUpdateTime { get { return m_lastCipherKeyUpdateTime; } } /// <summary> /// Gets the IP address of the remote client connection. /// </summary> public IPAddress IPAddress { get { return m_ipAddress; } } /// <summary> /// Gets or sets subscription associated with this <see cref="ClientConnection"/>. /// </summary> public IClientSubscription Subscription { get { return m_subscription; } set { m_subscription = value; if (m_subscription != null) m_subscription.HostName = m_hostName; } } /// <summary> /// Gets the subscriber name of this <see cref="ClientConnection"/>. /// </summary> public string Name { get { return SubscriberName; } } /// <summary> /// Gets or sets a set of flags that define ways in /// which the subscriber and publisher communicate. /// </summary> public OperationalModes OperationalModes { get { return m_operationalModes; } set { m_operationalModes = value; switch ((OperationalEncoding)(value & Transport.OperationalModes.EncodingMask)) { case OperationalEncoding.Unicode: m_encoding = Encoding.Unicode; break; case OperationalEncoding.BigEndianUnicode: m_encoding = Encoding.BigEndianUnicode; break; case OperationalEncoding.UTF8: m_encoding = Encoding.UTF8; break; case OperationalEncoding.ANSI: m_encoding = Encoding.Default; break; default: throw new InvalidOperationException(string.Format("Unsupported encoding detected: {0}", value)); } } }