Please disclose if your mod was created primarily 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 HavocBot v0.1.2
HavocBot.dll
Decompiled 6 months agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security.Authentication; using System.Text; using System.Threading; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using UnityEngine; using WebSocketSharp; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyCompany("HavocBot")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("HavocBot")] [assembly: AssemblyTitle("HavocBot")] [assembly: AssemblyVersion("1.0.0.0")] [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.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace Havoc.ValheimDiscord { [BepInPlugin("havoc.bot.presence", "Havoc Bot Discord Presence", "0.1.0")] public class ValheimPresenceToDiscord : BaseUnityPlugin { public const string PluginGuid = "havoc.bot.presence"; public const string PluginName = "Havoc Bot Discord Presence"; public const string PluginVersion = "0.1.0"; private ConfigEntry<string> botToken; private ConfigEntry<int> intervalSeconds; private ConfigEntry<string> presenceActivityType; private ConfigEntry<string> manualPresenceText; private PropertyInfo znetInstanceProp; private FieldInfo znetPeersField; private FieldInfo znetServerPlayerLimitField; private DiscordGateway gateway; private float nextTickAt; private string lastPostText = ""; private FileSystemWatcher configWatcher; private void Awake() { botToken = ((BaseUnityPlugin)this).Config.Bind<string>("Discord", "BotToken", "", "Put your Discord Bot token here"); presenceActivityType = ((BaseUnityPlugin)this).Config.Bind<string>("Discord", "PresenceActivityType", "Watching", "Use: Watching|Playing|Listening"); intervalSeconds = ((BaseUnityPlugin)this).Config.Bind<int>("Update", "IntervalSeconds", 30, "How often to refresh counts (seconds)."); manualPresenceText = ((BaseUnityPlugin)this).Config.Bind<string>("Discord", "ManualPresenceText", "{onlineplayers}/10 Players Online", "Set the Discord presence text maximum players manually. Use {onlineplayers} to insert the current online player count."); Type type = AccessTools.TypeByName("ZNet"); if (type == null) { ((BaseUnityPlugin)this).Logger.LogError((object)"ZNet type not found. This must run on the dedicated server."); return; } znetInstanceProp = type.GetProperty("instance", BindingFlags.Static | BindingFlags.Public); znetPeersField = type.GetField("m_peers", BindingFlags.Instance | BindingFlags.NonPublic); znetServerPlayerLimitField = type.GetField("m_serverPlayerLimit", BindingFlags.Instance | BindingFlags.NonPublic) ?? type.GetField("m_serverPlayerLimit", BindingFlags.Instance | BindingFlags.Public); if (string.IsNullOrWhiteSpace(botToken.Value)) { ((BaseUnityPlugin)this).Logger.LogWarning((object)"BotToken is empty. Fill config and restart."); } else { string text = botToken.Value?.Trim(); if (!string.IsNullOrEmpty(text) && text.StartsWith("Bot ", StringComparison.OrdinalIgnoreCase)) { text = text.Substring(4).Trim(); } gateway = new DiscordGateway(text, ((BaseUnityPlugin)this).Logger); gateway.Connect(); } ((BaseUnityPlugin)this).Logger.LogInfo((object)"Havoc Bot Discord Presence 0.1.0 loaded."); StartConfigWatcher(); } private void Update() { if (!(Time.unscaledTime < nextTickAt)) { nextTickAt = Time.unscaledTime + (float)Mathf.Max(5, intervalSeconds.Value); if (!string.IsNullOrWhiteSpace(botToken.Value)) { int onlinePlayers = GetOnlinePlayers(); string activityName = manualPresenceText.Value.Replace("{onlineplayers}", onlinePlayers.ToString()); int activityType = ActivityTypeFromString(presenceActivityType.Value); gateway?.SetPresence("online", activityName, activityType); } } } private void OnApplicationQuit() { gateway?.SetPresence("dnd", "Offline", 3); Thread.Sleep(200); gateway?.Dispose(); } private void OnDestroy() { gateway?.SetPresence("dnd", "Offline", 3); Thread.Sleep(200); gateway?.Dispose(); if (configWatcher != null) { configWatcher.EnableRaisingEvents = false; configWatcher.Dispose(); configWatcher = null; } } private int GetOnlinePlayers() { object obj = znetInstanceProp?.GetValue(null); if (obj == null) { return 0; } return (znetPeersField?.GetValue(obj) as IList)?.Count ?? 0; } private static string JsonQuote(string s) { if (s == null) { s = ""; } s = s.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\n", "\\n") .Replace("\r", "\\r"); return "\"" + s + "\""; } private static int ActivityTypeFromString(string s) { if (string.Equals(s, "Playing", StringComparison.OrdinalIgnoreCase)) { return 0; } if (string.Equals(s, "Listening", StringComparison.OrdinalIgnoreCase)) { return 2; } return 3; } private void StartConfigWatcher() { string path = Path.Combine(Paths.ConfigPath, "havoc.bot.presence.cfg"); configWatcher = new FileSystemWatcher(Path.GetDirectoryName(path), Path.GetFileName(path)); configWatcher.NotifyFilter = NotifyFilters.Size | NotifyFilters.LastWrite; configWatcher.Changed += OnConfigFileChanged; configWatcher.EnableRaisingEvents = true; } private void OnConfigFileChanged(object sender, FileSystemEventArgs e) { try { Thread.Sleep(200); ((BaseUnityPlugin)this).Config.Reload(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"havoc bot config update successful"); } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("Config reload failed: " + ex.Message)); } } } internal sealed class DiscordGateway : IDisposable { private const string GatewayUrl = "wss://gateway.discord.gg/?v=10&encoding=json"; private readonly string token; private readonly ManualLogSource log; private WebSocket ws; private Timer heartbeatTimer; private int heartbeatIntervalMs = 45000; private DateTime lastAck = DateTime.UtcNow; private int? lastSeq; private bool isReady; private volatile bool disposing; private int reconnectBackoffMs = 2000; private readonly object connectLock = new object(); private bool connecting; private readonly List<DateTime> connectAttempts = new List<DateTime>(); private const int ConnectLimit = 100; private const int ConnectWindowMs = 60000; private const int TemporaryBanMs = 900000; private DateTime banUntil = DateTime.MinValue; private int reconnectScheduledFlag; private DateTime lastCloseLog = DateTime.MinValue; private int consecutive1005; private const int CloseLogThrottleMs = 60000; private const int Max1005BackoffMs = 300000; private string pendingStatus = "online"; private string pendingName = "Loading..."; private int pendingType = 3; private EventHandler onOpenHandler; private EventHandler<MessageEventArgs> onMessageHandler; private EventHandler<CloseEventArgs> onCloseHandler; private EventHandler<ErrorEventArgs> onErrorHandler; public DiscordGateway(string rawToken, ManualLogSource logger) { token = rawToken; log = logger; } public void Connect() { //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01eb: Expected O, but got Unknown lock (connectLock) { if (disposing) { return; } DateTime now = DateTime.UtcNow; if (now < banUntil) { log.LogWarning((object)$"Discord GW: in temporary backoff until {banUntil:O}, skipping Connect()"); return; } connectAttempts.RemoveAll((DateTime t) => (now - t).TotalMilliseconds > 60000.0); connectAttempts.Add(now); if (connectAttempts.Count > 100) { banUntil = now.AddMilliseconds(900000.0); log.LogWarning((object)$"Discord GW: excessive connect attempts detected ({connectAttempts.Count} in {60000}ms). Pausing reconnects until {banUntil:O}"); return; } if (connecting) { log.LogInfo((object)"Discord GW: Connect already in progress; ignoring duplicate call."); return; } connecting = true; try { if (ws != null) { try { if (onOpenHandler != null) { ws.OnOpen -= onOpenHandler; } if (onMessageHandler != null) { ws.OnMessage -= onMessageHandler; } if (onCloseHandler != null) { ws.OnClose -= onCloseHandler; } if (onErrorHandler != null) { ws.OnError -= onErrorHandler; } } catch { } try { ws.Close(); } catch { } ws = null; onOpenHandler = null; onMessageHandler = null; onCloseHandler = null; onErrorHandler = null; } } catch { } } try { ws = new WebSocket("wss://gateway.discord.gg/?v=10&encoding=json", Array.Empty<string>()); ws.SslConfiguration.EnabledSslProtocols = SslProtocols.Tls12; onOpenHandler = delegate { log.LogInfo((object)"Discord GW: connected"); reconnectBackoffMs = 2000; }; ws.OnOpen += onOpenHandler; onMessageHandler = delegate(object s, MessageEventArgs e) { if (e.IsText) { HandleMessage(e.Data); } }; ws.OnMessage += onMessageHandler; onCloseHandler = delegate(object s, CloseEventArgs e) { if (e.Code == 1005) { consecutive1005++; if ((DateTime.UtcNow - lastCloseLog).TotalMilliseconds > 60000.0) { lastCloseLog = DateTime.UtcNow; log.LogWarning((object)$"Discord GW: closed ({e.Code}) {e.Reason} (thr {consecutive1005})"); } TryReconnect(e.Code); } else { consecutive1005 = 0; lastCloseLog = DateTime.UtcNow; log.LogWarning((object)$"Discord GW: closed ({e.Code}) {e.Reason}"); TryReconnect(e.Code); } }; ws.OnClose += onCloseHandler; onErrorHandler = delegate(object s, ErrorEventArgs e) { log.LogWarning((object)("Discord GW error: " + e.Message)); }; ws.OnError += onErrorHandler; ws.ConnectAsync(); } catch (Exception ex) { log.LogWarning((object)("Discord GW connect failed: " + ex.Message)); TryReconnect(); } finally { lock (connectLock) { connecting = false; } } } public void SetPresence(string status, string activityName, int activityType) { pendingStatus = status ?? "online"; pendingName = activityName ?? ""; pendingType = activityType; if (isReady) { SendPresenceUpdate(); } } private void HandleMessage(string json) { try { if (json.Contains("\"op\":10")) { int num = json.IndexOf("heartbeat_interval", StringComparison.Ordinal); if (num >= 0) { int num2 = json.IndexOf(':', num); int num3 = json.IndexOfAny(new char[2] { ',', '}' }, num2 + 1); if (int.TryParse(json.Substring(num2 + 1, num3 - num2 - 1).Trim(), out var result)) { heartbeatIntervalMs = result; } } StartHeartbeat(); Identify(); } else if (json.Contains("\"op\":0")) { int num4 = json.IndexOf("\"s\":", StringComparison.Ordinal); if (num4 >= 0) { int num5 = json.IndexOfAny(new char[2] { ',', '}' }, num4 + 4); if (int.TryParse(json.Substring(num4 + 4, num5 - (num4 + 4)).Trim(), out var result2)) { lastSeq = result2; } } if (json.Contains("\"t\":\"READY\"")) { isReady = true; consecutive1005 = 0; SendPresenceUpdate(); } } else if (json.Contains("\"op\":11")) { lastAck = DateTime.UtcNow; } else if (json.Contains("\"op\":7")) { log.LogWarning((object)"Discord GW: RECONNECT requested"); ForceReconnect(); } else if (json.Contains("\"op\":9")) { log.LogWarning((object)"Discord GW: INVALID SESSION → full reconnect with jitter"); ForceReconnect(jitter: true); } } catch (Exception ex) { log.LogWarning((object)("Discord GW parse error: " + ex.Message)); } } private void Identify() { var obj = new { op = 2, d = new { token = token, properties = new { os = "linux", browser = "bepinex", device = "bepinex" }, intents = 0 } }; SendJson(obj); } private void StartHeartbeat() { try { heartbeatTimer?.Dispose(); } catch { } lastAck = DateTime.UtcNow; heartbeatTimer = new Timer(delegate { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 try { if (ws != null && (int)ws.ReadyState == 2) { SendJson(new { op = 1, d = lastSeq }); if ((DateTime.UtcNow - lastAck).TotalMilliseconds > (double)(heartbeatIntervalMs * 2)) { log.LogWarning((object)"Discord GW: heartbeat ACK timeout → reconnect"); ForceReconnect(); } } } catch (Exception ex) { log.LogWarning((object)("Heartbeat loop error: " + ex.Message)); } }, null, heartbeatIntervalMs, heartbeatIntervalMs); } private void SendPresenceUpdate() { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Invalid comparison between Unknown and I4 if (ws != null && (int)ws.ReadyState == 2 && isReady) { var obj = new { op = 3, d = new { since = (long?)null, activities = new[] { new { name = pendingName, type = pendingType } }, status = pendingStatus, afk = false } }; SendJson(obj); } } private void TryReconnect(int? closeCode = null) { if (disposing) { return; } if (DateTime.UtcNow < banUntil) { log.LogWarning((object)$"Discord GW: currently paused until {banUntil:O}, not scheduling reconnect."); } else { if (Interlocked.Exchange(ref reconnectScheduledFlag, 1) == 1) { return; } try { heartbeatTimer?.Dispose(); } catch { } heartbeatTimer = null; int delay; lock (connectLock) { delay = Math.Min(reconnectBackoffMs, 30000); reconnectBackoffMs = Math.Min(reconnectBackoffMs * 2, 30000); } if (closeCode.GetValueOrDefault() == 1005) { int num = Math.Min(delay * (1 + consecutive1005), 300000); delay = num; } Task.Run(async delegate { try { await Task.Delay(delay); if (!disposing && !(DateTime.UtcNow < banUntil)) { ForceReconnect(); } } finally { Interlocked.Exchange(ref reconnectScheduledFlag, 0); } }); } } private void ForceReconnect(bool jitter = false) { try { WebSocket obj = ws; if (obj != null) { obj.Close(); } } catch { } if (jitter) { Thread.Sleep(Random.Range(1000, 4000)); } Connect(); } private void SendJson(object obj) { try { string text = MiniJson.Serialize(obj); WebSocket obj2 = ws; if (obj2 != null) { obj2.Send(text); } } catch (Exception ex) { log.LogWarning((object)("Discord GW send error: " + ex.Message)); } } public void Dispose() { //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001d: Invalid comparison between Unknown and I4 disposing = true; try { if (ws != null && (int)ws.ReadyState == 2 && isReady) { pendingStatus = "dnd"; pendingName = "Offline"; pendingType = 3; SendPresenceUpdate(); Thread.Sleep(200); } } catch { } try { heartbeatTimer?.Dispose(); } catch { } try { if (ws != null) { try { if (onOpenHandler != null) { ws.OnOpen -= onOpenHandler; } if (onMessageHandler != null) { ws.OnMessage -= onMessageHandler; } if (onCloseHandler != null) { ws.OnClose -= onCloseHandler; } if (onErrorHandler != null) { ws.OnError -= onErrorHandler; } } catch { } } } catch { } try { WebSocket obj5 = ws; if (obj5 != null) { obj5.Close((CloseStatusCode)1000, "shutdown"); } } catch { } ws = null; isReady = false; } } internal static class MiniJson { public static string Serialize(object o) { StringBuilder stringBuilder = new StringBuilder(); WriteValue(o, stringBuilder); return stringBuilder.ToString(); } private static void WriteValue(object v, StringBuilder sb) { if (v == null) { sb.Append("null"); } else if (!(v is string text)) { if (!(v is bool flag)) { if (!(v is int value)) { if (!(v is long value2)) { if (!(v is float num)) { if (!(v is double num2)) { if (!(v is IDictionary<string, object> dictionary)) { if (v is IEnumerable enumerable) { sb.Append('['); bool flag2 = true; foreach (object item in enumerable) { if (!flag2) { sb.Append(','); } flag2 = false; WriteValue(item, sb); } sb.Append(']'); return; } Type type = v.GetType(); if (type.IsClass) { sb.Append('{'); bool flag3 = true; PropertyInfo[] properties = type.GetProperties(BindingFlags.Instance | BindingFlags.Public); foreach (PropertyInfo propertyInfo in properties) { if (propertyInfo.CanRead) { if (!flag3) { sb.Append(','); } flag3 = false; sb.Append('"').Append(propertyInfo.Name).Append("\":"); WriteValue(propertyInfo.GetValue(v, null), sb); } } sb.Append('}'); } else { sb.Append('"').Append(v.ToString()).Append('"'); } return; } sb.Append('{'); bool flag4 = true; foreach (KeyValuePair<string, object> item2 in dictionary) { if (!flag4) { sb.Append(','); } flag4 = false; sb.Append('"').Append(item2.Key).Append("\":"); WriteValue(item2.Value, sb); } sb.Append('}'); } else { sb.Append(num2.ToString(CultureInfo.InvariantCulture)); } } else { sb.Append(num.ToString(CultureInfo.InvariantCulture)); } } else { sb.Append(value2); } } else { sb.Append(value); } } else { sb.Append(flag ? "true" : "false"); } } else { sb.Append('"').Append(text.Replace("\\", "\\\\").Replace("\"", "\\\"")).Append('"'); } } } internal static class AccessTools { public static Type TypeByName(string name) { Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies(); for (int i = 0; i < assemblies.Length; i++) { Type type = assemblies[i].GetType(name, throwOnError: false); if (type != null) { return type; } } return null; } } }
websocket-sharp.dll
Decompiled 6 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.Linq; 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; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: AssemblyTitle("websocket-sharp")] [assembly: AssemblyDescription("A C# implementation of the WebSocket protocol client and server")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("websocket-sharp.dll")] [assembly: AssemblyCopyright("sta.blockhead")] [assembly: AssemblyTrademark("")] [assembly: AssemblyVersion("1.0.2.41709")] namespace WebSocketSharp { public static class Ext { [CompilerGenerated] private sealed class <SplitHeaderValue>d__55 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private string value; public string <>3__value; private char[] separators; public char[] <>3__separators; private int <len>5__1; private int <end>5__2; private StringBuilder <buff>5__3; private bool <escaped>5__4; private bool <quoted>5__5; private int <i>5__6; private char <c>5__7; string IEnumerator<string>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <SplitHeaderValue>d__55(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { <buff>5__3 = null; <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <len>5__1 = value.Length; <end>5__2 = <len>5__1 - 1; <buff>5__3 = new StringBuilder(32); <escaped>5__4 = false; <quoted>5__5 = false; <i>5__6 = 0; goto IL_01a9; case 1: <>1__state = -1; <buff>5__3.Length = 0; goto IL_0197; case 2: { <>1__state = -1; return false; } IL_01a9: if (<i>5__6 <= <end>5__2) { <c>5__7 = value[<i>5__6]; <buff>5__3.Append(<c>5__7); if (<c>5__7 == '"') { if (<escaped>5__4) { <escaped>5__4 = false; } else { <quoted>5__5 = !<quoted>5__5; } } else if (<c>5__7 == '\\') { if (<i>5__6 == <end>5__2) { goto IL_01c3; } if (value[<i>5__6 + 1] == '"') { <escaped>5__4 = true; } } else if (Array.IndexOf(separators, <c>5__7) > -1 && !<quoted>5__5) { <buff>5__3.Length--; <>2__current = <buff>5__3.ToString(); <>1__state = 1; return true; } goto IL_0197; } goto IL_01c3; IL_0197: <i>5__6++; goto IL_01a9; IL_01c3: <>2__current = <buff>5__3.ToString(); <>1__state = 2; return true; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<string> IEnumerable<string>.GetEnumerator() { <SplitHeaderValue>d__55 <SplitHeaderValue>d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; <SplitHeaderValue>d__ = this; } else { <SplitHeaderValue>d__ = new <SplitHeaderValue>d__55(0); } <SplitHeaderValue>d__.value = <>3__value; <SplitHeaderValue>d__.separators = <>3__separators; return <SplitHeaderValue>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<string>)this).GetEnumerator(); } } [CompilerGenerated] private sealed class <TrimEach>d__68 : IEnumerable<string>, IEnumerable, IEnumerator<string>, IDisposable, IEnumerator { private int <>1__state; private string <>2__current; private int <>l__initialThreadId; private IEnumerable<string> source; public IEnumerable<string> <>3__source; private IEnumerator<string> <>s__1; private string <elm>5__2; string IEnumerator<string>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <TrimEach>d__68(int <>1__state) { this.<>1__state = <>1__state; <>l__initialThreadId = Thread.CurrentThread.ManagedThreadId; } [DebuggerHidden] void IDisposable.Dispose() { int num = <>1__state; if (num == -3 || num == 1) { try { } finally { <>m__Finally1(); } } <>s__1 = null; <elm>5__2 = null; <>1__state = -2; } private bool MoveNext() { try { switch (<>1__state) { default: return false; case 0: <>1__state = -1; <>s__1 = source.GetEnumerator(); <>1__state = -3; break; case 1: <>1__state = -3; <elm>5__2 = null; break; } if (<>s__1.MoveNext()) { <elm>5__2 = <>s__1.Current; <>2__current = <elm>5__2.Trim(); <>1__state = 1; return true; } <>m__Finally1(); <>s__1 = null; return false; } catch { //try-fault ((IDisposable)this).Dispose(); throw; } } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } private void <>m__Finally1() { <>1__state = -1; if (<>s__1 != null) { <>s__1.Dispose(); } } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } [DebuggerHidden] IEnumerator<string> IEnumerable<string>.GetEnumerator() { <TrimEach>d__68 <TrimEach>d__; if (<>1__state == -2 && <>l__initialThreadId == Thread.CurrentThread.ManagedThreadId) { <>1__state = 0; <TrimEach>d__ = this; } else { <TrimEach>d__ = new <TrimEach>d__68(0); } <TrimEach>d__.source = <>3__source; return <TrimEach>d__; } [DebuggerHidden] IEnumerator IEnumerable.GetEnumerator() { return ((IEnumerable<string>)this).GetEnumerator(); } } private static readonly byte[] _last = new byte[1]; private static readonly int _maxRetry = 5; private const string _tspecials = "()<>@,;:\\\"/[]?={} \t"; 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; CompressionMode mode = CompressionMode.Compress; using DeflateStream deflateStream = new DeflateStream(memoryStream, mode, 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; CompressionMode mode = CompressionMode.Decompress; using DeflateStream sourceStream = new DeflateStream(stream, mode, leaveOpen: true); CopyTo(sourceStream, 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 bool isPredefinedScheme(this string value) { switch (value[0]) { case 'h': return value == "http" || value == "https"; case 'w': return value == "ws" || value == "wss"; case 'f': return value == "file" || value == "ftp"; case 'g': return value == "gopher"; case 'm': return value == "mailto"; case 'n': { char c = value[1]; return (c != 'e') ? (value == "nntp") : (value == "news" || value == "net.pipe" || value == "net.tcp"); } default: return false; } } internal static byte[] Append(this ushort code, string reason) { byte[] array = code.ToByteArray(ByteOrder.Big); if (reason == null || reason.Length == 0) { return array; } List<byte> list = new List<byte>(array); byte[] bytes = Encoding.UTF8.GetBytes(reason); list.AddRange(bytes); return list.ToArray(); } 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 bool Contains(this string value, params char[] anyOf) { return anyOf != null && anyOf.Length != 0 && value.IndexOfAny(anyOf) > -1; } internal static bool Contains(this NameValueCollection collection, string name) { return collection[name] != null; } internal static bool Contains(this NameValueCollection collection, string name, string value, StringComparison comparisonTypeForValue) { 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, comparisonTypeForValue)) { return true; } } return false; } 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; int end = len - 1; Func<int, bool> seek = null; seek = delegate(int idx) { if (idx == end) { return false; } string text = values[idx]; for (int i = idx + 1; i < len; i++) { if (values[i] == text) { return true; } } return seek(++idx); }; return seek(0); } internal static T[] Copy<T>(this T[] sourceArray, int length) { T[] array = new T[length]; Array.Copy(sourceArray, 0, array, 0, length); return array; } internal static T[] Copy<T>(this T[] sourceArray, long length) { T[] array = new T[length]; Array.Copy(sourceArray, 0L, array, 0L, length); return array; } internal static void CopyTo(this Stream sourceStream, Stream destinationStream, int bufferLength) { byte[] buffer = new byte[bufferLength]; while (true) { int num = sourceStream.Read(buffer, 0, bufferLength); if (num <= 0) { break; } destinationStream.Write(buffer, 0, num); } } internal static void CopyToAsync(this Stream sourceStream, Stream destinationStream, int bufferLength, Action completed, Action<Exception> error) { byte[] buff = new byte[bufferLength]; AsyncCallback callback = null; callback = delegate(IAsyncResult ar) { try { int num = sourceStream.EndRead(ar); if (num <= 0) { if (completed != null) { completed(); } } else { destinationStream.Write(buff, 0, num); sourceStream.BeginRead(buff, 0, bufferLength, callback, null); } } catch (Exception obj2) { if (error != null) { error(obj2); } } }; try { sourceStream.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 void Emit(this EventHandler eventHandler, object sender, EventArgs e) { eventHandler?.Invoke(sender, e); } internal static void Emit<TEventArgs>(this EventHandler<TEventArgs> eventHandler, object sender, TEventArgs e) where TEventArgs : EventArgs { eventHandler?.Invoke(sender, e); } 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 WebSocketSharp.Net.CookieCollection GetCookies(this NameValueCollection headers, bool response) { string name = (response ? "Set-Cookie" : "Cookie"); string text = headers[name]; return (text != null) ? WebSocketSharp.Net.CookieCollection.Parse(text, response) : new WebSocketSharp.Net.CookieCollection(); } internal static string GetDnsSafeHost(this Uri uri, bool bracketIPv6) { return (bracketIPv6 && uri.HostNameType == UriHostNameType.IPv6) ? uri.Host : uri.DnsSafeHost; } internal static string GetErrorMessage(this ushort code) { return code switch { 1002 => "A protocol error has occurred.", 1003 => "Unsupported data has been received.", 1006 => "An abnormal error has occurred.", 1007 => "Invalid data has been received.", 1008 => "A policy violation has occurred.", 1009 => "A too big message has been received.", 1010 => "The client did not receive expected extension(s).", 1011 => "The server got an internal error.", 1015 => "An error has occurred during a TLS handshake.", _ => string.Empty, }; } internal static string GetErrorMessage(this CloseStatusCode code) { return ((ushort)code).GetErrorMessage(); } 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 GetUTF8DecodedString(this byte[] bytes) { try { return Encoding.UTF8.GetString(bytes); } catch { return null; } } internal static byte[] GetUTF8EncodedBytes(this string s) { try { return Encoding.UTF8.GetBytes(s); } catch { return null; } } internal static string GetValue(this string nameAndValue, char separator) { return nameAndValue.GetValue(separator, unquote: false); } 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 bool IsCompressionExtension(this string value, CompressionMethod method) { string value2 = method.ToExtensionString(); StringComparison comparisonType = StringComparison.Ordinal; return value.StartsWith(value2, comparisonType); } internal static bool IsDefined(this CloseStatusCode code) { return Enum.IsDefined(typeof(CloseStatusCode), code); } internal static bool IsEqualTo(this int value, char c, Action<int> beforeComparing) { beforeComparing(value); return value == c; } internal static bool IsHttpMethod(this string value) { int result; switch (value) { default: result = ((value == "TRACE") ? 1 : 0); break; case "GET": case "HEAD": case "POST": case "PUT": case "DELETE": case "CONNECT": case "OPTIONS": result = 1; break; } return (byte)result != 0; } internal static bool IsPortNumber(this int value) { return value > 0 && value < 65536; } internal static bool IsReserved(this CloseStatusCode code) { return ((ushort)code).IsReservedStatusCode(); } internal static bool IsReservedStatusCode(this ushort code) { return code == 1004 || code == 1005 || code == 1006 || code == 1015; } internal static bool IsSupportedOpcode(this int 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 < ' ') { if ("\r\n\t".IndexOf(c) == -1) { return false; } if (c == '\n') { i++; if (i == length) { break; } c = value[i]; if (" \t".IndexOf(c) == -1) { return false; } } } else if (c == '\u007f') { return false; } } return true; } internal static bool IsToken(this string value) { foreach (char c in value) { if (c < ' ') { return false; } if (c > '~') { return false; } if ("()<>@,;:\\\"/[]?={} \t".IndexOf(c) > -1) { return false; } } return true; } internal static bool KeepsAlive(this NameValueCollection headers, Version version) { StringComparison comparisonTypeForValue = StringComparison.OrdinalIgnoreCase; return (version > WebSocketSharp.Net.HttpVersion.Version10) ? (!headers.Contains("Connection", "close", comparisonTypeForValue)) : headers.Contains("Connection", "keep-alive", comparisonTypeForValue); } internal static bool MaybeUri(this string value) { int num = value.IndexOf(':'); if (num < 2 || num > 9) { return false; } string value2 = value.Substring(0, num); return value2.isPredefinedScheme(); } internal static string Quote(this string value) { string format = "\"{0}\""; string arg = value.Replace("\"", "\\\""); return string.Format(format, arg); } internal static byte[] ReadBytes(this Stream stream, int length) { byte[] array = new byte[length]; int num = 0; int num2 = 0; while (length > 0) { int num3 = stream.Read(array, num, length); if (num3 <= 0) { if (num2 >= _maxRetry) { return array.SubArray(0, num); } num2++; } else { num2 = 0; num += num3; length -= num3; } } return array; } internal static byte[] ReadBytes(this Stream stream, long length, int bufferLength) { using MemoryStream memoryStream = new MemoryStream(); byte[] buffer = new byte[bufferLength]; int num = 0; while (length > 0) { if (length < bufferLength) { bufferLength = (int)length; } int num2 = stream.Read(buffer, 0, bufferLength); if (num2 <= 0) { if (num >= _maxRetry) { break; } num++; } else { num = 0; memoryStream.Write(buffer, 0, num2); length -= num2; } } memoryStream.Close(); return memoryStream.ToArray(); } internal static void ReadBytesAsync(this Stream stream, int length, Action<byte[]> completed, Action<Exception> error) { byte[] ret = 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) { if (retry < _maxRetry) { retry++; stream.BeginRead(ret, offset, length, callback, null); } else if (completed != null) { completed(ret.SubArray(0, offset)); } } else if (num == length) { if (completed != null) { completed(ret); } } else { retry = 0; offset += num; length -= num; stream.BeginRead(ret, offset, length, callback, null); } } catch (Exception obj2) { if (error != null) { error(obj2); } } }; try { stream.BeginRead(ret, 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) { if (retry < _maxRetry) { int num2 = retry; retry = num2 + 1; read(len); } else { if (completed != null) { dest.Close(); byte[] obj2 = dest.ToArray(); completed(obj2); } dest.Dispose(); } } else { dest.Write(buff, 0, num); if (num == len) { if (completed != null) { dest.Close(); byte[] obj3 = dest.ToArray(); completed(obj3); } dest.Dispose(); } else { retry = 0; read(len - num); } } } catch (Exception obj4) { dest.Dispose(); if (error != null) { error(obj4); } } }, null); }; try { read(length); } catch (Exception obj) { dest.Dispose(); if (error != null) { error(obj); } } } internal static T[] Reverse<T>(this T[] array) { long num = array.LongLength; T[] array2 = new T[num]; long num2 = num - 1; for (long num3 = 0L; num3 <= num2; num3++) { array2[num3] = array[num2 - num3]; } return array2; } internal static IEnumerable<string> SplitHeaderValue(this string value, params char[] separators) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <SplitHeaderValue>d__55(-2) { <>3__value = value, <>3__separators = separators }; } internal static byte[] ToByteArray(this Stream stream) { stream.Position = 0L; using MemoryStream memoryStream = new MemoryStream(); CopyTo(stream, memoryStream, 1024); memoryStream.Close(); return memoryStream.ToArray(); } internal static byte[] ToByteArray(this ushort value, ByteOrder order) { byte[] bytes = BitConverter.GetBytes(value); if (!order.IsHostOrder()) { Array.Reverse((Array)bytes); } return bytes; } internal static byte[] ToByteArray(this ulong value, ByteOrder order) { byte[] bytes = BitConverter.GetBytes(value); if (!order.IsHostOrder()) { Array.Reverse((Array)bytes); } return bytes; } internal static CompressionMethod ToCompressionMethod(this string value) { Array values = Enum.GetValues(typeof(CompressionMethod)); foreach (CompressionMethod item in values) { if (item.ToExtensionString() == value) { return item; } } return CompressionMethod.None; } internal static string ToExtensionString(this CompressionMethod method, params string[] parameters) { if (method == CompressionMethod.None) { return string.Empty; } string arg = method.ToString().ToLower(); string text = $"permessage-{arg}"; if (parameters == null || parameters.Length == 0) { return text; } string arg2 = parameters.ToString("; "); return $"{text}; {arg2}"; } internal static int ToInt32(this string numericString) { return int.Parse(numericString); } internal static IPAddress ToIPAddress(this string value) { if (value == null || value.Length == 0) { return null; } if (IPAddress.TryParse(value, out IPAddress address)) { return address; } try { IPAddress[] hostAddresses = Dns.GetHostAddresses(value); return hostAddresses[0]; } catch { return null; } } internal static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) { return new List<TSource>(source); } internal static string ToString(this IPAddress address, bool bracketIPv6) { return (bracketIPv6 && address.AddressFamily == AddressFamily.InterNetworkV6) ? $"[{address}]" : address.ToString(); } internal static ushort ToUInt16(this byte[] source, ByteOrder sourceOrder) { byte[] value = source.ToHostOrder(sourceOrder); return BitConverter.ToUInt16(value, 0); } internal static ulong ToUInt64(this byte[] source, ByteOrder sourceOrder) { byte[] value = source.ToHostOrder(sourceOrder); return BitConverter.ToUInt64(value, 0); } internal static Version ToVersion(this string versionString) { return new Version(versionString); } internal static IEnumerable<string> TrimEach(this IEnumerable<string> source) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <TrimEach>d__68(-2) { <>3__source = source }; } internal static string TrimSlashFromEnd(this string value) { string text = value.TrimEnd(new char[1] { '/' }); return (text.Length > 0) ? text : "/"; } internal static string TrimSlashOrBackslashFromEnd(this string value) { string text = value.TrimEnd('/', '\\'); return (text.Length > 0) ? text : value[0].ToString(); } internal static bool TryCreateVersion(this string versionString, out Version result) { result = null; try { result = new Version(versionString); } catch { return false; } return true; } internal static bool TryCreateWebSocketUri(this string uriString, out Uri result, out string message) { result = null; message = null; Uri uri = uriString.ToUri(); if (uri == null) { message = "An invalid URI string."; return false; } if (!uri.IsAbsoluteUri) { message = "A relative URI."; return false; } string scheme = uri.Scheme; if (!(scheme == "ws") && !(scheme == "wss")) { message = "The scheme part is not \"ws\" or \"wss\"."; return false; } int port = uri.Port; if (port == 0) { message = "The port part is zero."; return false; } if (uri.Fragment.Length > 0) { message = "It includes the fragment component."; return false; } if (port == -1) { port = ((scheme == "ws") ? 80 : 443); uriString = $"{scheme}://{uri.Host}:{port}{uri.PathAndQuery}"; result = new Uri(uriString); } else { result = uri; } return true; } internal static bool TryGetUTF8DecodedString(this byte[] bytes, out string s) { s = null; try { s = Encoding.UTF8.GetString(bytes); } catch { return false; } return true; } internal static bool TryGetUTF8EncodedBytes(this string s, out byte[] bytes) { bytes = null; try { bytes = Encoding.UTF8.GetBytes(s); } catch { return false; } return true; } internal static bool TryOpenRead(this FileInfo fileInfo, out FileStream fileStream) { fileStream = null; try { fileStream = fileInfo.OpenRead(); } catch { return false; } return true; } internal static string Unquote(this string value) { int num = value.IndexOf('"'); if (num == -1) { return value; } int num2 = value.LastIndexOf('"'); if (num2 == num) { return value; } int num3 = num2 - num - 1; return (num3 > 0) ? value.Substring(num + 1, num3).Replace("\\\"", "\"") : string.Empty; } internal static bool Upgrades(this NameValueCollection headers, string protocol) { StringComparison comparisonTypeForValue = StringComparison.OrdinalIgnoreCase; return headers.Contains("Upgrade", protocol, comparisonTypeForValue) && headers.Contains("Connection", "Upgrade", comparisonTypeForValue); } internal static string UrlDecode(this string value, Encoding encoding) { return (value.IndexOfAny(new char[2] { '%', '+' }) > -1) ? HttpUtility.UrlDecode(value, encoding) : value; } internal static string UrlEncode(this string value, Encoding encoding) { return HttpUtility.UrlEncode(value, encoding); } internal static void WriteBytes(this Stream stream, byte[] bytes, int bufferLength) { using MemoryStream sourceStream = new MemoryStream(bytes); CopyTo(sourceStream, stream, bufferLength); } internal static void WriteBytesAsync(this Stream stream, byte[] bytes, int bufferLength, Action completed, Action<Exception> error) { MemoryStream src = new MemoryStream(bytes); src.CopyToAsync(stream, bufferLength, delegate { if (completed != null) { completed(); } src.Dispose(); }, delegate(Exception ex) { src.Dispose(); if (error != null) { error(ex); } }); } 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) { if (value == null) { return false; } int length = value.Length; return length > 1 && value[0] == c && 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) { throw new ArgumentNullException("address"); } 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 T[] SubArray<T>(this T[] array, int startIndex, int length) { if (array == null) { throw new ArgumentNullException("array"); } int num = array.Length; if (num == 0) { if (startIndex != 0) { throw new ArgumentOutOfRangeException("startIndex"); } if (length != 0) { throw new ArgumentOutOfRangeException("length"); } return array; } if (startIndex < 0 || startIndex >= num) { throw new ArgumentOutOfRangeException("startIndex"); } if (length < 0 || length > num - startIndex) { throw new ArgumentOutOfRangeException("length"); } if (length == 0) { return new T[0]; } if (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) { if (array == null) { throw new ArgumentNullException("array"); } long num = array.LongLength; if (num == 0) { if (startIndex != 0) { throw new ArgumentOutOfRangeException("startIndex"); } if (length != 0) { throw new ArgumentOutOfRangeException("length"); } return array; } if (startIndex < 0 || startIndex >= num) { throw new ArgumentOutOfRangeException("startIndex"); } if (length < 0 || length > num - startIndex) { throw new ArgumentOutOfRangeException("length"); } if (length == 0) { return new T[0]; } if (length == num) { return array; } T[] array2 = new T[length]; Array.Copy(array, startIndex, array2, 0L, length); return array2; } 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 byte[] ToHostOrder(this byte[] source, ByteOrder sourceOrder) { if (source == null) { throw new ArgumentNullException("source"); } if (source.Length < 2) { return source; } if (sourceOrder.IsHostOrder()) { return source; } return source.Reverse(); } 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; } StringBuilder stringBuilder = new StringBuilder(64); int num2 = num - 1; for (int i = 0; i < num2; i++) { stringBuilder.AppendFormat("{0}{1}", array[i], separator); } stringBuilder.AppendFormat("{0}", array[num2]); return stringBuilder.ToString(); } public static Uri ToUri(this string value) { if (value == null || value.Length == 0) { return null; } UriKind uriKind = (value.MaybeUri() ? UriKind.Absolute : UriKind.Relative); Uri.TryCreate(value, uriKind, out Uri result); return result; } } public class MessageEventArgs : EventArgs { private string _data; private bool _dataSet; private Opcode _opcode; private byte[] _rawData; internal Opcode Opcode => _opcode; public string Data { get { setData(); return _data; } } public bool IsBinary => _opcode == Opcode.Binary; public bool IsPing => _opcode == Opcode.Ping; public bool IsText => _opcode == Opcode.Text; public byte[] RawData { get { setData(); return _rawData; } } 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; } private void setData() { if (_dataSet) { return; } if (_opcode == Opcode.Binary) { _dataSet = true; return; } if (_rawData.TryGetUTF8DecodedString(out var s)) { _data = s; } _dataSet = true; } } public class CloseEventArgs : EventArgs { private PayloadData _payloadData; private bool _wasClean; public ushort Code => _payloadData.Code; public string Reason => _payloadData.Reason; public bool WasClean => _wasClean; internal CloseEventArgs(PayloadData payloadData, bool clean) { _payloadData = payloadData; _wasClean = clean; } } 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 AuthenticationChallenge _authChallenge; private string _base64Key; private Action _closeContext; private CompressionMethod _compression; private WebSocketContext _context; private WebSocketSharp.Net.CookieCollection _cookies; private WebSocketSharp.Net.NetworkCredential _credentials; private bool _emitOnPing; private static readonly byte[] _emptyBytes; private bool _enableRedirection; private string _extensions; private object _forMessageEventQueue; private object _forPing; private object _forSend; private object _forState; private MemoryStream _fragmentsBuffer; private bool _fragmentsCompressed; private Opcode _fragmentsOpcode; private const string _guid = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; private Func<WebSocketContext, string> _handshakeRequestChecker; private Action<WebSocketContext> _handshakeRequestResponder; private WebSocketSharp.Net.CookieCollection _handshakeResponseCookies; private NameValueCollection _handshakeResponseHeaders; private bool _hasExtension; private bool _hasProtocol; private bool _ignoreExtensions; private bool _inContinuation; private volatile bool _inMessage; private bool _isClient; private bool _isSecure; private volatile Logger _log; private static readonly int _maxRetryCountForConnect; private Action<MessageEventArgs> _message; private Queue<MessageEventArgs> _messageEventQueue; private bool _noDelay; private uint _nonceCount; private string _origin; private ManualResetEvent _pongReceived; private bool _preAuth; private string _protocol; private string[] _protocols; private WebSocketSharp.Net.NetworkCredential _proxyCredentials; private Uri _proxyUri; private volatile WebSocketState _readyState; private ManualResetEvent _receivingExited; private int _retryCountForConnect; private Socket _socket; private ClientSslConfiguration _sslConfig; private Stream _stream; private TcpClient _tcpClient; private Uri _uri; private WebSocketSharp.Net.WebHeaderCollection _userHeaders; private const string _version = "13"; private TimeSpan _waitTime; internal static readonly int FragmentLength; internal static readonly RandomNumberGenerator RandomNumber; internal WebSocketSharp.Net.CookieCollection Cookies { get { if (_cookies == null) { _cookies = new WebSocketSharp.Net.CookieCollection(); } return _cookies; } } internal Func<WebSocketContext, string> CustomHandshakeRequestChecker { get { return _handshakeRequestChecker; } set { _handshakeRequestChecker = value; } } internal Action<WebSocketContext> CustomHandshakeRequestResponder { get { return _handshakeRequestResponder; } set { _handshakeRequestResponder = value; } } internal bool IgnoreExtensions { get { return _ignoreExtensions; } set { _ignoreExtensions = value; } } internal WebSocketSharp.Net.WebHeaderCollection UserHeaders { get { if (_userHeaders == null) { HttpHeaderType state = (_isClient ? HttpHeaderType.Request : HttpHeaderType.Response); _userHeaders = new WebSocketSharp.Net.WebHeaderCollection(state, internallyUsed: false); } return _userHeaders; } } public CompressionMethod Compression { get { return _compression; } set { if (!_isClient) { string text = "The set operation is not available."; throw new InvalidOperationException(text); } lock (_forState) { if (!canSet()) { string text2 = "The set operation is not available."; throw new InvalidOperationException(text2); } _compression = value; } } } public WebSocketSharp.Net.NetworkCredential Credentials => _credentials; public bool EmitOnPing { get { return _emitOnPing; } set { lock (_forState) { if (!canSet()) { string text = "The set operation is not available."; throw new InvalidOperationException(text); } _emitOnPing = value; } } } public bool EnableRedirection { get { return _enableRedirection; } set { if (!_isClient) { string text = "The set operation is not available."; throw new InvalidOperationException(text); } lock (_forState) { if (!canSet()) { string text2 = "The set operation is not available."; throw new InvalidOperationException(text2); } _enableRedirection = value; } } } public string Extensions => _extensions ?? string.Empty; public WebSocketSharp.Net.CookieCollection HandshakeResponseCookies { get { if (!_isClient) { string text = "The get operation is not available."; throw new InvalidOperationException(text); } lock (_forState) { if ((int)_readyState <= 1) { string text2 = "The get operation is not available."; throw new InvalidOperationException(text2); } return _handshakeResponseCookies; } } } public NameValueCollection HandshakeResponseHeaders { get { if (!_isClient) { string text = "The get operation is not available."; throw new InvalidOperationException(text); } lock (_forState) { if ((int)_readyState <= 1) { string text2 = "The get operation is not available."; throw new InvalidOperationException(text2); } return _handshakeResponseHeaders; } } } public bool IsAlive => ping(_emptyBytes); public bool IsSecure => _isSecure; public Logger Log { get { if (!_isClient) { string text = "The get operation is not available."; throw new InvalidOperationException(text); } return _log; } internal set { _log = value; } } public bool NoDelay { get { return _noDelay; } set { lock (_forState) { if (!canSet()) { string text = "The set operation is not available."; throw new InvalidOperationException(text); } _noDelay = value; } } } public string Origin { get { return _origin; } set { if (!_isClient) { string text = "The set operation is not available."; throw new InvalidOperationException(text); } if (!value.IsNullOrEmpty()) { if (!Uri.TryCreate(value, UriKind.Absolute, out Uri result)) { string text2 = "Not an absolute URI string."; throw new ArgumentException(text2, "value"); } if (result.Segments.Length > 1) { string text3 = "It includes the path segments."; throw new ArgumentException(text3, "value"); } } lock (_forState) { if (!canSet()) { string text4 = "The set operation is not available."; throw new InvalidOperationException(text4); } _origin = ((!value.IsNullOrEmpty()) ? value.TrimEnd(new char[1] { '/' }) : value); } } } public string Protocol { get { return _protocol ?? string.Empty; } internal set { _protocol = value; } } public WebSocketState ReadyState => _readyState; public ClientSslConfiguration SslConfiguration { get { if (!_isClient) { string text = "The get operation is not available."; throw new InvalidOperationException(text); } if (!_isSecure) { string text2 = "The get operation is not available."; throw new InvalidOperationException(text2); } return getSslConfiguration(); } } public Uri Url => _isClient ? _uri : _context.RequestUri; public TimeSpan WaitTime { get { return _waitTime; } set { if (value <= TimeSpan.Zero) { string text = "Zero or less."; throw new ArgumentOutOfRangeException("value", text); } lock (_forState) { if (!canSet()) { string text2 = "The set operation is not available."; throw new InvalidOperationException(text2); } _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]; _maxRetryCountForConnect = 10; FragmentLength = 1016; RandomNumber = new RNGCryptoServiceProvider(); } internal WebSocket(HttpListenerWebSocketContext context, string protocol) { _context = context; _protocol = protocol; _closeContext = context.Close; _isSecure = context.IsSecureConnection; _log = context.Log; _message = messages; _socket = context.Socket; _stream = context.Stream; _waitTime = TimeSpan.FromSeconds(1.0); init(); } internal WebSocket(TcpListenerWebSocketContext context, string protocol) { _context = context; _protocol = protocol; _closeContext = context.Close; _isSecure = context.IsSecureConnection; _log = context.Log; _message = messages; _socket = context.Socket; _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) { if (!checkProtocols(protocols, out text)) { throw new ArgumentException(text, "protocols"); } _protocols = protocols; _hasProtocol = true; } _base64Key = CreateBase64Key(); _isClient = true; _isSecure = _uri.Scheme == "wss"; _log = new Logger(); _message = messagec; _retryCountForConnect = -1; _waitTime = TimeSpan.FromSeconds(5.0); init(); } private void abort(string reason, Exception exception) { ushort code = (ushort)((exception is WebSocketException) ? ((WebSocketException)exception).Code : 1006); abort(code, reason); } private void abort(ushort code, string reason) { PayloadData payloadData = new PayloadData(code, reason); close(payloadData, send: false, received: false); } private bool accept() { lock (_forState) { if (_readyState == WebSocketState.Open) { _log.Trace("The connection has already been established."); return false; } if (_readyState == WebSocketState.Closing) { _log.Error("The close process is in progress."); error("An error has occurred before accepting.", null); return false; } if (_readyState == WebSocketState.Closed) { _log.Error("The connection has been closed."); error("An error has occurred before accepting.", null); return false; } _readyState = WebSocketState.Connecting; bool flag = false; try { flag = acceptHandshake(); } catch (Exception ex) { _log.Fatal(ex.Message); _log.Debug(ex.ToString()); abort(1011, "An exception has occurred while accepting."); } if (!flag) { return false; } _readyState = WebSocketState.Open; return true; } } private bool acceptHandshake() { if (!checkHandshakeRequest(_context, out var text)) { _log.Error(text); _log.Debug(_context.ToString()); refuseHandshake(1002, "A handshake error has occurred."); return false; } if (!customCheckHandshakeRequest(_context, out text)) { _log.Error(text); _log.Debug(_context.ToString()); refuseHandshake(1002, "A handshake error has occurred."); return false; } _base64Key = _context.Headers["Sec-WebSocket-Key"]; if (_protocol != null && !_context.SecWebSocketProtocols.Contains((string p) => p == _protocol)) { _protocol = null; } if (!_ignoreExtensions) { string value = _context.Headers["Sec-WebSocket-Extensions"]; processSecWebSocketExtensionsClientHeader(value); } customRespondToHandshakeRequest(_context); if (_noDelay) { _socket.NoDelay = true; } createHandshakeResponse().WriteTo(_stream); return true; } private bool canSet() { return _readyState == WebSocketState.New || _readyState == WebSocketState.Closed; } private bool checkHandshakeRequest(WebSocketContext context, out string message) { message = null; if (!context.IsWebSocketRequest) { message = "Not a WebSocket handshake request."; return false; } NameValueCollection headers = context.Headers; string text = headers["Sec-WebSocket-Key"]; if (text == null) { message = "The Sec-WebSocket-Key header is non-existent."; return false; } if (text.Length == 0) { message = "The Sec-WebSocket-Key header is invalid."; return false; } string text2 = headers["Sec-WebSocket-Version"]; if (text2 == null) { message = "The Sec-WebSocket-Version header is non-existent."; return false; } if (text2 != "13") { message = "The Sec-WebSocket-Version header is invalid."; return false; } string text3 = headers["Sec-WebSocket-Protocol"]; if (text3 != null && text3.Length == 0) { message = "The Sec-WebSocket-Protocol header is invalid."; return false; } if (!_ignoreExtensions) { string text4 = headers["Sec-WebSocket-Extensions"]; if (text4 != null && text4.Length == 0) { message = "The Sec-WebSocket-Extensions header is invalid."; return false; } } return true; } private bool checkHandshakeResponse(HttpResponse response, out string message) { message = null; if (response.IsRedirect) { message = "The redirection is indicated."; return false; } if (response.IsUnauthorized) { message = "The authentication is required."; return false; } if (!response.IsWebSocketResponse) { message = "Not a WebSocket handshake response."; return false; } NameValueCollection headers = response.Headers; string text = headers["Sec-WebSocket-Accept"]; if (text == null) { message = "The Sec-WebSocket-Accept header is non-existent."; return false; } if (text != CreateResponseKey(_base64Key)) { message = "The Sec-WebSocket-Accept header is invalid."; return false; } string text2 = headers["Sec-WebSocket-Version"]; if (text2 != null && text2 != "13") { message = "The Sec-WebSocket-Version header is invalid."; return false; } string subp = headers["Sec-WebSocket-Protocol"]; if (subp == null) { if (_hasProtocol) { message = "The Sec-WebSocket-Protocol header is non-existent."; return false; } } else if (!_hasProtocol || subp.Length <= 0 || !_protocols.Contains((string p) => p == subp)) { message = "The Sec-WebSocket-Protocol header is invalid."; return false; } string text3 = headers["Sec-WebSocket-Extensions"]; if (text3 != null && !validateSecWebSocketExtensionsServerHeader(text3)) { message = "The Sec-WebSocket-Extensions header is invalid."; return false; } return true; } private static bool checkProtocols(string[] protocols, out string message) { message = null; Func<string, bool> condition = (string p) => p.IsNullOrEmpty() || !p.IsToken(); if (protocols.Contains(condition)) { message = "It contains a value that is not a token."; return false; } if (protocols.ContainsTwice()) { message = "It contains a value twice."; return false; } return true; } private bool checkProxyConnectResponse(HttpResponse response, out string message) { message = null; if (response.IsProxyAuthenticationRequired) { message = "The proxy authentication is required."; return false; } if (!response.IsSuccess) { message = "The proxy has failed a connection to the requested URL."; return false; } return true; } private bool checkReceivedFrame(WebSocketFrame frame, out string message) { message = null; if (frame.IsMasked) { if (_isClient) { message = "A frame from the server is masked."; return false; } } else if (!_isClient) { message = "A frame from a client is not masked."; return false; } if (frame.IsCompressed) { if (_compression == CompressionMethod.None) { message = "A frame is compressed without any agreement for it."; return false; } if (!frame.IsData) { message = "A non data frame is compressed."; return false; } } if (frame.IsData && _inContinuation) { message = "A data frame was received while receiving continuation frames."; return false; } if (frame.IsControl) { if (frame.Fin == Fin.More) { message = "A control frame is fragmented."; return false; } if (frame.PayloadLength > 125) { message = "The payload length of a control frame is greater than 125."; 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(ushort code, string reason) { if (_readyState == WebSocketState.Closing) { _log.Trace("The close process is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _log.Trace("The connection has already been closed."); return; } if (code == 1005) { close(PayloadData.Empty, send: true, received: false); return; } PayloadData payloadData = new PayloadData(code, reason); bool flag = !code.IsReservedStatusCode(); close(payloadData, flag, received: false); } private void close(PayloadData payloadData, bool send, bool received) { lock (_forState) { if (_readyState == WebSocketState.Closing) { _log.Trace("The close process is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _log.Trace("The connection has already been closed."); return; } send = send && _readyState == WebSocketState.Open; _readyState = WebSocketState.Closing; } _log.Trace("Begin closing the connection."); bool clean = closeHandshake(payloadData, send, received); releaseResources(); _log.Trace("End closing the connection."); _readyState = WebSocketState.Closed; CloseEventArgs e = new CloseEventArgs(payloadData, clean); try { this.OnClose.Emit(this, e); } catch (Exception ex) { _log.Error(ex.Message); _log.Debug(ex.ToString()); } } private void closeAsync(ushort code, string reason) { if (_readyState == WebSocketState.Closing) { _log.Trace("The close process is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _log.Trace("The connection has already been closed."); return; } if (code == 1005) { closeAsync(PayloadData.Empty, send: true, received: false); return; } PayloadData payloadData = new PayloadData(code, reason); bool flag = !code.IsReservedStatusCode(); closeAsync(payloadData, flag, received: false); } private void closeAsync(PayloadData payloadData, bool send, bool received) { Action<PayloadData, bool, bool> closer = close; closer.BeginInvoke(payloadData, send, received, delegate(IAsyncResult ar) { closer.EndInvoke(ar); }, null); } private bool closeHandshake(PayloadData payloadData, bool send, bool received) { bool flag = false; if (send) { WebSocketFrame webSocketFrame = WebSocketFrame.CreateCloseFrame(payloadData, _isClient); byte[] bytes = webSocketFrame.ToArray(); flag = sendBytes(bytes); if (_isClient) { webSocketFrame.Unmask(); } } if (!received && flag && _receivingExited != null) { received = _receivingExited.WaitOne(_waitTime); } bool flag2 = flag && received; string text = $"The closing was clean? {flag2} (sent: {flag} received: {received})"; _log.Debug(text); return flag2; } private bool connect() { if (_readyState == WebSocketState.Connecting) { _log.Trace("The connect process is in progress."); return false; } lock (_forState) { if (_readyState == WebSocketState.Open) { _log.Trace("The connection has already been established."); return false; } if (_readyState == WebSocketState.Closing) { _log.Error("The close process is in progress."); error("An error has occurred before connecting.", null); return false; } if (_retryCountForConnect >= _maxRetryCountForConnect) { _log.Error("An opportunity for reconnecting has been lost."); error("An error has occurred before connecting.", null); return false; } if (_readyState == WebSocketState.Closed) { initr(); } _retryCountForConnect++; _readyState = WebSocketState.Connecting; bool flag = false; try { flag = doHandshake(); } catch (Exception ex) { _log.Fatal(ex.Message); _log.Debug(ex.ToString()); abort("An exception has occurred while connecting.", ex); } if (!flag) { return false; } _retryCountForConnect = -1; _readyState = WebSocketState.Open; return true; } } private AuthenticationResponse createAuthenticationResponse() { if (_credentials == null) { return null; } if (_authChallenge == null) { return _preAuth ? new AuthenticationResponse(_credentials) : null; } AuthenticationResponse authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount); _nonceCount = authenticationResponse.NonceCount; return authenticationResponse; } 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) { return null; } stringBuilder.Length = length - 2; return stringBuilder.ToString(); } private HttpResponse createHandshakeFailureResponse() { HttpResponse httpResponse = HttpResponse.CreateCloseResponse(WebSocketSharp.Net.HttpStatusCode.BadRequest); httpResponse.Headers["Sec-WebSocket-Version"] = "13"; return httpResponse; } private HttpRequest createHandshakeRequest() { HttpRequest httpRequest = HttpRequest.CreateWebSocketHandshakeRequest(_uri); NameValueCollection headers = httpRequest.Headers; headers["Sec-WebSocket-Key"] = _base64Key; headers["Sec-WebSocket-Version"] = "13"; if (!_origin.IsNullOrEmpty()) { headers["Origin"] = _origin; } if (_hasProtocol) { headers["Sec-WebSocket-Protocol"] = _protocols.ToString(", "); } string text = createExtensions(); _hasExtension = text != null; if (_hasExtension) { headers["Sec-WebSocket-Extensions"] = text; } AuthenticationResponse authenticationResponse = createAuthenticationResponse(); if (authenticationResponse != null) { headers["Authorization"] = authenticationResponse.ToString(); } if (_userHeaders != null && _userHeaders.Count > 0) { headers.Add(_userHeaders); } if (_cookies != null && _cookies.Count > 0) { httpRequest.SetCookies(_cookies); } return httpRequest; } private HttpResponse createHandshakeResponse() { HttpResponse httpResponse = HttpResponse.CreateWebSocketHandshakeResponse(); 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 (_userHeaders != null && _userHeaders.Count > 0) { headers.Add(_userHeaders); } if (_cookies != null && _cookies.Count > 0) { httpResponse.SetCookies(_cookies); } return httpResponse; } private TcpClient createTcpClient(string hostname, int port) { TcpClient tcpClient = new TcpClient(hostname, port); if (_noDelay) { tcpClient.NoDelay = true; } return tcpClient; } private bool customCheckHandshakeRequest(WebSocketContext context, out string message) { message = null; if (_handshakeRequestChecker == null) { return true; } message = _handshakeRequestChecker(context); return message == null; } private void customRespondToHandshakeRequest(WebSocketContext context) { if (_handshakeRequestResponder != null) { _handshakeRequestResponder(context); } } private MessageEventArgs dequeueFromMessageEventQueue() { lock (_forMessageEventQueue) { return (_messageEventQueue.Count > 0) ? _messageEventQueue.Dequeue() : null; } } private bool doHandshake() { setClientStream(); HttpResponse httpResponse = sendHandshakeRequest(); _log.Debug(httpResponse.ToString()); _handshakeResponseHeaders = httpResponse.Headers; _handshakeResponseCookies = httpResponse.Cookies; if (!checkHandshakeResponse(httpResponse, out var text)) { _log.Error(text); abort(1002, "A handshake error has occurred."); return false; } if (_hasProtocol) { _protocol = _handshakeResponseHeaders["Sec-WebSocket-Protocol"]; } if (_hasExtension) { string text2 = _handshakeResponseHeaders["Sec-WebSocket-Extensions"]; if (text2 != null) { _extensions = text2; } else { _compression = CompressionMethod.None; } } if (_handshakeResponseCookies.Count > 0) { Cookies.SetOrRemove(_handshakeResponseCookies); } return true; } private void enqueueToMessageEventQueue(MessageEventArgs e) { lock (_forMessageEventQueue) { _messageEventQueue.Enqueue(e); } } private void error(string message, Exception exception) { ErrorEventArgs e = new ErrorEventArgs(message, exception); try { this.OnError.Emit(this, e); } catch (Exception ex) { _log.Error(ex.Message); _log.Debug(ex.ToString()); } } private ClientSslConfiguration getSslConfiguration() { if (_sslConfig == null) { _sslConfig = new ClientSslConfiguration(_uri.DnsSafeHost); } return _sslConfig; } private void init() { _compression = CompressionMethod.None; _forPing = new object(); _forSend = new object(); _forState = new object(); _messageEventQueue = new Queue<MessageEventArgs>(); _forMessageEventQueue = ((ICollection)_messageEventQueue).SyncRoot; _readyState = WebSocketState.New; } private void initr() { _handshakeResponseCookies = null; _handshakeResponseHeaders = null; } private void message() { MessageEventArgs obj = null; lock (_forMessageEventQueue) { if (_inMessage || _messageEventQueue.Count == 0 || _readyState != WebSocketState.Open) { return; } obj = _messageEventQueue.Dequeue(); _inMessage = true; } _message(obj); } private void messagec(MessageEventArgs e) { while (true) { try { this.OnMessage.Emit(this, e); } catch (Exception ex) { _log.Error(ex.Message); _log.Debug(ex.ToString()); error("An exception has occurred during an OnMessage event.", ex); } lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0) { _inMessage = false; break; } if (_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) { _log.Error(ex.Message); _log.Debug(ex.ToString()); error("An exception has occurred during an OnMessage event.", ex); } lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0) { _inMessage = false; return; } if (_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) { _log.Error(ex.Message); _log.Debug(ex.ToString()); error("An exception has occurred during the OnOpen event.", ex); } MessageEventArgs obj = null; lock (_forMessageEventQueue) { if (_messageEventQueue.Count == 0) { _inMessage = false; return; } if (_readyState != WebSocketState.Open) { _inMessage = false; return; } obj = _messageEventQueue.Dequeue(); } _message.BeginInvoke(obj, delegate(IAsyncResult ar) { _message.EndInvoke(ar); }, null); } private bool ping(byte[] data) { if (_readyState != WebSocketState.Open) { return false; } ManualResetEvent pongReceived = _pongReceived; if (pongReceived == null) { return false; } lock (_forPing) { try { pongReceived.Reset(); if (!send(Fin.Final, Opcode.Ping, data, compressed: false)) { return false; } return pongReceived.WaitOne(_waitTime); } catch (ObjectDisposedException) { return false; } } } private bool processCloseFrame(WebSocketFrame frame) { PayloadData payloadData = frame.PayloadData; bool flag = !payloadData.HasReservedCode; close(payloadData, flag, received: true); return false; } private bool processDataFrame(WebSocketFrame frame) { MessageEventArgs e = (frame.IsCompressed ? new MessageEventArgs(frame.Opcode, frame.PayloadData.ApplicationData.Decompress(_compression)) : new MessageEventArgs(frame)); enqueueToMessageEventQueue(e); 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()); MessageEventArgs e = new MessageEventArgs(_fragmentsOpcode, rawData); enqueueToMessageEventQueue(e); } _fragmentsBuffer = null; _inContinuation = false; } return true; } private bool processPingFrame(WebSocketFrame frame) { _log.Trace("A ping was received."); WebSocketFrame webSocketFrame = WebSocketFrame.CreatePongFrame(frame.PayloadData, _isClient); lock (_forState) { if (_readyState != WebSocketState.Open) { _log.Trace("A pong to this ping cannot be sent."); return true; } byte[] bytes = webSocketFrame.ToArray(); if (!sendBytes(bytes)) { return false; } } _log.Trace("A pong to this ping has been sent."); if (_emitOnPing) { if (_isClient) { webSocketFrame.Unmask(); } MessageEventArgs e = new MessageEventArgs(frame); enqueueToMessageEventQueue(e); } return true; } private bool processPongFrame(WebSocketFrame frame) { _log.Trace("A pong was received."); try { _pongReceived.Set(); } catch (NullReferenceException) { return false; } catch (ObjectDisposedException) { return false; } _log.Trace("It has been signaled."); return true; } private bool processReceivedFrame(WebSocketFrame frame) { if (!checkReceivedFrame(frame, out var text)) { _log.Error(text); _log.Debug(frame.ToString(dump: false)); abort(1002, "An error has occurred while receiving."); return false; } 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 text = item.Trim(); if (text.Length != 0 && !flag && text.IsCompressionExtension(CompressionMethod.Deflate)) { _compression = CompressionMethod.Deflate; string arg = _compression.ToExtensionString("client_no_context_takeover", "server_no_context_takeover"); stringBuilder.AppendFormat("{0}, ", arg); flag = true; } } int length = stringBuilder.Length; if (length > 2) { stringBuilder.Length = length - 2; _extensions = stringBuilder.ToString(); } } private bool processUnsupportedFrame(WebSocketFrame frame) { _log.Fatal("An unsupported frame was received."); _log.Debug(frame.ToString(dump: false)); abort(1003, "There is no way to handle it."); return false; } private void refuseHandshake(ushort code, string reason) { createHandshakeFailureResponse().WriteTo(_stream); abort(code, reason); } 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 (_pongReceived != null) { _pongReceived.Close(); _pongReceived = null; } if (_receivingExited != null) { _receivingExited.Close(); _receivingExited = null; } } private void releaseResources() { if (_isClient) { releaseClientResources(); } else { releaseServerResources(); } releaseCommonResources(); } private void releaseServerResources() { if (_closeContext != null) { _closeContext(); _closeContext = null; } _stream = null; _context = null; } private bool send(byte[] rawFrame) { lock (_forState) { if (_readyState != WebSocketState.Open) { _log.Error("The current state of the interface is not Open."); return false; } return sendBytes(rawFrame); } } private bool send(Opcode opcode, Stream sourceStream) { lock (_forSend) { Stream stream = sourceStream; bool flag = false; bool flag2 = false; try { if (_compression != 0) { stream = sourceStream.Compress(_compression); flag = true; } flag2 = send(opcode, stream, flag); if (!flag2) { error("A send has failed.", null); } } catch (Exception ex) { _log.Error(ex.Message); _log.Debug(ex.ToString()); error("An exception has occurred during a send.", ex); } finally { if (flag) { stream.Dispose(); } sourceStream.Dispose(); } return flag2; } } private bool send(Opcode opcode, Stream dataStream, bool compressed) { long length = dataStream.Length; if (length == 0) { return send(Fin.Final, opcode, _emptyBytes, compressed: false); } long num = length / FragmentLength; int num2 = (int)(length % FragmentLength); byte[] array = null; switch (num) { case 0L: array = new byte[num2]; return dataStream.Read(array, 0, num2) == num2 && send(Fin.Final, opcode, array, compressed); case 1L: if (num2 == 0) { array = new byte[FragmentLength]; return dataStream.Read(array, 0, FragmentLength) == FragmentLength && send(Fin.Final, opcode, array, compressed); } break; } array = new byte[FragmentLength]; if (dataStream.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 (dataStream.Read(array, 0, FragmentLength) != FragmentLength || !send(Fin.More, Opcode.Cont, array, compressed: false)) { return false; } } if (num2 == 0) { num2 = FragmentLength; } else { array = new byte[num2]; } return dataStream.Read(array, 0, num2) == num2 && send(Fin.Final, Opcode.Cont, array, compressed: false); } private bool send(Fin fin, Opcode opcode, byte[] data, bool compressed) { WebSocketFrame webSocketFrame = new WebSocketFrame(fin, opcode, data, compressed, _isClient); byte[] rawFrame = webSocketFrame.ToArray(); return send(rawFrame); } private void sendAsync(Opcode opcode, Stream sourceStream, Action<bool> completed) { Func<Opcode, Stream, bool> sender = send; sender.BeginInvoke(opcode, sourceStream, delegate(IAsyncResult ar) { try { bool obj = sender.EndInvoke(ar); if (completed != null) { completed(obj); } } catch (Exception ex) { _log.Error(ex.Message); _log.Debug(ex.ToString()); error("An exception has occurred during the callback for an async send.", ex); } }, null); } private bool sendBytes(byte[] bytes) { try { _stream.Write(bytes, 0, bytes.Length); } catch (Exception ex) { _log.Error(ex.Message); _log.Debug(ex.ToString()); return false; } return true; } private HttpResponse sendHandshakeRequest() { HttpRequest httpRequest = createHandshakeRequest(); _log.Debug(httpRequest.ToString()); int millisecondsTimeout = 90000; HttpResponse response = httpRequest.GetResponse(_stream, millisecondsTimeout); if (response.IsUnauthorized) { string value = response.Headers["WWW-Authenticate"]; if (value.IsNullOrEmpty()) { _log.Debug("No authentication challenge is specified."); return response; } AuthenticationChallenge authenticationChallenge = AuthenticationChallenge.Parse(value); if (authenticationChallenge == null) { _log.Debug("An invalid authentication challenge is specified."); return response; } _authChallenge = authenticationChallenge; if (_credentials == null) { return response; } AuthenticationResponse authenticationResponse = new AuthenticationResponse(_authChallenge, _credentials, _nonceCount); _nonceCount = authenticationResponse.NonceCount; httpRequest.Headers["Authorization"] = authenticationResponse.ToString(); if (response.CloseConnection) { releaseClientResources(); setClientStream(); } _log.Debug(httpRequest.ToString()); millisecondsTimeout = 15000; response = httpRequest.GetResponse(_stream, millisecondsTimeout); } if (response.IsRedirect) { if (!_enableRedirection) { return response; } string text = response.Headers["Location"]; if (text.IsNullOrEmpty()) { _log.Debug("No URL to redirect is located."); return response; } if (!text.TryCreateWebSocketUri(out var result, out var _)) { _log.Debug("An invalid URL to redirect is located."); return response; } releaseClientResources(); _uri = result; _isSecure = result.Scheme == "wss"; setClientStream(); return sendHandshakeRequest(); } return response; } private HttpResponse sendProxyConnectRequest() { HttpRequest httpRequest = HttpRequest.CreateConnectRequest(_uri); int millisecondsTimeout = 90000; HttpResponse response = httpRequest.GetResponse(_stream, millisecondsTimeout); if (response.IsProxyAuthenticationRequired) { if (_proxyCredentials == null) { return response; } string value = response.Headers["Proxy-Authenticate"]; if (value.IsNullOrEmpty()) { _log.Debug("No proxy authentication challenge is specified."); return response; } AuthenticationChallenge authenticationChallenge = AuthenticationChallenge.Parse(value); if (authenticationChallenge == null) { _log.Debug("An invalid proxy authentication challenge is specified."); return response; } AuthenticationResponse authenticationResponse = new AuthenticationResponse(authenticationChallenge, _proxyCredentials, 0u); httpRequest.Headers["Proxy-Authorization"] = authenticationResponse.ToString(); if (response.CloseConnection) { releaseClientResources(); _tcpClient = createTcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port); _stream = _tcpClient.GetStream(); } millisecondsTimeout = 15000; response = httpRequest.GetResponse(_stream, millisecondsTimeout); } return response; } private void setClientStream() { if (_proxyUri != null) { _tcpClient = createTcpClient(_proxyUri.DnsSafeHost, _proxyUri.Port); _stream = _tcpClient.GetStream(); HttpResponse response = sendProxyConnectRequest(); if (!checkProxyConnectResponse(response, out var text)) { throw new WebSocketException(text); } } else { _tcpClient = createTcpClient(_uri.DnsSafeHost, _uri.Port); _stream = _tcpClient.GetStream(); } if (_isSecure) { ClientSslConfiguration sslConfiguration = getSslConfiguration(); string targetHost = sslConfiguration.TargetHost; if (targetHost != _uri.DnsSafeHost) { string text2 = "An invalid host name is specified."; throw new WebSocketException(CloseStatusCode.TlsHandshakeFailure, text2); } 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(); } _pongReceived = new ManualResetEvent(initialState: false); _receivingExited = new ManualResetEvent(initialState: false); Action receive = null; receive = delegate { WebSocketFrame.ReadFrameAsync(_stream, unmask: false, delegate(WebSocketFrame frame) { if (!processReceivedFrame(frame) || _readyState == WebSocketState.Closed) { _receivingExited?.Set(); } else { receive(); if (!_inMessage) { message(); } } }, delegate(Exception ex) { _log.Fatal(ex.Message); _log.Debug(ex.ToString()); abort("An exception has occurred while receiving.", ex); }); }; receive(); } private bool validateSecWebSocketExtensionsServerHeader(string value) { if (!_hasExtension) { return false; } if (value.Length == 0) { return false; } bool flag = _compression != CompressionMethod.None; foreach (string item in value.SplitHeaderValue(',')) { string text = item.Trim(); if (flag && text.IsCompressionExtension(_compression)) { string param1 = "server_no_context_takeover"; string param2 = "client_no_context_takeover"; if (!text.Contains(param1)) { return false; } string name = _compression.ToExtensionString(); if (text.SplitHeaderValue(';').Contains(delegate(string t) { t = t.Trim(); bool flag2 = t == name || t == param1 || t == param2; return !flag2; })) { return false; } flag = false; continue; } return false; } return true; } internal void Accept() { if (accept()) { open(); } } internal void AcceptAsync() { Func<bool> acceptor = accept; acceptor.BeginInvoke(delegate(IAsyncResult ar) { if (acceptor.EndInvoke(ar)) { open(); } }, null); } internal void Close(PayloadData payloadData, byte[] rawFrame) { lock (_forState) { if (_readyState == WebSocketState.Closing) { _log.Trace("The close process is already in progress."); return; } if (_readyState == WebSocketState.Closed) { _log.Trace("The connection has already been closed."); return; } _readyState = WebSocketState.Closing; } _log.Trace("Begin closing the connection."); bool flag = rawFrame != null && sendBytes(rawFrame); bool flag2 = flag && _receivingExited != null && _receivingExited.WaitOne(_waitTime); bool flag3 = flag && flag2; string text = $"The closing was clean? {flag3} (sent: {flag} received: {flag2})"; _log.Debug(text); releaseServerResources(); releaseCommonResources(); _log.Trace("End closing the connection."); _readyState = WebSocketState.Closed; CloseEventArgs e = new CloseEventArgs(payloadData, flag3); try { this.OnClose.Emit(this, e); } catch (Exception ex) { _log.Error(ex.Message); _log.Debug(ex.ToString()); } } internal static string CreateBase64Key() { byte[] array = new byte[16]; RandomNumber.GetBytes(array); return Convert.ToBase64String(array); } internal static string CreateResponseKey(string base64Key) { SHA1 sHA = new SHA1CryptoServiceProvider(); string s = base64Key + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"; byte[] uTF8EncodedBytes = s.GetUTF8EncodedBytes(); byte[] inArray = sHA.ComputeHash(uTF8EncodedBytes); return Convert.ToBase64String(inArray); } internal bool Ping(byte[] rawFrame) { if (_readyState != WebSocketState.Open) { return false; } ManualResetEvent pongReceived = _pongReceived; if (pongReceived == null) { return false; } lock (_forPing) { try { pongReceived.Reset(); if (!send(rawFrame)) { return false; } return pongReceived.WaitOne(_waitTime); } catch (ObjectDisposedException) { return false; } } } internal void Send(Opcode opcode, byte[] data, Dictionary<CompressionMethod, byte[]> cache) { lock (_forSend) { 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); } send(value); } } internal void Send(Opcode opcode, Stream sourceStream, Dictionary<CompressionMethod, Stream> cache) { lock (_forSend) { if (!cache.TryGetValue(_compression, out var value)) { value = sourceStream.Compress(_compression); cache.Add(_compression, value); } else { value.Position = 0L; } send(opcode, value, _compression != CompressionMethod.None); } } public void Close() { close(1005, string.Empty); } public void Close(ushort code) { Close(code, string.Empty); } public void Close(CloseStatusCode code) { Close(code, string.Empty); } public void Close(ushort code, string reason) { if (!code.IsCloseStatusCode()) { string text = "Less than 1000 or greater than 4999."; throw new ArgumentOutOfRangeException("code", text); } if (_isClient) { if (code == 1011) { string text2 = "1011 cannot be used."; throw new ArgumentException(text2, "code"); } } else if (code == 1010) { string text3 = "1010 cannot be used."; throw new ArgumentException(text3, "code"); } if (reason.IsNullOrEmpty()) { close(code, string.Empty); return; } if (code == 1005) { string text4 = "1005 cannot be used."; throw new ArgumentException(text4, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text5 = "It could not be UTF-8-encoded."; throw new ArgumentException(text5, "reason"); } if (bytes.Length > 123) { string text6 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text6); } close(code, reason); } public void Close(CloseStatusCode code, string reason) { if (!code.IsDefined()) { string text = "An undefined enum value."; throw new ArgumentException(text, "code"); } if (_isClient) { if (code == CloseStatusCode.ServerError) { string text2 = "ServerError cannot be used."; throw new ArgumentException(text2, "code"); } } else if (code == CloseStatusCode.MandatoryExtension) { string text3 = "MandatoryExtension cannot be used."; throw new ArgumentException(text3, "code"); } if (reason.IsNullOrEmpty()) { close((ushort)code, string.Empty); return; } if (code == CloseStatusCode.NoStatus) { string text4 = "NoStatus cannot be used."; throw new ArgumentException(text4, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text5 = "It could not be UTF-8-encoded."; throw new ArgumentException(text5, "reason"); } if (bytes.Length > 123) { string text6 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text6); } close((ushort)code, reason); } public void CloseAsync() { closeAsync(1005, string.Empty); } public void CloseAsync(ushort code) { CloseAsync(code, string.Empty); } public void CloseAsync(CloseStatusCode code) { CloseAsync(code, string.Empty); } public void CloseAsync(ushort code, string reason) { if (!code.IsCloseStatusCode()) { string text = "Less than 1000 or greater than 4999."; throw new ArgumentOutOfRangeException("code", text); } if (_isClient) { if (code == 1011) { string text2 = "1011 cannot be used."; throw new ArgumentException(text2, "code"); } } else if (code == 1010) { string text3 = "1010 cannot be used."; throw new ArgumentException(text3, "code"); } if (reason.IsNullOrEmpty()) { closeAsync(code, string.Empty); return; } if (code == 1005) { string text4 = "1005 cannot be used."; throw new ArgumentException(text4, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text5 = "It could not be UTF-8-encoded."; throw new ArgumentException(text5, "reason"); } if (bytes.Length > 123) { string text6 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text6); } closeAsync(code, reason); } public void CloseAsync(CloseStatusCode code, string reason) { if (!code.IsDefined()) { string text = "An undefined enum value."; throw new ArgumentException(text, "code"); } if (_isClient) { if (code == CloseStatusCode.ServerError) { string text2 = "ServerError cannot be used."; throw new ArgumentException(text2, "code"); } } else if (code == CloseStatusCode.MandatoryExtension) { string text3 = "MandatoryExtension cannot be used."; throw new ArgumentException(text3, "code"); } if (reason.IsNullOrEmpty()) { closeAsync((ushort)code, string.Empty); return; } if (code == CloseStatusCode.NoStatus) { string text4 = "NoStatus cannot be used."; throw new ArgumentException(text4, "code"); } if (!reason.TryGetUTF8EncodedBytes(out var bytes)) { string text5 = "It could not be UTF-8-encoded."; throw new ArgumentException(text5, "reason"); } if (bytes.Length > 123) { string text6 = "Its size is greater than 123 bytes."; throw new ArgumentOutOfRangeException("reason", text6); } closeAsync((ushort)code, reason); } public void Connect() { if (!_isClient) { string text = "The Connect method is not available."; throw new InvalidOperationException(text); } if (_retryCountForConnect >= _maxRetryCountForConnect) { string text2 = "The Connect method is not available."; throw new InvalidOperationException(text2); } if (connect()) { open(); } } public void ConnectAsync() { if (!_isClient) { string text = "The ConnectAsync method is not available."; throw new InvalidOperationException(text); } if (_retryCountForConnect >= _maxRetryCountForConnect) { string text2 = "The ConnectAsync method is not available."; throw new InvalidOperationException(text2); } Func<bool> connector = connect; connector.BeginInvoke(delegate(IAsyncResult ar) { if (connector.EndInvoke(ar)) { open(); } }, null); } public bool Ping() { return ping(_emptyBytes); } public bool Ping(string message) { if (message.IsNullOrEmpty()) { return ping(_emptyBytes); } if (!message.TryGetUTF8EncodedBytes(out var bytes)) { string text = "It could not be UTF-8-encoded."; throw new ArgumentException(text, "message"); } if (bytes.Length > 125) { string text2 = "Its size is greater than 125 bytes."; throw new ArgumentOutOfRangeException("message", text2); } return ping(bytes); } public void Send(byte[] data) { if (_readyState != WebSocketState.Open) { string text = "The Send method is not available."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } send(Opcode.Binary, new MemoryStream(data)); } public void Send(FileInfo fileInfo) { if (_readyState != WebSocketState.Open) { string text = "The Send method is not available."; throw new InvalidOperationException(text); } if (fileInfo == null) { throw new ArgumentNullException("fileInfo"); } if (!fileInfo.Exists) { string text2 = "The file does not exist."; throw new ArgumentException(text2, "fileInfo"); } if (!fileInfo.TryOpenRead(out var fileStream)) { string text3 = "The file could not be opened."; throw new ArgumentException(text3, "fileInfo"); } send(Opcode.Binary, fileStream); } public void Send(string data) { if (_readyState != WebSocketState.Open) { string text = "The Send method is not available."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } if (!data.TryGetUTF8EncodedBytes(out var bytes)) { string text2 = "It could not be UTF-8-encoded."; throw new ArgumentException(text2, "data"); } send(Opcode.Text, new MemoryStream(bytes)); } public void Send(Stream stream, int length) { if (_readyState != WebSocketState.Open) { string text = "The Send method is not available."; throw new InvalidOperationException(text); } if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { string text2 = "It cannot be read."; throw new ArgumentException(text2, "stream"); } if (length < 1) { string text3 = "Less than 1."; throw new ArgumentException(text3, "length"); } byte[] array = stream.ReadBytes(length); int num = array.Length; if (num == 0) { string text4 = "No data could be read from it."; throw new ArgumentException(text4, "stream"); } if (num < length) { string format = "Only {0} byte(s) of data could be read from the stream."; string text5 = string.Format(format, num); _log.Warn(text5); } send(Opcode.Binary, new MemoryStream(array)); } public void SendAsync(byte[] data, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The SendAsync method is not available."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } sendAsync(Opcode.Binary, new MemoryStream(data), completed); } public void SendAsync(FileInfo fileInfo, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The SendAsync method is not available."; throw new InvalidOperationException(text); } if (fileInfo == null) { throw new ArgumentNullException("fileInfo"); } if (!fileInfo.Exists) { string text2 = "The file does not exist."; throw new ArgumentException(text2, "fileInfo"); } if (!fileInfo.TryOpenRead(out var fileStream)) { string text3 = "The file could not be opened."; throw new ArgumentException(text3, "fileInfo"); } sendAsync(Opcode.Binary, fileStream, completed); } public void SendAsync(string data, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The SendAsync method is not available."; throw new InvalidOperationException(text); } if (data == null) { throw new ArgumentNullException("data"); } if (!data.TryGetUTF8EncodedBytes(out var bytes)) { string text2 = "It could not be UTF-8-encoded."; throw new ArgumentException(text2, "data"); } sendAsync(Opcode.Text, new MemoryStream(bytes), completed); } public void SendAsync(Stream stream, int length, Action<bool> completed) { if (_readyState != WebSocketState.Open) { string text = "The SendAsync method is not available."; throw new InvalidOperationException(text); } if (stream == null) { throw new ArgumentNullException("stream"); } if (!stream.CanRead) { string text2 = "It cannot be read."; throw new ArgumentException(text2, "stream"); } if (length < 1) { string text3 = "Less than 1."; throw new ArgumentException(text3, "length"); } byte[] array = stream.ReadBytes(length); int num = array.Length; if (num == 0) { string text4 = "No data could be read from it."; throw new ArgumentException(text4, "stream"); } if (num < length) { string format = "Only {0} byte(s) of data could be read from the stream."; string text5 = string.Format(format, num); _log.Warn(text5); } sendAsync(Opcode.Binary, new MemoryStream(array), completed); } public void SetCookie(WebSocketSharp.Net.Cookie cookie) { if (cookie == null) { throw new ArgumentNullException("cookie"); } lock (_forState) { if (!canSet()) { string text = "The SetCookie method is not available."; throw new InvalidOperationException(text); } Cookies.SetOrRemove(cookie); } } public void SetCredentials(string username, string password, bool preAuth) { if (!_isClient) { string text = "The SetCredentials method is not available."; throw new InvalidOperationException(text); } if (!username.IsNullOrEmpty() && (Ext.Contains(username, ':') || !username.IsText())) { string text2 = "It contains an invalid character."; throw new ArgumentException(text2, "username"); } if (!password.IsNullOrEmpty() && !password.IsText()) { string text3 = "It contains an invalid character."; throw new ArgumentException(text3, "password"); } lock (_forState) { if (!canSet()) { string text4 = "The SetCredentials method is not available."; throw new InvalidOperationException(text4); } if (username.IsNullOrEmpty()) { _credentials = null; _preAuth = false; } else { _credentials = new WebSocketSharp.Net.NetworkCredential(username, password, _uri.PathAndQuery); _preAuth = preAuth; } } } public void SetProxy(string url, string username, string password) { if (!_isClient) { string text = "The SetProxy method is not available."; throw new InvalidOperationException(text); } Uri result = null; if (!url.IsNullOrEmpty()) { if (!Uri.TryCreate(url, UriKind.Absolute, out result)) { string text2 = "Not an absolute URI string."; throw new ArgumentException(text2, "url"); } if (result.Scheme != "http") { string text3 = "The scheme part is not http."; throw new ArgumentException(text3, "url"); } if (result.Segments.Length > 1) { string text4 = "It includes the path segments."; throw new ArgumentException(text4, "url"); } } if (!username.IsNullOrEmpty() && (Ext.Contains(username, ':') || !username.IsText())) { string text5 = "It contains an invalid character."; throw new ArgumentException(text5, "username"); } if (!password.IsNullOrEmpty() && !password.IsText()) { string text6 = "It contains an invalid character."; throw new ArgumentException(text6, "password"); } lock (_forState) { if (!canSet()) { string text7 = "The SetProxy method is not available."; throw new InvalidOperationException(text7); } if (url.IsNullOrEmpty()) { _proxyUri = null; _proxyCredentials = null; return; } _proxyUri = result; if (username.IsNullOrEmpty()) { _proxyCredentials = null; return; } string domain = $"{_uri.DnsSafeHost}:{_uri.Port}"; _proxyCredentials = new WebSocketSharp.Net.NetworkCredential(username, password, domain); } } public void SetUserHeader(string name, string value) { lock (_forState) { if (!canSet()) { string text = "The SetUserHeader method is not available."; throw new InvalidOperationException(text); } UserHeaders.Set(name, value); } } void IDisposable.Dispose() { close(1001, string.Empty); } } public enum CloseStatusCode : ushort { Normal = 1000, Away = 1001, ProtocolError = 1002, UnsupportedData = 1003, Undefined = 1004, NoStatus = 1005, Abnormal = 1006, InvalidData = 1007, PolicyViolation = 1008, TooBig = 1009, MandatoryExtension = 1010, ServerError = 1011, TlsHandshakeFailure = 1015 } internal enum Fin { More, Final } internal enum Mask { Off, On } internal enum Opcode { Cont = 0, Text = 1, Binary = 2, Close = 8, Ping = 9, Pong = 10 } internal class PayloadData : IEnumerable<byte>, IEnumerable { [CompilerGenerated] private sealed class <GetEnumerator>d__26 : IEnumerator<byte>, IDisposable, IEnumerator { private int <>1__state; private byte <>2__current; public PayloadData <>4__this; private byte[] <>s__1; private int <>s__2; private byte <b>5__3; byte IEnumerator<byte>.Current { [DebuggerHidden] get { return <>2__curr