using System; using System.Collections.Generic; using System.Net; using System.Net.Sockets; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; namespace LiteNetLib { internal static class NativeSocket { static unsafe class WinSock { private const string LibName = "ws2_32.dll"; [DllImport(LibName, SetLastError = true)] public static extern int recvfrom( IntPtr socketHandle, [In, Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In, Out] ref int socketAddressSize); [DllImport(LibName, SetLastError = true)] internal static extern int sendto( IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize); } static unsafe class UnixSock { private const string LibName = "libc"; [DllImport(LibName, SetLastError = true)] public static extern int recvfrom( IntPtr socketHandle, [In, Out] byte[] pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [Out] byte[] socketAddress, [In, Out] ref int socketAddressSize); [DllImport(LibName, SetLastError = true)] internal static extern int sendto( IntPtr socketHandle, byte* pinnedBuffer, [In] int len, [In] SocketFlags socketFlags, [In] byte[] socketAddress, [In] int socketAddressSize); } public static readonly bool IsSupported = false; public static readonly bool UnixMode = false; public const int IPv4AddrSize = 16; public const int IPv6AddrSize = 28; public const int AF_INET = 2; public const int AF_INET6 = 10; private static readonly Dictionary NativeErrorToSocketError = new Dictionary { { 13, SocketError.AccessDenied }, //EACCES { 98, SocketError.AddressAlreadyInUse }, //EADDRINUSE { 99, SocketError.AddressNotAvailable }, //EADDRNOTAVAIL { 97, SocketError.AddressFamilyNotSupported }, //EAFNOSUPPORT { 11, SocketError.WouldBlock }, //EAGAIN { 114, SocketError.AlreadyInProgress }, //EALREADY { 9, SocketError.OperationAborted }, //EBADF { 125, SocketError.OperationAborted }, //ECANCELED { 103, SocketError.ConnectionAborted }, //ECONNABORTED { 111, SocketError.ConnectionRefused }, //ECONNREFUSED { 104, SocketError.ConnectionReset }, //ECONNRESET { 89, SocketError.DestinationAddressRequired }, //EDESTADDRREQ { 14, SocketError.Fault }, //EFAULT { 112, SocketError.HostDown }, //EHOSTDOWN { 6, SocketError.HostNotFound }, //ENXIO { 113, SocketError.HostUnreachable }, //EHOSTUNREACH { 115, SocketError.InProgress }, //EINPROGRESS { 4, SocketError.Interrupted }, //EINTR { 22, SocketError.InvalidArgument }, //EINVAL { 106, SocketError.IsConnected }, //EISCONN { 24, SocketError.TooManyOpenSockets }, //EMFILE { 90, SocketError.MessageSize }, //EMSGSIZE { 100, SocketError.NetworkDown }, //ENETDOWN { 102, SocketError.NetworkReset }, //ENETRESET { 101, SocketError.NetworkUnreachable }, //ENETUNREACH { 23, SocketError.TooManyOpenSockets }, //ENFILE { 105, SocketError.NoBufferSpaceAvailable }, //ENOBUFS { 61, SocketError.NoData }, //ENODATA { 2, SocketError.AddressNotAvailable }, //ENOENT { 92, SocketError.ProtocolOption }, //ENOPROTOOPT { 107, SocketError.NotConnected }, //ENOTCONN { 88, SocketError.NotSocket }, //ENOTSOCK { 3440, SocketError.OperationNotSupported }, //ENOTSUP { 1, SocketError.AccessDenied }, //EPERM { 32, SocketError.Shutdown }, //EPIPE { 96, SocketError.ProtocolFamilyNotSupported }, //EPFNOSUPPORT { 93, SocketError.ProtocolNotSupported }, //EPROTONOSUPPORT { 91, SocketError.ProtocolType }, //EPROTOTYPE { 94, SocketError.SocketNotSupported }, //ESOCKTNOSUPPORT { 108, SocketError.Disconnecting }, //ESHUTDOWN { 110, SocketError.TimedOut }, //ETIMEDOUT { 0, SocketError.Success } }; static NativeSocket() { if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) { IsSupported = true; UnixMode = true; } else if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { IsSupported = true; } } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static int RecvFrom( IntPtr socketHandle, byte[] pinnedBuffer, int len, byte[] socketAddress, ref int socketAddressSize) { return UnixMode ? UnixSock.recvfrom(socketHandle, pinnedBuffer, len, 0, socketAddress, ref socketAddressSize) : WinSock.recvfrom(socketHandle, pinnedBuffer, len, 0, socketAddress, ref socketAddressSize); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static unsafe int SendTo( IntPtr socketHandle, byte* pinnedBuffer, int len, byte[] socketAddress, int socketAddressSize) { return UnixMode ? UnixSock.sendto(socketHandle, pinnedBuffer, len, 0, socketAddress, socketAddressSize) : WinSock.sendto(socketHandle, pinnedBuffer, len, 0, socketAddress, socketAddressSize); } public static SocketError GetSocketError() { int error = Marshal.GetLastWin32Error(); if (UnixMode) return NativeErrorToSocketError.TryGetValue(error, out var err) ? err : SocketError.SocketError; return (SocketError)error; } public static SocketException GetSocketException() { int error = Marshal.GetLastWin32Error(); if (UnixMode) return NativeErrorToSocketError.TryGetValue(error, out var err) ? new SocketException((int)err) : new SocketException((int)SocketError.SocketError); return new SocketException(error); } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static short GetNativeAddressFamily(IPEndPoint remoteEndPoint) { return UnixMode ? (short)(remoteEndPoint.AddressFamily == AddressFamily.InterNetwork ? AF_INET : AF_INET6) : (short)remoteEndPoint.AddressFamily; } } }