Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SilkShock v0.1.0
SilkShock.dll
Decompiled 2 months agousing System; using System.ComponentModel; using System.Diagnostics; using System.Diagnostics.CodeAnalysis; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Threading.Tasks; using BepInEx; using HarmonyLib; using Microsoft.CodeAnalysis; using WebSocketSharp; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SilkShock")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Adds PiShock integration via the v4 MultiShock plugin DynamicShock")] [assembly: AssemblyFileVersion("0.1.0.0")] [assembly: AssemblyInformationalVersion("0.1.0+9405d0a8a339f89dd51226e89d28e98f743fa328")] [assembly: AssemblyProduct("SilkShock")] [assembly: AssemblyTitle("SilkShock")] [assembly: AssemblyMetadata("RepositoryUrl", "https://github.com/Aesteralias/SilkShock")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("0.1.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace System.Runtime.Versioning { [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiresPreviewFeaturesAttribute : Attribute { public string? Message { get; } public string? Url { get; set; } public RequiresPreviewFeaturesAttribute() { } public RequiresPreviewFeaturesAttribute(string? message) { Message = message; } } } namespace System.Runtime.CompilerServices { [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CallerArgumentExpressionAttribute : Attribute { public string ParameterName { get; } public CallerArgumentExpressionAttribute(string parameterName) { ParameterName = parameterName; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CollectionBuilderAttribute : Attribute { public Type BuilderType { get; } public string MethodName { get; } public CollectionBuilderAttribute(Type builderType, string methodName) { BuilderType = builderType; MethodName = methodName; } } [AttributeUsage(AttributeTargets.All, AllowMultiple = true, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class CompilerFeatureRequiredAttribute : Attribute { public const string RefStructs = "RefStructs"; public const string RequiredMembers = "RequiredMembers"; public string FeatureName { get; } public bool IsOptional { get; set; } public CompilerFeatureRequiredAttribute(string featureName) { FeatureName = featureName; } } [AttributeUsage(AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerArgumentAttribute : Attribute { public string[] Arguments { get; } public InterpolatedStringHandlerArgumentAttribute(string argument) { Arguments = new string[1] { argument }; } public InterpolatedStringHandlerArgumentAttribute(params string[] arguments) { Arguments = arguments; } } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class InterpolatedStringHandlerAttribute : Attribute { } [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal static class IsExternalInit { } [AttributeUsage(AttributeTargets.Method, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : Attribute { } [AttributeUsage(AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class OverloadResolutionPriorityAttribute : Attribute { public int Priority { get; } public OverloadResolutionPriorityAttribute(int priority) { Priority = priority; } } [AttributeUsage(AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)] [ExcludeFromCodeCoverage] internal sealed class ParamCollectionAttribute : Attribute { } [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Property | AttributeTargets.Field, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class RequiredMemberAttribute : Attribute { } [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [EditorBrowsable(EditorBrowsableState.Never)] [ExcludeFromCodeCoverage] internal sealed class RequiresLocationAttribute : Attribute { } [AttributeUsage(AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Event | AttributeTargets.Interface, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SkipLocalsInitAttribute : Attribute { } } namespace System.Diagnostics.CodeAnalysis { [AttributeUsage(AttributeTargets.Parameter, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ConstantExpectedAttribute : Attribute { public object? Min { get; set; } public object? Max { get; set; } } [AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Module | AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum | AttributeTargets.Constructor | AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Interface | AttributeTargets.Delegate, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class ExperimentalAttribute : Attribute { public string DiagnosticId { get; } public string? UrlFormat { get; set; } public ExperimentalAttribute(string diagnosticId) { DiagnosticId = diagnosticId; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullAttribute : Attribute { public string[] Members { get; } public MemberNotNullAttribute(string member) { Members = new string[1] { member }; } public MemberNotNullAttribute(params string[] members) { Members = members; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property, Inherited = false, AllowMultiple = true)] [ExcludeFromCodeCoverage] internal sealed class MemberNotNullWhenAttribute : Attribute { public bool ReturnValue { get; } public string[] Members { get; } public MemberNotNullWhenAttribute(bool returnValue, string member) { ReturnValue = returnValue; Members = new string[1] { member }; } public MemberNotNullWhenAttribute(bool returnValue, params string[] members) { ReturnValue = returnValue; Members = members; } } [AttributeUsage(AttributeTargets.Constructor, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class SetsRequiredMembersAttribute : Attribute { } [AttributeUsage(AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class StringSyntaxAttribute : Attribute { public const string CompositeFormat = "CompositeFormat"; public const string DateOnlyFormat = "DateOnlyFormat"; public const string DateTimeFormat = "DateTimeFormat"; public const string EnumFormat = "EnumFormat"; public const string GuidFormat = "GuidFormat"; public const string Json = "Json"; public const string NumericFormat = "NumericFormat"; public const string Regex = "Regex"; public const string TimeOnlyFormat = "TimeOnlyFormat"; public const string TimeSpanFormat = "TimeSpanFormat"; public const string Uri = "Uri"; public const string Xml = "Xml"; public string Syntax { get; } public object?[] Arguments { get; } public StringSyntaxAttribute(string syntax) { Syntax = syntax; Arguments = new object[0]; } public StringSyntaxAttribute(string syntax, params object?[] arguments) { Syntax = syntax; Arguments = arguments; } } [AttributeUsage(AttributeTargets.Method | AttributeTargets.Property | AttributeTargets.Parameter, AllowMultiple = false, Inherited = false)] [ExcludeFromCodeCoverage] internal sealed class UnscopedRefAttribute : Attribute { } } namespace BepInEx { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class BepInAutoPluginAttribute : Attribute { public BepInAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace BepInEx.Preloader.Core.Patching { [AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)] [Conditional("CodeGeneration")] internal sealed class PatcherAutoPluginAttribute : Attribute { public PatcherAutoPluginAttribute(string? id = null, string? name = null, string? version = null) { } } } namespace SilkShock { [BepInPlugin("io.github.aesteralias.silkshock", "SilkShock", "0.1.0")] public class SilkShockPlugin : BaseUnityPlugin { [HarmonyPatch(typeof(PlayerData), "TakeHealth")] private class Take_Damge { private static void Prefix(int amount, int ___health) { if (amount > 0) { if (___health - amount <= 0) { Send($"{{\"Event_Name\":\"Silksong/Death\", \"Input\":{amount}}}"); } else { Send($"{{\"Event_Name\":\"Silksong/Damage\", \"Input\":{amount}}}"); } } } } [HarmonyPatch(typeof(DeliveryQuestItem), "TakeHit")] private class Bonk { [HarmonyPatch(new Type[] { })] private static void Prefix() { Send("{\"Event_Name\":\"Silksong/Bonk\"}"); } } private const string Exported_Default = "{\"Event_Name\":\"\", \"Register_Events\":[{\"Name\":\"Damage\",\"Group\":\"Silksong\",\"Description\":\"On taking damage, scaling with damage taken\",\"Registered_Event\":true,\"Label_X\":\"Masks\",\"Min_X\":1,\"Max_X\":9,\"X_Precision\":0,\"Values\":{\"intensity\":{\"Setup\":24,\"Value_Type\":0,\"String_Output\":\"\",\"Static_Value\":20,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0,\"Max_Y\":100,\"Keyframes\":[{\"Input\":1,\"Output\":20,\"Interpolation\":0},{\"Input\":3,\"Output\":40,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Masks\",\"X_Precision\":0,\"Label_Y\":\"Intensity\",\"Y_Precision\":0,\"Clamp_Min\":0,\"Clamp_Max\":100}},\"duration\":{\"Setup\":24,\"Value_Type\":1,\"String_Output\":\"\",\"Static_Value\":1.5,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0.1,\"Max_Y\":15,\"Keyframes\":[{\"Input\":1,\"Output\":1,\"Interpolation\":0},{\"Input\":3,\"Output\":3,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Masks\",\"X_Precision\":0,\"Label_Y\":\"Duration\",\"Y_Precision\":1,\"Clamp_Min\":0.1,\"Clamp_Max\":15}},\"delay\":{\"Setup\":0,\"Value_Type\":2,\"String_Output\":\"\",\"Static_Value\":3,\"Dynamic_Value\":null},\"chance\":{\"Setup\":0,\"Value_Type\":3,\"String_Output\":\"\",\"Static_Value\":100,\"Dynamic_Value\":null},\"failure\":{\"Setup\":7,\"Value_Type\":4,\"String_Output\":\"\",\"Static_Value\":10,\"Dynamic_Value\":null}},\"Ids\":[],\"Selection\":0,\"Command\":0},{\"Name\":\"Death\",\"Group\":\"Silksong/\",\"Description\":\"On death scaling with how much damage killed you.\",\"Registered_Event\":true,\"Label_X\":\"Damage\",\"Min_X\":1,\"Max_X\":9,\"X_Precision\":0,\"Values\":{\"intensity\":{\"Setup\":24,\"Value_Type\":0,\"String_Output\":\"\",\"Static_Value\":50,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0,\"Max_Y\":100,\"Keyframes\":[{\"Input\":1,\"Output\":40,\"Interpolation\":0},{\"Input\":3,\"Output\":70,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Damage\",\"X_Precision\":0,\"Label_Y\":\"Intensity\",\"Y_Precision\":0,\"Clamp_Min\":0,\"Clamp_Max\":100}},\"duration\":{\"Setup\":24,\"Value_Type\":1,\"String_Output\":\"\",\"Static_Value\":4,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0.1,\"Max_Y\":15,\"Keyframes\":[{\"Input\":1,\"Output\":4,\"Interpolation\":0},{\"Input\":3,\"Output\":8,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Damage\",\"X_Precision\":0,\"Label_Y\":\"Duration\",\"Y_Precision\":1,\"Clamp_Min\":0.1,\"Clamp_Max\":15}},\"delay\":{\"Setup\":0,\"Value_Type\":2,\"String_Output\":\"\",\"Static_Value\":3,\"Dynamic_Value\":null},\"chance\":{\"Setup\":0,\"Value_Type\":3,\"String_Output\":\"\",\"Static_Value\":100,\"Dynamic_Value\":null},\"failure\":{\"Setup\":7,\"Value_Type\":4,\"String_Output\":\"\",\"Static_Value\":10,\"Dynamic_Value\":null}},\"Ids\":[],\"Selection\":0,\"Command\":0},{\"Name\":\"Bonk\",\"Group\":\"Silksong/\",\"Description\":\"When hard colliding with terrain.\",\"Registered_Event\":false,\"Label_X\":null,\"Min_X\":null,\"Max_X\":null,\"X_Precision\":null,\"Values\":{\"intensity\":{\"Setup\":24,\"Value_Type\":0,\"String_Output\":\"\",\"Static_Value\":15,\"Dynamic_Value\":null},\"duration\":{\"Setup\":24,\"Value_Type\":1,\"String_Output\":\"\",\"Static_Value\":0.3,\"Dynamic_Value\":null},\"delay\":{\"Setup\":0,\"Value_Type\":2,\"String_Output\":\"\",\"Static_Value\":3,\"Dynamic_Value\":null},\"chance\":{\"Setup\":0,\"Value_Type\":3,\"String_Output\":\"\",\"Static_Value\":100,\"Dynamic_Value\":null},\"failure\":{\"Setup\":7,\"Value_Type\":4,\"String_Output\":\"\",\"Static_Value\":10,\"Dynamic_Value\":null}},\"Ids\":[],\"Selection\":0,\"Command\":0}]}"; private static readonly WebSocket Socket = new WebSocket("ws://localhost:4569/Aes-DynamicShock/Event", Array.Empty<string>()); private static long next_attempt; public const string Id = "io.github.aesteralias.silkshock"; public static string Name => "SilkShock"; public static string Version => "0.1.0"; private void Awake() { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Expected O, but got Unknown Socket.OnOpen += Socket_OnOpen; Harmony val = new Harmony("Aes-SilkShock"); val.PatchAll(); Connect(); ((BaseUnityPlugin)this).Logger.LogInfo((object)("Plugin " + Name + " (io.github.aesteralias.silkshock) has loaded!")); } private void Socket_OnOpen(object sender, EventArgs e) { Socket.Send("{\"Event_Name\":\"\", \"Register_Events\":[{\"Name\":\"Damage\",\"Group\":\"Silksong\",\"Description\":\"On taking damage, scaling with damage taken\",\"Registered_Event\":true,\"Label_X\":\"Masks\",\"Min_X\":1,\"Max_X\":9,\"X_Precision\":0,\"Values\":{\"intensity\":{\"Setup\":24,\"Value_Type\":0,\"String_Output\":\"\",\"Static_Value\":20,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0,\"Max_Y\":100,\"Keyframes\":[{\"Input\":1,\"Output\":20,\"Interpolation\":0},{\"Input\":3,\"Output\":40,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Masks\",\"X_Precision\":0,\"Label_Y\":\"Intensity\",\"Y_Precision\":0,\"Clamp_Min\":0,\"Clamp_Max\":100}},\"duration\":{\"Setup\":24,\"Value_Type\":1,\"String_Output\":\"\",\"Static_Value\":1.5,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0.1,\"Max_Y\":15,\"Keyframes\":[{\"Input\":1,\"Output\":1,\"Interpolation\":0},{\"Input\":3,\"Output\":3,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Masks\",\"X_Precision\":0,\"Label_Y\":\"Duration\",\"Y_Precision\":1,\"Clamp_Min\":0.1,\"Clamp_Max\":15}},\"delay\":{\"Setup\":0,\"Value_Type\":2,\"String_Output\":\"\",\"Static_Value\":3,\"Dynamic_Value\":null},\"chance\":{\"Setup\":0,\"Value_Type\":3,\"String_Output\":\"\",\"Static_Value\":100,\"Dynamic_Value\":null},\"failure\":{\"Setup\":7,\"Value_Type\":4,\"String_Output\":\"\",\"Static_Value\":10,\"Dynamic_Value\":null}},\"Ids\":[],\"Selection\":0,\"Command\":0},{\"Name\":\"Death\",\"Group\":\"Silksong/\",\"Description\":\"On death scaling with how much damage killed you.\",\"Registered_Event\":true,\"Label_X\":\"Damage\",\"Min_X\":1,\"Max_X\":9,\"X_Precision\":0,\"Values\":{\"intensity\":{\"Setup\":24,\"Value_Type\":0,\"String_Output\":\"\",\"Static_Value\":50,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0,\"Max_Y\":100,\"Keyframes\":[{\"Input\":1,\"Output\":40,\"Interpolation\":0},{\"Input\":3,\"Output\":70,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Damage\",\"X_Precision\":0,\"Label_Y\":\"Intensity\",\"Y_Precision\":0,\"Clamp_Min\":0,\"Clamp_Max\":100}},\"duration\":{\"Setup\":24,\"Value_Type\":1,\"String_Output\":\"\",\"Static_Value\":4,\"Dynamic_Value\":{\"Min_X\":1,\"Max_X\":9,\"Min_Y\":0.1,\"Max_Y\":15,\"Keyframes\":[{\"Input\":1,\"Output\":4,\"Interpolation\":0},{\"Input\":3,\"Output\":8,\"Interpolation\":0}],\"T_Name\":\"\",\"Group\":\"\",\"Description\":\"\",\"Label_X\":\"Damage\",\"X_Precision\":0,\"Label_Y\":\"Duration\",\"Y_Precision\":1,\"Clamp_Min\":0.1,\"Clamp_Max\":15}},\"delay\":{\"Setup\":0,\"Value_Type\":2,\"String_Output\":\"\",\"Static_Value\":3,\"Dynamic_Value\":null},\"chance\":{\"Setup\":0,\"Value_Type\":3,\"String_Output\":\"\",\"Static_Value\":100,\"Dynamic_Value\":null},\"failure\":{\"Setup\":7,\"Value_Type\":4,\"String_Output\":\"\",\"Static_Value\":10,\"Dynamic_Value\":null}},\"Ids\":[],\"Selection\":0,\"Command\":0},{\"Name\":\"Bonk\",\"Group\":\"Silksong/\",\"Description\":\"When hard colliding with terrain.\",\"Registered_Event\":false,\"Label_X\":null,\"Min_X\":null,\"Max_X\":null,\"X_Precision\":null,\"Values\":{\"intensity\":{\"Setup\":24,\"Value_Type\":0,\"String_Output\":\"\",\"Static_Value\":15,\"Dynamic_Value\":null},\"duration\":{\"Setup\":24,\"Value_Type\":1,\"String_Output\":\"\",\"Static_Value\":0.3,\"Dynamic_Value\":null},\"delay\":{\"Setup\":0,\"Value_Type\":2,\"String_Output\":\"\",\"Static_Value\":3,\"Dynamic_Value\":null},\"chance\":{\"Setup\":0,\"Value_Type\":3,\"String_Output\":\"\",\"Static_Value\":100,\"Dynamic_Value\":null},\"failure\":{\"Setup\":7,\"Value_Type\":4,\"String_Output\":\"\",\"Static_Value\":10,\"Dynamic_Value\":null}},\"Ids\":[],\"Selection\":0,\"Command\":0}]}"); } private static void Connect() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)Socket.ReadyState != 1 && DateTime.UtcNow.Ticks > next_attempt) { next_attempt = DateTime.UtcNow.AddSeconds(10.0).Ticks; Task.Run(delegate { Socket.Connect(); }); } } private static void Send(string msg) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Invalid comparison between Unknown and I4 if ((int)Socket.ReadyState == 1) { Socket.Send(msg); } else { Connect(); } } } }
websocket-sharp.dll
Decompiled 2 months ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.ComponentModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.IO.Compression; using System.Net; using System.Net.Security; using System.Net.Sockets; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Serialization; using System.Security.Authentication; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Security.Permissions; using System.Security.Principal; using System.Text; using System.Threading; using System.Timers; using WebSocketSharp.Net; using WebSocketSharp.Net.WebSockets; using WebSocketSharp.Server; [assembly: AssemblyProduct("websocket-sharp.dll")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyCompany("")] [assembly: AssemblyCopyright("sta.blockhead")] [assembly: AssemblyTrademark("")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("websocket-sharp")] [assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyVersion("1.0.2.59611")] namespace WebSocketSharp { public static class Ext { private const string _tspecials = "()<>@,;:\\\"/[]?={} \t"; private static readonly byte[] _last; private static readonly int _retry; private static byte[] compress(this byte[] data) { if (data.LongLength == 0) { return data; } using MemoryStream stream = new MemoryStream(data); return stream.compressToArray(); } private static MemoryStream compress(this Stream stream) { MemoryStream memoryStream = new MemoryStream(); if (stream.Length == 0) { return memoryStream; } stream.Position = 0L; using DeflateStream deflateStream = new DeflateStream(memoryStream, CompressionMode.Compress, leaveOpen: true); CopyTo(stream, deflateStream, 1024); deflateStream.Close(); memoryStream.Write(_last, 0, 1); memoryStream.Position = 0L; return memoryStream; } private static byte[] compressToArray(this Stream stream) { using MemoryStream memoryStream = stream.compress(); memoryStream.Close(); return memoryStream.ToArray(); } private static byte[] decompress(this byte[] data) { if (data.LongLength == 0) { return data; } using MemoryStream stream = new MemoryStream(data); return stream.decompressToArray(); } private static MemoryStream decompress(this Stream stream) { MemoryStream memoryStream = new MemoryStream(); if (stream.Length == 0) { return memoryStream; } stream.Position = 0L; using DeflateStream source = new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: true); CopyTo(source, memoryStream, 1024); memoryStream.Position = 0L; return memoryStream; } private static byte[] decompressToArray(this Stream stream) { using MemoryStream memoryStream = stream.decompress(); memoryStream.Close(); return memoryStream.ToArray(); } private static void times(this ulong n, Action action) { for (ulong num = 0uL; num < n; num++) { action(); } } internal static byte[] Append(this ushort code, string reason) { byte[] array = code.InternalToByteArray(ByteOrder.Big); if (reason != null && reason.Length > 0) { List<byte> list = new List<byte>(array); list.AddRange(Encoding.UTF8.GetBytes(reason)); array = list.ToArray(); } return array; } internal static string CheckIfAvailable(this ServerState state, bool ready, bool start, bool shutting) { return ((!ready && (state == ServerState.Ready || state == ServerState.Stop)) || (!start && state == ServerState.Start) || (!shutting && state == ServerState.ShuttingDown)) ? ("This operation isn't available in: " + state.ToString().ToLower()) : null; } internal static string CheckIfAvailable(this WebSocketState state, bool connecting, bool open, bool closing, bool closed) { return ((!connecting && state == WebSocketState.Connecting) || (!open && state == WebSocketState.Open) || (!closing && state == WebSocketState.Closing) || (!closed && state == WebSocketState.Closed)) ? ("This operation isn't available in: " + state.ToString().ToLower()) : null; } internal static string CheckIfValidProtocols(this string[] protocols) { return protocols.Contains((string protocol) => protocol == null || protocol.Length == 0 || !protocol.IsToken()) ? "Contains an invalid value." : (protocols.ContainsTwice() ? "Contains a value twice." : null); } internal static string CheckIfValidServicePath(this string path) { return (path == null || path.Length == 0) ? "'path' is null or empty." : ((path[0] != '/') ? "'path' isn't an absolute path." : ((path.IndexOfAny(new char[2] { '?', '#' }) > -1) ? "'path' includes either or both query and fragment components." : null)); } internal static string CheckIfValidSessionID(this string id) { return (id == null || id.Length == 0) ? "'id' is null or empty." : null; } internal static string CheckIfValidWaitTime(this TimeSpan time) { return (time <= TimeSpan.Zero) ? "A wait time is zero or less." : null; } internal static bool CheckWaitTime(this TimeSpan time, out string message) { message = null; if (time <= TimeSpan.Zero) { message = "A wait time is zero or less."; return false; } return true; } internal static void Close(this WebSocketSharp.Net.HttpListenerResponse response, WebSocketSharp.Net.HttpStatusCode code) { response.StatusCode = (int)code; response.OutputStream.Close(); } internal static void CloseWithAuthChallenge(this WebSocketSharp.Net.HttpListenerResponse response, string challenge) { response.Headers.InternalSet("WWW-Authenticate", challenge, response: true); response.Close(WebSocketSharp.Net.HttpStatusCode.Unauthorized); } internal static byte[] Compress(this byte[] data, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? data.compress() : data; } internal static Stream Compress(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.compress() : stream; } internal static byte[] CompressToArray(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.compressToArray() : stream.ToByteArray(); } internal static bool Contains<T>(this IEnumerable<T> source, Func<T, bool> condition) { foreach (T item in source) { if (condition(item)) { return true; } } return false; } internal static bool ContainsTwice(this string[] values) { int len = values.Length; Func<int, bool> contains = null; contains = delegate(int idx) { if (idx < len - 1) { for (int i = idx + 1; i < len; i++) { if (values[i] == values[idx]) { return true; } } return contains(++idx); } return false; }; return contains(0); } internal static T[] Copy<T>(this T[] source, long length) { T[] array = new T[length]; Array.Copy(source, 0L, array, 0L, length); return array; } internal static void CopyTo(this Stream source, Stream destination, int bufferLength) { byte[] buffer = new byte[bufferLength]; int num = 0; while ((num = source.Read(buffer, 0, bufferLength)) > 0) { destination.Write(buffer, 0, num); } } internal static void CopyToAsync(this Stream source, Stream destination, int bufferLength, Action completed, Action<Exception> error) { byte[] buff = new byte[bufferLength]; AsyncCallback callback = null; callback = delegate(IAsyncResult ar) { try { int num = source.EndRead(ar); if (num <= 0) { if (completed != null) { completed(); } } else { destination.Write(buff, 0, num); source.BeginRead(buff, 0, bufferLength, callback, null); } } catch (Exception obj2) { if (error != null) { error(obj2); } } }; try { source.BeginRead(buff, 0, bufferLength, callback, null); } catch (Exception obj) { if (error != null) { error(obj); } } } internal static byte[] Decompress(this byte[] data, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? data.decompress() : data; } internal static Stream Decompress(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.decompress() : stream; } internal static byte[] DecompressToArray(this Stream stream, CompressionMethod method) { return (method == CompressionMethod.Deflate) ? stream.decompressToArray() : stream.ToByteArray(); } internal static bool EqualsWith(this int value, char c, Action<int> action) { action(value); return value == c; } internal static string GetAbsolutePath(this Uri uri) { if (uri.IsAbsoluteUri) { return uri.AbsolutePath; } string originalString = uri.OriginalString; if (originalString[0] != '/') { return null; } int num = originalString.IndexOfAny(new char[2] { '?', '#' }); return (num > 0) ? originalString.Substring(0, num) : originalString; } internal static string GetMessage(this CloseStatusCode code) { return code switch { CloseStatusCode.TlsHandshakeFailure => "An error has occurred during a TLS handshake.", CloseStatusCode.ServerError => "WebSocket server got an internal error.", CloseStatusCode.MandatoryExtension => "WebSocket client didn't receive expected extension(s).", CloseStatusCode.TooBig => "A too big message has been received.", CloseStatusCode.PolicyViolation => "A policy violation has occurred.", CloseStatusCode.InvalidData => "Invalid data has been received.", CloseStatusCode.Abnormal => "An exception has occurred.", CloseStatusCode.UnsupportedData => "Unsupported data has been received.", CloseStatusCode.ProtocolError => "A WebSocket protocol error has occurred.", _ => string.Empty, }; } internal static string GetName(this string nameAndValue, char separator) { int num = nameAndValue.IndexOf(separator); return (num > 0) ? nameAndValue.Substring(0, num).Trim() : null; } internal static string GetValue(this string nameAndValue, char separator) { int num = nameAndValue.IndexOf(separator); return (num > -1 && num < nameAndValue.Length - 1) ? nameAndValue.Substring(num + 1).Trim() : null; } internal static string GetValue(this string nameAndValue, char separator, bool unquote) { int num = nameAndValue.IndexOf(separator); if (num < 0 || num == nameAndValue.Length - 1) { return null; } string text = nameAndValue.Substring(num + 1).Trim(); return unquote ? text.Unquote() : text; } internal static TcpListenerWebSocketContext GetWebSocketContext(this TcpClient tcpClient, string protocol, bool secure, ServerSslConfiguration sslConfig, Logger logger) { return new TcpListenerWebSocketContext(tcpClient, protocol, secure, sslConfig, logger); } internal static byte[] InternalToByteArray(this ushort value, ByteOrder order) { byte[] bytes = BitConverter.GetBytes(value); if (!order.IsHostOrder()) { Array.Reverse((Array)bytes); } return bytes; } internal static byte[] InternalToByteArray(this ulong value, ByteOrder order) { byte[] bytes = BitConverter.GetBytes(value); if (!order.IsHostOrder()) { Array.Reverse((Array)bytes); } return bytes; } internal static bool IsCompressionExtension(this string value, CompressionMethod method) { return value.StartsWith(method.ToExtensionString()); } internal static bool IsControl(this byte opcode) { return opcode > 7 && opcode < 16; } internal static bool IsControl(this Opcode opcode) { return (int)opcode >= 8; } internal static bool IsData(this byte opcode) { return opcode == 1 || opcode == 2; } internal static bool IsData(this Opcode opcode) { return opcode == Opcode.Text || opcode == Opcode.Binary; } internal static bool IsPortNumber(this int value) { return value > 0 && value < 65536; } internal static bool IsReserved(this ushort code) { return code == 1004 || code == 1005 || code == 1006 || code == 1015; } internal static bool IsReserved(this CloseStatusCode code) { return code == CloseStatusCode.Undefined || code == CloseStatusCode.NoStatus || code == CloseStatusCode.Abnormal || code == CloseStatusCode.TlsHandshakeFailure; } internal static bool IsSupported(this byte opcode) { return Enum.IsDefined(typeof(Opcode), opcode); } internal static bool IsText(this string value) { int length = value.Length; for (int i = 0; i < length; i++) { char c = value[i]; if (c < ' ' && !Contains("\r\n\t", c)) { return false; } switch (c) { case '\u007f': return false; case '\n': if (++i < length) { c = value[i]; if (!Contains(" \t", c)) { return false; } } break; } } return true; } internal static bool IsToken(this string value) { foreach (char c in value) { if (c < ' ' || c >= '\u007f' || Contains("()<>@,;:\\\"/[]?={} \t", c)) { return false; } } return true; } internal static string Quote(this string value) { return string.Format("\"{0}\"", value.Replace("\"", "\\\"")); } internal static byte[] ReadBytes(this Stream stream, int length) { byte[] array = new byte[length]; int num = 0; try { int num2 = 0; while (length > 0) { num2 = stream.Read(array, num, length); if (num2 == 0) { break; } num += num2; length -= num2; } } catch { } return array.SubArray(0, num); } internal static byte[] ReadBytes(this Stream stream, long length, int bufferLength) { using MemoryStream memoryStream = new MemoryStream(); try { byte[] buffer = new byte[bufferLength]; int num = 0; while (length > 0) { if (length < bufferLength) { bufferLength = (int)length; } num = stream.Read(buffer, 0, bufferLength); if (num == 0) { break; } memoryStream.Write(buffer, 0, num); length -= num; } } catch { } memoryStream.Close(); return memoryStream.ToArray(); } internal static void ReadBytesAsync(this Stream stream, int length, Action<byte[]> completed, Action<Exception> error) { byte[] buff = new byte[length]; int offset = 0; int retry = 0; AsyncCallback callback = null; callback = delegate(IAsyncResult ar) { try { int num = stream.EndRead(ar); if (num == 0 && retry < _retry) { retry++; stream.BeginRead(buff, offset, length, callback, null); } else if (num == 0 || num == length) { if (completed != null) { completed(buff.SubArray(0, offset + num)); } } else { retry = 0; offset += num; length -= num; stream.BeginRead(buff, offset, length, callback, null); } } catch (Exception obj2) { if (error != null) { error(obj2); } } }; try { stream.BeginRead(buff, offset, length, callback, null); } catch (Exception obj) { if (error != null) { error(obj); } } } internal static void ReadBytesAsync(this Stream stream, long length, int bufferLength, Action<byte[]> completed, Action<Exception> error) { MemoryStream dest = new MemoryStream(); byte[] buff = new byte[bufferLength]; int retry = 0; Action<long> read = null; read = delegate(long len) { if (len < bufferLength) { bufferLength = (int)len; } stream.BeginRead(buff, 0, bufferLength, delegate(IAsyncResult ar) { try { int num = stream.EndRead(ar); if (num > 0) { dest.Write(buff, 0, num); } if (num == 0 && retry < _retry) { retry++; read(len); } else if (num == 0 || num == len) { if (completed != null) { dest.Close(); completed(dest.ToArray()); } dest.Dispose(); } else { retry = 0; read(len - num); } } catch (Exception obj2) { dest.Dispose(); if (error != null) { error(obj2); } } }, null); }; try { read(length); } catch (Exception obj) { dest.Dispose(); if (error != null) { error(obj); } } } internal static string RemovePrefix(this string value, params string[] prefixes) { int num = 0; foreach (string text in prefixes) { if (value.StartsWith(text)) { num = text.Length; break; } } return (num > 0) ? value.Substring(num) : value; } internal static T[] Reverse<T>(this T[] array) { int num = array.Length; T[] array2 = new T[num]; int num2 = num - 1; for (int i = 0; i <= num2; i++) { array2[i] = array[num2 - i]; } return array2; } internal static IEnumerable<string> SplitHeaderValue(this string value, params char[] separators) { int len = value.Length; string seps = new string(separators); StringBuilder buff = new StringBuilder(32); bool escaped = false; bool quoted = false; for (int i = 0; i < len; i++) { char c = value[i]; switch (c) { case '"': if (escaped) { escaped = !escaped; } else { quoted = !quoted; } break; case '\\': if (i < len - 1 && value[i + 1] == '"') { escaped = true; } break; default: if (Contains(seps, c) && !quoted) { yield return buff.ToString(); buff.Length = 0; continue; } break; } buff.Append(c); } if (buff.Length > 0) { yield return buff.ToString(); } } internal static byte[] ToByteArray(this Stream stream) { using MemoryStream memoryStream = new MemoryStream(); stream.Position = 0L; CopyTo(stream, memoryStream, 1024); memoryStream.Close(); return memoryStream.ToArray(); } internal static CompressionMethod ToCompressionMethod(this string value) { foreach (CompressionMethod value2 in Enum.GetValues(typeof(CompressionMethod))) { if (value2.ToExtensionString() == value) { return value2; } } return CompressionMethod.None; } internal static string ToExtensionString(this CompressionMethod method, params string[] parameters) { if (method == CompressionMethod.None) { return string.Empty; } string text = $"permessage-{method.ToString().ToLower()}"; if (parameters == null || parameters.Length == 0) { return text; } return string.Format("{0}; {1}", text, parameters.ToString("; ")); } internal static IPAddress ToIPAddress(this string hostnameOrAddress) { if (IPAddress.TryParse(hostnameOrAddress, out IPAddress address)) { return address; } try { return Dns.GetHostAddresses(hostnameOrAddress)[0]; } catch { return null; } } internal static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { return new List<TSource>(source); } internal static ushort ToUInt16(this byte[] source, ByteOrder sourceOrder) { return BitConverter.ToUInt16(source.ToHostOrder(sourceOrder), 0); } internal static ulong ToUInt64(this byte[] source, ByteOrder sourceOrder) { return BitConverter.ToUInt64(source.ToHostOrder(sourceOrder), 0); } internal static string TrimEndSlash(this string value) { value = value.TrimEnd(new char[1] { '/' }); return (value.Length > 0) ? value : "/"; } internal static bool TryCreateWebSocketUri(this string uriString, out Uri result, out string message) { result = null; Uri uri = uriString.ToUri(); if (uri == null) { message = "An invalid URI string: " + uriString; return false; } if (!uri.IsAbsoluteUri) { message = "Not an absolute URI: " + uriString; return false; } string scheme = uri.Scheme; if (!(scheme == "ws") && !(scheme == "wss")) { message = "The scheme part isn't 'ws' or 'wss': " + uriString; return false; } if (uri.Fragment.Length > 0) { message = "Includes the fragment component: " + uriString; return false; } int port = uri.Port; if (port == 0) { message = "The port part is zero: " + uriString; return false; } result = ((port != -1) ? uri : new Uri(string.Format("{0}://{1}:{2}{3}", scheme, uri.Host, (scheme == "ws") ? 80 : 443, uri.PathAndQuery))); message = string.Empty; return true; } internal static string Unquote(this string value) { int num = value.IndexOf('"'); if (num < 0) { return value; } int num2 = value.LastIndexOf('"'); int num3 = num2 - num - 1; return (num3 < 0) ? value : ((num3 == 0) ? string.Empty : value.Substring(num + 1, num3).Replace("\\\"", "\"")); } internal static string UTF8Decode(this byte[] bytes) { try { return Encoding.UTF8.GetString(bytes); } catch { return null; } } internal static byte[] UTF8Encode(this string s) { return Encoding.UTF8.GetBytes(s); } internal static void WriteBytes(this Stream stream, byte[] bytes, int bufferLength) { using MemoryStream source = new MemoryStream(bytes); CopyTo(source, stream, bufferLength); } internal static void WriteBytesAsync(this Stream stream, byte[] bytes, int bufferLength, Action completed, Action<Exception> error) { MemoryStream input = new MemoryStream(bytes); input.CopyToAsync(stream, bufferLength, delegate { if (completed != null) { completed(); } input.Dispose(); }, delegate(Exception ex) { input.Dispose(); if (error != null) { error(ex); } }); } public static bool Contains(this string value, params char[] chars) { return chars == null || chars.Length == 0 || (value != null && value.Length != 0 && value.IndexOfAny(chars) > -1); } public static bool Contains(this NameValueCollection collection, string name) { return collection != null && collection.Count > 0 && collection[name] != null; } public static bool Contains(this NameValueCollection collection, string name, string value) { if (collection == null || collection.Count == 0) { return false; } string text = collection[name]; if (text == null) { return false; } string[] array = text.Split(new char[1] { ',' }); foreach (string text2 in array) { if (text2.Trim().Equals(value, StringComparison.OrdinalIgnoreCase)) { return true; } } return false; } public static void Emit(this EventHandler eventHandler, object sender, EventArgs e) { eventHandler?.Invoke(sender, e); } public static void Emit<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) where TEventArgs : EventArgs { eventHandler?.Invoke(sender, e); } public static WebSocketSharp.Net.CookieCollection GetCookies(this NameValueCollection headers, bool response) { string name = (response ? "Set-Cookie" : "Cookie"); return (headers != null && headers.Contains(name)) ? WebSocketSharp.Net.CookieCollection.Parse(headers[name], response) : new WebSocketSharp.Net.CookieCollection(); } public static string GetDescription(this WebSocketSharp.Net.HttpStatusCode code) { return ((int)code).GetStatusDescription(); } public static string GetStatusDescription(this int code) { return code switch { 100 => "Continue", 101 => "Switching Protocols", 102 => "Processing", 200 => "OK", 201 => "Created", 202 => "Accepted", 203 => "Non-Authoritative Information", 204 => "No Content", 205 => "Reset Content", 206 => "Partial Content", 207 => "Multi-Status", 300 => "Multiple Choices", 301 => "Moved Permanently", 302 => "Found", 303 => "See Other", 304 => "Not Modified", 305 => "Use Proxy", 307 => "Temporary Redirect", 400 => "Bad Request", 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", 404 => "Not Found", 405 => "Method Not Allowed", 406 => "Not Acceptable", 407 => "Proxy Authentication Required", 408 => "Request Timeout", 409 => "Conflict", 410 => "Gone", 411 => "Length Required", 412 => "Precondition Failed", 413 => "Request Entity Too Large", 414 => "Request-Uri Too Long", 415 => "Unsupported Media Type", 416 => "Requested Range Not Satisfiable", 417 => "Expectation Failed", 422 => "Unprocessable Entity", 423 => "Locked", 424 => "Failed Dependency", 500 => "Internal Server Error", 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", 504 => "Gateway Timeout", 505 => "Http Version Not Supported", 507 => "Insufficient Storage", _ => string.Empty, }; } public static bool IsCloseStatusCode(this ushort value) { return value > 999 && value < 5000; } public static bool IsEnclosedIn(this string value, char c) { return value != null && value.Length > 1 && value[0] == c && value[value.Length - 1] == c; } public static bool IsHostOrder(this ByteOrder order) { return !(BitConverter.IsLittleEndian ^ (order == ByteOrder.Little)); } public static bool IsLocal(this IPAddress address) { if (address == null) { return false; } if (address.Equals(IPAddress.Any)) { return true; } if (address.Equals(IPAddress.Loopback)) { return true; } if (Socket.OSSupportsIPv6) { if (address.Equals(IPAddress.IPv6Any)) { return true; } if (address.Equals(IPAddress.IPv6Loopback)) { return true; } } string hostName = Dns.GetHostName(); IPAddress[] hostAddresses = Dns.GetHostAddresses(hostName); IPAddress[] array = hostAddresses; foreach (IPAddress obj in array) { if (address.Equals(obj)) { return true; } } return false; } public static bool IsNullOrEmpty(this string value) { return value == null || value.Length == 0; } public static bool IsPredefinedScheme(this string value) { if (value == null || value.Length < 2) { return false; } char c = value[0]; if (c == 'h') { return value == "http" || value == "https"; } if (c == 'w') { return value == "ws" || value == "wss"; } if (c == 'f') { return value == "file" || value == "ftp"; } if (c == 'n') { c = value[1]; return (c != 'e') ? (value == "nntp") : (value == "news" || value == "net.pipe" || value == "net.tcp"); } return (c == 'g' && value == "gopher") || (c == 'm' && value == "mailto"); } public static bool IsUpgradeTo(this WebSocketSharp.Net.HttpListenerRequest request, string protocol) { if (request == null) { throw new ArgumentNullException("request"); } if (protocol == null) { throw new ArgumentNullException("protocol"); } if (protocol.Length == 0) { throw new ArgumentException("An empty string.", "protocol"); } return request.Headers.Contains("Upgrade", protocol) && request.Headers.Contains("Connection", "Upgrade"); } public static bool MaybeUri(this string value) { if (value == null || value.Length == 0) { return false; } int num = value.IndexOf(':'); if (num == -1) { return false; } if (num >= 10) { return false; } return value.Substring(0, num).IsPredefinedScheme(); } public static T[] SubArray<T>(this T[] array, int startIndex, int length) { int num; if (array == null || (num = array.Length) == 0) { return new T[0]; } if (startIndex < 0 || length <= 0 || startIndex + length > num) { return new T[0]; } if (startIndex == 0 && length == num) { return array; } T[] array2 = new T[length]; Array.Copy(array, startIndex, array2, 0, length); return array2; } public static T[] SubArray<T>(this T[] array, long startIndex, long length) { long longLength; if (array == null || (longLength = array.LongLength) == 0) { return new T[0]; } if (startIndex < 0 || length <= 0 || startIndex + length > longLength) { return new T[0]; } if (startIndex == 0 && length == longLength) { return array; } T[] array2 = new T[length]; Array.Copy(array, startIndex, array2, 0L, length); return array2; } public static void Times(this int n, Action action) { if (n > 0 && action != null) { ((ulong)n).times(action); } } public static void Times(this long n, Action action) { if (n > 0 && action != null) { ((ulong)n).times(action); } } public static void Times(this uint n, Action action) { if (n != 0 && action != null) { times(n, action); } } public static void Times(this ulong n, Action action) { if (n != 0 && action != null) { n.times(action); } } public static void Times(this int n, Action<int> action) { if (n > 0 && action != null) { for (int i = 0; i < n; i++) { action(i); } } } public static void Times(this long n, Action<long> action) { if (n > 0 && action != null) { for (long num = 0L; num < n; num++) { action(num); } } } public static void Times(this uint n, Action<uint> action) { if (n != 0 && action != null) { for (uint num = 0u; num < n; num++) { action(num); } } } public static void Times(this ulong n, Action<ulong> action) { if (n != 0 && action != null) { for (ulong num = 0uL; num < n; num++) { action(num); } } } public static T To<T>(this byte[] source, ByteOrder sourceOrder) where T : struct { if (source == null) { throw new ArgumentNullException("source"); } if (source.Length == 0) { return default(T); } Type typeFromHandle = typeof(T); byte[] value = source.ToHostOrder(sourceOrder); return ((object)typeFromHandle == typeof(bool)) ? ((T)(object)BitConverter.ToBoolean(value, 0)) : (((object)typeFromHandle == typeof(char)) ? ((T)(object)BitConverter.ToChar(value, 0)) : (((object)typeFromHandle == typeof(double)) ? ((T)(object)BitConverter.ToDouble(value, 0)) : (((object)typeFromHandle == typeof(short)) ? ((T)(object)BitConverter.ToInt16(value, 0)) : (((object)typeFromHandle == typeof(int)) ? ((T)(object)BitConverter.ToInt32(value, 0)) : (((object)typeFromHandle == typeof(long)) ? ((T)(object)BitConverter.ToInt64(value, 0)) : (((object)typeFromHandle == typeof(float)) ? ((T)(object)BitConverter.ToSingle(value, 0)) : (((object)typeFromHandle == typeof(ushort)) ? ((T)(object)BitConverter.ToUInt16(value, 0)) : (((object)typeFromHandle == typeof(uint)) ? ((T)(object)BitConverter.ToUInt32(value, 0)) : (((object)typeFromHandle == typeof(ulong)) ? ((T)(object)BitConverter.ToUInt64(value, 0)) : default(T)))))))))); } public static byte[] ToByteArray<T>(this T value, ByteOrder order) where T : struct { Type typeFromHandle = typeof(T); byte[] array = (((object)typeFromHandle == typeof(bool)) ? BitConverter.GetBytes((bool)(object)value) : (((object)typeFromHandle == typeof(byte)) ? new byte[1] { (byte)(object)value } : (((object)typeFromHandle == typeof(char)) ? BitConverter.GetBytes((char)(object)value) : (((object)typeFromHandle == typeof(double)) ? BitConverter.GetBytes((double)(object)value) : (((object)typeFromHandle == typeof(short)) ? BitConverter.GetBytes((short)(object)value) : (((object)typeFromHandle == typeof(int)) ? BitConverter.GetBytes((int)(object)value) : (((object)typeFromHandle == typeof(long)) ? BitConverter.GetBytes((long)(object)value) : (((object)typeFromHandle == typeof(float)) ? BitConverter.GetBytes((float)(object)value) : (((object)typeFromHandle == typeof(ushort)) ? BitConverter.GetBytes((ushort)(object)value) : (((object)typeFromHandle == typeof(uint)) ? BitConverter.GetBytes((uint)(object)value) : (((object)typeFromHandle == typeof(ulong)) ? BitConverter.GetBytes((ulong)(object)value) : WebSocket.EmptyBytes))))))))))); if (array.Length > 1 && !order.IsHostOrder()) { Array.Reverse((Array)array); } return array; } public static byte[] ToHostOrder(this byte[] source, ByteOrder sourceOrder) { if (source == null) { throw new ArgumentNullException("source"); } return (source.Length > 1 && !sourceOrder.IsHostOrder()) ? source.Reverse() : source; } public static string ToString<T>(this T[] array, string separator) { if (array == null) { throw new ArgumentNullException("array"); } int num = array.Length; if (num == 0) { return string.Empty; } if (separator == null) { separator = string.Empty; } StringBuilder buff = new StringBuilder(64); (num - 1).Times(delegate(int i) { buff.AppendFormat("{0}{1}", array[i].ToString(), separator); }); buff.Append(array[num - 1].ToString()); return buff.ToString(); } public static Uri ToUri(this string uriString) { Uri.TryCreate(uriString, uriString.MaybeUri() ? UriKind.Absolute : UriKind.Relative, out Uri result); return result; } public static string UrlDecode(this string value) { return (value != null && value.Length > 0) ? HttpUtility.UrlDecode(value) : value; } public static string UrlEncode(this string value) { return (value != null && value.Length > 0) ? HttpUtility.UrlEncode(value) : value; } public static void WriteContent(this WebSocketSharp.Net.HttpListenerResponse response, byte[] content) { if (response == null) { throw new ArgumentNullException("response"); } if (content == null) { throw new ArgumentNullException("content"); } long longLength = content.LongLength; if (longLength == 0) { response.Close(); return; } response.ContentLength64 = longLength; Stream outputStream = response.OutputStream; if (longLength <= int.MaxValue) { outputStream.Write(content, 0, (int)longLength); } else { outputStream.WriteBytes(content, 1024); } outputStream.Close(); } static Ext() { byte[] last = new byte[1]; _last = last; _retry = 5; } } public class MessageEventArgs : EventArgs { private string _data; private bool _dataSet; private Opcode _opcode; private byte[] _rawData; public string Data { get { if (!_dataSet) { _data = ((_opcode != Opcode.Binary) ? _rawData.UTF8Decode() : BitConverter.ToString(_rawData)); _dataSet = true; } return _data; } } public bool IsBinary => _opcode == Opcode.Binary; public bool IsPing => _opcode == Opcode.Ping; public bool IsText => _opcode == Opcode.Text; public byte[] RawData => _rawData; [Obsolete("This property will be removed. Use any of the Is properties instead.")] public Opcode Type => _opcode; internal MessageEventArgs(WebSocketFrame frame) { _opcode = frame.Opcode; _rawData = frame.PayloadData.ApplicationData; } internal MessageEventArgs(Opcode opcode, byte[] rawData) { if ((ulong)rawData.LongLength > PayloadData.MaxLength) { throw new WebSocketException(CloseStatusCode.TooBig); } _opcode = opcode; _rawData = rawData; } } public class CloseEventArgs : EventArgs { private bool _clean; private ushort _code; private PayloadData _payloadData; private string _reason; internal PayloadData PayloadData => _payloadData ?? (_payloadData = new PayloadData(_code.Append(_reason))); public ushort Code => _code; public string Reason => _reason ?? string.Empty; public bool WasClean { get { return _clean; } internal set { _clean = value; } } internal CloseEventArgs() { _code = 1005; _payloadData = PayloadData.Empty; } internal CloseEventArgs(ushort code) { _code = code; } internal CloseEventArgs(CloseStatusCode code) : this((ushort)code) { } internal CloseEventArgs(PayloadData payloadData) { _payloadData = payloadData; byte[] applicationData = payloadData.ApplicationData; int num = applicationData.Length; _code = (ushort)((num > 1) ? applicationData.SubArray(0, 2).ToUInt16(ByteOrder.Big) : 1005); _reason = ((num > 2) ? applicationData.SubArray(2, num - 2).UTF8Decode() : string.Empty); } internal CloseEventArgs(ushort code, string reason) { _code = code; _reason = reason; } internal CloseEventArgs(CloseStatusCode code, string reason) : this((ushort)code, reason) { } } public enum ByteOrder { Little, Big } public class ErrorEventArgs : EventArgs { private Exception _exception; private string _message; public Exception Exception => _exception; public string Message => _message; internal ErrorEventArgs(string message) : this(message, null) { } internal ErrorEventArgs(string message, Exception exception) { _message = message; _exception = exception; } } public class WebSocket : IDisposable { private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private const string _version = "13"; private AuthenticationChallenge _authChallenge; private string _base64Key; private bool _client; private Action _closeContext; private CompressionMethod _compression; private WebSocketContext _context; private WebSocketSharp.Net.CookieCollection _cookies; private WebSocketSharp.Net.NetworkCredential _credentials; private bool _emitOnPing; private bool _enableRedirection; private AutoResetEvent _exitReceiving; private string _extensions; private bool _extensionsRequested; private object _forConn; private object _forMessageEventQueue; private object _forSend; private MemoryStream _fragmentsBuffer; private bool _fragmentsCompressed; private Opcode _fragmentsOpcode; private Func<WebSocketContext, string> _handshakeRequestChecker; private bool _ignoreExtensions; private bool _inContinuation; private volatile bool _inMessage; private volatile Logger _logger; private Action<MessageEventArgs> _message; private Queue<MessageEventArgs> _messageEventQueue; private uint _nonceCount; private string _origin; private bool _preAuth; private string _protocol; private string[] _protocols; private bool _protocolsRequested; private WebSocketSharp.Net.NetworkCredential _proxyCredentials; private Uri _proxyUri; private volatile WebSocketState _readyState; private AutoResetEvent _receivePong; private bool _secure; private ClientSslConfiguration _sslConfig; private Stream _stream; private TcpClient _tcpClient; private Uri _uri; private TimeSpan _waitTime; internal static readonly byte[] EmptyBytes; internal static readonly int FragmentLength; internal static readonly RandomNumberGenerator RandomNumber; internal WebSocketSharp.Net.CookieCollection CookieCollection => _cookies; internal Func<WebSocketContext, string> CustomHandshakeRequestChecker { get { return _handshakeRequestChecker; } set { _handshakeRequestChecker = value; } } internal bool HasMessage { get { lock (_forMessageEventQueue) { return _messageEventQueue.Count > 0; } } } internal bool IgnoreExtensions { get { return _ignoreExtensions; } set { _ignoreExtensions = value; } } internal bool IsConnected => _readyState == WebSocketState.Open || _readyState == WebSocketState.Closing; public CompressionMethod Compression { get { return _compression; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the compression.", null); } else { _compression = value; } } } } public IEnumerable<WebSocketSharp.Net.Cookie> Cookies { get { object syncRoot; object obj = (syncRoot = _cookies.SyncRoot); Monitor.Enter(syncRoot); try { foreach (WebSocketSharp.Net.Cookie cookie in _cookies) { yield return cookie; } } finally { Monitor.Exit(obj); } } } public WebSocketSharp.Net.NetworkCredential Credentials => _credentials; public bool EmitOnPing { get { return _emitOnPing; } set { _emitOnPing = value; } } public bool EnableRedirection { get { return _enableRedirection; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the enable redirection.", null); } else { _enableRedirection = value; } } } } public string Extensions => _extensions ?? string.Empty; public bool IsAlive => Ping(); public bool IsSecure => _secure; public Logger Log { get { return _logger; } internal set { _logger = value; } } public string Origin { get { return _origin; } set { lock (_forConn) { Uri result; if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the origin.", null); } else if (value.IsNullOrEmpty()) { _origin = value; } else if (!Uri.TryCreate(value, UriKind.Absolute, out result) || result.Segments.Length > 1) { _logger.Error("The syntax of an origin must be '<scheme>://<host>[:<port>]'."); error("An error has occurred in setting the origin.", null); } else { _origin = value.TrimEnd(new char[1] { '/' }); } } } } public string Protocol { get { return _protocol ?? string.Empty; } internal set { _protocol = value; } } public WebSocketState ReadyState => _readyState; public ClientSslConfiguration SslConfiguration { get { return _client ? (_sslConfig ?? (_sslConfig = new ClientSslConfiguration(_uri.DnsSafeHost))) : null; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the ssl configuration.", null); } else { _sslConfig = value; } } } } public Uri Url => _client ? _uri : _context.RequestUri; public TimeSpan WaitTime { get { return _waitTime; } set { lock (_forConn) { if (!checkIfAvailable(client: true, server: true, connecting: true, open: false, closing: false, closed: true, out var text) || !value.CheckWaitTime(out text)) { _logger.Error(text); error("An error has occurred in setting the wait time.", null); } else { _waitTime = value; } } } } public event EventHandler<CloseEventArgs> OnClose; public event EventHandler<ErrorEventArgs> OnError; public event EventHandler<MessageEventArgs> OnMessage; public event EventHandler OnOpen; static WebSocket() { EmptyBytes = new byte[0]; FragmentLength = 1016; RandomNumber = new RNGCryptoServiceProvider(); } internal WebSocket(HttpListenerWebSocketContext context, string protocol) { _context = context; _protocol = protocol; _closeContext = context.Close; _logger = context.Log; _message = messages; _secure = context.IsSecureConnection; _stream = context.Stream; _waitTime = TimeSpan.FromSeconds(1.0); init(); } internal WebSocket(TcpListenerWebSocketContext context, string protocol) { _context = context; _protocol = protocol; _closeContext = context.Close; _logger = context.Log; _message = messages; _secure = context.IsSecureConnection; _stream = context.Stream; _waitTime = TimeSpan.FromSeconds(1.0); init(); } public WebSocket(string url, params string[] protocols) { if (url == null) { throw new ArgumentNullException("url"); } if (url.Length == 0) { throw new ArgumentException("An empty string.", "url"); } if (!url.TryCreateWebSocketUri(out _uri, out var text)) { throw new ArgumentException(text, "url"); } if (protocols != null && protocols.Length > 0) { text = protocols.CheckIfValidProtocols(); if (text != null) { throw new ArgumentException(text, "protocols"); } _protocols = protocols; } _base64Key = CreateBase64Key(); _client = true; _logger = new Logger(); _message = messagec; _secure = _uri.Scheme == "wss"; _waitTime = TimeSpan.FromSeconds(5.0); init(); } private bool accept() { lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in accepting.", null); return false; } try { if (!acceptHandshake()) { return false; } _readyState = WebSocketState.Open; } catch (Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while accepting.", ex); return false; } return true; } } private bool acceptHandshake() { _logger.Debug($"A request from {_context.UserEndPoint}:\n{_context}"); if (!checkHandshakeRequest(_context, out var text)) { sendHttpResponse(createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest)); _logger.Fatal(text); fatal("An error has occurred while accepting.", CloseStatusCode.ProtocolError); return false; } if (!customCheckHandshakeRequest(_context, out text)) { sendHttpResponse(createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest)); _logger.Fatal(text); fatal("An error has occurred while accepting.", CloseStatusCode.PolicyViolation); return false; } _base64Key = _context.Headers["Sec-WebSocket-Key"]; if (_protocol != null) { processSecWebSocketProtocolHeader(_context.SecWebSocketProtocols); } if (!_ignoreExtensions) { processSecWebSocketExtensionsClientHeader(_context.Headers["Sec-WebSocket-Extensions"]); } return sendHttpResponse(createHandshakeResponse()); } private bool checkHandshakeRequest(WebSocketContext context, out string message) { message = null; if (context.RequestUri == null) { message = "Specifies an invalid Request-URI."; return false; } if (!context.IsWebSocketRequest) { message = "Not a WebSocket handshake request."; return false; } NameValueCollection headers = context.Headers; if (!validateSecWebSocketKeyHeader(headers["Sec-WebSocket-Key"])) { message = "Includes no Sec-WebSocket-Key header, or it has an invalid value."; return false; } if (!validateSecWebSocketVersionClientHeader(headers["Sec-WebSocket-Version"])) { message = "Includes no Sec-WebSocket-Version header, or it has an invalid value."; return false; } if (!validateSecWebSocketProtocolClientHeader(headers["Sec-WebSocket-Protocol"])) { message = "Includes an invalid Sec-WebSocket-Protocol header."; return false; } if (!_ignoreExtensions && !validateSecWebSocketExtensionsClientHeader(headers["Sec-WebSocket-Extensions"])) { message = "Includes an invalid Sec-WebSocket-Extensions header."; return false; } return true; } private bool checkHandshakeResponse(HttpResponse response, out string message) { message = null; if (response.IsRedirect) { message = "Indicates the redirection."; return false; } if (response.IsUnauthorized) { message = "Requires the authentication."; return false; } if (!response.IsWebSocketResponse) { message = "Not a WebSocket handshake response."; return false; } NameValueCollection headers = response.Headers; if (!validateSecWebSocketAcceptHeader(headers["Sec-WebSocket-Accept"])) { message = "Includes no Sec-WebSocket-Accept header, or it has an invalid value."; return false; } if (!validateSecWebSocketProtocolServerHeader(headers["Sec-WebSocket-Protocol"])) { message = "Includes no Sec-WebSocket-Protocol header, or it has an invalid value."; return false; } if (!validateSecWebSocketExtensionsServerHeader(headers["Sec-WebSocket-Extensions"])) { message = "Includes an invalid Sec-WebSocket-Extensions header."; return false; } if (!validateSecWebSocketVersionServerHeader(headers["Sec-WebSocket-Version"])) { message = "Includes an invalid Sec-WebSocket-Version header."; return false; } return true; } private bool checkIfAvailable(bool connecting, bool open, bool closing, bool closed, out string message) { message = null; if (!connecting && _readyState == WebSocketState.Connecting) { message = "This operation isn't available in: connecting"; return false; } if (!open && _readyState == WebSocketState.Open) { message = "This operation isn't available in: open"; return false; } if (!closing && _readyState == WebSocketState.Closing) { message = "This operation isn't available in: closing"; return false; } if (!closed && _readyState == WebSocketState.Closed) { message = "This operation isn't available in: closed"; return false; } return true; } private bool checkIfAvailable(bool client, bool server, bool connecting, bool open, bool closing, bool closed, out string message) { message = null; if (!client && _client) { message = "This operation isn't available in: client"; return false; } if (!server && !_client) { message = "This operation isn't available in: server"; return false; } return checkIfAvailable(connecting, open, closing, closed, out message); } private bool checkReceivedFrame(WebSocketFrame frame, out string message) { message = null; bool isMasked = frame.IsMasked; if (_client && isMasked) { message = "A frame from the server is masked."; return false; } if (!_client && !isMasked) { message = "A frame from a client isn't masked."; return false; } if (_inContinuation && frame.IsData) { message = "A data frame has been received while receiving continuation frames."; return false; } if (frame.IsCompressed && _compression == CompressionMethod.None) { message = "A compressed frame has been received without any agreement for it."; return false; } if (frame.Rsv2 == Rsv.On) { message = "The RSV2 of a frame is non-zero without any negotiation for it."; return false; } if (frame.Rsv3 == Rsv.On) { message = "The RSV3 of a frame is non-zero without any negotiation for it."; return false; } return true; } private void close(CloseEventArgs e, bool send, bool receive, bool received) { lock (_forConn) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has been closed."); return; } send = send && _readyState == WebSocketState.Open; receive = receive && send; _readyState = WebSocketState.Closing; } _logger.Trace("Begin closing the connection."); byte[] frameAsBytes = (send ? WebSocketFrame.CreateCloseFrame(e.PayloadData, _client).ToArray() : null); e.WasClean = closeHandshake(frameAsBytes, receive, received); releaseResources(); _logger.Trace("End closing the connection."); _readyState = WebSocketState.Closed; try { this.OnClose.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during the OnClose event.", ex); } } private void closeAsync(CloseEventArgs e, bool send, bool receive, bool received) { Action<CloseEventArgs, bool, bool, bool> closer = close; closer.BeginInvoke(e, send, receive, received, delegate(IAsyncResult ar) { closer.EndInvoke(ar); }, null); } private bool closeHandshake(byte[] frameAsBytes, bool receive, bool received) { bool flag = frameAsBytes != null && sendBytes(frameAsBytes); received = received || (receive && flag && _exitReceiving != null && _exitReceiving.WaitOne(_waitTime)); bool flag2 = flag && received; _logger.Debug($"Was clean?: {flag2}\n sent: {flag}\n received: {received}"); return flag2; } private bool connect() { lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in connecting.", null); return false; } try { _readyState = WebSocketState.Connecting; if (!doHandshake()) { return false; } _readyState = WebSocketState.Open; } catch (Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while connecting.", ex); return false; } return true; } } private string createExtensions() { StringBuilder stringBuilder = new StringBuilder(80); if (_compression != 0) { string arg = _compression.ToExtensionString("server_no_context_takeover", "client_no_context_takeover"); stringBuilder.AppendFormat("{0}, ", arg); } int length = stringBuilder.Length; if (length > 2) { stringBuilder.Length = length - 2; return stringBuilder.ToString(); } return null; } private HttpResponse createHandshakeFailureResponse(WebSocketSharp.Net.HttpStatusCode code) { HttpResponse httpResponse = HttpResponse.CreateCloseResponse(code); httpResponse.Headers["Sec-WebSocket-Version"] = "13"; return httpResponse; } private HttpRequest createHandshakeRequest() { HttpRequest httpRequest = HttpRequest.CreateWebSocketRequest(_uri); NameValueCollection headers = httpRequest.Headers; if (!_origin.IsNullOrEmpty()) { headers["Origin"] = _origin; } headers["Sec-WebSocket-Key"] = _base64Key; _protocolsRequested = _protocols != null; if (_protocolsRequested) { headers["Sec-WebSocket-Protocol"] = _protocols.ToString(", "); } _extensionsRequested = _compression != CompressionMethod.None; if (_extensionsRequested) { headers["Sec-WebSocket-Extensions"] = createExtensions(); } headers["Sec-WebSocket-Version"] = "13"; AuthenticationResponse authenticationResponse = null; if (_authChallenge != null && _credentials != null) { authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount); _nonceCount = authenticationResponse.NonceCount; } else if (_preAuth) { authenticationResponse = new AuthenticationResponse(_credentials); } if (authenticationResponse != null) { headers["Authorization"] = authenticationResponse.ToString(); } if (_cookies.Count > 0) { httpRequest.SetCookies(_cookies); } return httpRequest; } private HttpResponse createHandshakeResponse() { HttpResponse httpResponse = HttpResponse.CreateWebSocketResponse(); NameValueCollection headers = httpResponse.Headers; headers["Sec-WebSocket-Accept"] = CreateResponseKey(_base64Key); if (_protocol != null) { headers["Sec-WebSocket-Protocol"] = _protocol; } if (_extensions != null) { headers["Sec-WebSocket-Extensions"] = _extensions; } if (_cookies.Count > 0) { httpResponse.SetCookies(_cookies); } return httpResponse; } private bool customCheckHandshakeRequest(WebSocketContext context, out string message) { message = null; return _handshakeRequestChecker == null || (message = _handshakeRequestChecker(context)) == null; } private MessageEventArgs dequeueFromMessageEventQueue() { lock (_forMessageEventQueue) { return (_messageEventQueue.Count > 0) ? _messageEventQueue.Dequeue() : null; } } private bool doHandshake() { setClientStream(); HttpResponse httpResponse = sendHandshakeRequest(); if (!checkHandshakeResponse(httpResponse, out var text)) { _logger.Fatal(text); fatal("An error has occurred while connecting.", CloseStatusCode.ProtocolError); return false; } if (_protocolsRequested) { _protocol = httpResponse.Headers["Sec-WebSocket-Protocol"]; } if (_extensionsRequested) { processSecWebSocketExtensionsServerHeader(httpResponse.Headers["Sec-WebSocket-Extensions"]); } processCookies(httpResponse.Cookies); return true; } private void enqueueToMessageEventQueue(MessageEventArgs e) { lock (_forMessageEventQueue) { _messageEventQueue.Enqueue(e); } } private void error(string message, Exception exception) { try { this.OnError.Emit(this, new ErrorEventArgs(message, exception)); } catch (Exception ex) { _logger.Error(ex.ToString()); } } private void fatal(string message, Exception exception) { CloseStatusCode code = ((exception is WebSocketException) ? ((WebSocketException)exception).Code : CloseStatusCode.Abnormal); fatal(message, code); } private void fatal(string message, CloseStatusCode code) { close(new CloseEventArgs(code, message), !code.IsReserved(), receive: false, received: false); } private void init() { _compression = CompressionMethod.None; _cookies = new WebSocketSharp.Net.CookieCollection(); _forConn = new object(); _forSend = new object(); _messageEventQueue = new Queue<MessageEventArgs>(); _forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot; _readyState = WebSocketState.Connecting; } private void message() { MessageEventArgs obj = null; lock (_forMessageEventQueue) { if (_inMessage || _messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { return; } _inMessage = true; obj = _messageEventQueue.Dequeue(); } _message(obj); } private void messagec(MessageEventArgs e) { while (true) { try { this.OnMessage.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during an OnMessage event.", ex); } lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { _inMessage = false; break; } e = _messageEventQueue.Dequeue(); } bool flag = true; } } private void messages(MessageEventArgs e) { try { this.OnMessage.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during an OnMessage event.", ex); } lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { _inMessage = false; return; } e = _messageEventQueue.Dequeue(); } ThreadPool.QueueUserWorkItem(delegate { messages(e); }); } private void open() { _inMessage = true; startReceiving(); try { this.OnOpen.Emit(this, EventArgs.Empty); } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during the OnOpen event.", ex); } MessageEventArgs obj = null; lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { _inMessage = false; return; } obj = _messageEventQueue.Dequeue(); } _message.BeginInvoke(obj, delegate(IAsyncResult ar) { _message.EndInvoke(ar); }, null); } private bool processCloseFrame(WebSocketFrame frame) { PayloadData payloadData = frame.PayloadData; close(new CloseEventArgs(payloadData), !payloadData.IncludesReservedCloseStatusCode, receive: false, received: true); return false; } private void processCookies(WebSocketSharp.Net.CookieCollection cookies) { if (cookies.Count != 0) { _cookies.SetOrRemove(cookies); } } private bool processDataFrame(WebSocketFrame frame) { enqueueToMessageEventQueue(frame.IsCompressed ? new MessageEventArgs(frame.Opcode, frame.PayloadData.ApplicationData.Decompress(_compression)) : new MessageEventArgs(frame)); return true; } private bool processFragmentFrame(WebSocketFrame frame) { if (!_inContinuation) { if (frame.IsContinuation) { return true; } _fragmentsOpcode = frame.Opcode; _fragmentsCompressed = frame.IsCompressed; _fragmentsBuffer = new MemoryStream(); _inContinuation = true; } _fragmentsBuffer.WriteBytes(frame.PayloadData.ApplicationData, 1024); if (frame.IsFinal) { using (_fragmentsBuffer) { byte[] rawData = (_fragmentsCompressed ? _fragmentsBuffer.DecompressToArray(_compression) : _fragmentsBuffer.ToArray()); enqueueToMessageEventQueue(new MessageEventArgs(_fragmentsOpcode, rawData)); } _fragmentsBuffer = null; _inContinuation = false; } return true; } private bool processPingFrame(WebSocketFrame frame) { if (send(new WebSocketFrame(Opcode.Pong, frame.PayloadData, _client).ToArray())) { _logger.Trace("Returned a pong."); } if (_emitOnPing) { enqueueToMessageEventQueue(new MessageEventArgs(frame)); } return true; } private bool processPongFrame(WebSocketFrame frame) { _receivePong.Set(); _logger.Trace("Received a pong."); return true; } private bool processReceivedFrame(WebSocketFrame frame) { if (!checkReceivedFrame(frame, out var text)) { throw new WebSocketException(CloseStatusCode.ProtocolError, text); } frame.Unmask(); return frame.IsFragment ? processFragmentFrame(frame) : (frame.IsData ? processDataFrame(frame) : (frame.IsPing ? processPingFrame(frame) : (frame.IsPong ? processPongFrame(frame) : (frame.IsClose ? processCloseFrame(frame) : processUnsupportedFrame(frame))))); } private void processSecWebSocketExtensionsClientHeader(string value) { if (value == null) { return; } StringBuilder stringBuilder = new StringBuilder(80); bool flag = false; foreach (string item in value.SplitHeaderValue(',')) { string value2 = item.Trim(); if (!flag && value2.IsCompressionExtension(CompressionMethod.Deflate)) { _compression = CompressionMethod.Deflate; stringBuilder.AppendFormat("{0}, ", _compression.ToExtensionString("client_no_context_takeover", "server_no_context_takeover")); flag = true; } } int length = stringBuilder.Length; if (length > 2) { stringBuilder.Length = length - 2; _extensions = stringBuilder.ToString(); } } private void processSecWebSocketExtensionsServerHeader(string value) { if (value == null) { _compression = CompressionMethod.None; } else { _extensions = value; } } private void processSecWebSocketProtocolHeader(IEnumerable<string> values) { if (!values.Contains((string p) => p == _protocol)) { _protocol = null; } } private bool processUnsupportedFrame(WebSocketFrame frame) { _logger.Fatal("An unsupported frame:" + frame.PrintToString(dumped: false)); fatal("There is no way to handle it.", CloseStatusCode.PolicyViolation); return false; } private void releaseClientResources() { if (_stream != null) { _stream.Dispose(); _stream = null; } if (_tcpClient != null) { _tcpClient.Close(); _tcpClient = null; } } private void releaseCommonResources() { if (_fragmentsBuffer != null) { _fragmentsBuffer.Dispose(); _fragmentsBuffer = null; _inContinuation = false; } if (_receivePong != null) { _receivePong.Close(); _receivePong = null; } if (_exitReceiving != null) { _exitReceiving.Close(); _exitReceiving = null; } } private void releaseResources() { if (_client) { releaseClientResources(); } else { releaseServerResources(); } releaseCommonResources(); } private void releaseServerResources() { if (_closeContext != null) { _closeContext(); _closeContext = null; _stream = null; _context = null; } } private bool send(byte[] frameAsBytes) { lock (_forConn) { if (_readyState != WebSocketState.Open) { _logger.Error("The sending has been interrupted."); return false; } return sendBytes(frameAsBytes); } } private bool send(Opcode opcode, Stream stream) { lock (_forSend) { Stream stream2 = stream; bool flag = false; bool flag2 = false; try { if (_compression != 0) { stream = stream.Compress(_compression); flag = true; } flag2 = send(opcode, stream, flag); if (!flag2) { error("The sending has been interrupted.", null); } } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred while sending data.", ex); } finally { if (flag) { stream.Dispose(); } stream2.Dispose(); } return flag2; } } private bool send(Opcode opcode, Stream stream, bool compressed) { long length = stream.Length; if (length == 0) { return send(Fin.Final, opcode, EmptyBytes, compressed); } long num = length / FragmentLength; int num2 = (int)(length % FragmentLength); byte[] array = null; if (num == 0) { array = new byte[num2]; return stream.Read(array, 0, num2) == num2 && send(Fin.Final, opcode, array, compressed); } array = new byte[FragmentLength]; if (num == 1 && num2 == 0) { return stream.Read(array, 0, FragmentLength) == FragmentLength && send(Fin.Final, opcode, array, compressed); } if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, opcode, array, compressed)) { return false; } long num3 = ((num2 == 0) ? (num - 2) : (num - 1)); for (long num4 = 0L; num4 < num3; num4++) { if (stream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, Opcode.Cont, array, compressed)) { return false; } } if (num2 == 0) { num2 = FragmentLength; } else { array = new byte[num2]; } return stream.Read(array, 0, num2) == num2 && send(Fin.Final, Opcode.Cont, array, compressed); } private bool send(Fin fin, Opcode opcode, byte[] data, bool compressed) { lock (_forConn) { if (_readyState != WebSocketState.Open) { _logger.Error("The sending has been interrupted."); return false; } return sendBytes(new WebSocketFrame(fin, opcode, data, compressed, _client).ToArray()); } } private void sendAsync(Opcode opcode, Stream stream, Action<bool> completed) { Func<Opcode, Stream, bool> sender = send; sender.BeginInvoke(opcode, stream, delegate(IAsyncResult ar) { try { bool obj = sender.EndInvoke(ar); if (completed != null) { completed(obj); } } catch (Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred during a send callback.", ex); } }, null); } private bool sendBytes(byte[] bytes) { try { _stream.Write(bytes, 0, bytes.Length); return true; } catch (Exception ex) { _logger.Error(ex.ToString()); return false; } } private HttpResponse sendHandshakeRequest() { HttpRequest httpRequest = createHandshakeRequest(); HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000); if (httpResponse.IsUnauthorized) { string text = httpResponse.Headers["WWW-Authenticate"]; _logger.Warn($"Received an authentication requirement for '{text}'."); if (text.IsNullOrEmpty()) { _logger.Error("No authentication challenge is specified."); return httpResponse; } _authChallenge = AuthenticationChallenge.Parse(text); if (_authChallenge == null) { _logger.Error("An invalid authentication challenge is specified."); return httpResponse; } if (_credentials != null && (!_preAuth || _authChallenge.Scheme == WebSocketSharp.Net.AuthenticationSchemes.Digest)) { if (httpResponse.HasConnectionClose) { releaseClientResources(); setClientStream(); } AuthenticationResponse authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount); _nonceCount = authenticationResponse.NonceCount; httpRequest.Headers["Authorization"] = authenticationResponse.ToString(); httpResponse = sendHttpRequest(httpRequest, 15000); } } if (httpResponse.IsRedirect) { string text2 = httpResponse.Headers["Location"]; _logger.Warn($"Received a redirection to '{text2}'."); if (_enableRedirection) { if (text2.IsNullOrEmpty()) { _logger.Error("No url to redirect is located."); return httpResponse; } if (!text2.TryCreateWebSocketUri(out var result, out var text3)) { _logger.Error("An invalid url to redirect is located: " + text3); return httpResponse; } releaseClientResources(); _uri = result; _secure = result.Scheme == "wss"; setClientStream(); return sendHandshakeRequest(); } } return httpResponse; } private HttpResponse sendHttpRequest(HttpRequest request, int millisecondsTimeout) { _logger.Debug("A request to the server:\n" + request.ToString()); HttpResponse response = request.GetResponse(_stream, millisecondsTimeout); _logger.Debug("A response to this request:\n" + response.ToString()); return response; } private bool sendHttpResponse(HttpResponse response) { _logger.Debug("A response to this request:\n" + response.ToString()); return sendBytes(response.ToByteArray()); } private void sendProxyConnectRequest() { HttpRequest httpRequest = HttpRequest.CreateConnectRequest(_uri); HttpResponse httpResponse = sendHttpRequest(httpRequest, 90000); if (httpResponse.IsProxyAuthenticationRequired) { string text = httpResponse.Headers["Proxy-Authenticate"]; _logger.Warn($"Received a proxy authentication requirement for '{text}'."); if (text.IsNullOrEmpty()) { throw new WebSocketException("No proxy authentication challenge is specified."); } AuthenticationChallenge authenticationChallenge = AuthenticationChallenge.Parse(text); if (authenticationChallenge == null) { throw new WebSocketException("An invalid proxy authentication challenge is specified."); } if (_proxyCredentials != null) { if (httpResponse.HasConnectionClose) { releaseClientResources(); _tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port); _stream = _tcpClient.GetStream(); } AuthenticationResponse authenticationResponse = new AuthenticationResponse(authenticationChallenge, _proxyCredentials, 0u); httpRequest.Headers["Proxy-Authorization"] = authenticationResponse.ToString(); httpResponse = sendHttpRequest(httpRequest, 15000); } if (httpResponse.IsProxyAuthenticationRequired) { throw new WebSocketException("A proxy authentication is required."); } } if (httpResponse.StatusCode[0] != '2') { throw new WebSocketException("The proxy has failed a connection to the requested host and port."); } } private void setClientStream() { if (_proxyUri != null) { _tcpClient = new TcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port); _stream = _tcpClient.GetStream(); sendProxyConnectRequest(); } else { _tcpClient = new TcpClient(_uri.DnsSafeHost, _uri.Port); _stream = _tcpClient.GetStream(); } if (_secure) { ClientSslConfiguration sslConfiguration = SslConfiguration; string targetHost = sslConfiguration.TargetHost; if (targetHost != _uri.DnsSafeHost) { throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, "An invalid host name is specified."); } try { SslStream sslStream = new SslStream(_stream, leaveInnerStreamOpen: false, sslConfiguration.ServerCertificateValidationCallback, sslConfiguration.ClientCertificateSelectionCallback); sslStream.AuthenticateAsClient(targetHost, sslConfiguration.ClientCertificates, sslConfiguration.EnabledSslProtocols, sslConfiguration.CheckCertificateRevocation); _stream = sslStream; } catch (Exception innerException) { throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, innerException); } } } private void startReceiving() { if (_messageEventQueue.Count > 0) { _messageEventQueue.Clear(); } _exitReceiving = new AutoResetEvent(initialState: false); _receivePong = new AutoResetEvent(initialState: false); Action receive = null; receive = delegate { WebSocketFrame.ReadFrameAsync(_stream, unmask: false, delegate(WebSocketFrame frame) { if (!processReceivedFrame(frame) || _readyState == WebSocketState.Closed) { _exitReceiving?.Set(); } else { receive(); if (!_inMessage && HasMessage && _readyState == WebSocketState.Open) { message(); } } }, delegate(Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while receiving.", ex); }); }; receive(); } private bool validateSecWebSocketAcceptHeader(string value) { return value != null && value == CreateResponseKey(_base64Key); } private bool validateSecWebSocketExtensionsClientHeader(string value) { return value == null || value.Length > 0; } private bool validateSecWebSocketExtensionsServerHeader(string value) { if (value == null) { return true; } if (value.Length == 0) { return false; } if (!_extensionsRequested) { return false; } bool flag = _compression != CompressionMethod.None; foreach (string item in value.SplitHeaderValue(',')) { string text = item.Trim(); if (flag && text.IsCompressionExtension(_compression)) { if (!text.Contains("server_no_context_takeover")) { _logger.Error("The server hasn't sent back 'server_no_context_takeover'."); return false; } if (!text.Contains("client_no_context_takeover")) { _logger.Warn("The server hasn't sent back 'client_no_context_takeover'."); } string method = _compression.ToExtensionString(); if (text.SplitHeaderValue(';').Contains(delegate(string t) { t = t.Trim(); return t != method && t != "server_no_context_takeover" && t != "client_no_context_takeover"; })) { return false; } continue; } return false; } return true; } private bool validateSecWebSocketKeyHeader(string value) { return value != null && value.Length > 0; } private bool validateSecWebSocketProtocolClientHeader(string value) { return value == null || value.Length > 0; } private bool validateSecWebSocketProtocolServerHeader(string value) { if (value == null) { return !_protocolsRequested; } if (value.Length == 0) { return false; } return _protocolsRequested && _protocols.Contains((string p) => p == value); } private bool validateSecWebSocketVersionClientHeader(string value) { return value != null && value == "13"; } private bool validateSecWebSocketVersionServerHeader(string value) { return value == null || value == "13"; } internal static string CheckCloseParameters(ushort code, string reason, bool client) { return (!code.IsCloseStatusCode()) ? "An invalid close status code." : ((code != 1005) ? ((code == 1010 && !client) ? "MandatoryExtension cannot be used by a server." : ((code == 1011 && client) ? "ServerError cannot be used by a client." : ((!reason.IsNullOrEmpty() && reason.UTF8Encode().Length > 123) ? "A reason has greater than the allowable max size." : null))) : ((!reason.IsNullOrEmpty()) ? "NoStatus cannot have a reason." : null)); } internal static string CheckCloseParameters(CloseStatusCode code, string reason, bool client) { return (code != CloseStatusCode.NoStatus) ? ((code == CloseStatusCode.MandatoryExtension && !client) ? "MandatoryExtension cannot be used by a server." : ((code == CloseStatusCode.ServerError && client) ? "ServerError cannot be used by a client." : ((!reason.IsNullOrEmpty() && reason.UTF8Encode().Length > 123) ? "A reason has greater than the allowable max size." : null))) : ((!reason.IsNullOrEmpty()) ? "NoStatus cannot have a reason." : null); } internal static string CheckPingParameter(string message, out byte[] bytes) { bytes = message.UTF8Encode(); return (bytes.Length > 125) ? "A message has greater than the allowable max size." : null; } internal static string CheckSendParameter(byte[] data) { return (data == null) ? "'data' is null." : null; } internal static string CheckSendParameter(FileInfo file) { return (file == null) ? "'file' is null." : null; } internal static string CheckSendParameter(string data) { return (data == null) ? "'data' is null." : null; } internal static string CheckSendParameters(Stream stream, int length) { return (stream == null) ? "'stream' is null." : ((!stream.CanRead) ? "'stream' cannot be read." : ((length < 1) ? "'length' is less than 1." : null)); } internal void Close(HttpResponse response) { _readyState = WebSocketState.Closing; sendHttpResponse(response); releaseServerResources(); _readyState = WebSocketState.Closed; } internal void Close(WebSocketSharp.Net.HttpStatusCode code) { Close(createHandshakeFailureResponse(code)); } internal void Close(CloseEventArgs e, byte[] frameAsBytes, bool receive) { lock (_forConn) { if (_readyState == WebSocketState.Closing) { _logger.Info("The closing is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _logger.Info("The connection has been closed."); return; } _readyState = WebSocketState.Closing; } e.WasClean = closeHandshake(frameAsBytes, receive, received: false); releaseServerResources(); releaseCommonResources(); _readyState = WebSocketState.Closed; try { this.OnClose.Emit(this, e); } catch (Exception ex) { _logger.Error(ex.ToString()); } } internal static string CreateBase64Key() { byte[] array = new byte[16]; RandomNumber.GetBytes(array); return Convert.ToBase64String(array); } internal static string CreateResponseKey(string base64Key) { StringBuilder stringBuilder = new StringBuilder(base64Key, 64); stringBuilder.Append("258EAFA5-E914-47DA-95CA-C5AB0DC85B11"); SHA1 sHA = new SHA1CryptoServiceProvider(); byte[] inArray = sHA.ComputeHash(stringBuilder.ToString().UTF8Encode()); return Convert.ToBase64String(inArray); } internal void InternalAccept() { try { if (!acceptHandshake()) { return; } _readyState = WebSocketState.Open; } catch (Exception ex) { _logger.Fatal(ex.ToString()); fatal("An exception has occurred while accepting.", ex); return; } open(); } internal bool Ping(byte[] frameAsBytes, TimeSpan timeout) { if (_readyState != WebSocketState.Open) { return false; } if (!send(frameAsBytes)) { return false; } return _receivePong?.WaitOne(timeout) ?? false; } internal void Send(Opcode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache) { lock (_forSend) { lock (_forConn) { if (_readyState != WebSocketState.Open) { _logger.Error("The sending has been interrupted."); return; } try { if (!cache.TryGetValue(_compression, out var value)) { value = new WebSocketFrame(Fin.Final, opcode, data.Compress(_compression), _compression != CompressionMethod.None, mask: false).ToArray(); cache.Add(_compression, value); } sendBytes(value); } catch (Exception ex) { _logger.Error(ex.ToString()); } } } } internal void Send(Opcode opcode, Stream stream, Dictionary<CompressionMethod, Stream> cache) { lock (_forSend) { try { if (!cache.TryGetValue(_compression, out var value)) { value = stream.Compress(_compression); cache.Add(_compression, value); } else { value.Position = 0L; } send(opcode, value, _compression != CompressionMethod.None); } catch (Exception ex) { _logger.Error(ex.ToString()); } } } public void Accept() { if (!checkIfAvailable(client: false, server: true, connecting: true, open: false, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in accepting.", null); } else if (accept()) { open(); } } public void AcceptAsync() { if (!checkIfAvailable(client: false, server: true, connecting: true, open: false, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in accepting.", null); return; } Func<bool> acceptor = accept; acceptor.BeginInvoke(delegate(IAsyncResult ar) { if (acceptor.EndInvoke(ar)) { open(); } }, null); } public void Close() { if (!checkIfAvailable(connecting: true, open: true, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else { close(new CloseEventArgs(), send: true, receive: true, received: false); } } public void Close(ushort code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code), receive, receive, received: false); } } public void Close(CloseStatusCode code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code), receive, receive, received: false); } } public void Close(ushort code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void Close(CloseStatusCode code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { close(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); close(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void CloseAsync() { if (!checkIfAvailable(connecting: true, open: true, closing: false, closed: false, out var text)) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } } public void CloseAsync(ushort code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code), receive, receive, received: false); } } public void CloseAsync(CloseStatusCode code) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, null, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code), receive, receive, received: false); } } public void CloseAsync(ushort code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == 1005) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void CloseAsync(CloseStatusCode code, string reason) { string text = _readyState.CheckIfAvailable(connecting: true, open: true, closing: false, closed: false) ?? CheckCloseParameters(code, reason, _client); if (text != null) { _logger.Error(text); error("An error has occurred in closing the connection.", null); } else if (code == CloseStatusCode.NoStatus) { closeAsync(new CloseEventArgs(), send: true, receive: true, received: false); } else { bool receive = !code.IsReserved(); closeAsync(new CloseEventArgs(code, reason), receive, receive, received: false); } } public void Connect() { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in connecting.", null); } else if (connect()) { open(); } } public void ConnectAsync() { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in connecting.", null); return; } Func<bool> connector = connect; connector.BeginInvoke(delegate(IAsyncResult ar) { if (connector.EndInvoke(ar)) { open(); } }, null); } public bool Ping() { byte[] frameAsBytes = (_client ? WebSocketFrame.CreatePingFrame(mask: true).ToArray() : WebSocketFrame.EmptyPingBytes); return Ping(frameAsBytes, _waitTime); } public bool Ping(string message) { if (message == null || message.Length == 0) { return Ping(); } byte[] bytes; string text = CheckPingParameter(message, out bytes); if (text != null) { _logger.Error(text); error("An error has occurred in sending a ping.", null); return false; } return Ping(WebSocketFrame.CreatePingFrame(bytes, _client).ToArray(), _waitTime); } public void Send(byte[] data) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { send(Opcode.Binary, new MemoryStream(data)); } } public void Send(FileInfo file) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(file); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { send(Opcode.Binary, file.OpenRead()); } } public void Send(string data) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { send(Opcode.Text, new MemoryStream(data.UTF8Encode())); } } public void SendAsync(byte[] data, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { sendAsync(Opcode.Binary, new MemoryStream(data), completed); } } public void SendAsync(FileInfo file, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(file); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { sendAsync(Opcode.Binary, file.OpenRead(), completed); } } public void SendAsync(string data, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameter(data); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); } else { sendAsync(Opcode.Text, new MemoryStream(data.UTF8Encode()), completed); } } public void SendAsync(Stream stream, int length, Action<bool> completed) { string text = _readyState.CheckIfAvailable(connecting: false, open: true, closing: false, closed: false) ?? CheckSendParameters(stream, length); if (text != null) { _logger.Error(text); error("An error has occurred in sending data.", null); return; } stream.ReadBytesAsync(length, delegate(byte[] data) { int num = data.Length; if (num == 0) { _logger.Error("The data cannot be read from 'stream'."); error("An error has occurred in sending data.", null); } else { if (num < length) { _logger.Warn($"The length of the data is less than 'length':\n expected: {length}\n actual: {num}"); } bool obj = send(Opcode.Binary, new MemoryStream(data)); if (completed != null) { completed(obj); } } }, delegate(Exception ex) { _logger.Error(ex.ToString()); error("An exception has occurred while sending data.", ex); }); } public void SetCookie(WebSocketSharp.Net.Cookie cookie) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting a cookie.", null); return; } lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out text)) { _logger.Error(text); error("An error has occurred in setting a cookie.", null); return; } if (cookie == null) { _logger.Error("'cookie' is null."); error("An error has occurred in setting a cookie.", null); return; } lock (_cookies.SyncRoot) { _cookies.SetOrRemove(cookie); } } } public void SetCredentials(string username, string password, bool preAuth) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the credentials.", null); return; } lock (_forConn) { if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out text)) { _logger.Error(text); error("An error has occurred in setting the credentials.", null); } else if (username.IsNullOrEmpty()) { _logger.Warn("The credentials are set back to the default."); _credentials = null; _preAuth = false; } else if (Ext.Contains(username, ':') || !username.IsText()) { _logger.Error("'username' contains an invalid character."); error("An error has occurred in setting the credentials.", null); } else if (!password.IsNullOrEmpty() && !password.IsText()) { _logger.Error("'password' contains an invalid character."); error("An error has occurred in setting the credentials.", null); } else { _credentials = new WebSocketSharp.Net.NetworkCredential(username, password, _uri.PathAndQuery); _preAuth = preAuth; } } } public void SetProxy(string url, string username, string password) { if (!checkIfAvailable(client: true, server: false, connecting: true, open: false, closing: false, closed: true, out var text)) { _logger.Error(text); error("An error has occurred in setting the proxy.", null); return; } lock (_forConn) { Uri result; if (!checkIfAvailable(connecting: true, open: false, closing: false, closed: true, out text)) { _logger.Error(text); error("An error has occurred in setting the proxy.", null); } else if (url.IsNullOrEmpty()) { _logger.Warn("The proxy url and credentials are set back to the default."); _proxyUri = null; _proxyCredentials = null; } else if (!Uri.TryCreate(url, UriKind.Absolute, out result) || result.Scheme != "http" || result.Segments.Length > 1) { _logger.Error("The syntax of a proxy url must be 'http://<host>[:<port>]'."); error("An error has occurred in setting the proxy.", null); } else if (username.IsNullOrEmpty()) { _logger.Warn("The proxy credentials are set back to the default."); _proxyUri = result; _proxyCredentials = null; } else if (Ext.Contains(username, ':') || !username.IsText()) { _logger.Error("'username' contains an invalid character."); error("An error has occurred in setting the proxy.", null); } else if (!password.IsNullOrEmpty() && !password.IsText()) { _logger.Error("'password' contains an invalid character."); error("An error has occurred in setting the proxy.", null); } else { _proxyUri = result; _proxyCredentials = new WebSocketSharp.Net.NetworkCredential(username, password, $"{_uri.DnsSafeHost}:{_uri.Port}"); } } } void IDisposable.Dispose() { close(new CloseEventArgs(CloseStatusCode.Away), send: true, receive: true, received: false); } } } namespace WebSocketSharp.Server { public class WebSocketServer { private IPAddress _address; private WebSocketSharp.Net.AuthenticationSchemes _authSchemes; private static readonly string _defaultRealm; private bool _dnsStyle; private string _hostname; private TcpListener _listener; private Logger _logger; private int _port; private string _realm; private Thread _receiveThread; private bool _reuseAddress; private bool _secure; private WebSocketServiceManager _services; private ServerSslConfiguration _sslConfig; private volatile ServerState _state; private object _sync; private Func<IIdentity, WebSocketSharp.Net.NetworkCredential> _userCredFinder; public IPAddress Address => _address; public WebSocketSharp.Net.AuthenticationSchemes AuthenticationSchemes { get { return _authSchemes; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _authSchemes = value; } } } public bool IsListening => _state == ServerState.Start; public bool IsSecure => _secure; public bool KeepClean { get { return _services.KeepClean; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _services.KeepClean = value; } } } public Logger Log => _logger; public int Port => _port; public string Realm { get { return _realm; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _realm = value; } } } public bool ReuseAddress { get { return _reuseAddress; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _reuseAddress = value; } } } public ServerSslConfiguration SslConfiguration { get { return _sslConfig ?? (_sslConfig = new ServerSslConfiguration(null)); } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _sslConfig = value; } } } public Func<IIdentity, WebSocketSharp.Net.NetworkCredential> UserCredentialsFinder { get { return _userCredFinder; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false); if (text != null) { _logger.Error(text); } else { _userCredFinder = value; } } } public TimeSpan WaitTime { get { return _services.WaitTime; } set { string text = _state.CheckIfAvailable(ready: true, start: false, shutting: false) ?? value.CheckIfValidWaitTime(); if (text != null) { _logger.Error(text); } else { _services.WaitTime = value; } } } public WebSocketServiceManager WebSocketServices => _services; static WebSocketServer() { _defaultRealm = "SECRET AREA"; } public WebSocketServer() { init(null, IPAddress.Any, 80, secure: false); } public WebSocketServer(int port) : this(port, port == 443) { } public WebSocketServer(string url) { if (url == null) { throw new ArgumentNullException("url"); } if (url.Length == 0) { throw new ArgumentException("An empty string.", "url"); } if (!tryCreateUri(url, out var result, out var message)) { throw new ArgumentException(message, "url"); } string dnsSafeHost = result.DnsSafeHost; IPAddress address = dnsSafeHost.ToIPAddress(); if (!address.IsLocal()) { throw new ArgumentException("The host part isn't a local host name: " + url, "url"); } init(dnsSafeHost, address, result.Port, result.Scheme == "wss"); } public WebSocketServer(int port, bool secure) { if (!port.IsPortNumber()) { throw new ArgumentOutOfRangeException("port", "Not between 1 and 65535 inclusive: " + port); } init(null, IPAddress.Any, port, secure); } public WebSocketServer(IPAddress address, int port) : this(address, port, port == 443) { } public WebSocketServer(IPAddress address, int port, bool secure) { if (address == null) { throw new ArgumentNullException("address"); } if (!address.IsLocal()) { throw new ArgumentException("Not a local IP address: " + address, "address"); } if (!port.IsPortNumber()) { throw new ArgumentOutOfRangeException("port", "Not between 1 and 65535 inclusive: " + port); } init(null, address, port, secure); } private void abort() { lock (_sync) { if (!IsListening) { return; } _state = ServerState.ShuttingDown; } _listener.Stop(); _services.Stop(new CloseEventArgs(CloseStatusCode.ServerError), send: true, receive: false); _state = ServerState.Stop; } private string checkIfCertificateExists() { return (_secure && (_sslConfig == null || _sslConfig.ServerCertificate == null)) ? "The secure connection requires a server certificate." : null; } private string getRealm() { string realm = _realm; return (realm != null && realm.Length > 0) ? realm : _defaultRealm; } private void init(string hostname, IPAddress address, int port, bool secure) { _hostname = hostname ?? address.ToString(); _address = address; _port = port; _secure = se