1107 lines · 45.0 KB · C#
RawDownload
//******************************************************************************************************//  ClientBase.cs - Gbtc////  Copyright © 2015, 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 MIT License (MIT), 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/MIT////  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/01/2006 - Pinal C. Patel//       Original version of source code generated.//  09/06/2006 - J. Ritchie Carroll//       Added bypass optimizations for high-speed client data access.//  11/30/2007 - Pinal C. Patel//       Modified the "design time" check in EndInit() method to use LicenseManager.UsageMode property//       instead of DesignMode property as the former is more accurate than the latter.//  02/19/2008 - Pinal C. Patel//       Added code to detect and avoid redundant calls to Dispose().//  09/29/2008 - J. Ritchie Carroll//       Converted to C#.//  06/18/2009 - Pinal C. Patel//       Fixed the implementation of Enabled property.//  07/02/2009 - Pinal C. Patel//       Modified state altering properties to reconnect the client when changed.//  07/08/2009 - J. Ritchie Carroll//       Added WaitHandle return value from asynchronous connection.//  07/15/2009 - Pinal C. Patel//       Modified Connect() to wait for post-connection processing to complete.//  07/17/2009 - Pinal C. Patel//       Modified SharedSecret to be persisted as an encrypted value.//  08/05/2009 - Josh L. Patterson//       Edited Comments.//  09/14/2009 - Stephen C. Wills//       Added new header and license agreement.//  11/29/2010 - Pinal C. Patel//       Updated the implementation of Connect() method so it blocks correctly after updates made to //       ConnectAsync() method in the derived classes.//  04/14/2011 - Pinal C. Patel//       Updated to use new serialization methods in GSF.Serialization class.//  12/02/2011 - J. Ritchie Carroll//       Updated event data publication to provide "copy" of reusable buffer instead of original//       buffer since you cannot assume how user will use the buffer (they may cache it).//  12/29/2011 - J. Ritchie Carroll//       Updated Status property to show ConnectionString information.//  04/26/2012 - Pinal C. Patel//       Updated Create() static method to apply settings from the connection string to the created //       client instance using reflection.//  05/22/2015 - J. Ritchie Carroll//       Added ZeroMQ to the create IClient options.////****************************************************************************************************** using System;using System.Collections.Generic;using System.ComponentModel;using System.Configuration;using System.Diagnostics.CodeAnalysis;using System.Drawing;using System.Reflection;using System.Text;using System.Threading;using GSF.Configuration;using GSF.Diagnostics;using GSF.Units; // ReSharper disable VirtualMemberCallInConstructornamespace GSF.Communication{    /// <summary>    /// Base class for a client involved in server-client communication.    /// </summary>    [ToolboxBitmap(typeof(ClientBase))]    public abstract class ClientBase : Component, IClient, ISupportInitialize, IPersistSettings    {        #region [ Members ]         // Constants         /// <summary>        /// Specifies the default value for the <see cref="MaxConnectionAttempts"/> property.        /// </summary>        public const int DefaultMaxConnectionAttempts = -1;         /// <summary>        /// Specifies the default value for the <see cref="SendBufferSize"/> property.        /// </summary>        public const int DefaultSendBufferSize = 32768;         /// <summary>        /// Specifies the default value for the <see cref="ReceiveBufferSize"/> property.        /// </summary>        public const int DefaultReceiveBufferSize = 32768;         /// <summary>        /// Specifies the default value for the <see cref="PersistSettings"/> property.        /// </summary>        public const bool DefaultPersistSettings = false;         /// <summary>        /// Specifies the default value for the <see cref="SettingsCategory"/> property.        /// </summary>        public const string DefaultSettingsCategory = "CommunicationClient";         // Events         /// <summary>        /// Occurs when client is attempting connection to the server.        /// </summary>        [Category("Connection")]        [Description("Occurs when client is attempting connection to the server.")]        public event EventHandler ConnectionAttempt;         /// <summary>        /// Occurs when client connection to the server is established.        /// </summary>        [Category("Connection")]        [Description("Occurs when client connection to the server is established.")]        public event EventHandler ConnectionEstablished;         /// <summary>        /// Occurs when client connection to the server is terminated.        /// </summary>        [Category("Connection")]        [Description("Occurs when client connection to the server is terminated")]        public event EventHandler ConnectionTerminated;         /// <summary>        /// Occurs when an <see cref="Exception"/> is encountered during connection attempt to the server.        /// </summary>        [Category("Connection")]        [Description("Occurs when an Exception is encountered during connection attempt to the server.")]        public event EventHandler<EventArgs<Exception>> ConnectionException;         /// <summary>        /// Occurs when the client begins sending data to the server.        /// </summary>        [Category("Data")]        [Description("Occurs when the client begins sending data to the server.")]        public event EventHandler SendDataStart;         /// <summary>        /// Occurs when the client has successfully sent data to the server.        /// </summary>        [Category("Data")]        [Description("Occurs when the client has successfully sent data to the server.")]        public event EventHandler SendDataComplete;         /// <summary>        /// Occurs when an <see cref="Exception"/> is encountered when sending data to the server.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the <see cref="Exception"/> encountered when sending data to the server.        /// </remarks>        [Category("Data")]        [Description("Occurs when an Exception is encountered when sending data to the server.")]        public event EventHandler<EventArgs<Exception>> SendDataException;         /// <summary>        /// Occurs when unprocessed data has been received from the server.        /// </summary>        /// <remarks>        /// <para>        /// This event can be used to receive a notification that server data has arrived. The <see cref="Read"/> method can then be used        /// to copy data to an existing buffer. In many cases it will be optimal to use an existing buffer instead of subscribing to the        /// <see cref="ReceiveDataComplete"/> event.        /// </para>        /// <para>        /// <see cref="EventArgs{T}.Argument"/> is the number of bytes received in the buffer from the server.        /// </para>        /// </remarks>        [Category("Data")]        [Description("Occurs when unprocessed data has been received from the server.")]        public event EventHandler<EventArgs<int>> ReceiveData;         /// <summary>        /// Occurs when data received from the server has been processed and is ready for consumption.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T1,T2}.Argument1"/> is a new buffer containing post-processed data received from the server starting at index zero.<br/>        /// <see cref="EventArgs{T1,T2}.Argument2"/> is the number of post-processed bytes received in the buffer from the server.        /// </remarks>        [Category("Data")]        [Description("Occurs when data received from the server has been processed and is ready for consumption.")]        public event EventHandler<EventArgs<byte[], int>> ReceiveDataComplete;         /// <summary>        /// Occurs when an <see cref="Exception"/> is encountered when receiving data from the server.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the <see cref="Exception"/> encountered when receiving data from the server.        /// </remarks>        [Category("Data")]        [Description("Occurs when an Exception is encountered when receiving data from the server.")]        public event EventHandler<EventArgs<Exception>> ReceiveDataException;         /// <summary>        /// Occurs when an <see cref="Exception"/> is encountered in a user-defined function via an event dispatch.        /// </summary>        /// <remarks>        /// <see cref="EventArgs{T}.Argument"/> is the <see cref="Exception"/> thrown by the user-defined function.        /// </remarks>        [Category("User")]        [Description("Occurs when an Exception is encountered when calling a user-defined function.")]        public event EventHandler<EventArgs<Exception>> UnhandledUserException;         // Fields        private string m_connectionString;        private int m_maxConnectionAttempts;        private int m_sendBufferSize;        private int m_receiveBufferSize;        private string m_settingsCategory;        private Encoding m_textEncoding;        private ClientState m_currentState;        private readonly TransportProtocol m_transportProtocol;        private Ticks m_connectTime;        private Ticks m_disconnectTime;        private ManualResetEvent m_connectHandle;        private bool m_initialized;         private readonly Action<int> m_updateBytesSent;        private readonly Action<int> m_updateBytesReceived;         #endregion         #region [ Constructors ]         /// <summary>        /// Initializes a new instance of the client.        /// </summary>        protected ClientBase()        {            m_textEncoding = Encoding.ASCII;            m_currentState = ClientState.Disconnected;            m_maxConnectionAttempts = DefaultMaxConnectionAttempts;            m_sendBufferSize = DefaultSendBufferSize;            m_receiveBufferSize = DefaultReceiveBufferSize;            PersistSettings = DefaultPersistSettings;            m_settingsCategory = DefaultSettingsCategory;            Statistics = new TransportStatistics();            m_updateBytesSent = TrackStatistics ? UpdateBytesSent : new Action<int>(bytes => { });            m_updateBytesReceived = TrackStatistics ? UpdateBytesReceived : new Action<int>(bytes => { });        }         /// <summary>        /// Initializes a new instance of the client.        /// </summary>        /// <param name="transportProtocol">One of the <see cref="TransportProtocol"/> values.</param>        /// <param name="connectionString">The data used by the client for connection to a server.</param>        protected ClientBase(TransportProtocol transportProtocol, string connectionString) : this()        {            m_transportProtocol = transportProtocol;            ConnectionString = connectionString;        }         #endregion         #region [ Properties ]         /// <summary>        /// Gets the server URI.        /// </summary>        [Browsable(false)]        public abstract string ServerUri { get; }         /// <summary>        /// Gets the current server index, when multiple server end points are defined.        /// </summary>        [Browsable(false)]        public int ServerIndex { get; internal set; } = 0;         /// <summary>        /// Gets or sets the data required by the client to connect to the server.        /// </summary>        [Category("Settings")]        [Description("The data required by the client to connect to the server.")]        public virtual string ConnectionString        {            get => m_connectionString;            set            {                ValidateConnectionString(value);                 m_connectionString = value;                ReConnect();            }        }         /// <summary>        /// Gets or sets the maximum number of times the client will attempt to connect to the server.        /// </summary>        /// <remarks>Set <see cref="MaxConnectionAttempts"/> to -1 for infinite connection attempts.</remarks>        [Category("Settings")]        [DefaultValue(DefaultMaxConnectionAttempts)]        [Description("The maximum number of times the client will attempt to connect to the server. Set MaxConnectionAttempts to -1 for infinite connection attempts.")]        public virtual int MaxConnectionAttempts        {            get => m_maxConnectionAttempts;            set => m_maxConnectionAttempts = value < 1 ? -1 : value;        }         /// <summary>        /// Gets or sets the size of the buffer used by the client for sending data to the server.        /// </summary>        /// <exception cref="ArgumentException">The value being assigned is either zero or negative.</exception>        [Category("Data")]        [DefaultValue(DefaultSendBufferSize)]        [Description("The size of the buffer used by the client for receiving data from the server.")]        public virtual int SendBufferSize        {            get => m_sendBufferSize;            set            {                if (value < 1)                    throw new ArgumentException("Value cannot be zero or negative");                 m_sendBufferSize = value;            }        }         /// <summary>        /// Gets or sets the size of the buffer used by the client for receiving data from the server.        /// </summary>        /// <exception cref="ArgumentException">The value being assigned is either zero or negative.</exception>        [Category("Data")]        [DefaultValue(DefaultReceiveBufferSize)]        [Description("The size of the buffer used by the client for receiving data from the server.")]        public virtual int ReceiveBufferSize        {            get => m_receiveBufferSize;            set            {                if (value < 1)                    throw new ArgumentException("Value cannot be zero or negative");                 m_receiveBufferSize = value;            }        }         /// <summary>        /// Gets or sets a boolean value that indicates whether the client settings are to be saved to the config file.        /// </summary>        [Category("Persistence")]        [DefaultValue(DefaultPersistSettings)]        [Description("Indicates whether the client settings are to be saved to the config file.")]        public bool PersistSettings { get; set; }         /// <summary>        /// Gets or sets the category under which the client settings are to be saved to the config file if the <see cref="PersistSettings"/> property is set to true.        /// </summary>        /// <exception cref="ArgumentNullException">The value being assigned is a null or empty string.</exception>        [Category("Persistence")]        [DefaultValue(DefaultSettingsCategory)]        [Description("Category under which the client settings are to be saved to the config file if the PersistSettings property is set to true.")]        public string SettingsCategory        {            get => m_settingsCategory;            set            {                if (string.IsNullOrEmpty(value))                    throw new ArgumentNullException(nameof(value));                 m_settingsCategory = value;            }        }         /// <summary>        /// Gets or sets a boolean value that indicates whether the client is currently enabled.        /// </summary>        /// <remarks>        /// Setting <see cref="Enabled"/> to true will start connection cycle for the client if it        /// is not connected, setting to false will disconnect the client if it is connected.        /// </remarks>        [Browsable(false)]        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]        public bool Enabled        {            get => m_currentState == ClientState.Connected;            set            {                if (value && !Enabled)                    Connect();                else if (!value && Enabled)                    Disconnect();            }        }         /// <summary>        /// Gets a flag that indicates whether the object has been disposed.        /// </summary>        [Browsable(false)]        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]        public bool IsDisposed { get; private set; }         /// <summary>        /// Gets or sets the <see cref="Encoding"/> to be used for the text sent to the server.        /// </summary>        [Browsable(false)]        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]        public virtual Encoding TextEncoding        {            get => m_textEncoding;            set => m_textEncoding = value;        }         /// <summary>        /// Gets the current <see cref="ClientState"/>.        /// </summary>        [Browsable(false)]        public virtual ClientState CurrentState => m_currentState;         /// <summary>        /// Gets the <see cref="TransportProtocol"/> used by the client for the transportation of data with the server.        /// </summary>        [Browsable(false)]        public virtual TransportProtocol TransportProtocol => m_transportProtocol;         /// <summary>        /// Gets the <see cref="Time"/> for which the client has been connected to the server.        /// </summary>        [Browsable(false)]        public virtual Time ConnectionTime        {            get            {                Time clientConnectionTime = 0.0D;                 if (m_connectTime > 0)                {                    if (m_currentState == ClientState.Connected)                    {                        // Client is connected to the server.                        clientConnectionTime = (DateTime.UtcNow.Ticks - m_connectTime).ToSeconds();                    }                    else                    {                        // Client is not connected to the server.                        clientConnectionTime = (m_disconnectTime - m_connectTime).ToSeconds();                    }                }                 return clientConnectionTime;            }        }         /// <summary>        /// Gets or sets current read index for received data buffer incremented at each <see cref="Read"/> call.        /// </summary>        protected int ReadIndex { get; set; }         /// <summary>        /// Gets the unique identifier of the client.        /// </summary>        [Browsable(false)]        public virtual string Name => m_settingsCategory;         /// <summary>        /// Gets the <see cref="TransportStatistics"/> for the client connection.        /// </summary>        public TransportStatistics Statistics { get; }         /// <summary>        /// Determines whether the base class should track statistics.        /// </summary>        protected virtual bool TrackStatistics => true;         /// <summary>        /// Gets the descriptive status of the client.        /// </summary>        [Browsable(false)]        public virtual string Status        {            get            {                StringBuilder status = new StringBuilder();                 status.Append("              Client state: ");                status.Append(m_currentState);                status.AppendLine();                status.Append("           Connection time: ");                status.Append(ConnectionTime.ToString(3));                status.AppendLine();                status.Append("            Receive buffer: ");                status.Append(m_receiveBufferSize.ToString());                status.AppendLine();                status.Append("        Transport protocol: ");                status.Append(m_transportProtocol.ToString());                status.AppendLine();                status.Append("        Text encoding used: ");                status.Append(m_textEncoding.EncodingName);                status.AppendLine(); 

Lines 1–500 of 1107.

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