Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of AsyncIO v0.1.6901
BepInEx/core/AsyncIO/netstandard2.0/AsyncIO.dll
Decompiled 2 years agousing 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); } } } }