Decompiled source of HavocBot v0.1.2

HavocBot.dll

Decompiled 2 months ago
using 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 2 months ago
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