768 lines · 26.7 KB · C#
RawDownload
//******************************************************************************************************//  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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t