4727 lines · 222.1 KB · C#
RawDownload
//******************************************************************************************************//  ServiceHelper.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://  ----------------------------------------------------------------------------------------------------//  08/29/2006 - Pinal C. Patel//       Original version of source code generated.//  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.//  12/14/2007 - Pinal C. Patel//       Made monitoring of service health optional via the MonitorServiceHealth property.//  09/30/2008 - J. Ritchie Carroll//       Converted to C#.//  03/06/2009 - Pinal C. Patel//       Edited code comments.//  06/19/2009 - Pinal C. Patel//       Modified Initialize() method to just load settings from the config file.//  06/30/2009 - Pinal C. Patel//       Changed ServiceComponents to be a collection of object instead of ISupportLifecycle so it can//       host a wide range of object implementing various interfaces used by the ServiceHelper commands.//  07/15/2009 - Pinal C. Patel//       Added AllowedRemoteUsers and ImpersonateRemoteUser properties as part of security.//  07/16/2009 - Pinal C. Patel//       Added SupportTelnetSessions property so that telnet support can be optionally turned-on.//  07/17/2009 - Pinal C. Patel//       Modified MonitorServiceHealth to default to false as it is not always needed.//  07/30/2009 - Pinal C. Patel//       Modified to set the principal of the thread where client request are handled to that of the the //       process or remote client (if transmitted by the remote client upon connection).//  08/07/2009 - Pinal C. Patel//       Subscribed to ErrorLogger.LoggingException event.//  08/10/2009 - Josh L. Patterson//       Edited Comments//  09/08/2009 - Pinal C. Patel//       Modified GetProcess(), GetConnectedClient() and GetClientRequestHandler() to use lambda//       functions instead of manual iteration of collection items.//       Renamed GetProcess(), GetConnectedClient() and GetClientRequestHandler() to FindProcess(), //       FindConnectedClient() and FindClientRequestHandler() respectively.//  09/14/2009 - Stephen C. Wills//       Added new header and license agreement.//  10/23/2009 - Pinal C. Patel//       Modified UpdateStatus() method to allow the type of update to be specified.//  12/18/2009 - Pinal C. Patel//       Added message flooding control to UpdateStatus().//  06/16/2010 - Pinal C. Patel//       Made changes necessary to implement role-based security.//       Added thread synchronization to list-based member variable.//  10/14/2010 - Pinal C. Patel//       Updated security implementation to include the entire client request text including command //       and arguments instead of just the command.//  12/16/2010 - Pinal C. Patel//       Added SupportSystemCommands property that can be used to enable or disable system-level access //       via the build-in commands.//  01/04/2011 - J. Ritchie Carroll//       Changed default performance sampling interval on services to every 5 seconds instead of every//       second to reduce overhead and increase performance. Added a "-lifetime" option to the Health//       command to show lifetime performance statistics. Made sampling interval a user config option.//  01/17/2011 - J. Ritchie Carroll//       Added default "version" and "time" service commands.//  02/11/2011 - Pinal C. Patel//       Updated VerifySecurity() to work correctly with TCP integrated windows authentication. //  03/09/2011 - Pinal C. Patel//       Moved UpdateType enumeration to GSF namespace in GSF.Core.dll for broader usage.//  04/14/2011 - Pinal C. Patel//       Updated to use new serialization methods in GSF.Serialization class.//  09/22/2011 - J. Ritchie Carroll//       Added Mono implementation exception regions.//  02/17/2012 - Stephen C. Wills//       Added ReloadCryptoCache service command.//  04/12/2012 - Pinal C. Patel//       Added new UnscheduleProcess() and RemoveScheduledProcess methods.//       Changed AddProcess(), AddScheduledProcess() and ScheduleProcess() method to return a boolean.//  12/20/2012 - Starlynn Danyelle Gilliam//       Modified Header.//  02/09/2016 - Pinal C. Patel//       Added new Files and Transfer commands.////****************************************************************************************************** using GSF.Annotations;using GSF.Collections;using GSF.Communication;using GSF.Configuration;using GSF.Console;using GSF.Diagnostics;using GSF.ErrorManagement;using GSF.IO;using GSF.Reflection;using GSF.Scheduling;using GSF.Security;using GSF.Security.Cryptography;using GSF.Threading;using GSF.Units;using System;using System.Collections.Generic;using System.ComponentModel;using System.Configuration;using System.Diagnostics;using System.Drawing;using System.Globalization;using System.IO;using System.Linq;using System.Reflection;using System.Security;using System.Security.Principal;using System.ServiceProcess;using System.Text;using System.Text.RegularExpressions;using System.Threading;using System.Web; // ReSharper disable InconsistentlySynchronizedFieldnamespace GSF.ServiceProcess{    #region [ Enumerations ]     /// <summary>    /// Indicates the state of a Windows Service.    /// </summary>    public enum ServiceState    {        /// <summary>        /// Service has started.        /// </summary>        Started,        /// <summary>        /// Service has stopped.        /// </summary>        Stopped,        /// <summary>        /// Service has paused.        /// </summary>        Paused,        /// <summary>        /// Service has resumed.        /// </summary>        Resumed,        /// <summary>        /// Service has shutdown.        /// </summary>        Shutdown    }     #endregion     /// <summary>    /// Component that provides added functionality to a Windows Service.    /// </summary>    /// <seealso cref="ServiceProcess"/>    /// <seealso cref="ServiceResponse"/>    /// <seealso cref="ClientInfo"/>    /// <seealso cref="ClientRequest"/>    /// <seealso cref="ClientRequestHandler"/>    [ToolboxBitmap(typeof(ServiceHelper))]    public class ServiceHelper : Component, ISupportLifecycle, ISupportInitialize, IProvideStatus, IPersistSettings    {        #region [ Members ]         // Nested Types        private class StatusUpdate        {            public StatusUpdate(Guid client, UpdateType type, string message)            {                Client = client;                Type = type;                Message = message;            }             public readonly Guid Client;            public readonly UpdateType Type;            public readonly string Message;        }         private class ClientFilter        {            public ClientFilter()            {                TypeInclusionFilters = new List<UpdateType>();                TypeExclusionFilters = new List<UpdateType>();                PatternInclusionFilters = new List<string>();                PatternExclusionFilters = new List<string>();            }             public bool PassesFilter(StatusUpdate update)            {                UpdateType updateType = update.Type;                string message = update.Message;                 return TypeInclusionFilters.DefaultIfEmpty(update.Type).Any(type => type == updateType) &&                       TypeExclusionFilters.All(type => type != updateType) &&                       PatternInclusionFilters.DefaultIfEmpty("").Any(pattern => Regex.IsMatch(message, pattern, RegexOptions.IgnoreCase)) &&                       PatternExclusionFilters.All(pattern => !Regex.IsMatch(message, pattern, RegexOptions.IgnoreCase));            }             public readonly List<UpdateType> TypeInclusionFilters;            public readonly List<UpdateType> TypeExclusionFilters;            public readonly List<string> PatternInclusionFilters;            public readonly List<string> PatternExclusionFilters;        }         private class ClientStatusUpdateConfiguration        {            #region [ Members ]             // Constants            private const int HighPriority = 2;            private const int LowPriority = 1;             // Fields            private readonly Guid m_clientID;            private readonly ClientFilter m_filter;            private readonly LogicalThread m_thread;            private readonly List<Tuple<DateTime, int>> m_messageCounts;            private readonly ServiceHelper m_serviceHelper;             #endregion             #region [ Constructors ]             public ClientStatusUpdateConfiguration(Guid clientID, ServiceHelper serviceHelper)            {                m_clientID = clientID;                m_filter = new ClientFilter();                m_thread = serviceHelper.m_threadScheduler.CreateThread();                m_messageCounts = new List<Tuple<DateTime, int>>();                m_serviceHelper = serviceHelper;            }             #endregion             #region [ Methods ]             public void PrioritizeUpdate(StatusUpdate update)            {                m_thread.Push(HighPriority, () => m_serviceHelper.SendUpdateClientStatusResponse(update.Client, update.Type, update.Message));            }             public void SendBroadcastUpdates(List<StatusUpdate> updates)            {                m_thread.Push(LowPriority, () =>                {                    UpdateType type = UpdateType.Information;                    StringBuilder messageBuilder = new StringBuilder();                    List<StatusUpdate> messages = new List<StatusUpdate>();                    int messageCount = GetRecentMessageCount();                    int suppressedMessageCount = 0;                     foreach (StatusUpdate update in updates.Where(m_filter.PassesFilter))                    {                        // If the message count exceeds the maximum status update frequency, suppress the message                        if (messageCount + messages.Count >= m_serviceHelper.m_maxStatusUpdatesFrequency)                        {                            suppressedMessageCount++;                            continue;                        }                         // If the string builder is empty,                        // set the initial state of type                        if (messageBuilder.Length == 0)                            type = update.Type;                         // If the current update's type is not the same as the                        // current message, start a new message with the new type                        if (update.Type != type)                        {                            // Add the current message to the list of messages                            messages.Add(new StatusUpdate(m_clientID, type, messageBuilder.ToString()));                             // If the message count exceeds the maximum status update frequency, begin message suppression                            if (messageCount + messages.Count >= m_serviceHelper.m_maxStatusUpdatesFrequency)                            {                                suppressedMessageCount++;                                continue;                            }                             // Update the message type                            // and reset the string builder                            type = update.Type;                            messageBuilder.Clear();                        }                         // Update the message and increment the counter variable                        messageBuilder.Append(update.Message);                    }                     // If the maximum frequency has not been reached, add the final message to the list of messages;                    // otherwise, add a message warning the user that messages were suppressed due to high frequency                    if (messageCount + messages.Count < m_serviceHelper.m_maxStatusUpdatesFrequency)                        messages.Add(new StatusUpdate(m_clientID, type, messageBuilder.ToString()));                    else                        messages.Add(new StatusUpdate(m_clientID, UpdateType.Warning, $"Suppressed {suppressedMessageCount:N0} status updates due to high frequency to avoid flooding.\r\n\r\n"));                     // Send messages to the client                    foreach (StatusUpdate message in messages)                        m_serviceHelper.SendUpdateClientStatusResponse(message.Client, message.Type, message.Message);                     // Add the number of messages sent to the list of messages for the current time                    m_messageCounts.Add(Tuple.Create(DateTime.UtcNow, messages.Count));                });            }             public void UpdateFilters(ClientFilter mergeFilter, List<int> removalIDs)            {                m_thread.Push(HighPriority, () =>                {                    foreach (int filterID in removalIDs.OrderByDescending(id => id))                        RemoveFilter(filterID);                     m_filter.TypeInclusionFilters.AddRange(mergeFilter.TypeInclusionFilters);                    m_filter.TypeExclusionFilters.AddRange(mergeFilter.TypeExclusionFilters);                    m_filter.PatternInclusionFilters.AddRange(mergeFilter.PatternInclusionFilters);                    m_filter.PatternExclusionFilters.AddRange(mergeFilter.PatternExclusionFilters);                });            }             public void ListFilters(ClientRequestInfo requestInfo)            {                m_thread.Push(HighPriority, () =>                {                    StringBuilder messageBuilder = new StringBuilder();                    StringBuilder commandBuilder = new StringBuilder();                    int i = 0;                     commandBuilder.Append("Filter");                     // List type inclusion filters                    if (m_filter.TypeInclusionFilters.Any())                    {                        messageBuilder.AppendLine("Type Inclusion Filters:");                         foreach (UpdateType filter in m_filter.TypeInclusionFilters)                        {                            messageBuilder.AppendLine($"[{i++}] {filter}");                            commandBuilder.Append($" -Include Type {Arguments.Escape(filter.ToString())}");                        }                    }                     // List type exclusion filters                    if (m_filter.TypeExclusionFilters.Any())                    {                        if (messageBuilder.Length > 0)                            messageBuilder.AppendLine();                         messageBuilder.AppendLine("Type Exclusion Filters:");                         foreach (UpdateType filter in m_filter.TypeExclusionFilters)                        {                            messageBuilder.AppendLine($"[{i++}] {filter}");                            commandBuilder.Append($" -Exclude Type {Arguments.Escape(filter.ToString())}");                        }                    }                     // List pattern exclusion filters                    if (m_filter.PatternInclusionFilters.Any())                    {                        if (messageBuilder.Length > 0)                            messageBuilder.AppendLine();                         messageBuilder.AppendLine("Pattern Inclusion Filters:");                         foreach (string filter in m_filter.PatternInclusionFilters)                        {                            messageBuilder.AppendLine($"[{i++}] {filter}");                            commandBuilder.Append($" -Include Regex {Arguments.Escape(filter)}");                        }                    }                     // List pattern exclusion filters                    if (m_filter.PatternExclusionFilters.Any())                    {                        if (messageBuilder.Length > 0)                            messageBuilder.AppendLine();                         messageBuilder.AppendLine("Pattern Exclusion Filters:");                         foreach (string filter in m_filter.PatternExclusionFilters)                        {                            messageBuilder.AppendLine($"[{i++}] {filter}");                            commandBuilder.Append($" -Exclude Regex {Arguments.Escape(filter)}");                        }                    }                     // Display a message if no filters are defined                    if (messageBuilder.Length == 0)                    {                        messageBuilder.AppendLine("No filters defined.");                    }                    else                    {                        string command = commandBuilder.ToString();                        string argument = Arguments.Escape(command);                        string url = HttpUtility.UrlEncode(command);                         messageBuilder.AppendLine();                        messageBuilder.AppendLine("Command:");                        messageBuilder.AppendLine(command);                        messageBuilder.AppendLine();                        messageBuilder.AppendLine("Argument:");                        messageBuilder.AppendLine(argument);                        messageBuilder.AppendLine();                        messageBuilder.AppendLine("URL:");                        messageBuilder.AppendLine(url);                    }                      // Send the message to the client                    m_serviceHelper.SendActionableResponse(requestInfo, true, null, messageBuilder.ToString().TrimEnd());                });            }             private int GetRecentMessageCount()            {                // Get the total number of messages sent to the client in the last second                DateTime lastSecond = DateTime.UtcNow.AddSeconds(-1.0D);                int oldestMessageIndex = m_messageCounts.TakeWhile(tuple => tuple.Item1 < lastSecond).Count();                m_messageCounts.RemoveRange(0, oldestMessageIndex);                return m_messageCounts.Sum(tuple => tuple.Item2);            }             private void RemoveFilter(int filterID)            {                int index = filterID;                 // Attempt to remove a filter from the list of type inclusion filters                if (index < m_filter.TypeInclusionFilters.Count)                {                    m_filter.TypeInclusionFilters.RemoveAt(index);                    return;                }                 index -= m_filter.TypeInclusionFilters.Count;                 // Attempt to remove a filter from the list of type exclusion filters                if (index < m_filter.TypeExclusionFilters.Count)                {                    m_filter.TypeExclusionFilters.RemoveAt(index);                    return;                }                 index -= m_filter.TypeExclusionFilters.Count;                 // Attempt to remove a filter from the list of pattern inclusion filters                if (index < m_filter.PatternInclusionFilters.Count)                {                    m_filter.PatternInclusionFilters.RemoveAt(index);                    return;                }                 index -= m_filter.PatternInclusionFilters.Count;                 // Attempt to remove a filter from the list of pattern exclusion filters                if (index < m_filter.PatternExclusionFilters.Count)                    m_filter.PatternExclusionFilters.RemoveAt(index);            }             #endregion        }         // Delegates        private delegate bool TryGetClientPrincipalFunctionSignature(Guid clientID, out WindowsPrincipal clientPrincipal);         // Constants         /// <summary>        /// Specifies the default value for the <see cref="LogStatusUpdates"/> property.        /// </summary>        public const bool DefaultLogStatusUpdates = true;         /// <summary>        /// Specifies the default value for the <see cref="MaxStatusUpdatesLength"/> property.        /// </summary>        public const int DefaultMaxStatusUpdatesLength = 8192;         /// <summary>        /// Specifies the default value for the <see cref="MaxStatusUpdatesFrequency"/> property.        /// </summary>        public const int DefaultMaxStatusUpdatesFrequency = 30;         /// <summary>        /// Specifies the default value for the <see cref="MonitorServiceHealth"/> property.        /// </summary>        public const bool DefaultMonitorServiceHealth = false;         /// <summary>        /// Specifies the default value for the <see cref="HealthMonitorInterval"/> property.        /// </summary>

Lines 1–500 of 4727.

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