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);
}
}
}
}