180 lines
7.6 KiB
C#
180 lines
7.6 KiB
C#
|
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<int, SocketError> NativeErrorToSocketError = new Dictionary<int, SocketError>
|
|||
|
{
|
|||
|
{ 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;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|