Decompiled source of AsyncIO v0.1.6901

BepInEx/core/AsyncIO/netstandard2.0/AsyncIO.dll

Decompiled 5 months ago
using System;
using System.Collections.Concurrent;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Threading;
using AsyncIO.DotNet;
using AsyncIO.Windows;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("AsyncIO")]
[assembly: AssemblyDescription("Portable completion port library for .Net.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("somdoron")]
[assembly: AssemblyProduct("AsyncIO")]
[assembly: AssemblyCopyright("Copyright ©  2014-2017")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("abd49658-af51-4138-91b1-6a500fc389d5")]
[assembly: AssemblyFileVersion("0.1.69")]
[assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = "")]
[assembly: AssemblyInformationalVersion("0.1.69")]
[assembly: AssemblyVersion("0.1.69.0")]
namespace AsyncIO
{
	public enum OperationType
	{
		Send,
		Receive,
		Accept,
		Connect,
		Disconnect,
		Signal
	}
	public abstract class AsyncSocket : IDisposable
	{
		private SocketOptionName IPv6Only = SocketOptionName.IPv6Only;

		public AddressFamily AddressFamily { get; private set; }

		public SocketType SocketType { get; private set; }

		public ProtocolType ProtocolType { get; private set; }

		public abstract IPEndPoint LocalEndPoint { get; }

		public abstract IPEndPoint RemoteEndPoint { get; }

		public bool NoDelay
		{
			get
			{
				return (int)GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.Debug) != 0;
			}
			set
			{
				SetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.Debug, value ? 1 : 0);
			}
		}

		public bool ExclusiveAddressUse
		{
			get
			{
				return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse) != 0;
			}
			set
			{
				SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0);
			}
		}

		public bool DualMode
		{
			get
			{
				if (AddressFamily != AddressFamily.InterNetworkV6)
				{
					throw new NotSupportedException("invalid version");
				}
				return (int)GetSocketOption(SocketOptionLevel.IPv6, IPv6Only) == 0;
			}
			set
			{
				if (AddressFamily != AddressFamily.InterNetworkV6)
				{
					throw new NotSupportedException("invalid version");
				}
				SetSocketOption(SocketOptionLevel.IPv6, IPv6Only, (!value) ? 1 : 0);
			}
		}

		public int ReceiveBufferSize
		{
			get
			{
				return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer);
			}
			set
			{
				if (value < 0)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, value);
			}
		}

		public int SendBufferSize
		{
			get
			{
				return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer);
			}
			set
			{
				if (value < 0)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendBuffer, value);
			}
		}

		public LingerOption LingerState
		{
			get
			{
				return (LingerOption)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger);
			}
			set
			{
				SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value);
			}
		}

		public bool EnableBroadcast
		{
			get
			{
				return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast) != 0;
			}
			set
			{
				SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0);
			}
		}

		public bool MulticastLoopback
		{
			get
			{
				if (AddressFamily == AddressFamily.InterNetwork)
				{
					return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback) != 0;
				}
				if (AddressFamily != AddressFamily.InterNetworkV6)
				{
					throw new NotSupportedException("invalid version");
				}
				return (int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback) != 0;
			}
			set
			{
				if (AddressFamily == AddressFamily.InterNetwork)
				{
					SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0);
					return;
				}
				if (AddressFamily != AddressFamily.InterNetworkV6)
				{
					throw new NotSupportedException("invalid version");
				}
				SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.MulticastLoopback, value ? 1 : 0);
			}
		}

		public short Ttl
		{
			get
			{
				if (AddressFamily == AddressFamily.InterNetwork)
				{
					return (short)(int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress);
				}
				if (AddressFamily == AddressFamily.InterNetworkV6)
				{
					return (short)(int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.ReuseAddress);
				}
				throw new NotSupportedException("invalid version");
			}
			set
			{
				if (value < 0 || value > 255)
				{
					throw new ArgumentOutOfRangeException("value");
				}
				if (AddressFamily == AddressFamily.InterNetwork)
				{
					SetSocketOption(SocketOptionLevel.IP, SocketOptionName.ReuseAddress, value);
					return;
				}
				if (AddressFamily != AddressFamily.InterNetworkV6)
				{
					throw new NotSupportedException("invalid version");
				}
				SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.ReuseAddress, value);
			}
		}

		internal AsyncSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
		{
			AddressFamily = addressFamily;
			SocketType = socketType;
			ProtocolType = protocolType;
		}

		public static AsyncSocket Create(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
		{
			if (Environment.OSVersion.Platform != PlatformID.Win32NT || ForceDotNet.Forced)
			{
				return new NativeSocket(addressFamily, socketType, protocolType);
			}
			return new AsyncIO.Windows.Socket(addressFamily, socketType, protocolType);
		}

		public static AsyncSocket CreateIPv4Tcp()
		{
			return Create(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
		}

		public static AsyncSocket CreateIPv6Tcp()
		{
			return Create(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);
		}

		public abstract void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue);

		public abstract void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue);

		public abstract void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue);

		public abstract void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue);

		public abstract object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName);

		public abstract void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue);

		public abstract byte[] GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength);

		public abstract int IOControl(IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue);

		public abstract void Dispose();

		public abstract void Bind(IPEndPoint localEndPoint);

		public abstract void Listen(int backlog);

		public abstract void Connect(IPEndPoint endPoint);

		[Obsolete("Use Accept without parameter and GetAcceptedSocket")]
		public abstract void Accept(AsyncSocket socket);

		public abstract void Accept();

		public abstract AsyncSocket GetAcceptedSocket();

		public abstract void Send(byte[] buffer, int offset, int count, SocketFlags flags);

		public abstract void Receive(byte[] buffer, int offset, int count, SocketFlags flags);
	}
	public abstract class CompletionPort : IDisposable
	{
		public static CompletionPort Create()
		{
			if (Environment.OSVersion.Platform != PlatformID.Win32NT || ForceDotNet.Forced)
			{
				return new AsyncIO.DotNet.CompletionPort();
			}
			return new AsyncIO.Windows.CompletionPort();
		}

		public abstract void Dispose();

		public abstract bool GetQueuedCompletionStatus(int timeout, out CompletionStatus completionStatus);

		public abstract bool GetMultipleQueuedCompletionStatus(int timeout, CompletionStatus[] completionStatuses, out int removed);

		public abstract void AssociateSocket(AsyncSocket socket, object state = null);

		public abstract void Signal(object state);
	}
	public struct CompletionStatus
	{
		public AsyncSocket AsyncSocket { get; private set; }

		public object State { get; internal set; }

		public OperationType OperationType { get; internal set; }

		public SocketError SocketError { get; internal set; }

		public int BytesTransferred { get; internal set; }

		internal CompletionStatus(AsyncSocket asyncSocket, object state, OperationType operationType, SocketError socketError, int bytesTransferred)
		{
			this = default(CompletionStatus);
			AsyncSocket = asyncSocket;
			State = state;
			OperationType = operationType;
			SocketError = socketError;
			BytesTransferred = bytesTransferred;
		}
	}
	public static class ForceDotNet
	{
		internal static bool Forced { get; private set; }

		public static void Force()
		{
			Forced = true;
		}

		public static void Unforce()
		{
			Forced = false;
		}
	}
	public static class SocketExtensions
	{
		public static void Bind(this AsyncSocket socket, IPAddress ipAddress, int port)
		{
			socket.Bind(new IPEndPoint(ipAddress, port));
		}

		public static void Connect(this AsyncSocket socket, IPAddress ipAddress, int port)
		{
			socket.Connect(new IPEndPoint(ipAddress, port));
		}

		public static void Connect(this AsyncSocket socket, string host, int port)
		{
			if (host == null)
			{
				throw new ArgumentNullException("host");
			}
			if (port < 0 || port > 65535)
			{
				throw new ArgumentOutOfRangeException("port");
			}
			IPAddress iPAddress = Dns.GetHostAddresses(host).FirstOrDefault((IPAddress ip) => ip.AddressFamily == socket.AddressFamily || (socket.AddressFamily == AddressFamily.InterNetworkV6 && socket.DualMode && ip.AddressFamily == AddressFamily.InterNetwork));
			if (iPAddress != null)
			{
				socket.Connect(iPAddress, port);
				return;
			}
			throw new ArgumentException("invalid host", "host");
		}

		public static void Send(this AsyncSocket socket, byte[] buffer)
		{
			socket.Send(buffer, 0, buffer.Length, SocketFlags.None);
		}

		public static void Receive(this AsyncSocket socket, byte[] buffer)
		{
			socket.Receive(buffer, 0, buffer.Length, SocketFlags.None);
		}
	}
}
namespace AsyncIO.Windows
{
	internal class CompletionPort : AsyncIO.CompletionPort
	{
		private readonly IntPtr m_completionPortHandle;

		private readonly IntPtr InvalidCompletionPort = IntPtr.Zero;

		private readonly IntPtr InvalidCompletionPortMinusOne = new IntPtr(-1);

		private readonly IntPtr SignalPostCompletionKey = new IntPtr(1);

		private readonly IntPtr SocketCompletionKey = new IntPtr(2);

		private readonly IntPtr SocketManualCompletionKey = new IntPtr(3);

		private const int WaitTimeoutError = 258;

		private const SocketError ConnectionAborted = (SocketError)1236;

		private const SocketError NetworkNameDeleted = (SocketError)64;

		private bool m_disposed;

		private ConcurrentQueue<object> m_signalQueue;

		private OverlappedEntry[] m_overlappedEntries;

		private GCHandle m_overlappedEntriesHandle;

		private IntPtr m_overlappedEntriesAddress;

		public CompletionPort()
		{
			m_completionPortHandle = UnsafeMethods.CreateIoCompletionPort(UnsafeMethods.INVALID_HANDLE_VALUE, InvalidCompletionPort, IntPtr.Zero, 1u);
			if (m_completionPortHandle == InvalidCompletionPort || m_completionPortHandle == InvalidCompletionPortMinusOne)
			{
				throw new Win32Exception();
			}
			m_signalQueue = new ConcurrentQueue<object>();
		}

		~CompletionPort()
		{
			Dispose();
		}

		public override void AssociateSocket(AsyncSocket socket, object state)
		{
			if (!(socket is Socket))
			{
				throw new ArgumentException("socket must be of type Windows.Socket", "socket");
			}
			Socket socket2 = socket as Socket;
			if (socket2.CompletionPort != this)
			{
				IntPtr intPtr = UnsafeMethods.CreateIoCompletionPort(socket2.Handle, m_completionPortHandle, SocketCompletionKey, 0u);
				if (intPtr == InvalidCompletionPort || intPtr == InvalidCompletionPortMinusOne)
				{
					throw new Win32Exception();
				}
			}
			socket2.SetCompletionPort(this, state);
		}

		internal void PostCompletionStatus(IntPtr overlapped)
		{
			UnsafeMethods.PostQueuedCompletionStatus(m_completionPortHandle, 0, SocketManualCompletionKey, overlapped);
		}

		public override bool GetMultipleQueuedCompletionStatus(int timeout, CompletionStatus[] completionStatuses, out int removed)
		{
			if (Environment.OSVersion.Version.Major == 5)
			{
				removed = 0;
				CompletionStatus completionStatus;
				bool queuedCompletionStatus = GetQueuedCompletionStatus(timeout, out completionStatus);
				if (queuedCompletionStatus)
				{
					completionStatuses[0] = completionStatus;
					removed = 1;
				}
				return queuedCompletionStatus;
			}
			if (m_overlappedEntries == null || m_overlappedEntries.Length < completionStatuses.Length)
			{
				if (m_overlappedEntries != null)
				{
					m_overlappedEntriesHandle.Free();
				}
				m_overlappedEntries = new OverlappedEntry[completionStatuses.Length];
				m_overlappedEntriesHandle = GCHandle.Alloc(m_overlappedEntries, GCHandleType.Pinned);
				m_overlappedEntriesAddress = Marshal.UnsafeAddrOfPinnedArrayElement(m_overlappedEntries, 0);
			}
			if (!UnsafeMethods.GetQueuedCompletionStatusEx(m_completionPortHandle, m_overlappedEntriesAddress, completionStatuses.Length, out removed, timeout, alertable: false))
			{
				int lastWin32Error = Marshal.GetLastWin32Error();
				if (lastWin32Error == 258)
				{
					removed = 0;
					return false;
				}
				throw new Win32Exception(lastWin32Error);
			}
			for (int i = 0; i < removed; i++)
			{
				HandleCompletionStatus(out completionStatuses[i], m_overlappedEntries[i].Overlapped, m_overlappedEntries[i].CompletionKey, m_overlappedEntries[i].BytesTransferred);
			}
			return true;
		}

		public override bool GetQueuedCompletionStatus(int timeout, out CompletionStatus completionStatus)
		{
			if (!UnsafeMethods.GetQueuedCompletionStatus(m_completionPortHandle, out var numberOfBytes, out var completionKey, out var overlapped, timeout) && overlapped == IntPtr.Zero)
			{
				int lastWin32Error = Marshal.GetLastWin32Error();
				if (lastWin32Error == 258)
				{
					completionStatus = default(CompletionStatus);
					return false;
				}
				throw new Win32Exception(lastWin32Error);
			}
			HandleCompletionStatus(out completionStatus, overlapped, completionKey, numberOfBytes);
			return true;
		}

		private void HandleCompletionStatus(out CompletionStatus completionStatus, IntPtr overlappedAddress, IntPtr completionKey, int bytesTransferred)
		{
			if (completionKey.Equals((object?)(nint)SignalPostCompletionKey))
			{
				m_signalQueue.TryDequeue(out var result);
				completionStatus = new CompletionStatus(null, result, OperationType.Signal, SocketError.Success, 0);
				return;
			}
			Overlapped overlapped = Overlapped.CompleteOperation(overlappedAddress);
			if (completionKey.Equals((object?)(nint)SocketCompletionKey))
			{
				if (overlapped.Success)
				{
					SocketError socketError = SocketError.Success;
					try
					{
						if (overlapped.OperationType == OperationType.Accept)
						{
							overlapped.AsyncSocket.UpdateAccept();
						}
						else if (overlapped.OperationType == OperationType.Connect)
						{
							overlapped.AsyncSocket.UpdateConnect();
						}
					}
					catch (SocketException ex)
					{
						socketError = ex.SocketErrorCode;
					}
					completionStatus = new CompletionStatus(overlapped.AsyncSocket, overlapped.State, overlapped.OperationType, socketError, bytesTransferred);
				}
				else
				{
					SocketError socketError2 = SocketError.Success;
					SocketFlags socketFlags;
					if (overlapped.Disposed)
					{
						socketError2 = SocketError.OperationAborted;
					}
					else if (!UnsafeMethods.WSAGetOverlappedResult(overlapped.AsyncSocket.Handle, overlappedAddress, out bytesTransferred, wait: false, out socketFlags))
					{
						socketError2 = (SocketError)Marshal.GetLastWin32Error();
					}
					completionStatus = new CompletionStatus(overlapped.AsyncSocket, overlapped.State, overlapped.OperationType, socketError2, bytesTransferred);
				}
			}
			else
			{
				completionStatus = new CompletionStatus(overlapped.AsyncSocket, overlapped.State, overlapped.OperationType, SocketError.Success, 0);
			}
		}

		public override void Signal(object state)
		{
			m_signalQueue.Enqueue(state);
			UnsafeMethods.PostQueuedCompletionStatus(m_completionPortHandle, 0, SignalPostCompletionKey, IntPtr.Zero);
		}

		public override void Dispose()
		{
			if (!m_disposed)
			{
				m_disposed = true;
				if (m_overlappedEntries != null)
				{
					m_overlappedEntries = null;
					m_overlappedEntriesHandle.Free();
				}
				UnsafeMethods.CloseHandle(m_completionPortHandle);
				GC.SuppressFinalize(this);
			}
		}
	}
	internal class Overlapped : IDisposable
	{
		private static readonly int Size = IntPtr.Size * 4 + 8;

		private static readonly int BytesTransferredOffset = IntPtr.Size;

		private static readonly int OffsetOffset = IntPtr.Size * 2;

		private static readonly int EventOffset = IntPtr.Size * 2 + 8;

		private static readonly int ManagedOverlappedOffset = IntPtr.Size * 3 + 8;

		private IntPtr m_address;

		private GCHandle m_handle;

		private PinnedBuffer m_pinnedBuffer;

		public IntPtr Address => m_address;

		public long BufferAddress
		{
			get
			{
				if (m_pinnedBuffer == null)
				{
					return 0L;
				}
				return m_pinnedBuffer.Address;
			}
		}

		public OperationType OperationType { get; private set; }

		public Socket AsyncSocket { get; private set; }

		public bool Success { get; private set; }

		public bool InProgress { get; private set; }

		public bool Disposed { get; private set; }

		public object State { get; set; }

		public Overlapped(Socket asyncSocket)
		{
			Disposed = false;
			InProgress = false;
			AsyncSocket = asyncSocket;
			m_address = Marshal.AllocHGlobal(Size);
			Marshal.WriteIntPtr(m_address, IntPtr.Zero);
			Marshal.WriteIntPtr(m_address, BytesTransferredOffset, IntPtr.Zero);
			Marshal.WriteInt64(m_address, OffsetOffset, 0L);
			Marshal.WriteIntPtr(m_address, EventOffset, IntPtr.Zero);
			m_handle = GCHandle.Alloc(this, GCHandleType.Normal);
			Marshal.WriteIntPtr(m_address, ManagedOverlappedOffset, GCHandle.ToIntPtr(m_handle));
		}

		public void Dispose()
		{
			if (!InProgress)
			{
				Free();
			}
			Disposed = true;
		}

		private void Free()
		{
			Marshal.FreeHGlobal(m_address);
			if (m_handle.IsAllocated)
			{
				m_handle.Free();
			}
			if (m_pinnedBuffer != null)
			{
				m_pinnedBuffer.Dispose();
				m_pinnedBuffer = null;
			}
		}

		public void StartOperation(OperationType operationType)
		{
			StartOperation(operationType, null);
		}

		public void StartOperation(OperationType operationType, byte[] buffer)
		{
			InProgress = true;
			Success = false;
			OperationType = operationType;
			if (buffer != null)
			{
				if (m_pinnedBuffer == null)
				{
					m_pinnedBuffer = new PinnedBuffer(buffer);
				}
				else if (m_pinnedBuffer.Buffer != buffer)
				{
					m_pinnedBuffer.Switch(buffer);
				}
			}
		}

		public static Overlapped CompleteOperation(IntPtr overlappedAddress)
		{
			Overlapped overlapped = (Overlapped)GCHandle.FromIntPtr(Marshal.ReadIntPtr(overlappedAddress, ManagedOverlappedOffset)).Target;
			overlapped.InProgress = false;
			if (overlapped.Disposed)
			{
				overlapped.Free();
				overlapped.Success = false;
			}
			else
			{
				overlapped.Success = Marshal.ReadIntPtr(overlapped.m_address).Equals((object?)(nint)IntPtr.Zero);
			}
			return overlapped;
		}
	}
	internal class PinnedBuffer : IDisposable
	{
		private GCHandle m_handle;

		public byte[] Buffer { get; private set; }

		public long Address { get; private set; }

		public PinnedBuffer(byte[] buffer)
		{
			SetBuffer(buffer);
		}

		public void Switch(byte[] buffer)
		{
			m_handle.Free();
			SetBuffer(buffer);
		}

		private void SetBuffer(byte[] buffer)
		{
			Buffer = buffer;
			m_handle = GCHandle.Alloc(buffer, GCHandleType.Pinned);
			Address = Marshal.UnsafeAddrOfPinnedArrayElement(Buffer, 0).ToInt64();
		}

		public void Dispose()
		{
			m_handle.Free();
			Buffer = null;
			Address = 0L;
		}
	}
	internal sealed class Socket : AsyncSocket
	{
		private sealed class Connector
		{
			internal readonly ConnectExDelegate m_connectEx;

			public Connector(Socket socket)
			{
				m_connectEx = (ConnectExDelegate)socket.LoadDynamicMethod<ConnectExDelegate>(UnsafeMethods.WSAID_CONNECTEX);
			}
		}

		private sealed class Listener : IDisposable
		{
			private readonly Socket m_socket;

			internal readonly AcceptExDelegate m_acceptEx;

			private IntPtr m_acceptSocketBufferAddress;

			private int m_acceptSocketBufferSize;

			internal Socket m_acceptSocket;

			public Listener(Socket socket)
			{
				m_socket = socket;
				m_acceptEx = (AcceptExDelegate)m_socket.LoadDynamicMethod<AcceptExDelegate>(UnsafeMethods.WSAID_ACCEPT_EX);
			}

			~Listener()
			{
				Dispose(disposing: false);
			}

			public Socket GetAcceptedSocket()
			{
				return Interlocked.Exchange(ref m_acceptSocket, null);
			}

			public void Dispose()
			{
				Dispose(disposing: true);
				GC.SuppressFinalize(this);
			}

			public void AcceptInternal(AsyncSocket socket)
			{
				if (m_acceptSocketBufferAddress == IntPtr.Zero)
				{
					m_acceptSocketBufferSize = m_socket.m_boundAddress.Size + 16;
					m_acceptSocketBufferAddress = Marshal.AllocHGlobal(m_acceptSocketBufferSize << 1);
				}
				m_acceptSocket = socket as Socket;
				m_socket.m_inOverlapped.StartOperation(OperationType.Accept);
				if (!m_acceptEx(m_socket.Handle, m_acceptSocket.Handle, m_acceptSocketBufferAddress, 0, m_acceptSocketBufferSize, m_acceptSocketBufferSize, out var _, m_socket.m_inOverlapped.Address))
				{
					SocketError lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
					if (lastWin32Error != SocketError.IOPending)
					{
						throw new SocketException((int)lastWin32Error);
					}
				}
				else
				{
					m_socket.CompletionPort.PostCompletionStatus(m_socket.m_inOverlapped.Address);
				}
			}

			private void Dispose(bool disposing)
			{
				if (m_acceptSocketBufferAddress != IntPtr.Zero)
				{
					Marshal.FreeHGlobal(m_acceptSocketBufferAddress);
					m_acceptSocketBufferAddress = IntPtr.Zero;
				}
				if (m_acceptSocket != null)
				{
					m_acceptSocket.Dispose(disposing);
					m_acceptSocket = null;
				}
			}
		}

		private Overlapped m_inOverlapped;

		private Overlapped m_outOverlapped;

		private Connector m_connector;

		private Listener m_listener;

		private bool m_disposed;

		private SocketAddress m_boundAddress;

		private SocketAddress m_remoteAddress;

		public IntPtr Handle { get; private set; }

		public CompletionPort CompletionPort { get; private set; }

		public override IPEndPoint RemoteEndPoint
		{
			get
			{
				using SocketAddress socketAddress = new SocketAddress(base.AddressFamily, (base.AddressFamily == AddressFamily.InterNetwork) ? 16 : 28);
				int socketAddressSize = socketAddress.Size;
				if (UnsafeMethods.getpeername(Handle, socketAddress.Buffer, ref socketAddressSize) != 0)
				{
					throw new SocketException();
				}
				return socketAddress.GetEndPoint();
			}
		}

		public override IPEndPoint LocalEndPoint
		{
			get
			{
				using SocketAddress socketAddress = new SocketAddress(base.AddressFamily, (base.AddressFamily == AddressFamily.InterNetwork) ? 16 : 28);
				int socketAddressSize = socketAddress.Size;
				if (UnsafeMethods.getsockname(Handle, socketAddress.Buffer, ref socketAddressSize) != 0)
				{
					throw new SocketException();
				}
				return socketAddress.GetEndPoint();
			}
		}

		public Socket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
			: base(addressFamily, socketType, protocolType)
		{
			m_disposed = false;
			m_inOverlapped = new Overlapped(this);
			m_outOverlapped = new Overlapped(this);
			InitSocket();
		}

		static Socket()
		{
			using (new System.Net.Sockets.Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
			{
			}
		}

		~Socket()
		{
			Dispose(disposing: false);
		}

		private void Dispose(bool disposing)
		{
			if (!m_disposed)
			{
				m_disposed = true;
				m_inOverlapped.Dispose();
				m_outOverlapped.Dispose();
				if (Environment.OSVersion.Version.Major == 5)
				{
					UnsafeMethods.CancelIo(Handle);
				}
				else
				{
					UnsafeMethods.CancelIoEx(Handle, IntPtr.Zero);
				}
				if (UnsafeMethods.closesocket(Handle) != 0)
				{
					Marshal.GetLastWin32Error();
				}
				if (m_remoteAddress != null)
				{
					m_remoteAddress.Dispose();
					m_remoteAddress = null;
				}
				if (m_boundAddress != null)
				{
					m_boundAddress.Dispose();
					m_boundAddress = null;
				}
				if (m_listener != null)
				{
					m_listener.Dispose();
				}
			}
		}

		public override void Dispose()
		{
			Dispose(disposing: true);
			GC.SuppressFinalize(this);
		}

		private void InitSocket()
		{
			Handle = UnsafeMethods.WSASocket(base.AddressFamily, base.SocketType, base.ProtocolType, IntPtr.Zero, 0u, SocketConstructorFlags.WSA_FLAG_OVERLAPPED);
			if (Handle == UnsafeMethods.INVALID_HANDLE_VALUE)
			{
				throw new SocketException();
			}
		}

		private Delegate LoadDynamicMethod<T>(Guid guid)
		{
			IntPtr lpvOutBuffer = IntPtr.Zero;
			int lpcbBytesReturned = 0;
			if (UnsafeMethods.WSAIoctl(Handle, -939524090, ref guid, Marshal.SizeOf(guid), ref lpvOutBuffer, IntPtr.Size, ref lpcbBytesReturned, IntPtr.Zero, IntPtr.Zero) != 0)
			{
				throw new SocketException();
			}
			return Marshal.GetDelegateForFunctionPointer(lpvOutBuffer, typeof(T));
		}

		internal void SetCompletionPort(CompletionPort completionPort, object state)
		{
			CompletionPort = completionPort;
			m_inOverlapped.State = state;
			m_outOverlapped.State = state;
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue)
		{
			if (UnsafeMethods.setsockopt(Handle, optionLevel, optionName, optionValue, (optionValue != null) ? optionValue.Length : 0) == SocketError.SocketError)
			{
				throw new SocketException();
			}
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
		{
			if (UnsafeMethods.setsockopt(Handle, optionLevel, optionName, ref optionValue, 4) == SocketError.SocketError)
			{
				throw new SocketException();
			}
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
		{
			SetSocketOption(optionLevel, optionName, optionValue ? 1 : 0);
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
		{
			if (optionValue == null)
			{
				throw new ArgumentNullException("optionValue");
			}
			if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger)
			{
				if (!(optionValue is LingerOption lingerOption))
				{
					throw new ArgumentException("invalid option value", "optionValue");
				}
				if (lingerOption.LingerTime < 0 || lingerOption.LingerTime > 65535)
				{
					throw new ArgumentOutOfRangeException("optionValue.LingerTime");
				}
				SetLingerOption(lingerOption);
			}
			else if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership))
			{
				if (!(optionValue is MulticastOption mr))
				{
					throw new ArgumentException("optionValue");
				}
				SetMulticastOption(optionName, mr);
			}
			else
			{
				if (optionLevel != SocketOptionLevel.IPv6 || (optionName != SocketOptionName.AddMembership && optionName != SocketOptionName.DropMembership))
				{
					throw new ArgumentException("optionValue");
				}
				if (!(optionValue is IPv6MulticastOption mr2))
				{
					throw new ArgumentException("optionValue");
				}
				SetIPv6MulticastOption(optionName, mr2);
			}
		}

		private void SetIPv6MulticastOption(SocketOptionName optionName, IPv6MulticastOption mr)
		{
			IPv6MulticastRequest pv6MulticastRequest = default(IPv6MulticastRequest);
			pv6MulticastRequest.MulticastAddress = mr.Group.GetAddressBytes();
			pv6MulticastRequest.InterfaceIndex = (int)mr.InterfaceIndex;
			IPv6MulticastRequest mreq = pv6MulticastRequest;
			if (UnsafeMethods.setsockopt(Handle, SocketOptionLevel.IPv6, optionName, ref mreq, IPv6MulticastRequest.Size) == SocketError.SocketError)
			{
				throw new SocketException();
			}
		}

		private int GetIP4Address(IPAddress ipAddress)
		{
			byte[] addressBytes = ipAddress.GetAddressBytes();
			return addressBytes[0] | (addressBytes[1] << 8) | (addressBytes[2] << 16) | (addressBytes[3] << 24);
		}

		private void SetMulticastOption(SocketOptionName optionName, MulticastOption mr)
		{
			IPMulticastRequest mreq = default(IPMulticastRequest);
			mreq.MulticastAddress = GetIP4Address(mr.Group);
			if (mr.LocalAddress != null)
			{
				mreq.InterfaceAddress = GetIP4Address(mr.LocalAddress);
			}
			else
			{
				int interfaceAddress = IPAddress.HostToNetworkOrder(mr.InterfaceIndex);
				mreq.InterfaceAddress = interfaceAddress;
			}
			if (UnsafeMethods.setsockopt(Handle, SocketOptionLevel.IPv6, optionName, ref mreq, IPv6MulticastRequest.Size) == SocketError.SocketError)
			{
				throw new SocketException();
			}
		}

		private void SetLingerOption(LingerOption lref)
		{
			Linger linger = default(Linger);
			linger.OnOff = (ushort)(lref.Enabled ? 1 : 0);
			linger.Time = (ushort)lref.LingerTime;
			Linger linger2 = linger;
			if (UnsafeMethods.setsockopt(Handle, SocketOptionLevel.Socket, SocketOptionName.Linger, ref linger2, 4) == SocketError.SocketError)
			{
				throw new SocketException();
			}
		}

		public override void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue)
		{
			int optionLength = ((optionValue != null) ? optionValue.Length : 0);
			if (UnsafeMethods.getsockopt(Handle, optionLevel, optionName, optionValue, ref optionLength) == SocketError.SocketError)
			{
				throw new SocketException();
			}
		}

		public override byte[] GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
		{
			byte[] array = new byte[optionLength];
			int optionLength2 = optionLength;
			if (UnsafeMethods.getsockopt(Handle, optionLevel, optionName, array, ref optionLength2) != SocketError.SocketError)
			{
				if (optionLength != optionLength2)
				{
					byte[] array2 = new byte[optionLength2];
					Buffer.BlockCopy(array, 0, array2, 0, optionLength2);
					array = array2;
				}
				return array;
			}
			throw new SocketException();
		}

		public override object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName)
		{
			if (optionLevel == SocketOptionLevel.Socket && optionName == SocketOptionName.Linger)
			{
				return GetLingerOpt();
			}
			if (optionLevel == SocketOptionLevel.IP && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership))
			{
				return GetMulticastOpt(optionName);
			}
			if (optionLevel == SocketOptionLevel.IPv6 && (optionName == SocketOptionName.AddMembership || optionName == SocketOptionName.DropMembership))
			{
				return GetIPv6MulticastOpt(optionName);
			}
			int optionValue = 0;
			int optionLength = 4;
			if (UnsafeMethods.getsockopt(Handle, optionLevel, optionName, out optionValue, ref optionLength) != SocketError.SocketError)
			{
				return optionValue;
			}
			throw new SocketException();
		}

		private object GetIPv6MulticastOpt(SocketOptionName optionName)
		{
			throw new NotImplementedException();
		}

		private object GetMulticastOpt(SocketOptionName optionName)
		{
			throw new NotImplementedException();
		}

		private object GetLingerOpt()
		{
			throw new NotImplementedException();
		}

		public override int IOControl(IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
		{
			int bytesTransferred = 0;
			if (UnsafeMethods.WSAIoctl_Blocking(Handle, (int)ioControlCode, optionInValue, (optionInValue != null) ? optionInValue.Length : 0, optionOutValue, (optionOutValue != null) ? optionOutValue.Length : 0, out bytesTransferred, IntPtr.Zero, IntPtr.Zero) != SocketError.SocketError)
			{
				return bytesTransferred;
			}
			throw new SocketException();
		}

		public override void Bind(IPEndPoint localEndPoint)
		{
			if (m_boundAddress != null)
			{
				m_boundAddress.Dispose();
				m_boundAddress = null;
			}
			m_boundAddress = new SocketAddress(localEndPoint.Address, localEndPoint.Port);
			if (UnsafeMethods.bind(Handle, m_boundAddress.Buffer, m_boundAddress.Size) != 0)
			{
				throw new SocketException();
			}
		}

		public override void Listen(int backlog)
		{
			if (UnsafeMethods.listen(Handle, backlog) != 0)
			{
				throw new SocketException();
			}
			m_listener = new Listener(this);
		}

		public override void Connect(IPEndPoint endPoint)
		{
			if (m_remoteAddress != null)
			{
				m_remoteAddress.Dispose();
				m_remoteAddress = null;
			}
			m_remoteAddress = new SocketAddress(endPoint.Address, endPoint.Port);
			if (m_boundAddress == null)
			{
				if (endPoint.AddressFamily == AddressFamily.InterNetwork)
				{
					Bind(new IPEndPoint(IPAddress.Any, 0));
				}
				else
				{
					Bind(new IPEndPoint(IPAddress.IPv6Any, 0));
				}
			}
			m_outOverlapped.StartOperation(OperationType.Connect);
			if ((m_connector ?? (m_connector = new Connector(this))).m_connectEx(Handle, m_remoteAddress.Buffer, m_remoteAddress.Size, IntPtr.Zero, 0, out var _, m_outOverlapped.Address))
			{
				CompletionPort.PostCompletionStatus(m_outOverlapped.Address);
				return;
			}
			SocketError lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
			if (lastWin32Error == SocketError.IOPending)
			{
				return;
			}
			throw new SocketException((int)lastWin32Error);
		}

		internal void UpdateConnect()
		{
			SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.UpdateConnectContext, null);
		}

		public override AsyncSocket GetAcceptedSocket()
		{
			return m_listener.GetAcceptedSocket();
		}

		public override void Accept()
		{
			m_listener.AcceptInternal(new Socket(base.AddressFamily, base.SocketType, base.ProtocolType));
		}

		public override void Accept(AsyncSocket socket)
		{
			m_listener.AcceptInternal(socket);
		}

		internal void UpdateAccept()
		{
			byte[] optionValue = ((IntPtr.Size != 4) ? BitConverter.GetBytes(Handle.ToInt64()) : BitConverter.GetBytes(Handle.ToInt32()));
			m_listener.m_acceptSocket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.UpdateAcceptContext, optionValue);
		}

		public override void Send(byte[] buffer, int offset, int count, SocketFlags flags)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			m_outOverlapped.StartOperation(OperationType.Send, buffer);
			WSABuffer wSABuffer = default(WSABuffer);
			wSABuffer.Pointer = new IntPtr(m_outOverlapped.BufferAddress + offset);
			wSABuffer.Length = count;
			WSABuffer buffer2 = wSABuffer;
			if (UnsafeMethods.WSASend(Handle, ref buffer2, 1, out var _, flags, m_outOverlapped.Address, IntPtr.Zero) != 0)
			{
				SocketError lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
				if (lastWin32Error != SocketError.IOPending)
				{
					throw new SocketException((int)lastWin32Error);
				}
			}
		}

		public override void Receive(byte[] buffer, int offset, int count, SocketFlags flags)
		{
			if (buffer == null)
			{
				throw new ArgumentNullException("buffer");
			}
			m_inOverlapped.StartOperation(OperationType.Receive, buffer);
			WSABuffer buffer2 = default(WSABuffer);
			buffer2.Pointer = new IntPtr(m_inOverlapped.BufferAddress + offset);
			buffer2.Length = count;
			if (UnsafeMethods.WSARecv(Handle, ref buffer2, 1, out var _, ref flags, m_inOverlapped.Address, IntPtr.Zero) != 0)
			{
				SocketError lastWin32Error = (SocketError)Marshal.GetLastWin32Error();
				if (lastWin32Error != SocketError.IOPending)
				{
					throw new SocketException((int)lastWin32Error);
				}
			}
		}
	}
	internal class SocketAddress : IDisposable
	{
		private byte[] m_buffer;

		private AddressFamily m_addressFamily;

		private bool m_disposed;

		private GCHandle m_bufferHandle;

		private IntPtr m_bufferAddress;

		public int Size { get; private set; }

		public IntPtr PinnedAddressBuffer => m_bufferAddress;

		public byte[] Buffer => m_buffer;

		public SocketAddress(AddressFamily addressFamily, int size)
		{
			Size = size;
			m_addressFamily = addressFamily;
			m_buffer = new byte[size];
			m_buffer = new byte[(size / IntPtr.Size + 2) * IntPtr.Size];
			m_buffer[0] = (byte)addressFamily;
			m_buffer[1] = (byte)((uint)addressFamily >> 8);
			m_bufferHandle = GCHandle.Alloc(m_buffer, GCHandleType.Pinned);
			m_bufferAddress = Marshal.UnsafeAddrOfPinnedArrayElement(m_buffer, 0);
		}

		public SocketAddress(IPAddress ipAddress)
			: this(ipAddress.AddressFamily, (ipAddress.AddressFamily == AddressFamily.InterNetwork) ? 16 : 28)
		{
			m_buffer[2] = 0;
			m_buffer[3] = 0;
			if (ipAddress.AddressFamily == AddressFamily.InterNetworkV6)
			{
				m_buffer[4] = 0;
				m_buffer[5] = 0;
				m_buffer[6] = 0;
				m_buffer[7] = 0;
				long scopeId = ipAddress.ScopeId;
				m_buffer[24] = (byte)scopeId;
				m_buffer[25] = (byte)(scopeId >> 8);
				m_buffer[26] = (byte)(scopeId >> 16);
				m_buffer[27] = (byte)(scopeId >> 24);
				byte[] addressBytes = ipAddress.GetAddressBytes();
				for (int i = 0; i < addressBytes.Length; i++)
				{
					m_buffer[8 + i] = addressBytes[i];
				}
			}
			else
			{
				System.Buffer.BlockCopy(ipAddress.GetAddressBytes(), 0, m_buffer, 4, 4);
			}
		}

		public IPEndPoint GetEndPoint()
		{
			return new IPEndPoint(GetIPAddress(), ((Buffer[2] << 8) & 0xFF00) | Buffer[3]);
		}

		internal IPAddress GetIPAddress()
		{
			if (m_addressFamily == AddressFamily.InterNetworkV6)
			{
				byte[] array = new byte[16];
				for (int i = 0; i < array.Length; i++)
				{
					array[i] = Buffer[i + 8];
				}
				long scopeid = (Buffer[27] << 24) + (Buffer[26] << 16) + (Buffer[25] << 8) + Buffer[24];
				return new IPAddress(array, scopeid);
			}
			if (m_addressFamily == AddressFamily.InterNetwork)
			{
				return new IPAddress(((Buffer[4] & 0xFF) | ((Buffer[5] << 8) & 0xFF00) | ((Buffer[6] << 16) & 0xFF0000) | (Buffer[7] << 24)) & 0xFFFFFFFFu);
			}
			throw new SocketException(10047);
		}

		public SocketAddress(IPAddress ipAddress, int port)
			: this(ipAddress)
		{
			m_buffer[2] = (byte)(port >> 8);
			m_buffer[3] = (byte)port;
		}

		public void Dispose()
		{
			if (!m_disposed)
			{
				m_disposed = true;
				m_bufferHandle.Free();
			}
		}
	}
	internal delegate bool ConnectExDelegate(IntPtr socketHandle, byte[] socketAddress, int socketAddressSize, IntPtr buffer, int dataLength, out int bytesSent, IntPtr overlapped);
	internal delegate bool AcceptExDelegate(IntPtr listenSocketHandle, IntPtr acceptSocketHandle, IntPtr buffer, int len, int localAddressLength, int remoteAddressLength, out int bytesReceived, IntPtr overlapped);
	[Flags]
	internal enum SocketConstructorFlags
	{
		WSA_FLAG_OVERLAPPED = 1,
		WSA_FLAG_MULTIPOINT_C_ROOT = 2,
		WSA_FLAG_MULTIPOINT_C_LEAF = 4,
		WSA_FLAG_MULTIPOINT_D_ROOT = 8,
		WSA_FLAG_MULTIPOINT_D_LEAF = 0x10
	}
	internal struct WSABuffer
	{
		internal int Length;

		internal IntPtr Pointer;
	}
	internal struct Linger
	{
		internal ushort OnOff;

		internal ushort Time;
	}
	internal struct IPv6MulticastRequest
	{
		internal static readonly int Size;

		[MarshalAs(UnmanagedType.ByValArray, SizeConst = 16)]
		internal byte[] MulticastAddress;

		internal int InterfaceIndex;

		static IPv6MulticastRequest()
		{
			Size = Marshal.SizeOf(typeof(IPv6MulticastRequest));
		}
	}
	internal struct IPMulticastRequest
	{
		internal static readonly int Size;

		internal int MulticastAddress;

		internal int InterfaceAddress;

		static IPMulticastRequest()
		{
			Size = Marshal.SizeOf(typeof(IPMulticastRequest));
		}
	}
	internal struct OverlappedEntry
	{
		public IntPtr CompletionKey;

		public IntPtr Overlapped;

		public IntPtr Internal;

		public int BytesTransferred;
	}
	internal static class UnsafeMethods
	{
		public static readonly IntPtr INVALID_HANDLE_VALUE = new IntPtr(-1);

		public static readonly Guid WSAID_CONNECTEX = new Guid("25a207b9-ddf3-4660-8ee9-76e58c74063e");

		public static readonly Guid WSAID_ACCEPT_EX = new Guid("b5367df1-cbac-11cf-95ca-00805f48a192");

		public const int GetExtensionFunctionPointer = -939524090;

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern IntPtr CreateIoCompletionPort(IntPtr fileHandle, IntPtr existingCompletionPort, IntPtr completionKey, uint numberOfConcurrentThreads);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern bool GetQueuedCompletionStatus(IntPtr completionPort, out int numberOfBytes, out IntPtr completionKey, out IntPtr overlapped, int milliseconds);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern bool GetQueuedCompletionStatusEx(IntPtr completionPort, IntPtr completionPortEntries, int count, out int removed, int milliseconds, bool alertable);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern bool PostQueuedCompletionStatus(IntPtr completionPort, int numberOfBytesTransferred, IntPtr completionKey, IntPtr overlapped);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern bool CloseHandle(IntPtr hHandle);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError WSASend([In] IntPtr socketHandle, [In] ref WSABuffer buffer, [In] int bufferCount, out int bytesTransferred, [In] SocketFlags socketFlags, [In] IntPtr overlapped, [In] IntPtr completionRoutine);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError WSARecv([In] IntPtr socketHandle, [In] ref WSABuffer buffer, [In] int bufferCount, out int bytesTransferred, [In][Out] ref SocketFlags socketFlags, [In] IntPtr overlapped, [In] IntPtr completionRoutine);

		[DllImport("Ws2_32.dll", SetLastError = true)]
		public static extern int WSAIoctl(IntPtr s, int dwIoControlCode, ref Guid lpvInBuffer, int cbInBuffer, ref IntPtr lpvOutBuffer, int cbOutBuffer, ref int lpcbBytesReturned, IntPtr lpOverlapped, IntPtr lpCompletionRoutine);

		[DllImport("ws2_32.dll", EntryPoint = "WSAIoctl", SetLastError = true)]
		public static extern SocketError WSAIoctl_Blocking([In] IntPtr socketHandle, [In] int ioControlCode, [In] byte[] inBuffer, [In] int inBufferSize, [Out] byte[] outBuffer, [In] int outBufferSize, out int bytesTransferred, [In] IntPtr overlapped, [In] IntPtr completionRoutine);

		[DllImport("Ws2_32.dll", SetLastError = true)]
		public static extern int bind(IntPtr s, byte[] socketAddress, int addrsize);

		[DllImport("Ws2_32.dll", SetLastError = true)]
		public static extern int listen(IntPtr s, int backlog);

		[DllImport("ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
		public static extern IntPtr WSASocket([In] AddressFamily addressFamily, [In] SocketType socketType, [In] ProtocolType protocolType, [In] IntPtr pinnedBuffer, [In] uint group, [In] SocketConstructorFlags flags);

		[DllImport("ws2_32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
		public static extern int closesocket(IntPtr s);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError setsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, [In] byte[] optionValue, [In] int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError setsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, [In] ref int optionValue, [In] int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError setsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, [In] ref Linger linger, [In] int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError setsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, [In] ref IPv6MulticastRequest mreq, [In] int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError setsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, [In] ref IPMulticastRequest mreq, [In] int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError getsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, out int optionValue, [In][Out] ref int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError getsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, [Out] byte[] optionValue, [In][Out] ref int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError getsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, out Linger optionValue, [In][Out] ref int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError getsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, out IPMulticastRequest optionValue, [In][Out] ref int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError getsockopt([In] IntPtr socketHandle, [In] SocketOptionLevel optionLevel, [In] SocketOptionName optionName, out IPv6MulticastRequest optionValue, [In][Out] ref int optionLength);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError getsockname([In] IntPtr socketHandle, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize);

		[DllImport("ws2_32.dll", SetLastError = true)]
		public static extern SocketError getpeername([In] IntPtr socketHandle, [Out] byte[] socketAddress, [In][Out] ref int socketAddressSize);

		[DllImport("ws2_32.dll", SetLastError = true)]
		internal static extern bool WSAGetOverlappedResult([In] IntPtr socketHandle, [In] IntPtr overlapped, out int bytesTransferred, [In] bool wait, out SocketFlags socketFlags);

		[DllImport("kernel32.dll", SetLastError = true)]
		public static extern bool CancelIoEx(IntPtr hFile, IntPtr overlapped);

		[DllImport("kernel32.dll")]
		public static extern bool CancelIo(IntPtr hFile);
	}
}
namespace AsyncIO.DotNet
{
	internal class CompletionPort : AsyncIO.CompletionPort
	{
		private BlockingCollection<CompletionStatus> m_queue;

		public CompletionPort()
		{
			m_queue = new BlockingCollection<CompletionStatus>();
		}

		internal void Queue(ref CompletionStatus completionStatus)
		{
			m_queue.Add(completionStatus);
		}

		public override void Dispose()
		{
		}

		public override bool GetQueuedCompletionStatus(int timeout, out CompletionStatus completionStatus)
		{
			if (m_queue.TryTake(out completionStatus, timeout))
			{
				return true;
			}
			return false;
		}

		public override bool GetMultipleQueuedCompletionStatus(int timeout, CompletionStatus[] completionStatuses, out int removed)
		{
			removed = 0;
			if (m_queue.TryTake(out completionStatuses[0], timeout))
			{
				removed++;
				while (removed < completionStatuses.Length && m_queue.TryTake(out completionStatuses[removed], 0))
				{
					removed++;
				}
				return true;
			}
			return false;
		}

		public override void AssociateSocket(AsyncSocket asyncSocket, object state)
		{
			((NativeSocket)asyncSocket).SetCompletionPort(this, state);
		}

		public override void Signal(object state)
		{
			m_queue.Add(new CompletionStatus(null, state, OperationType.Signal, SocketError.Success, 0));
		}
	}
	internal class NativeSocket : AsyncSocket
	{
		private System.Net.Sockets.Socket m_socket;

		private CompletionPort m_completionPort;

		private object m_state;

		private SocketAsyncEventArgs m_inSocketAsyncEventArgs;

		private SocketAsyncEventArgs m_outSocketAsyncEventArgs;

		private NativeSocket m_acceptedSocket;

		public override IPEndPoint LocalEndPoint => (IPEndPoint)m_socket.LocalEndPoint;

		public override IPEndPoint RemoteEndPoint => (IPEndPoint)m_socket.RemoteEndPoint;

		public NativeSocket(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType)
			: base(addressFamily, socketType, protocolType)
		{
			m_socket = new System.Net.Sockets.Socket(addressFamily, socketType, protocolType);
			m_inSocketAsyncEventArgs = new SocketAsyncEventArgs();
			m_inSocketAsyncEventArgs.Completed += OnAsyncCompleted;
			m_outSocketAsyncEventArgs = new SocketAsyncEventArgs();
			m_outSocketAsyncEventArgs.Completed += OnAsyncCompleted;
		}

		private NativeSocket(System.Net.Sockets.Socket socket)
			: base(socket.AddressFamily, socket.SocketType, socket.ProtocolType)
		{
			m_socket = socket;
			m_inSocketAsyncEventArgs = new SocketAsyncEventArgs();
			m_inSocketAsyncEventArgs.Completed += OnAsyncCompleted;
			m_outSocketAsyncEventArgs = new SocketAsyncEventArgs();
			m_outSocketAsyncEventArgs.Completed += OnAsyncCompleted;
		}

		private void OnAsyncCompleted(object sender, SocketAsyncEventArgs e)
		{
			OperationType operationType;
			switch (e.LastOperation)
			{
			case SocketAsyncOperation.Accept:
				operationType = OperationType.Accept;
				if (e.SocketError == SocketError.Success)
				{
					m_acceptedSocket = new NativeSocket(e.AcceptSocket);
				}
				break;
			case SocketAsyncOperation.Connect:
				operationType = OperationType.Connect;
				break;
			case SocketAsyncOperation.Receive:
				operationType = OperationType.Receive;
				break;
			case SocketAsyncOperation.Send:
				operationType = OperationType.Send;
				break;
			case SocketAsyncOperation.Disconnect:
				operationType = OperationType.Disconnect;
				break;
			default:
				throw new ArgumentOutOfRangeException();
			}
			CompletionStatus completionStatus = new CompletionStatus(this, m_state, operationType, e.SocketError, e.BytesTransferred);
			m_completionPort.Queue(ref completionStatus);
		}

		internal void SetCompletionPort(CompletionPort completionPort, object state)
		{
			m_completionPort = completionPort;
			m_state = state;
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, bool optionValue)
		{
			m_socket.SetSocketOption(optionLevel, optionName, optionValue);
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue)
		{
			m_socket.SetSocketOption(optionLevel, optionName, optionValue);
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, object optionValue)
		{
			m_socket.SetSocketOption(optionLevel, optionName, optionValue);
		}

		public override void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue)
		{
			m_socket.SetSocketOption(optionLevel, optionName, optionValue);
		}

		public override object GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName)
		{
			return m_socket.GetSocketOption(optionLevel, optionName);
		}

		public override void GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, byte[] optionValue)
		{
			m_socket.GetSocketOption(optionLevel, optionName, optionValue);
		}

		public override byte[] GetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionLength)
		{
			return m_socket.GetSocketOption(optionLevel, optionName, optionLength);
		}

		public override int IOControl(IOControlCode ioControlCode, byte[] optionInValue, byte[] optionOutValue)
		{
			return m_socket.IOControl(ioControlCode, optionInValue, optionOutValue);
		}

		public override void Dispose()
		{
			((IDisposable)m_socket).Dispose();
			m_inSocketAsyncEventArgs.Dispose();
			m_outSocketAsyncEventArgs.Dispose();
			if (m_acceptedSocket != null)
			{
				m_acceptedSocket.Dispose();
			}
		}

		public override void Bind(IPEndPoint localEndPoint)
		{
			m_socket.Bind(localEndPoint);
		}

		public override void Listen(int backlog)
		{
			m_socket.Listen(backlog);
		}

		public override void Connect(IPEndPoint endPoint)
		{
			m_outSocketAsyncEventArgs.RemoteEndPoint = endPoint;
			if (!m_socket.ConnectAsync(m_outSocketAsyncEventArgs))
			{
				CompletionStatus completionStatus = new CompletionStatus(this, m_state, OperationType.Connect, m_outSocketAsyncEventArgs.SocketError, 0);
				m_outSocketAsyncEventArgs.Completed -= OnAsyncCompleted;
				try
				{
					m_outSocketAsyncEventArgs.Dispose();
				}
				catch (Exception)
				{
				}
				m_outSocketAsyncEventArgs = new SocketAsyncEventArgs();
				m_outSocketAsyncEventArgs.Completed += OnAsyncCompleted;
				m_completionPort.Queue(ref completionStatus);
			}
		}

		public override void Accept()
		{
			m_inSocketAsyncEventArgs.AcceptSocket = null;
			if (!m_socket.AcceptAsync(m_inSocketAsyncEventArgs))
			{
				if (m_inSocketAsyncEventArgs.SocketError == SocketError.Success)
				{
					m_acceptedSocket = new NativeSocket(m_inSocketAsyncEventArgs.AcceptSocket);
				}
				CompletionStatus completionStatus = new CompletionStatus(this, m_state, OperationType.Accept, SocketError.Success, 0);
				m_completionPort.Queue(ref completionStatus);
			}
		}

		public override AsyncSocket GetAcceptedSocket()
		{
			m_inSocketAsyncEventArgs.AcceptSocket = null;
			NativeSocket acceptedSocket = m_acceptedSocket;
			m_acceptedSocket = null;
			return acceptedSocket;
		}

		[Obsolete("Use Accept without parameter and GetAcceptedSocket")]
		public override void Accept(AsyncSocket socket)
		{
			NativeSocket nativeSocket = (NativeSocket)socket;
			m_inSocketAsyncEventArgs.AcceptSocket = nativeSocket.m_socket;
			if (!m_socket.AcceptAsync(m_inSocketAsyncEventArgs))
			{
				CompletionStatus completionStatus = new CompletionStatus(this, m_state, OperationType.Accept, SocketError.Success, 0);
				m_completionPort.Queue(ref completionStatus);
			}
		}

		public override void Send(byte[] buffer, int offset, int count, SocketFlags flags)
		{
			if (m_outSocketAsyncEventArgs.Buffer != buffer)
			{
				m_outSocketAsyncEventArgs.SetBuffer(buffer, offset, count);
			}
			else if (m_outSocketAsyncEventArgs.Offset != offset || m_inSocketAsyncEventArgs.Count != count)
			{
				m_outSocketAsyncEventArgs.SetBuffer(offset, count);
			}
			if (!m_socket.SendAsync(m_outSocketAsyncEventArgs))
			{
				CompletionStatus completionStatus = new CompletionStatus(this, m_state, OperationType.Send, m_outSocketAsyncEventArgs.SocketError, m_outSocketAsyncEventArgs.BytesTransferred);
				m_completionPort.Queue(ref completionStatus);
			}
		}

		public override void Receive(byte[] buffer, int offset, int count, SocketFlags flags)
		{
			m_inSocketAsyncEventArgs.AcceptSocket = null;
			if (m_inSocketAsyncEventArgs.Buffer != buffer)
			{
				m_inSocketAsyncEventArgs.SetBuffer(buffer, offset, count);
			}
			else if (m_inSocketAsyncEventArgs.Offset != offset || m_inSocketAsyncEventArgs.Count != count)
			{
				m_inSocketAsyncEventArgs.SetBuffer(offset, count);
			}
			if (!m_socket.ReceiveAsync(m_inSocketAsyncEventArgs))
			{
				CompletionStatus completionStatus = new CompletionStatus(this, m_state, OperationType.Receive, m_inSocketAsyncEventArgs.SocketError, m_inSocketAsyncEventArgs.BytesTransferred);
				m_completionPort.Queue(ref completionStatus);
			}
		}
	}
}