├── .gitattributes ├── Test ├── Program.cs ├── Test.csproj └── TestWave.cs ├── enet-csharp ├── ENet │ ├── plugins │ │ ├── NativeSockets │ │ │ ├── Unix │ │ │ │ ├── Shared │ │ │ │ │ ├── include │ │ │ │ │ │ ├── iovec.cs │ │ │ │ │ │ ├── pollfd.cs │ │ │ │ │ │ ├── PollEvents.cs │ │ │ │ │ │ └── msghdr.cs │ │ │ │ │ └── c │ │ │ │ │ │ ├── iOSSocketPal.cs │ │ │ │ │ │ └── UnixSocketPal.cs │ │ │ │ └── Linux │ │ │ │ │ └── c │ │ │ │ │ └── LinuxSocketPal.cs │ │ │ ├── Windows │ │ │ │ └── include │ │ │ │ │ └── WSABuffer.cs │ │ │ ├── Shared │ │ │ │ └── include │ │ │ │ │ ├── sockaddr.cs │ │ │ │ │ ├── sockaddr_storage.cs │ │ │ │ │ ├── in_addr.cs │ │ │ │ │ ├── sockaddr_in.cs │ │ │ │ │ ├── addrinfo.cs │ │ │ │ │ ├── sockaddr_in6.cs │ │ │ │ │ ├── WinSock2.cs │ │ │ │ │ └── sa_family_t.cs │ │ │ └── SocketPal.cs │ │ └── Helpers │ │ │ ├── SpanHelpers.cs │ │ │ └── XxHash.cs │ ├── include │ │ ├── utility.cs │ │ ├── callback.cs │ │ ├── time.cs │ │ ├── list.cs │ │ ├── win32.cs │ │ └── protocol.cs │ ├── define │ │ └── system.cs │ └── c │ │ ├── list.cs │ │ ├── callback.cs │ │ ├── packet.cs │ │ ├── win32.cs │ │ ├── host.cs │ │ └── enet.cs └── enet-csharp.csproj ├── README.md ├── enet-csharp.sln ├── LICENSE └── .gitignore /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Test/Program.cs: -------------------------------------------------------------------------------- 1 | namespace enet 2 | { 3 | internal sealed class Program 4 | { 5 | private static void Main() 6 | { 7 | TestWave.Start(); 8 | } 9 | } 10 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Unix/Shared/include/iovec.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | #pragma warning disable CS8981 3 | 4 | // ReSharper disable ALL 5 | 6 | namespace NativeSockets 7 | { 8 | public unsafe struct iovec 9 | { 10 | public void* iov_base; 11 | public nuint iov_len; 12 | } 13 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Windows/include/WSABuffer.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | #pragma warning disable CS8981 3 | 4 | // ReSharper disable ALL 5 | 6 | namespace NativeSockets 7 | { 8 | public unsafe struct WSABuffer 9 | { 10 | public nuint Length; 11 | public void* Pointer; 12 | } 13 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Unix/Shared/include/pollfd.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [StructLayout(LayoutKind.Sequential)] 11 | internal struct pollfd 12 | { 13 | public int fd; 14 | public short events; 15 | public short revents; 16 | } 17 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/include/utility.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | // ReSharper disable ALL 4 | 5 | namespace enet 6 | { 7 | public static partial class ENet 8 | { 9 | public static uint ENET_MAX(uint x, uint y) => ((x) > (y) ? (x) : (y)); 10 | public static uint ENET_MIN(uint x, uint y) => ((x) < (y) ? (x) : (y)); 11 | public static uint ENET_DIFFERENCE(uint x, uint y) => ((x) < (y) ? (y) - (x) : (x) - (y)); 12 | } 13 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/sockaddr.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [StructLayout(LayoutKind.Explicit, Size = 16)] 11 | public unsafe struct sockaddr 12 | { 13 | [FieldOffset(0)] public sa_family_t sa_family; 14 | [FieldOffset(2)] public fixed byte sa_data[14]; 15 | } 16 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/sockaddr_storage.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [StructLayout(LayoutKind.Explicit, Size = 128)] 11 | public struct sockaddr_storage 12 | { 13 | [FieldOffset(0)] public sa_family_t ss_family; 14 | [FieldOffset(8)] public long __ss_align; 15 | } 16 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Unix/Shared/include/PollEvents.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [Flags] 11 | internal enum PollEvents : short 12 | { 13 | POLLIN = 0x0001, 14 | POLLPRI = 0x0002, 15 | POLLOUT = 0x0004, 16 | POLLERR = 0x0008, 17 | POLLHUP = 0x0010, 18 | POLLNVAL = 0x0020 19 | } 20 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Unix/Shared/include/msghdr.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | #pragma warning disable CS8981 3 | 4 | // ReSharper disable ALL 5 | 6 | namespace NativeSockets 7 | { 8 | public unsafe struct msghdr 9 | { 10 | public void* msg_name; 11 | public nuint msg_namelen; 12 | public iovec* msg_iov; 13 | public int msg_iovlen; 14 | public void* msg_control; 15 | public nuint msg_controllen; 16 | public int msg_flags; 17 | } 18 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/in_addr.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [StructLayout(LayoutKind.Explicit, Size = 4)] 11 | public unsafe struct in_addr 12 | { 13 | [FieldOffset(0)] public fixed byte S_un_b[4]; 14 | [FieldOffset(0)] public fixed ushort S_un_w[2]; 15 | [FieldOffset(0)] public uint S_addr; 16 | } 17 | } -------------------------------------------------------------------------------- /Test/Test.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Exe 5 | net8.0 6 | disable 7 | enable 8 | true 9 | App 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/sockaddr_in.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [StructLayout(LayoutKind.Explicit, Size = 16)] 11 | public unsafe struct sockaddr_in 12 | { 13 | [FieldOffset(0)] public sa_family_t sin_family; 14 | [FieldOffset(2)] public ushort sin_port; 15 | [FieldOffset(4)] public in_addr sin_addr; 16 | [FieldOffset(8)] public fixed byte sin_zero[8]; 17 | } 18 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This project is a pure C# translation of [enet](https://github.com/lsalzman/enet), no binaries. 2 | 3 | Where udp implementation: [NativeSockets](https://github.com/Molth/NativeSockets). 4 | 5 | ## Why? 6 | 7 | The original ENet relies on platform-specific native binaries, 8 | 9 | which poses challenges for cross-platform distribution and deployment. 10 | 11 | This project eliminates that dependency while preserving full compatibility with the original implementation. 12 | 13 | [![NuGet](https://img.shields.io/nuget/v/ENet-no_binaries.svg?style=flat-square)](https://www.nuget.org/packages/ENet-no_binaries/) -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/addrinfo.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [StructLayout(LayoutKind.Sequential)] 11 | public unsafe struct addrinfo 12 | { 13 | public int ai_flags; 14 | public int ai_family; 15 | public int ai_socktype; 16 | public int ai_protocol; 17 | public nuint ai_addrlen; 18 | public byte* ai_canonname; 19 | public sockaddr* ai_addr; 20 | public addrinfo* ai_next; 21 | } 22 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/include/callback.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | // ReSharper disable ALL 4 | 5 | namespace enet 6 | { 7 | public unsafe struct ENetCallbacks 8 | { 9 | public delegate* managed malloc; 10 | public delegate* managed free; 11 | public delegate* managed no_memory; 12 | 13 | public ENetCallbacks(delegate* managed malloc, delegate* managed free, delegate* managed no_memory) 14 | { 15 | this.malloc = malloc; 16 | this.free = free; 17 | this.no_memory = no_memory; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/sockaddr_in6.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | #pragma warning disable CS8981 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace NativeSockets 9 | { 10 | [StructLayout(LayoutKind.Explicit, Size = 28)] 11 | public unsafe struct sockaddr_in6 12 | { 13 | [FieldOffset(0)] public sa_family_t sin6_family; 14 | [FieldOffset(2)] public ushort sin6_port; 15 | [FieldOffset(4)] public uint sin6_flowinfo; 16 | [FieldOffset(8)] public fixed byte sin6_addr[16]; 17 | [FieldOffset(24)] public uint sin6_scope_id; 18 | } 19 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/include/time.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | // ReSharper disable ALL 4 | 5 | namespace enet 6 | { 7 | public static partial class ENet 8 | { 9 | public const uint ENET_TIME_OVERFLOW = 86400000; 10 | 11 | public static bool ENET_TIME_LESS(uint a, uint b) => ((a) - (b) >= ENET_TIME_OVERFLOW); 12 | public static bool ENET_TIME_GREATER(uint a, uint b) => ((b) - (a) >= ENET_TIME_OVERFLOW); 13 | public static bool ENET_TIME_LESS_EQUAL(uint a, uint b) => (!ENET_TIME_GREATER(a, b)); 14 | public static bool ENET_TIME_GREATER_EQUAL(uint a, uint b) => (!ENET_TIME_LESS(a, b)); 15 | 16 | public static uint ENET_TIME_DIFFERENCE(uint a, uint b) => ((a) - (b) >= ENET_TIME_OVERFLOW ? (b) - (a) : (a) - (b)); 17 | } 18 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/include/list.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | // ReSharper disable ALL 4 | 5 | namespace enet 6 | { 7 | public unsafe struct ENetListNode 8 | { 9 | public ENetListNode* next; 10 | public ENetListNode* previous; 11 | } 12 | 13 | public struct ENetList 14 | { 15 | public ENetListNode sentinel; 16 | } 17 | 18 | public static unsafe partial class ENet 19 | { 20 | public static ENetListNode* enet_list_begin(ENetList* list) => ((list)->sentinel.next); 21 | public static ENetListNode* enet_list_end(ENetList* list) => (&(list)->sentinel); 22 | 23 | public static bool enet_list_empty(ENetList* list) => (enet_list_begin(list) == enet_list_end(list)); 24 | 25 | public static ENetListNode* enet_list_next(ENetListNode* iterator) => ((iterator)->next); 26 | public static ENetListNode* enet_list_previous(ENetListNode* iterator) => ((iterator)->previous); 27 | 28 | public static void* enet_list_front(ENetList* list) => ((void*)(list)->sentinel.next); 29 | public static void* enet_list_back(ENetList* list) => ((void*)(list)->sentinel.previous); 30 | } 31 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/Helpers/SpanHelpers.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // ReSharper disable ALL 6 | 7 | namespace NativeSockets 8 | { 9 | internal static class SpanHelpers 10 | { 11 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 12 | public static bool Compare(ref byte left, ref byte right, nuint byteCount) 13 | { 14 | nuint quotient = byteCount >> 30; 15 | nuint remainder = byteCount & 1073741823; 16 | for (nuint i = 0; i < quotient; ++i) 17 | { 18 | if (!MemoryMarshal.CreateReadOnlySpan(ref left, 1073741824).SequenceEqual(MemoryMarshal.CreateReadOnlySpan(ref right, 1073741824))) 19 | return false; 20 | left = ref Unsafe.AddByteOffset(ref left, new IntPtr(1073741824)); 21 | right = ref Unsafe.AddByteOffset(ref right, new IntPtr(1073741824)); 22 | } 23 | 24 | return MemoryMarshal.CreateReadOnlySpan(ref left, (int)remainder).SequenceEqual(MemoryMarshal.CreateReadOnlySpan(ref right, (int)remainder)); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/define/system.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Diagnostics; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | 6 | #pragma warning disable CS1591 7 | 8 | // ReSharper disable ALL 9 | 10 | namespace enet 11 | { 12 | public static unsafe partial class ENet 13 | { 14 | public static void* malloc(nuint size) 15 | { 16 | #if NET6_0_OR_GREATER 17 | return NativeMemory.Alloc((nuint)size); 18 | #else 19 | return (void*)Marshal.AllocHGlobal((nint)size); 20 | #endif 21 | } 22 | 23 | public static void free(void* memory) 24 | { 25 | #if NET6_0_OR_GREATER 26 | NativeMemory.Free(memory); 27 | #else 28 | Marshal.FreeHGlobal((nint)memory); 29 | #endif 30 | } 31 | 32 | public static void memcpy(void* dst, void* src, nuint size) => Unsafe.CopyBlockUnaligned(dst, src, (uint)size); 33 | 34 | public static void memset(void* dst, byte val, nuint size) => Unsafe.InitBlockUnaligned(dst, val, (uint)size); 35 | 36 | public static void abort() => Environment.Exit(-1); 37 | 38 | public static long timeGetTime() => Stopwatch.GetTimestamp() * 1000L / Stopwatch.Frequency; 39 | } 40 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/WinSock2.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers.Binary; 3 | using System.Runtime.CompilerServices; 4 | 5 | #pragma warning disable CS1591 6 | 7 | // ReSharper disable ALL 8 | 9 | namespace NativeSockets 10 | { 11 | public static class WinSock2 12 | { 13 | internal static int ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6 { get; } = (BitConverter.IsLittleEndian ? -65536 : 65535); 14 | 15 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 16 | public static ushort HOST_TO_NET_16(ushort host) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(host) : host; 17 | 18 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 19 | public static uint HOST_TO_NET_32(uint host) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(host) : host; 20 | 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | public static ushort NET_TO_HOST_16(ushort network) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(network) : network; 23 | 24 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 25 | public static uint NET_TO_HOST_32(uint network) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(network) : network; 26 | } 27 | } -------------------------------------------------------------------------------- /enet-csharp.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "enet-csharp", "enet-csharp\enet-csharp.csproj", "{E4BCA651-24F7-4E44-9725-B786BF53B2CA}" 4 | EndProject 5 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Test", "Test\Test.csproj", "{88FC4909-A666-4EF6-B96A-5432255B27A0}" 6 | EndProject 7 | Global 8 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 9 | Debug|Any CPU = Debug|Any CPU 10 | Release|Any CPU = Release|Any CPU 11 | EndGlobalSection 12 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 13 | {E4BCA651-24F7-4E44-9725-B786BF53B2CA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 14 | {E4BCA651-24F7-4E44-9725-B786BF53B2CA}.Debug|Any CPU.Build.0 = Debug|Any CPU 15 | {E4BCA651-24F7-4E44-9725-B786BF53B2CA}.Release|Any CPU.ActiveCfg = Release|Any CPU 16 | {E4BCA651-24F7-4E44-9725-B786BF53B2CA}.Release|Any CPU.Build.0 = Release|Any CPU 17 | {88FC4909-A666-4EF6-B96A-5432255B27A0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 18 | {88FC4909-A666-4EF6-B96A-5432255B27A0}.Debug|Any CPU.Build.0 = Debug|Any CPU 19 | {88FC4909-A666-4EF6-B96A-5432255B27A0}.Release|Any CPU.ActiveCfg = Release|Any CPU 20 | {88FC4909-A666-4EF6-B96A-5432255B27A0}.Release|Any CPU.Build.0 = Release|Any CPU 21 | EndGlobalSection 22 | EndGlobal 23 | -------------------------------------------------------------------------------- /enet-csharp/ENet/include/win32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Buffers.Binary; 3 | 4 | #pragma warning disable CS1591 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace enet 9 | { 10 | public static partial class ENet 11 | { 12 | public const nint INVALID_SOCKET = ~0; 13 | 14 | public const nint ENET_SOCKET_NULL = INVALID_SOCKET; 15 | 16 | public static ushort ENET_HOST_TO_NET_16(ushort host) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(host) : host; 17 | 18 | public static uint ENET_HOST_TO_NET_32(uint host) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(host) : host; 19 | 20 | public static ushort ENET_NET_TO_HOST_16(ushort network) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(network) : network; 21 | 22 | public static uint ENET_NET_TO_HOST_32(uint network) => BitConverter.IsLittleEndian ? BinaryPrimitives.ReverseEndianness(network) : network; 23 | } 24 | 25 | public unsafe struct ENetBuffer 26 | { 27 | public nuint dataLength; 28 | public void* data; 29 | } 30 | 31 | public struct ENetSocket 32 | { 33 | public nint handle; 34 | public bool IsIPv4 => !IsIPv6; 35 | public bool IsIPv6; 36 | 37 | public static implicit operator bool(ENetSocket socket) => socket.handle > 0; 38 | public static implicit operator nint(ENetSocket socket) => socket.handle; 39 | } 40 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/c/list.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | 3 | // ReSharper disable ALL 4 | 5 | namespace enet 6 | { 7 | public static unsafe partial class ENet 8 | { 9 | public static void enet_list_clear(ENetList* list) 10 | { 11 | list->sentinel.next = &list->sentinel; 12 | list->sentinel.previous = &list->sentinel; 13 | } 14 | 15 | public static ENetListNode* enet_list_insert(ENetListNode* position, void* data) 16 | { 17 | ENetListNode* result = (ENetListNode*)data; 18 | 19 | result->previous = position->previous; 20 | result->next = position; 21 | 22 | result->previous->next = result; 23 | position->previous = result; 24 | 25 | return result; 26 | } 27 | 28 | public static void* enet_list_remove(ENetListNode* position) 29 | { 30 | position->previous->next = position->next; 31 | position->next->previous = position->previous; 32 | 33 | return position; 34 | } 35 | 36 | public static ENetListNode* enet_list_move(ENetListNode* position, void* dataFirst, void* dataLast) 37 | { 38 | ENetListNode* first = (ENetListNode*)dataFirst, 39 | last = (ENetListNode*)dataLast; 40 | 41 | first->previous->next = last->next; 42 | last->next->previous = first->previous; 43 | 44 | first->previous = position->previous; 45 | last->next = position; 46 | 47 | first->previous->next = first; 48 | position->previous = last; 49 | 50 | return first; 51 | } 52 | 53 | public static nuint enet_list_size(ENetList* list) 54 | { 55 | nuint size = 0; 56 | ENetListNode* position; 57 | 58 | for (position = enet_list_begin(list); 59 | position != enet_list_end(list); 60 | position = enet_list_next(position)) 61 | ++size; 62 | 63 | return size; 64 | } 65 | } 66 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Shared/include/sa_family_t.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | #pragma warning disable CS1591 6 | #pragma warning disable CS8981 7 | 8 | // ReSharper disable ALL 9 | 10 | namespace NativeSockets 11 | { 12 | [StructLayout(LayoutKind.Explicit, Size = 2)] 13 | public struct sa_family_t 14 | { 15 | [FieldOffset(0)] public byte bsd_len; 16 | [FieldOffset(1)] public byte bsd_family; 17 | [FieldOffset(0)] public ushort family; 18 | 19 | public bool IsIPv4 20 | { 21 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 22 | get => SocketPal.IsBSD ? bsd_family == (int)AddressFamily.InterNetwork : family == (int)AddressFamily.InterNetwork; 23 | } 24 | 25 | public bool IsIPv6 26 | { 27 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 28 | get => SocketPal.IsBSD ? bsd_family == BSDSocketPal.ADDRESS_FAMILY_INTER_NETWORK_V6 : family == SocketPal.ADDRESS_FAMILY_INTER_NETWORK_V6; 29 | } 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public static sa_family_t FromBSD(ushort value) 33 | { 34 | Unsafe.SkipInit(out sa_family_t result); 35 | result.bsd_len = value == BSDSocketPal.ADDRESS_FAMILY_INTER_NETWORK_V6 ? (byte)28 : (byte)16; 36 | result.bsd_family = (byte)value; 37 | return result; 38 | } 39 | 40 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 41 | public static implicit operator sa_family_t(ushort value) 42 | { 43 | Unsafe.SkipInit(out sa_family_t result); 44 | if (SocketPal.IsBSD) 45 | { 46 | result.bsd_len = value == BSDSocketPal.ADDRESS_FAMILY_INTER_NETWORK_V6 ? (byte)28 : (byte)16; 47 | result.bsd_family = (byte)value; 48 | return result; 49 | } 50 | 51 | result.family = value; 52 | return result; 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /enet-csharp/enet-csharp.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net9.0;net8.0;net7.0;net6.0;net5.0;netstandard2.1 5 | enet 6 | disable 7 | enable 8 | 9 | true 10 | 11 | ENet-no_binaries 12 | 1.0.8 13 | Molth Nevin 14 | Hell 15 | ENet reliable UDP networking library 16 | https://github.com/Molth/enet-csharp 17 | MIT 18 | enet;udp;performance;networking 19 | 20 | ./nupkgs 21 | README.md 22 | true 23 | 24 | $(MSBuildThisFileDirectory)../ 25 | 26 | 27 | 28 | 9.0 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | true 38 | \ 39 | README.md 40 | 41 | 42 | 43 | true 44 | \ 45 | LICENSE 46 | 47 | 48 | 49 | 50 | true 51 | 52 | 53 | 54 | false 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /enet-csharp/ENet/c/callback.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable CS1591 2 | #pragma warning disable CA2211 3 | 4 | // ReSharper disable ALL 5 | 6 | namespace enet 7 | { 8 | public static unsafe partial class ENet 9 | { 10 | public static ENetCallbacks callbacks = new ENetCallbacks(&malloc, &free, &abort); 11 | 12 | /// 13 | /// Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in 14 | /// ENet. 15 | /// Do not use if you use this variant. Make sure the 16 | /// structure 17 | /// is zeroed out so that any additional callbacks added in future versions will be properly ignored. 18 | /// 19 | /// 20 | /// the constant should be supplied so ENet knows which version of 21 | /// struct to use 22 | /// 23 | /// user-overridden callbacks where any NULL callbacks will use ENet's defaults 24 | /// 0 on success, < 0 on failure 25 | public static int enet_initialize_with_callbacks(uint version, ENetCallbacks* inits) 26 | { 27 | if (version < ENET_VERSION_CREATE(1, 3, 0)) 28 | return -1; 29 | 30 | if (inits->malloc != null || inits->free != null) 31 | { 32 | if (inits->malloc == null || inits->free == null) 33 | return -1; 34 | 35 | callbacks.malloc = inits->malloc; 36 | callbacks.free = inits->free; 37 | } 38 | 39 | if (inits->no_memory != null) 40 | callbacks.no_memory = inits->no_memory; 41 | 42 | return enet_initialize(); 43 | } 44 | 45 | /// 46 | /// Gives the linked version of the ENet library. 47 | /// 48 | /// the version number 49 | public static uint enet_linked_version() => ENET_VERSION; 50 | 51 | public static void* enet_malloc(nuint size) 52 | { 53 | void* memory = callbacks.malloc(size); 54 | 55 | if (memory == null) 56 | callbacks.no_memory(); 57 | 58 | return memory; 59 | } 60 | 61 | public static void enet_free(void* memory) => callbacks.free(memory); 62 | } 63 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Nevin 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | --- 24 | 25 | enet 26 | 27 | MIT License 28 | 29 | Copyright (c) 2002-2024 Lee Salzman 30 | 31 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 32 | 33 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 34 | 35 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 36 | 37 | --- 38 | 39 | NanoSockets 40 | 41 | MIT License 42 | 43 | Copyright (c) 2019 Stanislav Denisov (nxrighthere@gmail.com) 44 | 45 | Permission is hereby granted, free of charge, to any person obtaining a copy 46 | of this software and associated documentation files (the "Software"), to deal 47 | in the Software without restriction, including without limitation the rights 48 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 49 | copies of the Software, and to permit persons to whom the Software is 50 | furnished to do so, subject to the following conditions: 51 | 52 | The above copyright notice and this permission notice shall be included in all 53 | copies or substantial portions of the Software. 54 | 55 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 56 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 57 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 58 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 59 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 60 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 61 | SOFTWARE. -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/Helpers/XxHash.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using System.Security.Cryptography; 5 | 6 | #pragma warning disable CS1591 7 | 8 | // ReSharper disable ALL 9 | 10 | namespace NativeSockets 11 | { 12 | internal static class XxHash 13 | { 14 | public static uint XXHASH_32_SEED { get; } 15 | 16 | static XxHash() 17 | { 18 | Span buffer = stackalloc byte[4]; 19 | RandomNumberGenerator.Fill(buffer); 20 | XXHASH_32_SEED = Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(buffer)); 21 | } 22 | 23 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 24 | public static int Hash32(in T obj) where T : unmanaged => Hash32(MemoryMarshal.CreateReadOnlySpan(ref Unsafe.As(ref Unsafe.AsRef(in obj)), Unsafe.SizeOf()), XXHASH_32_SEED); 25 | 26 | public static int Hash32(ReadOnlySpan buffer, uint seed) 27 | { 28 | int length = buffer.Length; 29 | ref byte local1 = ref MemoryMarshal.GetReference(buffer); 30 | uint num1; 31 | if (buffer.Length >= 16) 32 | { 33 | uint num2 = seed + 606290984U; 34 | uint num3 = seed + 2246822519U; 35 | uint num4 = seed; 36 | uint num5 = seed - 2654435761U; 37 | for (; length >= 16; length -= 16) 38 | { 39 | ref byte local2 = ref Unsafe.AddByteOffset(ref local1, new IntPtr(buffer.Length - length)); 40 | uint num6 = num2 + Unsafe.ReadUnaligned(ref local2) * 2246822519U; 41 | num2 = (uint)((((int)num6 << 13) | (int)(num6 >> 19)) * -1640531535); 42 | uint num7 = num3 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new IntPtr(4))) * 2246822519U; 43 | num3 = (uint)((((int)num7 << 13) | (int)(num7 >> 19)) * -1640531535); 44 | uint num8 = num4 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new IntPtr(8))) * 2246822519U; 45 | num4 = (uint)((((int)num8 << 13) | (int)(num8 >> 19)) * -1640531535); 46 | uint num9 = num5 + Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local2, new IntPtr(12))) * 2246822519U; 47 | num5 = (uint)((((int)num9 << 13) | (int)(num9 >> 19)) * -1640531535); 48 | } 49 | 50 | num1 = (uint)((((int)num2 << 1) | (int)(num2 >> 31)) + (((int)num3 << 7) | (int)(num3 >> 25)) + (((int)num4 << 12) | (int)(num4 >> 20)) + (((int)num5 << 18) | (int)(num5 >> 14)) + buffer.Length); 51 | } 52 | else 53 | num1 = (uint)((int)seed + 374761393 + buffer.Length); 54 | 55 | for (; length >= 4; length -= 4) 56 | { 57 | uint num10 = Unsafe.ReadUnaligned(ref Unsafe.AddByteOffset(ref local1, new IntPtr(buffer.Length - length))); 58 | uint num11 = num1 + num10 * 3266489917U; 59 | num1 = (uint)((((int)num11 << 17) | (int)(num11 >> 15)) * 668265263); 60 | } 61 | 62 | ref byte local3 = ref Unsafe.AddByteOffset(ref local1, new IntPtr(buffer.Length - length)); 63 | for (int index = 0; index < length; ++index) 64 | { 65 | uint num12 = Unsafe.AddByteOffset(ref local3, new IntPtr(index)); 66 | uint num13 = num1 + num12 * 374761393U; 67 | num1 = (uint)((((int)num13 << 11) | (int)(num13 >> 21)) * -1640531535); 68 | } 69 | 70 | #if NET7_0_OR_GREATER 71 | int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777; 72 | int num15 = (num14 ^ (num14 >>> 13)) * -1028477379; 73 | return num15 ^ (num15 >>> 16); 74 | #else 75 | int num14 = ((int)num1 ^ (int)(num1 >> 15)) * -2048144777; 76 | int num15 = (num14 ^ (int)((uint)num14 >> 13)) * -1028477379; 77 | return num15 ^ (int)((uint)num15 >> 16); 78 | #endif 79 | } 80 | } 81 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Unix/Shared/c/iOSSocketPal.cs: -------------------------------------------------------------------------------- 1 | using System.Net.Sockets; 2 | using System.Runtime.InteropServices; 3 | using System.Security; 4 | 5 | #pragma warning disable CA1401 6 | #pragma warning disable CS1591 7 | #pragma warning disable CS8981 8 | #pragma warning disable SYSLIB1054 9 | 10 | // ReSharper disable ALL 11 | 12 | namespace NativeSockets 13 | { 14 | [SuppressUnmanagedCodeSecurity] 15 | internal static unsafe class iOSSocketPal 16 | { 17 | private const string NATIVE_LIBRARY = "__Internal"; 18 | 19 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 20 | public static extern int getpid(); 21 | 22 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 23 | public static extern SocketError bind(int __socketHandle_native, sockaddr* __socketAddress_native, int __socketAddressSize_native); 24 | 25 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 26 | public static extern SocketError getsockname(int __socketHandle_native, sockaddr* __socketAddress_native, int* __socketAddressSize_native); 27 | 28 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 29 | public static extern int socket(int af, int type, int protocol); 30 | 31 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 32 | public static extern int fcntl(int fd, int cmd, int arg); 33 | 34 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 35 | public static extern SocketError setsockopt(int __socketHandle_native, SocketOptionLevel __optionLevel_native, SocketOptionName __optionName_native, int* __optionValue_native, int __optionLength_native); 36 | 37 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 38 | public static extern SocketError getsockopt(int s, int level, int optname, byte* optval, int* optlen); 39 | 40 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 41 | public static extern SocketError connect(int s, sockaddr* name, int namelen); 42 | 43 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 44 | public static extern SocketError close(int __socketHandle_native); 45 | 46 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.StdCall)] 47 | public static extern int send(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native); 48 | 49 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.StdCall)] 50 | public static extern int recv(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native); 51 | 52 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 53 | public static extern int sendto(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native, byte* __socketAddress_native, int __socketAddressSize_native); 54 | 55 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 56 | public static extern int recvfrom(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native, byte* __socketAddress_native, int* __socketAddressSize_native); 57 | 58 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 59 | public static extern int poll(pollfd* fds, nuint nfds, int timeout); 60 | 61 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 62 | public static extern int inet_pton(int Family, void* pszAddrString, void* pAddrBuf); 63 | 64 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 65 | public static extern int getaddrinfo(byte* pNodeName, byte* pServiceName, addrinfo* pHints, addrinfo** ppResult); 66 | 67 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 68 | public static extern void freeaddrinfo(addrinfo* pAddrInfo); 69 | 70 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 71 | public static extern byte* inet_ntop(int Family, void* pAddr, ref byte pStringBuf, nuint StringBufSize); 72 | 73 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 74 | public static extern int getnameinfo(sockaddr* pSockaddr, int SockaddrLength, ref byte pNodeBuffer, ulong NodeBufferSize, byte* pServiceBuffer, ulong ServiceBufferSize, int Flags); 75 | 76 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 77 | public static extern nint sendmsg(int sockfd, msghdr* msg, int flags); 78 | 79 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 80 | public static extern nint recvmsg(int sockfd, msghdr* msg, int flags); 81 | } 82 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/include/protocol.cs: -------------------------------------------------------------------------------- 1 | using System.Runtime.InteropServices; 2 | 3 | #pragma warning disable CS1591 4 | 5 | // ReSharper disable ALL 6 | 7 | namespace enet 8 | { 9 | public static partial class ENet 10 | { 11 | public const uint ENET_PROTOCOL_MINIMUM_MTU = 576; 12 | public const uint ENET_PROTOCOL_MAXIMUM_MTU = 4096; 13 | public const uint ENET_PROTOCOL_MAXIMUM_PACKET_COMMANDS = 32; 14 | public const uint ENET_PROTOCOL_MINIMUM_WINDOW_SIZE = 4096; 15 | public const uint ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE = 65536; 16 | public const uint ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT = 1; 17 | public const uint ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT = 255; 18 | public const uint ENET_PROTOCOL_MAXIMUM_PEER_ID = 0xFFF; 19 | public const uint ENET_PROTOCOL_MAXIMUM_FRAGMENT_COUNT = 1024 * 1024; 20 | } 21 | 22 | public enum ENetProtocolCommand 23 | { 24 | ENET_PROTOCOL_COMMAND_NONE = 0, 25 | ENET_PROTOCOL_COMMAND_ACKNOWLEDGE = 1, 26 | ENET_PROTOCOL_COMMAND_CONNECT = 2, 27 | ENET_PROTOCOL_COMMAND_VERIFY_CONNECT = 3, 28 | ENET_PROTOCOL_COMMAND_DISCONNECT = 4, 29 | ENET_PROTOCOL_COMMAND_PING = 5, 30 | ENET_PROTOCOL_COMMAND_SEND_RELIABLE = 6, 31 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE = 7, 32 | ENET_PROTOCOL_COMMAND_SEND_FRAGMENT = 8, 33 | ENET_PROTOCOL_COMMAND_SEND_UNSEQUENCED = 9, 34 | ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT = 10, 35 | ENET_PROTOCOL_COMMAND_THROTTLE_CONFIGURE = 11, 36 | ENET_PROTOCOL_COMMAND_SEND_UNRELIABLE_FRAGMENT = 12, 37 | ENET_PROTOCOL_COMMAND_COUNT = 13, 38 | 39 | ENET_PROTOCOL_COMMAND_MASK = 0x0F 40 | } 41 | 42 | public enum ENetProtocolFlag 43 | { 44 | ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE = (1 << 7), 45 | ENET_PROTOCOL_COMMAND_FLAG_UNSEQUENCED = (1 << 6), 46 | 47 | ENET_PROTOCOL_HEADER_FLAG_COMPRESSED = (1 << 14), 48 | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME = (1 << 15), 49 | ENET_PROTOCOL_HEADER_FLAG_MASK = ENET_PROTOCOL_HEADER_FLAG_COMPRESSED | ENET_PROTOCOL_HEADER_FLAG_SENT_TIME, 50 | 51 | ENET_PROTOCOL_HEADER_SESSION_MASK = (3 << 12), 52 | ENET_PROTOCOL_HEADER_SESSION_SHIFT = 12 53 | } 54 | 55 | public struct ENetProtocolHeader 56 | { 57 | public ushort peerID; 58 | public ushort sentTime; 59 | } 60 | 61 | public struct ENetProtocolCommandHeader 62 | { 63 | public byte command; 64 | public byte channelID; 65 | public ushort reliableSequenceNumber; 66 | } 67 | 68 | public struct ENetProtocolAcknowledge 69 | { 70 | public ENetProtocolCommandHeader header; 71 | public ushort receivedReliableSequenceNumber; 72 | public ushort receivedSentTime; 73 | } 74 | 75 | public struct ENetProtocolConnect 76 | { 77 | public ENetProtocolCommandHeader header; 78 | public ushort outgoingPeerID; 79 | public byte incomingSessionID; 80 | public byte outgoingSessionID; 81 | public uint mtu; 82 | public uint windowSize; 83 | public uint channelCount; 84 | public uint incomingBandwidth; 85 | public uint outgoingBandwidth; 86 | public uint packetThrottleInterval; 87 | public uint packetThrottleAcceleration; 88 | public uint packetThrottleDeceleration; 89 | public uint connectID; 90 | public uint data; 91 | } 92 | 93 | public struct ENetProtocolVerifyConnect 94 | { 95 | public ENetProtocolCommandHeader header; 96 | public ushort outgoingPeerID; 97 | public byte incomingSessionID; 98 | public byte outgoingSessionID; 99 | public uint mtu; 100 | public uint windowSize; 101 | public uint channelCount; 102 | public uint incomingBandwidth; 103 | public uint outgoingBandwidth; 104 | public uint packetThrottleInterval; 105 | public uint packetThrottleAcceleration; 106 | public uint packetThrottleDeceleration; 107 | public uint connectID; 108 | } 109 | 110 | public struct ENetProtocolBandwidthLimit 111 | { 112 | public ENetProtocolCommandHeader header; 113 | public uint incomingBandwidth; 114 | public uint outgoingBandwidth; 115 | } 116 | 117 | public struct ENetProtocolThrottleConfigure 118 | { 119 | public ENetProtocolCommandHeader header; 120 | public uint packetThrottleInterval; 121 | public uint packetThrottleAcceleration; 122 | public uint packetThrottleDeceleration; 123 | } 124 | 125 | public struct ENetProtocolDisconnect 126 | { 127 | public ENetProtocolCommandHeader header; 128 | public uint data; 129 | } 130 | 131 | public struct ENetProtocolPing 132 | { 133 | public ENetProtocolCommandHeader header; 134 | } 135 | 136 | public struct ENetProtocolSendReliable 137 | { 138 | public ENetProtocolCommandHeader header; 139 | public ushort dataLength; 140 | } 141 | 142 | public struct ENetProtocolSendUnreliable 143 | { 144 | public ENetProtocolCommandHeader header; 145 | public ushort unreliableSequenceNumber; 146 | public ushort dataLength; 147 | } 148 | 149 | public struct ENetProtocolSendUnsequenced 150 | { 151 | public ENetProtocolCommandHeader header; 152 | public ushort unsequencedGroup; 153 | public ushort dataLength; 154 | } 155 | 156 | public struct ENetProtocolSendFragment 157 | { 158 | public ENetProtocolCommandHeader header; 159 | public ushort startSequenceNumber; 160 | public ushort dataLength; 161 | public uint fragmentCount; 162 | public uint fragmentNumber; 163 | public uint totalLength; 164 | public uint fragmentOffset; 165 | } 166 | 167 | [StructLayout(LayoutKind.Explicit)] 168 | public struct ENetProtocol 169 | { 170 | [FieldOffset(0)] public ENetProtocolCommandHeader header; 171 | [FieldOffset(0)] public ENetProtocolAcknowledge acknowledge; 172 | [FieldOffset(0)] public ENetProtocolConnect connect; 173 | [FieldOffset(0)] public ENetProtocolVerifyConnect verifyConnect; 174 | [FieldOffset(0)] public ENetProtocolDisconnect disconnect; 175 | [FieldOffset(0)] public ENetProtocolPing ping; 176 | [FieldOffset(0)] public ENetProtocolSendReliable sendReliable; 177 | [FieldOffset(0)] public ENetProtocolSendUnreliable sendUnreliable; 178 | [FieldOffset(0)] public ENetProtocolSendUnsequenced sendUnsequenced; 179 | [FieldOffset(0)] public ENetProtocolSendFragment sendFragment; 180 | [FieldOffset(0)] public ENetProtocolBandwidthLimit bandwidthLimit; 181 | [FieldOffset(0)] public ENetProtocolThrottleConfigure throttleConfigure; 182 | } 183 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/c/packet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | using static enet.ENetPacketFlag; 5 | 6 | #pragma warning disable CS1591 7 | 8 | // ReSharper disable ALL 9 | 10 | namespace enet 11 | { 12 | public static unsafe partial class ENet 13 | { 14 | /// 15 | /// Creates a packet that may be sent to a peer. 16 | /// 17 | /// initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL. 18 | /// size of the data allocated for this packet 19 | /// flags for this packet as described for the ENetPacket structure. 20 | /// the packet on success, NULL on failure 21 | public static ENetPacket* enet_packet_create(void* data, nuint dataLength, uint flags) 22 | { 23 | ENetPacket* packet = (ENetPacket*)enet_malloc((nuint)sizeof(ENetPacket)); 24 | if (packet == null) 25 | return null; 26 | 27 | if ((flags & (uint)ENET_PACKET_FLAG_NO_ALLOCATE) != 0) 28 | packet->data = (byte*)data; 29 | else if (dataLength <= 0) 30 | packet->data = null; 31 | else 32 | { 33 | packet->data = (byte*)enet_malloc(dataLength); 34 | if (packet->data == null) 35 | { 36 | enet_free(packet); 37 | return null; 38 | } 39 | 40 | if (data != null) 41 | memcpy(packet->data, data, dataLength); 42 | } 43 | 44 | packet->referenceCount = 0; 45 | packet->flags = flags; 46 | packet->dataLength = dataLength; 47 | packet->freeCallback = null; 48 | packet->userData = null; 49 | 50 | return packet; 51 | } 52 | 53 | /// 54 | /// Destroys the packet and deallocates its data. 55 | /// 56 | /// packet to be destroyed 57 | public static void enet_packet_destroy(ENetPacket* packet) 58 | { 59 | if (packet == null) 60 | return; 61 | 62 | if (packet->freeCallback != null) 63 | (packet->freeCallback)(packet); 64 | if (!((packet->flags & (uint)ENET_PACKET_FLAG_NO_ALLOCATE) != 0) && 65 | packet->data != null) 66 | enet_free(packet->data); 67 | enet_free(packet); 68 | } 69 | 70 | /// 71 | /// Attempts to resize the data in the packet to length specified in the 72 | /// dataLength parameter. 73 | /// 74 | /// packet to resize 75 | /// new size for the packet data 76 | /// 0 on success, < 0 on failure 77 | public static int enet_packet_resize(ENetPacket* packet, nuint dataLength) 78 | { 79 | byte* newData; 80 | 81 | if (dataLength <= packet->dataLength || ((packet->flags & (uint)ENET_PACKET_FLAG_NO_ALLOCATE) != 0)) 82 | { 83 | packet->dataLength = dataLength; 84 | 85 | return 0; 86 | } 87 | 88 | newData = (byte*)enet_malloc(dataLength); 89 | if (newData == null) 90 | return -1; 91 | 92 | if (packet->data != null) 93 | { 94 | if (packet->dataLength > 0) 95 | memcpy(newData, packet->data, packet->dataLength); 96 | 97 | enet_free(packet->data); 98 | } 99 | 100 | packet->data = newData; 101 | packet->dataLength = dataLength; 102 | 103 | return 0; 104 | } 105 | 106 | public static ReadOnlySpan crcTable => new uint[256] 107 | { 108 | 0, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535, 0x9E6495A3, 109 | 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, 0x90BF1D91, 110 | 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 111 | 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 112 | 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 113 | 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 114 | 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F, 115 | 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 116 | 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, 0x9FBFE4A5, 0xE8B8D433, 117 | 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, 118 | 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 119 | 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 120 | 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 121 | 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9, 122 | 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, 123 | 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 124 | 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, 0x73DC1683, 125 | 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 126 | 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 127 | 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 128 | 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 129 | 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, 0x4669BE79, 130 | 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 131 | 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 132 | 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x5005713, 133 | 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0xBDBDF21, 134 | 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 135 | 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 136 | 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D, 0x3E6E77DB, 137 | 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, 138 | 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693, 0x54DE5729, 0x23D967BF, 139 | 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D 140 | }; 141 | 142 | public static uint enet_crc32(ENetBuffer* buffers, nuint bufferCount) 143 | { 144 | uint crc = 0xFFFFFFFF; 145 | 146 | while (bufferCount-- > 0) 147 | { 148 | byte* data = (byte*)buffers->data; 149 | byte* dataEnd = &data[buffers->dataLength]; 150 | 151 | while (data < dataEnd) 152 | { 153 | crc = (crc >> 8) ^ Unsafe.Add(ref MemoryMarshal.GetReference(crcTable), (int)((crc & 0xFF) ^ *data++)); 154 | } 155 | 156 | ++buffers; 157 | } 158 | 159 | return ENET_HOST_TO_NET_32(~ crc); 160 | } 161 | } 162 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Unix/Shared/c/UnixSocketPal.cs: -------------------------------------------------------------------------------- 1 | #if !NET6_0_OR_GREATER 2 | using System.Collections.Generic; 3 | #endif 4 | using System.Net.Sockets; 5 | using System.Runtime.CompilerServices; 6 | using System.Runtime.InteropServices; 7 | using System.Security; 8 | 9 | #pragma warning disable CA1401 10 | #pragma warning disable CS1591 11 | #pragma warning disable CS8981 12 | #pragma warning disable SYSLIB1054 13 | 14 | // ReSharper disable ALL 15 | 16 | namespace NativeSockets 17 | { 18 | [SuppressUnmanagedCodeSecurity] 19 | internal static unsafe class UnixSocketPal 20 | { 21 | private const string NATIVE_LIBRARY = "libc"; 22 | 23 | #if !NET6_0_OR_GREATER 24 | private static readonly Dictionary SocketErrors = new Dictionary 25 | { 26 | { 0, SocketError.Success }, 27 | { 1, SocketError.AccessDenied }, 28 | { 2, SocketError.AddressNotAvailable }, 29 | { 4, SocketError.Interrupted }, 30 | { 6, SocketError.HostNotFound }, 31 | { 7, SocketError.MessageSize }, 32 | { 9, SocketError.OperationAborted }, 33 | { 11, SocketError.WouldBlock }, 34 | { 12, SocketError.NoBufferSpaceAvailable }, 35 | { 13, SocketError.AccessDenied }, 36 | { 14, SocketError.Fault }, 37 | { 20, SocketError.InvalidArgument }, 38 | { 22, SocketError.InvalidArgument }, 39 | { 23, SocketError.TooManyOpenSockets }, 40 | { 24, SocketError.TooManyOpenSockets }, 41 | { 28, SocketError.NoBufferSpaceAvailable }, 42 | { 32, SocketError.Shutdown }, 43 | { 36, SocketError.InvalidArgument }, 44 | { 40, SocketError.AccessDenied }, 45 | { 59, SocketError.TooManyOpenSockets }, 46 | { 61, SocketError.NoData }, 47 | { 63, SocketError.NoBufferSpaceAvailable }, 48 | { 67, SocketError.NetworkUnreachable }, 49 | { 70, SocketError.ConnectionReset }, 50 | { 72, SocketError.NetworkUnreachable }, 51 | { 74, SocketError.InvalidArgument }, 52 | { 75, SocketError.MessageSize }, 53 | { 84, SocketError.InvalidArgument }, 54 | { 88, SocketError.NotSocket }, 55 | { 89, SocketError.DestinationAddressRequired }, 56 | { 90, SocketError.MessageSize }, 57 | { 91, SocketError.ProtocolType }, 58 | { 92, SocketError.ProtocolOption }, 59 | { 93, SocketError.ProtocolNotSupported }, 60 | { 94, SocketError.SocketNotSupported }, 61 | { 96, SocketError.ProtocolFamilyNotSupported }, 62 | { 97, SocketError.AddressFamilyNotSupported }, 63 | { 98, SocketError.AddressAlreadyInUse }, 64 | { 99, SocketError.AddressNotAvailable }, 65 | { 100, SocketError.NetworkDown }, 66 | { 101, SocketError.NetworkUnreachable }, 67 | { 102, SocketError.NetworkReset }, 68 | { 103, SocketError.ConnectionAborted }, 69 | { 104, SocketError.ConnectionReset }, 70 | { 105, SocketError.NoBufferSpaceAvailable }, 71 | { 106, SocketError.IsConnected }, 72 | { 107, SocketError.NotConnected }, 73 | { 108, SocketError.Disconnecting }, 74 | { 110, SocketError.TimedOut }, 75 | { 111, SocketError.ConnectionRefused }, 76 | { 112, SocketError.HostDown }, 77 | { 113, SocketError.HostUnreachable }, 78 | { 114, SocketError.AlreadyInProgress }, 79 | { 115, SocketError.InProgress } 80 | }; 81 | #endif 82 | 83 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 84 | public static SocketError GetLastSocketError() 85 | { 86 | #if NET6_0_OR_GREATER 87 | return (SocketError)Marshal.GetLastPInvokeError(); 88 | #else 89 | int errno = Marshal.GetLastWin32Error(); 90 | return SocketErrors.TryGetValue(errno, out SocketError error) ? (SocketError)error : (SocketError)errno; 91 | #endif 92 | } 93 | 94 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 95 | public static extern SocketError bind(int __socketHandle_native, sockaddr* __socketAddress_native, int __socketAddressSize_native); 96 | 97 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 98 | public static extern SocketError getsockname(int __socketHandle_native, sockaddr* __socketAddress_native, int* __socketAddressSize_native); 99 | 100 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 101 | public static extern int socket(int af, int type, int protocol); 102 | 103 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 104 | public static extern int fcntl(int fd, int cmd, int arg); 105 | 106 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 107 | public static extern SocketError setsockopt(int __socketHandle_native, SocketOptionLevel __optionLevel_native, SocketOptionName __optionName_native, int* __optionValue_native, int __optionLength_native); 108 | 109 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 110 | public static extern SocketError getsockopt(int s, int level, int optname, byte* optval, int* optlen); 111 | 112 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 113 | public static extern SocketError connect(int s, sockaddr* name, int namelen); 114 | 115 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 116 | public static extern SocketError close(int __socketHandle_native); 117 | 118 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.StdCall)] 119 | public static extern int send(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native); 120 | 121 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.StdCall)] 122 | public static extern int recv(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native); 123 | 124 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 125 | public static extern int sendto(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native, byte* __socketAddress_native, int __socketAddressSize_native); 126 | 127 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 128 | public static extern int recvfrom(int __socketHandle_native, byte* __pinnedBuffer_native, int __len_native, SocketFlags __socketFlags_native, byte* __socketAddress_native, int* __socketAddressSize_native); 129 | 130 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 131 | public static extern int poll(pollfd* fds, nuint nfds, int timeout); 132 | 133 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 134 | public static extern int inet_pton(int Family, void* pszAddrString, void* pAddrBuf); 135 | 136 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 137 | public static extern int getaddrinfo(byte* pNodeName, byte* pServiceName, addrinfo* pHints, addrinfo** ppResult); 138 | 139 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 140 | public static extern void freeaddrinfo(addrinfo* pAddrInfo); 141 | 142 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 143 | public static extern byte* inet_ntop(int Family, void* pAddr, ref byte pStringBuf, nuint StringBufSize); 144 | 145 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 146 | public static extern int getnameinfo(sockaddr* pSockaddr, int SockaddrLength, ref byte pNodeBuffer, ulong NodeBufferSize, byte* pServiceBuffer, ulong ServiceBufferSize, int Flags); 147 | 148 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 149 | public static extern nint sendmsg(int sockfd, msghdr* msg, int flags); 150 | 151 | [DllImport(NATIVE_LIBRARY, CallingConvention = CallingConvention.Cdecl)] 152 | public static extern nint recvmsg(int sockfd, msghdr* msg, int flags); 153 | } 154 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | ## 4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore 5 | 6 | # User-specific files 7 | *.rsuser 8 | *.suo 9 | *.user 10 | *.userosscache 11 | *.sln.docstates 12 | 13 | # User-specific files (MonoDevelop/Xamarin Studio) 14 | *.userprefs 15 | 16 | # Mono auto generated files 17 | mono_crash.* 18 | 19 | # Build results 20 | [Dd]ebug/ 21 | [Dd]ebugPublic/ 22 | [Rr]elease/ 23 | [Rr]eleases/ 24 | x64/ 25 | x86/ 26 | [Ww][Ii][Nn]32/ 27 | [Aa][Rr][Mm]/ 28 | [Aa][Rr][Mm]64/ 29 | bld/ 30 | [Bb]in/ 31 | [Oo]bj/ 32 | [Ll]og/ 33 | [Ll]ogs/ 34 | 35 | # Visual Studio 2015/2017 cache/options directory 36 | .vs/ 37 | # Uncomment if you have tasks that create the project's static files in wwwroot 38 | #wwwroot/ 39 | 40 | # JetBrains Rider 41 | .idea/ 42 | enet-csharp.sln.DotSettings 43 | enet-csharp.sln.DotSettings.user 44 | 45 | # Visual Studio 2017 auto generated files 46 | Generated\ Files/ 47 | 48 | # MSTest test Results 49 | [Tt]est[Rr]esult*/ 50 | [Bb]uild[Ll]og.* 51 | 52 | # NUnit 53 | *.VisualState.xml 54 | TestResult.xml 55 | nunit-*.xml 56 | 57 | # Build Results of an ATL Project 58 | [Dd]ebugPS/ 59 | [Rr]eleasePS/ 60 | dlldata.c 61 | 62 | # Benchmark Results 63 | BenchmarkDotNet.Artifacts/ 64 | 65 | # .NET Core 66 | project.lock.json 67 | project.fragment.lock.json 68 | artifacts/ 69 | 70 | # ASP.NET Scaffolding 71 | ScaffoldingReadMe.txt 72 | 73 | # StyleCop 74 | StyleCopReport.xml 75 | 76 | # Files built by Visual Studio 77 | *_i.c 78 | *_p.c 79 | *_h.h 80 | *.ilk 81 | *.meta 82 | *.obj 83 | *.iobj 84 | *.pch 85 | *.pdb 86 | *.ipdb 87 | *.pgc 88 | *.pgd 89 | *.rsp 90 | *.sbr 91 | *.tlb 92 | *.tli 93 | *.tlh 94 | *.tmp 95 | *.tmp_proj 96 | *_wpftmp.csproj 97 | *.log 98 | *.tlog 99 | *.vspscc 100 | *.vssscc 101 | .builds 102 | *.pidb 103 | *.svclog 104 | *.scc 105 | 106 | # Chutzpah Test files 107 | _Chutzpah* 108 | 109 | # Visual C++ cache files 110 | ipch/ 111 | *.aps 112 | *.ncb 113 | *.opendb 114 | *.opensdf 115 | *.sdf 116 | *.cachefile 117 | *.VC.db 118 | *.VC.VC.opendb 119 | 120 | # Visual Studio profiler 121 | *.psess 122 | *.vsp 123 | *.vspx 124 | *.sap 125 | 126 | # Visual Studio Trace Files 127 | *.e2e 128 | 129 | # TFS 2012 Local Workspace 130 | $tf/ 131 | 132 | # Guidance Automation Toolkit 133 | *.gpState 134 | 135 | # ReSharper is a .NET coding add-in 136 | _ReSharper*/ 137 | *.[Rr]e[Ss]harper 138 | *.DotSettings.user 139 | 140 | # TeamCity is a build add-in 141 | _TeamCity* 142 | 143 | # DotCover is a Code Coverage Tool 144 | *.dotCover 145 | 146 | # AxoCover is a Code Coverage Tool 147 | .axoCover/* 148 | !.axoCover/settings.json 149 | 150 | # Coverlet is a free, cross platform Code Coverage Tool 151 | coverage*.json 152 | coverage*.xml 153 | coverage*.info 154 | 155 | # Visual Studio code coverage results 156 | *.coverage 157 | *.coveragexml 158 | 159 | # NCrunch 160 | _NCrunch_* 161 | .*crunch*.local.xml 162 | nCrunchTemp_* 163 | 164 | # MightyMoose 165 | *.mm.* 166 | AutoTest.Net/ 167 | 168 | # Web workbench (sass) 169 | .sass-cache/ 170 | 171 | # Installshield output folder 172 | [Ee]xpress/ 173 | 174 | # DocProject is a documentation generator add-in 175 | DocProject/buildhelp/ 176 | DocProject/Help/*.HxT 177 | DocProject/Help/*.HxC 178 | DocProject/Help/*.hhc 179 | DocProject/Help/*.hhk 180 | DocProject/Help/*.hhp 181 | DocProject/Help/Html2 182 | DocProject/Help/html 183 | 184 | # Click-Once directory 185 | publish/ 186 | 187 | # Publish Web Output 188 | *.[Pp]ublish.xml 189 | *.azurePubxml 190 | # Note: Comment the next line if you want to checkin your web deploy settings, 191 | # but database connection strings (with potential passwords) will be unencrypted 192 | *.pubxml 193 | *.publishproj 194 | 195 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 196 | # checkin your Azure Web App publish settings, but sensitive information contained 197 | # in these scripts will be unencrypted 198 | PublishScripts/ 199 | 200 | # NuGet Packages 201 | *.nupkg 202 | # NuGet Symbol Packages 203 | *.snupkg 204 | # The packages folder can be ignored because of Package Restore 205 | **/[Pp]ackages/* 206 | # except build/, which is used as an MSBuild target. 207 | !**/[Pp]ackages/build/ 208 | # Uncomment if necessary however generally it will be regenerated when needed 209 | #!**/[Pp]ackages/repositories.config 210 | # NuGet v3's project.json files produces more ignorable files 211 | *.nuget.props 212 | *.nuget.targets 213 | 214 | # Microsoft Azure Build Output 215 | csx/ 216 | *.build.csdef 217 | 218 | # Microsoft Azure Emulator 219 | ecf/ 220 | rcf/ 221 | 222 | # Windows Store app package directories and files 223 | AppPackages/ 224 | BundleArtifacts/ 225 | Package.StoreAssociation.xml 226 | _pkginfo.txt 227 | *.appx 228 | *.appxbundle 229 | *.appxupload 230 | 231 | # Visual Studio cache files 232 | # files ending in .cache can be ignored 233 | *.[Cc]ache 234 | # but keep track of directories ending in .cache 235 | !?*.[Cc]ache/ 236 | 237 | # Others 238 | ClientBin/ 239 | ~$* 240 | *~ 241 | *.dbmdl 242 | *.dbproj.schemaview 243 | *.jfm 244 | *.pfx 245 | *.publishsettings 246 | orleans.codegen.cs 247 | 248 | # Including strong name files can present a security risk 249 | # (https://github.com/github/gitignore/pull/2483#issue-259490424) 250 | #*.snk 251 | 252 | # Since there are multiple workflows, uncomment next line to ignore bower_components 253 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) 254 | #bower_components/ 255 | 256 | # RIA/Silverlight projects 257 | Generated_Code/ 258 | 259 | # Backup & report files from converting an old project file 260 | # to a newer Visual Studio version. Backup files are not needed, 261 | # because we have git ;-) 262 | _UpgradeReport_Files/ 263 | Backup*/ 264 | UpgradeLog*.XML 265 | UpgradeLog*.htm 266 | ServiceFabricBackup/ 267 | *.rptproj.bak 268 | 269 | # SQL Server files 270 | *.mdf 271 | *.ldf 272 | *.ndf 273 | 274 | # Business Intelligence projects 275 | *.rdl.data 276 | *.bim.layout 277 | *.bim_*.settings 278 | *.rptproj.rsuser 279 | *- [Bb]ackup.rdl 280 | *- [Bb]ackup ([0-9]).rdl 281 | *- [Bb]ackup ([0-9][0-9]).rdl 282 | 283 | # Microsoft Fakes 284 | FakesAssemblies/ 285 | 286 | # GhostDoc plugin setting file 287 | *.GhostDoc.xml 288 | 289 | # Node.js Tools for Visual Studio 290 | .ntvs_analysis.dat 291 | node_modules/ 292 | 293 | # Visual Studio 6 build log 294 | *.plg 295 | 296 | # Visual Studio 6 workspace options file 297 | *.opt 298 | 299 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.) 300 | *.vbw 301 | 302 | # Visual Studio 6 auto-generated project file (contains which files were open etc.) 303 | *.vbp 304 | 305 | # Visual Studio 6 workspace and project file (working project files containing files to include in project) 306 | *.dsw 307 | *.dsp 308 | 309 | # Visual Studio 6 technical files 310 | *.ncb 311 | *.aps 312 | 313 | # Visual Studio LightSwitch build output 314 | **/*.HTMLClient/GeneratedArtifacts 315 | **/*.DesktopClient/GeneratedArtifacts 316 | **/*.DesktopClient/ModelManifest.xml 317 | **/*.Server/GeneratedArtifacts 318 | **/*.Server/ModelManifest.xml 319 | _Pvt_Extensions 320 | 321 | # Paket dependency manager 322 | .paket/paket.exe 323 | paket-files/ 324 | 325 | # FAKE - F# Make 326 | .fake/ 327 | 328 | # CodeRush personal settings 329 | .cr/personal 330 | 331 | # Python Tools for Visual Studio (PTVS) 332 | __pycache__/ 333 | *.pyc 334 | 335 | # Cake - Uncomment if you are using it 336 | # tools/** 337 | # !tools/packages.config 338 | 339 | # Tabs Studio 340 | *.tss 341 | 342 | # Telerik's JustMock configuration file 343 | *.jmconfig 344 | 345 | # BizTalk build output 346 | *.btp.cs 347 | *.btm.cs 348 | *.odx.cs 349 | *.xsd.cs 350 | 351 | # OpenCover UI analysis results 352 | OpenCover/ 353 | 354 | # Azure Stream Analytics local run output 355 | ASALocalRun/ 356 | 357 | # MSBuild Binary and Structured Log 358 | *.binlog 359 | 360 | # NVidia Nsight GPU debugger configuration file 361 | *.nvuser 362 | 363 | # MFractors (Xamarin productivity tool) working folder 364 | .mfractor/ 365 | 366 | # Local History for Visual Studio 367 | .localhistory/ 368 | 369 | # Visual Studio History (VSHistory) files 370 | .vshistory/ 371 | 372 | # BeatPulse healthcheck temp database 373 | healthchecksdb 374 | 375 | # Backup folder for Package Reference Convert tool in Visual Studio 2017 376 | MigrationBackup/ 377 | 378 | # Ionide (cross platform F# VS Code tools) working folder 379 | .ionide/ 380 | 381 | # Fody - auto-generated XML schema 382 | FodyWeavers.xsd 383 | 384 | # VS Code files for those working on multiple tools 385 | .vscode/* 386 | !.vscode/settings.json 387 | !.vscode/tasks.json 388 | !.vscode/launch.json 389 | !.vscode/extensions.json 390 | *.code-workspace 391 | 392 | # Local History for Visual Studio Code 393 | .history/ 394 | 395 | # Windows Installer files from build outputs 396 | *.cab 397 | *.msi 398 | *.msix 399 | *.msm 400 | *.msp 401 | 402 | # JetBrains Rider 403 | *.sln.iml 404 | -------------------------------------------------------------------------------- /Test/TestWave.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Security.Cryptography; 3 | using System.Threading; 4 | using static enet.ENet; 5 | 6 | #pragma warning disable CA1806 7 | 8 | // ReSharper disable ALL 9 | 10 | namespace enet 11 | { 12 | public sealed unsafe class TestWave 13 | { 14 | private static bool _running; 15 | 16 | public const int INTERVAL = 1; 17 | 18 | public static void Start() 19 | { 20 | Console.CancelKeyPress += (sender, args) => _running = false; 21 | _running = true; 22 | new Thread(StartServer).Start(); 23 | Thread.Sleep(1000); 24 | new Thread(StartClient).Start(); 25 | while (true) 26 | Thread.Sleep(1000); 27 | } 28 | 29 | private static void StartServer() 30 | { 31 | enet_initialize(); 32 | ENetHost* host = null; 33 | try 34 | { 35 | ENetAddress address = new ENetAddress(); 36 | enet_address_set_host_ip(&address, "0.0.0.0"); 37 | address.port = 7777; 38 | 39 | byte* hostName = stackalloc byte[1024]; 40 | int error = enet_address_get_host(&address, hostName, 1024); 41 | 42 | if (error == 0) 43 | Console.WriteLine(new string((sbyte*)hostName)); 44 | 45 | host = enet_host_create(&address, 4095, 0, 0, 0, ENetHostOption.ENET_HOSTOPT_IPV4); 46 | 47 | ENetPeer* peer = null; 48 | 49 | ENetEvent netEvent = new ENetEvent(); 50 | 51 | byte* buffer = stackalloc byte[1024]; 52 | 53 | while (_running) 54 | { 55 | bool polled = false; 56 | while (!polled) 57 | { 58 | if (enet_host_check_events(host, &netEvent) <= 0) 59 | { 60 | if (enet_host_service(host, &netEvent, 1) <= 0) 61 | break; 62 | polled = true; 63 | } 64 | 65 | switch (netEvent.type) 66 | { 67 | case ENetEventType.ENET_EVENT_TYPE_NONE: 68 | break; 69 | case ENetEventType.ENET_EVENT_TYPE_CONNECT: 70 | peer = netEvent.peer; 71 | Console.WriteLine($"server Connected {peer->address.ToString()}"); 72 | break; 73 | case ENetEventType.ENET_EVENT_TYPE_DISCONNECT: 74 | peer = null; 75 | Console.WriteLine("server Disconnected"); 76 | break; 77 | case ENetEventType.ENET_EVENT_TYPE_RECEIVE: 78 | enet_peer_send(peer, 0, netEvent.packet); 79 | break; 80 | } 81 | } 82 | 83 | enet_host_flush(host); 84 | Thread.Sleep(INTERVAL); 85 | } 86 | } 87 | finally 88 | { 89 | if (host != null) 90 | enet_host_destroy(host); 91 | enet_deinitialize(); 92 | } 93 | } 94 | 95 | private static void StartClient() 96 | { 97 | enet_initialize(); 98 | ENetHost* host = null; 99 | try 100 | { 101 | ENetAddress address = new ENetAddress(); 102 | enet_address_set_host_ip(&address, "127.0.0.1"); 103 | address.port = 7777; 104 | 105 | ENetAddress local = new ENetAddress(); 106 | enet_address_set_host_ip(&local, "0.0.0.0"); 107 | local.port = 7778; 108 | 109 | host = enet_host_create(&local, 1, 0, 0, 0, ENetHostOption.ENET_HOSTOPT_IPV4); 110 | 111 | ENetPeer* peer = enet_host_connect(host, &address, 0, 0); 112 | 113 | ENetEvent netEvent = new ENetEvent(); 114 | 115 | bool connected = false; 116 | byte* buffer = stackalloc byte[2048]; 117 | bool sent = false; 118 | bool reached = false; 119 | int count = 0; 120 | 121 | while (_running) 122 | { 123 | bool polled = false; 124 | while (!polled) 125 | { 126 | if (enet_host_check_events(host, &netEvent) <= 0) 127 | { 128 | if (enet_host_service(host, &netEvent, 1) <= 0) 129 | break; 130 | polled = true; 131 | } 132 | 133 | switch (netEvent.type) 134 | { 135 | case ENetEventType.ENET_EVENT_TYPE_NONE: 136 | break; 137 | case ENetEventType.ENET_EVENT_TYPE_CONNECT: 138 | connected = true; 139 | Console.WriteLine($"client Connected {netEvent.peer->address.ToString()}"); 140 | break; 141 | case ENetEventType.ENET_EVENT_TYPE_DISCONNECT: 142 | connected = false; 143 | Console.WriteLine("client Disconnected"); 144 | break; 145 | case ENetEventType.ENET_EVENT_TYPE_RECEIVE: 146 | sent = false; 147 | if ((int)netEvent.packet->dataLength == count) 148 | { 149 | for (int i = 0; i < count; ++i) 150 | { 151 | if (netEvent.packet->data[i] != buffer[i]) 152 | { 153 | Console.ForegroundColor = ConsoleColor.Red; 154 | Console.WriteLine("data not same"); 155 | Console.ForegroundColor = ConsoleColor.White; 156 | goto label; 157 | } 158 | } 159 | } 160 | else 161 | { 162 | Console.ForegroundColor = ConsoleColor.Red; 163 | Console.WriteLine($"length not same"); 164 | Console.ForegroundColor = ConsoleColor.White; 165 | Console.WriteLine((int)netEvent.packet->dataLength + " " + count); 166 | } 167 | 168 | label: 169 | enet_packet_destroy(netEvent.packet); 170 | break; 171 | } 172 | } 173 | 174 | if (connected && !sent) 175 | { 176 | sent = true; 177 | if (!reached) 178 | { 179 | count++; 180 | if (count == 100) 181 | { 182 | Console.ForegroundColor = ConsoleColor.Cyan; 183 | Console.WriteLine("reached max"); 184 | Console.ForegroundColor = ConsoleColor.White; 185 | Thread.Sleep(1000); 186 | reached = true; 187 | } 188 | } 189 | else 190 | { 191 | count--; 192 | if (count == 1) 193 | { 194 | Console.ForegroundColor = ConsoleColor.Cyan; 195 | Console.WriteLine("reached min"); 196 | Console.ForegroundColor = ConsoleColor.White; 197 | Thread.Sleep(1000); 198 | reached = false; 199 | } 200 | } 201 | 202 | RandomNumberGenerator.Fill(new Span(buffer, count)); 203 | ENetPacket* packet = enet_packet_create(buffer, (nuint)count, (uint)ENetPacketFlag.ENET_PACKET_FLAG_RELIABLE); 204 | enet_peer_send(peer, 0, packet); 205 | } 206 | 207 | enet_host_flush(host); 208 | Thread.Sleep(INTERVAL); 209 | } 210 | } 211 | finally 212 | { 213 | if (host != null) 214 | enet_host_destroy(host); 215 | enet_deinitialize(); 216 | } 217 | } 218 | } 219 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/c/win32.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using NativeSockets; 6 | using static enet.ENetSocketOption; 7 | using static enet.ENetSocketType; 8 | using static enet.ENetSocketWait; 9 | using static enet.ENetHostOption; 10 | using static NativeSockets.SocketPal; 11 | 12 | #pragma warning disable CA1401 13 | #pragma warning disable CA2101 14 | #pragma warning disable CA2211 15 | #pragma warning disable SYSLIB1054 16 | #pragma warning disable CS1591 17 | 18 | // ReSharper disable ALL 19 | 20 | namespace enet 21 | { 22 | public static unsafe partial class ENet 23 | { 24 | public const int SOCKET_ERROR = -1; 25 | 26 | public static uint timeBase = 0; 27 | 28 | /// 29 | /// Initializes ENet globally. Must be called prior to using any functions in 30 | /// ENet. 31 | /// 32 | /// 0 on success, < 0 on failure 33 | public static int enet_initialize() => (int)Initialize(); 34 | 35 | /// 36 | /// Shuts down ENet globally. Should be called when a program that has 37 | /// initialized ENet exits. 38 | /// 39 | public static void enet_deinitialize() => Cleanup(); 40 | 41 | public static uint enet_host_random_seed() => (uint)timeGetTime(); 42 | 43 | /// 44 | /// the wall-time in milliseconds. Its initial value is unspecified 45 | /// unless otherwise set. 46 | /// 47 | public static uint enet_time_get() => (uint)timeGetTime() - timeBase; 48 | 49 | /// 50 | /// Sets the current wall-time in milliseconds. 51 | /// 52 | public static void enet_time_set(uint newTimeBase) => timeBase = (uint)timeGetTime() - newTimeBase; 53 | 54 | public static int enet_socket_bind(ENetSocket socket, ENetAddress* address) 55 | { 56 | if (address == null) 57 | return socket.IsIPv6 ? (int)Bind6(socket, null) : (int)Bind4(socket, null); 58 | 59 | if (socket.IsIPv6) 60 | { 61 | sockaddr_in6 socketAddress; 62 | socketAddress.sin6_family = (ushort)ADDRESS_FAMILY_INTER_NETWORK_V6; 63 | socketAddress.sin6_port = address->port; 64 | socketAddress.sin6_flowinfo = 0; 65 | memcpy(socketAddress.sin6_addr, &address->host, 16); 66 | socketAddress.sin6_scope_id = address->scopeID; 67 | 68 | return (int)Bind6(socket, &socketAddress); 69 | } 70 | else 71 | { 72 | if (address->IsIPv6) 73 | return -1; 74 | 75 | sockaddr_in socketAddress; 76 | socketAddress.sin_family = (ushort)AddressFamily.InterNetwork; 77 | socketAddress.sin_port = address->port; 78 | Unsafe.WriteUnaligned(&socketAddress.sin_addr, address->address); 79 | memset(socketAddress.sin_zero, 0, 8); 80 | 81 | return (int)Bind4(socket, &socketAddress); 82 | } 83 | } 84 | 85 | public static int enet_socket_get_address(nint socket, ENetAddress* address) 86 | { 87 | sockaddr_in6 socketAddress; 88 | int result = (int)GetName6(socket, &socketAddress); 89 | if (result == 0) 90 | { 91 | memcpy(&address->host, socketAddress.sin6_addr, 16); 92 | address->port = socketAddress.sin6_port; 93 | address->scopeID = socketAddress.sin6_scope_id; 94 | } 95 | 96 | return result; 97 | } 98 | 99 | public static ENetSocket enet_socket_create(ENetSocketType type, ENetHostOption option = 0) 100 | { 101 | if (type == ENET_SOCKET_TYPE_DATAGRAM) 102 | { 103 | bool ipv6 = option == ENET_HOSTOPT_IPV6_ONLY || option == ENET_HOSTOPT_IPV6_DUALMODE; 104 | nint socket = Create(ipv6); 105 | if (socket != ENET_SOCKET_NULL && option == ENET_HOSTOPT_IPV6_DUALMODE && enet_socket_set_option(socket, ENET_SOCKOPT_IPV6_ONLY, 0) < 0) 106 | { 107 | Close(socket); 108 | goto error; 109 | } 110 | 111 | return new ENetSocket { handle = socket, IsIPv6 = ipv6 }; 112 | } 113 | 114 | error: 115 | return new ENetSocket { handle = INVALID_SOCKET }; 116 | } 117 | 118 | public static int enet_socket_set_option(nint socket, ENetSocketOption option, int value) 119 | { 120 | int result = SOCKET_ERROR; 121 | switch (option) 122 | { 123 | case ENET_SOCKOPT_NONBLOCK: 124 | result = enet_socket_set_nonblocking(socket, value); 125 | break; 126 | case ENET_SOCKOPT_BROADCAST: 127 | result = (int)SetOption(socket, SocketOptionLevel.Socket, SocketOptionName.Broadcast, &value); 128 | break; 129 | case ENET_SOCKOPT_RCVBUF: 130 | result = (int)SetOption(socket, SocketOptionLevel.Socket, SocketOptionName.ReceiveBuffer, &value); 131 | break; 132 | case ENET_SOCKOPT_SNDBUF: 133 | result = (int)SetOption(socket, SocketOptionLevel.Socket, SocketOptionName.SendBuffer, &value); 134 | break; 135 | case ENET_SOCKOPT_REUSEADDR: 136 | result = (int)SetOption(socket, SocketOptionLevel.Socket, SocketOptionName.ReuseAddress, &value); 137 | break; 138 | case ENET_SOCKOPT_RCVTIMEO: 139 | result = (int)SetOption(socket, SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, &value); 140 | break; 141 | case ENET_SOCKOPT_SNDTIMEO: 142 | result = (int)SetOption(socket, SocketOptionLevel.Socket, SocketOptionName.SendTimeout, &value); 143 | break; 144 | case ENET_SOCKOPT_NODELAY: 145 | result = (int)SetOption(socket, SocketOptionLevel.Socket, SocketOptionName.NoDelay, &value); 146 | break; 147 | case ENET_SOCKOPT_TTL: 148 | result = (int)SetOption(socket, SocketOptionLevel.IP, SocketOptionName.IpTimeToLive, &value); 149 | break; 150 | case ENET_SOCKOPT_IPV6_ONLY: 151 | result = (int)SetOption(socket, SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, &value); 152 | break; 153 | default: 154 | break; 155 | } 156 | 157 | return result == SOCKET_ERROR ? -1 : 0; 158 | } 159 | 160 | public static int enet_socket_set_nonblocking(nint socket, int nonBlocking) => (int)SetBlocking(socket, nonBlocking == 0); 161 | 162 | public static void enet_socket_destroy(ENetSocket* socket) 163 | { 164 | Close(socket->handle); 165 | socket->handle = -1; 166 | } 167 | 168 | public static int enet_socket_send(ENetSocket socket, ENetAddress* address, ENetBuffer* buffers, nuint bufferCount) 169 | { 170 | if (socket.IsIPv6) 171 | { 172 | sockaddr_in6 socketAddress; 173 | socketAddress.sin6_family = (ushort)ADDRESS_FAMILY_INTER_NETWORK_V6; 174 | socketAddress.sin6_port = address->port; 175 | socketAddress.sin6_flowinfo = 0; 176 | memcpy(socketAddress.sin6_addr, &address->host, 16); 177 | socketAddress.sin6_scope_id = address->scopeID; 178 | 179 | return WSASendTo6(socket, (WSABuffer*)buffers, (int)bufferCount, &socketAddress); 180 | } 181 | else 182 | { 183 | if (address->IsIPv6) 184 | return -1; 185 | 186 | sockaddr_in socketAddress; 187 | socketAddress.sin_family = (ushort)AddressFamily.InterNetwork; 188 | socketAddress.sin_port = address->port; 189 | Unsafe.WriteUnaligned(&socketAddress.sin_addr, address->address); 190 | memset(socketAddress.sin_zero, 0, 8); 191 | 192 | return WSASendTo4(socket, (WSABuffer*)buffers, (int)bufferCount, &socketAddress); 193 | } 194 | } 195 | 196 | public static int enet_socket_receive(ENetSocket socket, ENetAddress* address, ENetBuffer* buffers, nuint bufferCount) 197 | { 198 | int result; 199 | if (socket.IsIPv6) 200 | { 201 | sockaddr_in6 socketAddress; 202 | result = WSAReceiveFrom6(socket, (WSABuffer*)buffers, (int)bufferCount, &socketAddress); 203 | 204 | if (result <= 0) 205 | return result; 206 | 207 | memcpy(&address->host, socketAddress.sin6_addr, 16); 208 | address->port = socketAddress.sin6_port; 209 | address->scopeID = socketAddress.sin6_scope_id; 210 | return result; 211 | } 212 | else 213 | { 214 | sockaddr_in socketAddress; 215 | result = WSAReceiveFrom4(socket, (WSABuffer*)buffers, (int)bufferCount, &socketAddress); 216 | 217 | if (result <= 0) 218 | return result; 219 | 220 | memset(address, 0, 8); 221 | Unsafe.WriteUnaligned((byte*)address + 8, WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6); 222 | Unsafe.WriteUnaligned(&address->address, socketAddress.sin_addr); 223 | address->port = socketAddress.sin_port; 224 | address->scopeID = 0; 225 | return result; 226 | } 227 | } 228 | 229 | public static int enet_socket_wait(nint socket, uint* condition, uint timeout) 230 | { 231 | int error; 232 | bool status; 233 | 234 | if ((*condition & (uint)ENET_SOCKET_WAIT_SEND) != 0) 235 | { 236 | error = (int)Poll(socket, (int)(timeout * 1000), SelectMode.SelectWrite, out status); 237 | if (error == 0) 238 | { 239 | *condition = (uint)ENET_SOCKET_WAIT_NONE; 240 | if (status) 241 | { 242 | *condition |= (uint)ENET_SOCKET_WAIT_SEND; 243 | return 0; 244 | } 245 | } 246 | 247 | return -1; 248 | } 249 | 250 | if ((*condition & (uint)ENET_SOCKET_WAIT_RECEIVE) != 0) 251 | { 252 | error = (int)Poll(socket, (int)(timeout * 1000), SelectMode.SelectRead, out status); 253 | if (error == 0) 254 | { 255 | *condition = (uint)ENET_SOCKET_WAIT_NONE; 256 | if (status) 257 | { 258 | *condition |= (uint)ENET_SOCKET_WAIT_RECEIVE; 259 | return 0; 260 | } 261 | } 262 | 263 | return -1; 264 | } 265 | 266 | return 0; 267 | } 268 | 269 | /// 270 | /// Attempts to parse the printable form of the IP address in the parameter hostName 271 | /// and sets the host field in the address parameter if successful. 272 | /// 273 | /// destination to store the parsed IP address 274 | /// IP address to parse 275 | /// 276 | /// 277 | /// 278 | /// 0 on success 279 | /// 280 | /// 281 | /// < 0 on failure 282 | /// 283 | /// 284 | /// the address of the given hostName in address on success 285 | /// 286 | public static int enet_address_set_host_ip(ENetAddress* address, ReadOnlySpan ip) 287 | { 288 | sockaddr_in6 __socketAddress_native; 289 | SocketError error = SetIP6(&__socketAddress_native, ip); 290 | if (error == 0) 291 | { 292 | memcpy(address, __socketAddress_native.sin6_addr, 16); 293 | address->scopeID = __socketAddress_native.sin6_scope_id; 294 | } 295 | 296 | return (int)error; 297 | } 298 | 299 | /// 300 | /// Attempts to resolve the host named by the parameter hostName and sets 301 | /// the host field in the address parameter if successful. 302 | /// 303 | /// destination to store resolved address 304 | /// host name to lookup 305 | /// 306 | /// 307 | /// 308 | /// 0 on success 309 | /// 310 | /// 311 | /// < 0 on failure 312 | /// 313 | /// 314 | /// the address of the given hostName in address on success 315 | /// 316 | public static int enet_address_set_host(ENetAddress* address, ReadOnlySpan hostName) 317 | { 318 | sockaddr_in6 __socketAddress_native; 319 | SocketError error = SetHostName6(&__socketAddress_native, hostName); 320 | if (error == 0) 321 | { 322 | memcpy(address, __socketAddress_native.sin6_addr, 16); 323 | address->scopeID = __socketAddress_native.sin6_scope_id; 324 | } 325 | 326 | return (int)error; 327 | } 328 | 329 | /// 330 | /// Gives the printable form of the IP address specified in the address parameter. 331 | /// 332 | /// address printed 333 | /// destination for name, must not be NULL 334 | /// maximum length of hostName. 335 | /// 336 | /// 337 | /// 338 | /// 0 on success 339 | /// 340 | /// 341 | /// < 0 on failure 342 | /// 343 | /// 344 | /// the null-terminated name of the host in hostName on success 345 | /// 346 | public static int enet_address_get_host_ip(ENetAddress* address, byte* ip, nuint nameLength) 347 | { 348 | sockaddr_in6 __socketAddress_native; 349 | memcpy(__socketAddress_native.sin6_addr, address, 16); 350 | __socketAddress_native.sin6_scope_id = address->scopeID; 351 | 352 | SocketError error = GetIP6(&__socketAddress_native, MemoryMarshal.CreateSpan(ref *ip, (int)nameLength)); 353 | 354 | return (int)error; 355 | } 356 | 357 | /// 358 | /// Attempts to do a reverse lookup of the host field in the address parameter. 359 | /// 360 | /// address used for reverse lookup 361 | /// destination for name, must not be NULL 362 | /// maximum length of hostName. 363 | /// 364 | /// 365 | /// 366 | /// 0 on success 367 | /// 368 | /// 369 | /// < 0 on failure 370 | /// 371 | /// 372 | /// the null-terminated name of the host in hostName on success 373 | /// 374 | public static int enet_address_get_host(ENetAddress* address, byte* hostName, nuint nameLength) 375 | { 376 | sockaddr_in6 __socketAddress_native; 377 | 378 | __socketAddress_native.sin6_family = (ushort)ADDRESS_FAMILY_INTER_NETWORK_V6; 379 | __socketAddress_native.sin6_port = address->port; 380 | __socketAddress_native.sin6_flowinfo = 0; 381 | memcpy(__socketAddress_native.sin6_addr, address, 16); 382 | __socketAddress_native.sin6_scope_id = address->scopeID; 383 | 384 | SocketError error = GetHostName6(&__socketAddress_native, MemoryMarshal.CreateSpan(ref *hostName, (int)nameLength)); 385 | 386 | return (int)error; 387 | } 388 | } 389 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/SocketPal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | using System.Runtime.CompilerServices; 4 | 5 | #pragma warning disable CS1591 6 | 7 | // ReSharper disable ALL 8 | 9 | namespace NativeSockets 10 | { 11 | public static unsafe class SocketPal 12 | { 13 | public static ushort ADDRESS_FAMILY_INTER_NETWORK_V6 { get; } 14 | 15 | public static bool IsWindows => WindowsSocketPal.IsSupported; 16 | public static bool IsLinux => LinuxSocketPal.IsSupported; 17 | public static bool IsBSD => BSDSocketPal.IsSupported; 18 | 19 | private static readonly delegate* managed _GetLastSocketError; 20 | private static readonly delegate* managed _Initialize; 21 | private static readonly delegate* managed _Cleanup; 22 | private static readonly delegate* managed _Create; 23 | private static readonly delegate* managed _Close; 24 | private static readonly delegate* managed _SetDualMode6; 25 | private static readonly delegate* managed _Bind4; 26 | private static readonly delegate* managed _Bind6; 27 | private static readonly delegate* managed _Connect4; 28 | private static readonly delegate* managed _Connect6; 29 | private static readonly delegate* managed _SetOption; 30 | private static readonly delegate* managed _GetOption; 31 | private static readonly delegate* managed _SetBlocking; 32 | private static readonly delegate* managed _Poll; 33 | private static readonly delegate* managed _Send; 34 | private static readonly delegate* managed _SendTo4; 35 | private static readonly delegate* managed _SendTo6; 36 | private static readonly delegate* managed _Receive; 37 | private static readonly delegate* managed _ReceiveFrom4; 38 | private static readonly delegate* managed _ReceiveFrom6; 39 | private static readonly delegate* managed _WSASend; 40 | private static readonly delegate* managed _WSASendTo4; 41 | private static readonly delegate* managed _WSASendTo6; 42 | private static readonly delegate* managed _WSAReceive; 43 | private static readonly delegate* managed _WSAReceiveFrom4; 44 | private static readonly delegate* managed _WSAReceiveFrom6; 45 | private static readonly delegate* managed _GetName4; 46 | private static readonly delegate* managed _GetName6; 47 | private static readonly delegate* managed, SocketError> _SetIP4; 48 | private static readonly delegate* managed, SocketError> _SetIP6; 49 | private static readonly delegate* managed, SocketError> _GetIP4; 50 | private static readonly delegate* managed, SocketError> _GetIP6; 51 | private static readonly delegate* managed, SocketError> _SetHostName4; 52 | private static readonly delegate* managed, SocketError> _SetHostName6; 53 | private static readonly delegate* managed, SocketError> _GetHostName4; 54 | private static readonly delegate* managed, SocketError> _GetHostName6; 55 | 56 | static SocketPal() 57 | { 58 | if (IsWindows) 59 | { 60 | ADDRESS_FAMILY_INTER_NETWORK_V6 = WindowsSocketPal.ADDRESS_FAMILY_INTER_NETWORK_V6; 61 | 62 | _GetLastSocketError = &WindowsSocketPal.GetLastSocketError; 63 | _Initialize = &WindowsSocketPal.Initialize; 64 | _Cleanup = &WindowsSocketPal.Cleanup; 65 | _Create = &WindowsSocketPal.Create; 66 | _Close = &WindowsSocketPal.Close; 67 | _SetDualMode6 = &WindowsSocketPal.SetDualMode6; 68 | _Bind4 = &WindowsSocketPal.Bind4; 69 | _Bind6 = &WindowsSocketPal.Bind6; 70 | _Connect4 = &WindowsSocketPal.Connect4; 71 | _Connect6 = &WindowsSocketPal.Connect6; 72 | _SetOption = &WindowsSocketPal.SetOption; 73 | _GetOption = &WindowsSocketPal.GetOption; 74 | _SetBlocking = &WindowsSocketPal.SetBlocking; 75 | _Poll = &WindowsSocketPal.Poll; 76 | _Send = &WindowsSocketPal.Send; 77 | _SendTo4 = &WindowsSocketPal.SendTo4; 78 | _SendTo6 = &WindowsSocketPal.SendTo6; 79 | _Receive = &WindowsSocketPal.Receive; 80 | _ReceiveFrom4 = &WindowsSocketPal.ReceiveFrom4; 81 | _ReceiveFrom6 = &WindowsSocketPal.ReceiveFrom6; 82 | _WSASend = &WindowsSocketPal.WSASend; 83 | _WSASendTo4 = &WindowsSocketPal.WSASendTo4; 84 | _WSASendTo6 = &WindowsSocketPal.WSASendTo6; 85 | _WSAReceive = &WindowsSocketPal.WSAReceive; 86 | _WSAReceiveFrom4 = &WindowsSocketPal.WSAReceiveFrom4; 87 | _WSAReceiveFrom6 = &WindowsSocketPal.WSAReceiveFrom6; 88 | _GetName4 = &WindowsSocketPal.GetName4; 89 | _GetName6 = &WindowsSocketPal.GetName6; 90 | _SetIP4 = &WindowsSocketPal.SetIP4; 91 | _SetIP6 = &WindowsSocketPal.SetIP6; 92 | _GetIP4 = &WindowsSocketPal.GetIP4; 93 | _GetIP6 = &WindowsSocketPal.GetIP6; 94 | _SetHostName4 = &WindowsSocketPal.SetHostName4; 95 | _SetHostName6 = &WindowsSocketPal.SetHostName6; 96 | _GetHostName4 = &WindowsSocketPal.GetHostName4; 97 | _GetHostName6 = &WindowsSocketPal.GetHostName6; 98 | 99 | return; 100 | } 101 | 102 | if (IsLinux) 103 | { 104 | ADDRESS_FAMILY_INTER_NETWORK_V6 = LinuxSocketPal.ADDRESS_FAMILY_INTER_NETWORK_V6; 105 | 106 | _GetLastSocketError = &LinuxSocketPal.GetLastSocketError; 107 | _Initialize = &LinuxSocketPal.Initialize; 108 | _Cleanup = &LinuxSocketPal.Cleanup; 109 | _Create = &LinuxSocketPal.Create; 110 | _Close = &LinuxSocketPal.Close; 111 | _SetDualMode6 = &LinuxSocketPal.SetDualMode6; 112 | _Bind4 = &LinuxSocketPal.Bind4; 113 | _Bind6 = &LinuxSocketPal.Bind6; 114 | _Connect4 = &LinuxSocketPal.Connect4; 115 | _Connect6 = &LinuxSocketPal.Connect6; 116 | _SetOption = &LinuxSocketPal.SetOption; 117 | _GetOption = &LinuxSocketPal.GetOption; 118 | _SetBlocking = &LinuxSocketPal.SetBlocking; 119 | _Poll = &LinuxSocketPal.Poll; 120 | _Send = &LinuxSocketPal.Send; 121 | _SendTo4 = &LinuxSocketPal.SendTo4; 122 | _SendTo6 = &LinuxSocketPal.SendTo6; 123 | _Receive = &LinuxSocketPal.Receive; 124 | _ReceiveFrom4 = &LinuxSocketPal.ReceiveFrom4; 125 | _ReceiveFrom6 = &LinuxSocketPal.ReceiveFrom6; 126 | _WSASend = &LinuxSocketPal.WSASend; 127 | _WSASendTo4 = &LinuxSocketPal.WSASendTo4; 128 | _WSASendTo6 = &LinuxSocketPal.WSASendTo6; 129 | _WSAReceive = &LinuxSocketPal.WSAReceive; 130 | _WSAReceiveFrom4 = &LinuxSocketPal.WSAReceiveFrom4; 131 | _WSAReceiveFrom6 = &LinuxSocketPal.WSAReceiveFrom6; 132 | _GetName4 = &LinuxSocketPal.GetName4; 133 | _GetName6 = &LinuxSocketPal.GetName6; 134 | _SetIP4 = &LinuxSocketPal.SetIP4; 135 | _SetIP6 = &LinuxSocketPal.SetIP6; 136 | _GetIP4 = &LinuxSocketPal.GetIP4; 137 | _GetIP6 = &LinuxSocketPal.GetIP6; 138 | _SetHostName4 = &LinuxSocketPal.SetHostName4; 139 | _SetHostName6 = &LinuxSocketPal.SetHostName6; 140 | _GetHostName4 = &LinuxSocketPal.GetHostName4; 141 | _GetHostName6 = &LinuxSocketPal.GetHostName6; 142 | 143 | return; 144 | } 145 | 146 | ADDRESS_FAMILY_INTER_NETWORK_V6 = BSDSocketPal.ADDRESS_FAMILY_INTER_NETWORK_V6; 147 | 148 | _GetLastSocketError = &BSDSocketPal.GetLastSocketError; 149 | _Initialize = &BSDSocketPal.Initialize; 150 | _Cleanup = &BSDSocketPal.Cleanup; 151 | _Create = &BSDSocketPal.Create; 152 | _Close = &BSDSocketPal.Close; 153 | _SetDualMode6 = &BSDSocketPal.SetDualMode6; 154 | _Bind4 = &BSDSocketPal.Bind4; 155 | _Bind6 = &BSDSocketPal.Bind6; 156 | _Connect4 = &BSDSocketPal.Connect4; 157 | _Connect6 = &BSDSocketPal.Connect6; 158 | _SetOption = &BSDSocketPal.SetOption; 159 | _GetOption = &BSDSocketPal.GetOption; 160 | _SetBlocking = &BSDSocketPal.SetBlocking; 161 | _Poll = &BSDSocketPal.Poll; 162 | _Send = &BSDSocketPal.Send; 163 | _SendTo4 = &BSDSocketPal.SendTo4; 164 | _SendTo6 = &BSDSocketPal.SendTo6; 165 | _Receive = &BSDSocketPal.Receive; 166 | _ReceiveFrom4 = &BSDSocketPal.ReceiveFrom4; 167 | _ReceiveFrom6 = &BSDSocketPal.ReceiveFrom6; 168 | _WSASend = &BSDSocketPal.WSASend; 169 | _WSASendTo4 = &BSDSocketPal.WSASendTo4; 170 | _WSASendTo6 = &BSDSocketPal.WSASendTo6; 171 | _WSAReceive = &BSDSocketPal.WSAReceive; 172 | _WSAReceiveFrom4 = &BSDSocketPal.WSAReceiveFrom4; 173 | _WSAReceiveFrom6 = &BSDSocketPal.WSAReceiveFrom6; 174 | _GetName4 = &BSDSocketPal.GetName4; 175 | _GetName6 = &BSDSocketPal.GetName6; 176 | _SetIP4 = &BSDSocketPal.SetIP4; 177 | _SetIP6 = &BSDSocketPal.SetIP6; 178 | _GetIP4 = &BSDSocketPal.GetIP4; 179 | _GetIP6 = &BSDSocketPal.GetIP6; 180 | _SetHostName4 = &BSDSocketPal.SetHostName4; 181 | _SetHostName6 = &BSDSocketPal.SetHostName6; 182 | _GetHostName4 = &BSDSocketPal.GetHostName4; 183 | _GetHostName6 = &BSDSocketPal.GetHostName6; 184 | } 185 | 186 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 187 | public static SocketError GetLastSocketError() => _GetLastSocketError(); 188 | 189 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 190 | public static SocketError Initialize() => _Initialize(); 191 | 192 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 193 | public static SocketError Cleanup() => _Cleanup(); 194 | 195 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 196 | public static nint Create(bool ipv6) => _Create(ipv6); 197 | 198 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 199 | public static SocketError Close(nint socket) => _Close(socket); 200 | 201 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 202 | public static SocketError SetDualMode6(nint socket, bool dualMode) => _SetDualMode6(socket, dualMode); 203 | 204 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 205 | public static SocketError Bind4(nint socket, sockaddr_in* socketAddress) => _Bind4(socket, socketAddress); 206 | 207 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 208 | public static SocketError Bind6(nint socket, sockaddr_in6* socketAddress) => _Bind6(socket, socketAddress); 209 | 210 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 211 | public static SocketError Connect4(nint socket, sockaddr_in* socketAddress) => _Connect4(socket, socketAddress); 212 | 213 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 214 | public static SocketError Connect6(nint socket, sockaddr_in6* socketAddress) => _Connect6(socket, socketAddress); 215 | 216 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 217 | public static SocketError SetOption(nint socket, SocketOptionLevel level, SocketOptionName name, int* value, int length = sizeof(int)) => _SetOption(socket, level, name, value, length); 218 | 219 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 220 | public static SocketError GetOption(nint socket, SocketOptionLevel level, SocketOptionName name, int* value, int* length = null) => _GetOption(socket, level, name, value, length); 221 | 222 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 223 | public static SocketError SetBlocking(nint socket, bool blocking) => _SetBlocking(socket, blocking); 224 | 225 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 226 | public static SocketError Poll(nint socket, int microseconds, SelectMode mode, out bool status) => _Poll(socket, microseconds, mode, out status); 227 | 228 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 229 | public static int Send(nint socket, void* buffer, int length) => _Send(socket, buffer, length); 230 | 231 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 232 | public static int SendTo4(nint socket, void* buffer, int length, sockaddr_in* socketAddress) => _SendTo4(socket, buffer, length, socketAddress); 233 | 234 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 235 | public static int SendTo6(nint socket, void* buffer, int length, sockaddr_in6* socketAddress) => _SendTo6(socket, buffer, length, socketAddress); 236 | 237 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 238 | public static int Receive(nint socket, void* buffer, int length) => _Receive(socket, buffer, length); 239 | 240 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 241 | public static int ReceiveFrom4(nint socket, void* buffer, int length, sockaddr_in* socketAddress) => _ReceiveFrom4(socket, buffer, length, socketAddress); 242 | 243 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 244 | public static int ReceiveFrom6(nint socket, void* buffer, int length, sockaddr_in6* socketAddress) => _ReceiveFrom6(socket, buffer, length, socketAddress); 245 | 246 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 247 | public static int WSASend(nint socket, WSABuffer* buffers, int bufferCount) => _WSASend(socket, buffers, bufferCount); 248 | 249 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 250 | public static int WSASendTo4(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in* socketAddress) => _WSASendTo4(socket, buffers, bufferCount, socketAddress); 251 | 252 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 253 | public static int WSASendTo6(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in6* socketAddress) => _WSASendTo6(socket, buffers, bufferCount, socketAddress); 254 | 255 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 256 | public static int WSAReceive(nint socket, WSABuffer* buffers, int bufferCount) => _WSAReceive(socket, buffers, bufferCount); 257 | 258 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 259 | public static int WSAReceiveFrom4(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in* socketAddress) => _WSAReceiveFrom4(socket, buffers, bufferCount, socketAddress); 260 | 261 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 262 | public static int WSAReceiveFrom6(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in6* socketAddress) => _WSAReceiveFrom6(socket, buffers, bufferCount, socketAddress); 263 | 264 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 265 | public static SocketError GetName4(nint socket, sockaddr_in* socketAddress) => _GetName4(socket, socketAddress); 266 | 267 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 268 | public static SocketError GetName6(nint socket, sockaddr_in6* socketAddress) => _GetName6(socket, socketAddress); 269 | 270 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 271 | public static SocketError SetIP4(sockaddr_in* pAddrBuf, ReadOnlySpan ip) => _SetIP4(pAddrBuf, ip); 272 | 273 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 274 | public static SocketError SetIP6(sockaddr_in6* pAddrBuf, ReadOnlySpan ip) => _SetIP6(pAddrBuf, ip); 275 | 276 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 277 | public static SocketError GetIP4(sockaddr_in* pAddrBuf, Span ip) => _GetIP4(pAddrBuf, ip); 278 | 279 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 280 | public static SocketError GetIP6(sockaddr_in6* pAddrBuf, Span ip) => _GetIP6(pAddrBuf, ip); 281 | 282 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 283 | public static SocketError SetHostName4(sockaddr_in* pAddrBuf, ReadOnlySpan hostName) => _SetHostName4(pAddrBuf, hostName); 284 | 285 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 286 | public static SocketError SetHostName6(sockaddr_in6* pAddrBuf, ReadOnlySpan hostName) => _SetHostName6(pAddrBuf, hostName); 287 | 288 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 289 | public static SocketError GetHostName4(sockaddr_in* socketAddress, Span hostName) => _GetHostName4(socketAddress, hostName); 290 | 291 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 292 | public static SocketError GetHostName6(sockaddr_in6* socketAddress, Span hostName) => _GetHostName6(socketAddress, hostName); 293 | } 294 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/c/host.cs: -------------------------------------------------------------------------------- 1 | using static enet.ENetSocketOption; 2 | using static enet.ENetSocketType; 3 | using static enet.ENetPeerState; 4 | using static enet.ENetProtocolCommand; 5 | using static enet.ENetProtocolFlag; 6 | using static enet.ENetHostOption; 7 | 8 | #pragma warning disable CS1591 9 | 10 | // ReSharper disable ALL 11 | 12 | namespace enet 13 | { 14 | public static unsafe partial class ENet 15 | { 16 | /// 17 | /// Sends a ping request to an address. 18 | /// 19 | /// host ping the address 20 | /// destination for the ping request 21 | public static int enet_host_ping(ENetHost* host, ENetAddress* address) 22 | { 23 | ENetBuffer buffer; 24 | byte* data = stackalloc byte[1]; 25 | buffer.data = data; 26 | buffer.dataLength = 1; 27 | return enet_socket_send(host->socket, address, &buffer, 1) > 0 ? 0 : -1; 28 | } 29 | 30 | /// 31 | /// Creates a host for communicating to peers. 32 | /// 33 | /// 34 | /// The address at which other peers may connect to this host. If NULL, then no peers may connect to 35 | /// the host. 36 | /// 37 | /// The maximum number of peers that should be allocated for the host. 38 | /// 39 | /// The maximum number of channels allowed; if 0, then this is equivalent to 40 | /// ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT 41 | /// 42 | /// 43 | /// Downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited 44 | /// bandwidth. 45 | /// 46 | /// 47 | /// Upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited 48 | /// bandwidth. 49 | /// 50 | /// 51 | /// 52 | /// 53 | /// ENET_HOSTOPT_IPV4 (default): IPv4 54 | /// 55 | /// 56 | /// ENET_HOSTOPT_IPV6_ONLY: IPv6-only 57 | /// 58 | /// 59 | /// ENET_HOSTOPT_IPV6_DUALMODE: both IPv4 and IPv6 60 | /// 61 | /// 62 | /// 63 | /// The host on success and NULL on failure 64 | /// 65 | /// ENet will strategically drop packets on specific sides of a connection between hosts 66 | /// to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine 67 | /// the window size of a connection which limits the amount of reliable packets that may be in transit 68 | /// at any given time. 69 | /// 70 | public static ENetHost* enet_host_create(ENetAddress* address, nuint peerCount, nuint channelLimit, uint incomingBandwidth, uint outgoingBandwidth, ENetHostOption option = 0) 71 | { 72 | if (option < ENET_HOSTOPT_IPV4 || option > ENET_HOSTOPT_IPV6_DUALMODE) 73 | return null; 74 | 75 | ENetHost* host; 76 | ENetPeer* currentPeer; 77 | 78 | if (peerCount > ENET_PROTOCOL_MAXIMUM_PEER_ID) 79 | return null; 80 | 81 | host = (ENetHost*)enet_malloc((nuint)sizeof(ENetHost)); 82 | if (host == null) 83 | return null; 84 | 85 | memset(host, 0, (nuint)sizeof(ENetHost)); 86 | 87 | host->peers = (ENetPeer*)enet_malloc(peerCount * (nuint)sizeof(ENetPeer)); 88 | if (host->peers == null) 89 | { 90 | enet_free(host); 91 | 92 | return null; 93 | } 94 | 95 | memset(host->peers, 0, peerCount * (nuint)sizeof(ENetPeer)); 96 | 97 | host->socket = enet_socket_create(ENET_SOCKET_TYPE_DATAGRAM, option); 98 | 99 | if (host->socket == ENET_SOCKET_NULL || (address != null && enet_socket_bind(host->socket, address) < 0)) 100 | { 101 | if (host->socket != ENET_SOCKET_NULL) 102 | enet_socket_destroy(&host->socket); 103 | 104 | enet_free(host->peers); 105 | enet_free(host); 106 | 107 | return null; 108 | } 109 | 110 | enet_socket_set_option(host->socket, ENET_SOCKOPT_NONBLOCK, 1); 111 | enet_socket_set_option(host->socket, ENET_SOCKOPT_BROADCAST, 1); 112 | enet_socket_set_option(host->socket, ENET_SOCKOPT_RCVBUF, (int)ENET_HOST_RECEIVE_BUFFER_SIZE); 113 | enet_socket_set_option(host->socket, ENET_SOCKOPT_SNDBUF, (int)ENET_HOST_SEND_BUFFER_SIZE); 114 | 115 | if (address != null && enet_socket_get_address(host->socket, &host->address) < 0) 116 | host->address = *address; 117 | 118 | if (!(channelLimit != 0) || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) 119 | channelLimit = (nuint)ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; 120 | else if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) 121 | channelLimit = (nuint)ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; 122 | 123 | host->randomSeed = (uint)(nuint)host; 124 | host->randomSeed += enet_host_random_seed(); 125 | host->randomSeed = (host->randomSeed << 16) | (host->randomSeed >> 16); 126 | host->channelLimit = channelLimit; 127 | host->incomingBandwidth = incomingBandwidth; 128 | host->outgoingBandwidth = outgoingBandwidth; 129 | host->bandwidthThrottleEpoch = 0; 130 | host->recalculateBandwidthLimits = 0; 131 | host->mtu = ENET_HOST_DEFAULT_MTU; 132 | host->peerCount = peerCount; 133 | host->commandCount = 0; 134 | host->bufferCount = 0; 135 | host->checksum = null; 136 | host->receivedAddress.host = ENET_HOST_ANY; 137 | host->receivedAddress.port = 0; 138 | host->receivedAddress.scopeID = 0; 139 | host->receivedData = null; 140 | host->receivedDataLength = 0; 141 | 142 | host->totalSentData = 0; 143 | host->totalSentPackets = 0; 144 | host->totalReceivedData = 0; 145 | host->totalReceivedPackets = 0; 146 | host->totalQueued = 0; 147 | 148 | host->connectedPeers = 0; 149 | host->bandwidthLimitedPeers = 0; 150 | host->duplicatePeers = (nuint)ENET_PROTOCOL_MAXIMUM_PEER_ID; 151 | host->maximumPacketSize = (nuint)ENET_HOST_DEFAULT_MAXIMUM_PACKET_SIZE; 152 | host->maximumWaitingData = (nuint)ENET_HOST_DEFAULT_MAXIMUM_WAITING_DATA; 153 | 154 | host->compressor.context = null; 155 | host->compressor.compress = null; 156 | host->compressor.decompress = null; 157 | host->compressor.destroy = null; 158 | 159 | host->intercept = null; 160 | 161 | enet_list_clear(&host->dispatchQueue); 162 | 163 | for (currentPeer = host->peers; 164 | currentPeer < &host->peers[host->peerCount]; 165 | ++currentPeer) 166 | { 167 | currentPeer->host = host; 168 | currentPeer->incomingPeerID = (ushort)(currentPeer - host->peers); 169 | currentPeer->outgoingSessionID = currentPeer->incomingSessionID = 0xFF; 170 | currentPeer->data = null; 171 | 172 | enet_list_clear(¤tPeer->acknowledgements); 173 | enet_list_clear(¤tPeer->sentReliableCommands); 174 | enet_list_clear(¤tPeer->outgoingCommands); 175 | enet_list_clear(¤tPeer->outgoingSendReliableCommands); 176 | enet_list_clear(¤tPeer->dispatchedCommands); 177 | 178 | enet_peer_reset(currentPeer); 179 | } 180 | 181 | return host; 182 | } 183 | 184 | /// 185 | /// Destroys the host and all resources associated with it. 186 | /// 187 | /// pointer to the host to destroy 188 | public static void enet_host_destroy(ENetHost* host) 189 | { 190 | ENetPeer* currentPeer; 191 | 192 | if (host == null) 193 | return; 194 | 195 | enet_socket_destroy(&host->socket); 196 | 197 | for (currentPeer = host->peers; 198 | currentPeer < &host->peers[host->peerCount]; 199 | ++currentPeer) 200 | { 201 | enet_peer_reset(currentPeer); 202 | } 203 | 204 | if (host->compressor.context != null && host->compressor.destroy != null) 205 | (host->compressor.destroy)(host->compressor.context); 206 | 207 | enet_free(host->peers); 208 | enet_free(host); 209 | } 210 | 211 | public static uint enet_host_random(ENetHost* host) 212 | { 213 | uint n = (host->randomSeed += 0x6D2B79F5U); 214 | n = (n ^ (n >> 15)) * (n | 1U); 215 | n ^= n + (n ^ (n >> 7)) * (n | 61U); 216 | return n ^ (n >> 14); 217 | } 218 | 219 | /// 220 | /// Initiates a connection to a foreign host. 221 | /// 222 | /// host seeking the connection 223 | /// destination for the connection 224 | /// number of channels to allocate 225 | /// user data supplied to the receiving host 226 | /// a peer representing the foreign host on success, NULL on failure 227 | /// 228 | /// The peer returned will have not completed the connection until enet_host_service() 229 | /// notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. 230 | /// 231 | public static ENetPeer* enet_host_connect(ENetHost* host, ENetAddress* address, nuint channelCount, uint data) 232 | { 233 | ENetPeer* currentPeer; 234 | ENetChannel* channel; 235 | ENetProtocol command; 236 | 237 | if (channelCount < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) 238 | channelCount = (nuint)ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; 239 | else if (channelCount > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) 240 | channelCount = (nuint)ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; 241 | 242 | for (currentPeer = host->peers; 243 | currentPeer < &host->peers[host->peerCount]; 244 | ++currentPeer) 245 | { 246 | if (currentPeer->state == ENET_PEER_STATE_DISCONNECTED) 247 | break; 248 | } 249 | 250 | if (currentPeer >= &host->peers[host->peerCount]) 251 | return null; 252 | 253 | currentPeer->channels = (ENetChannel*)enet_malloc(channelCount * (nuint)sizeof(ENetChannel)); 254 | if (currentPeer->channels == null) 255 | return null; 256 | 257 | currentPeer->channelCount = channelCount; 258 | currentPeer->state = ENET_PEER_STATE_CONNECTING; 259 | currentPeer->address = *address; 260 | currentPeer->connectID = enet_host_random(host); 261 | currentPeer->mtu = host->mtu; 262 | 263 | if (host->outgoingBandwidth == 0) 264 | currentPeer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; 265 | else 266 | currentPeer->windowSize = (host->outgoingBandwidth / 267 | ENET_PEER_WINDOW_SIZE_SCALE) * 268 | ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; 269 | 270 | if (currentPeer->windowSize < ENET_PROTOCOL_MINIMUM_WINDOW_SIZE) 271 | currentPeer->windowSize = ENET_PROTOCOL_MINIMUM_WINDOW_SIZE; 272 | else if (currentPeer->windowSize > ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE) 273 | currentPeer->windowSize = ENET_PROTOCOL_MAXIMUM_WINDOW_SIZE; 274 | 275 | for (channel = currentPeer->channels; 276 | channel < ¤tPeer->channels[channelCount]; 277 | ++channel) 278 | { 279 | channel->outgoingReliableSequenceNumber = 0; 280 | channel->outgoingUnreliableSequenceNumber = 0; 281 | channel->incomingReliableSequenceNumber = 0; 282 | channel->incomingUnreliableSequenceNumber = 0; 283 | 284 | enet_list_clear(&channel->incomingReliableCommands); 285 | enet_list_clear(&channel->incomingUnreliableCommands); 286 | 287 | channel->usedReliableWindows = 0; 288 | memset(channel->reliableWindows, 0, (nuint)(ENET_PEER_RELIABLE_WINDOWS * sizeof(ushort))); 289 | } 290 | 291 | command.header.command = (byte)((uint)ENET_PROTOCOL_COMMAND_CONNECT | (uint)ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE); 292 | command.header.channelID = 0xFF; 293 | command.connect.outgoingPeerID = ENET_HOST_TO_NET_16(currentPeer->incomingPeerID); 294 | command.connect.incomingSessionID = currentPeer->incomingSessionID; 295 | command.connect.outgoingSessionID = currentPeer->outgoingSessionID; 296 | command.connect.mtu = ENET_HOST_TO_NET_32(currentPeer->mtu); 297 | command.connect.windowSize = ENET_HOST_TO_NET_32(currentPeer->windowSize); 298 | command.connect.channelCount = ENET_HOST_TO_NET_32((uint)channelCount); 299 | command.connect.incomingBandwidth = ENET_HOST_TO_NET_32(host->incomingBandwidth); 300 | command.connect.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); 301 | command.connect.packetThrottleInterval = ENET_HOST_TO_NET_32(currentPeer->packetThrottleInterval); 302 | command.connect.packetThrottleAcceleration = ENET_HOST_TO_NET_32(currentPeer->packetThrottleAcceleration); 303 | command.connect.packetThrottleDeceleration = ENET_HOST_TO_NET_32(currentPeer->packetThrottleDeceleration); 304 | command.connect.connectID = currentPeer->connectID; 305 | command.connect.data = ENET_HOST_TO_NET_32(data); 306 | 307 | enet_peer_queue_outgoing_command(currentPeer, &command, null, 0, 0); 308 | 309 | return currentPeer; 310 | } 311 | 312 | /// 313 | /// Queues a packet to be sent to all peers associated with the host. 314 | /// 315 | /// host on which to broadcast the packet 316 | /// channel on which to broadcast 317 | /// packet to broadcast 318 | public static void enet_host_broadcast(ENetHost* host, byte channelID, ENetPacket* packet) 319 | { 320 | ENetPeer* currentPeer; 321 | 322 | for (currentPeer = host->peers; 323 | currentPeer < &host->peers[host->peerCount]; 324 | ++currentPeer) 325 | { 326 | if (currentPeer->state != ENET_PEER_STATE_CONNECTED) 327 | continue; 328 | 329 | enet_peer_send(currentPeer, channelID, packet); 330 | } 331 | 332 | if (packet->referenceCount == 0) 333 | enet_packet_destroy(packet); 334 | } 335 | 336 | /// 337 | /// Sets the packet compressor the host should use to compress and decompress packets. 338 | /// 339 | /// host to enable or disable compression for 340 | /// callbacks for for the packet compressor; if NULL, then compression is disabled 341 | public static void enet_host_compress(ENetHost* host, ENetCompressor* compressor) 342 | { 343 | if (host->compressor.context != null && host->compressor.destroy != null) 344 | (host->compressor.destroy)(host->compressor.context); 345 | 346 | if (compressor != null) 347 | host->compressor = *compressor; 348 | else 349 | host->compressor.context = null; 350 | } 351 | 352 | /// 353 | /// Limits the maximum allowed channels of future incoming connections. 354 | /// 355 | /// host to limit 356 | /// 357 | /// the maximum number of channels allowed; if 0, then this is equivalent to 358 | /// ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT 359 | /// 360 | public static void enet_host_channel_limit(ENetHost* host, nuint channelLimit) 361 | { 362 | if (!(channelLimit != 0) || channelLimit > ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT) 363 | channelLimit = (nuint)ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT; 364 | else if (channelLimit < ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT) 365 | channelLimit = (nuint)ENET_PROTOCOL_MINIMUM_CHANNEL_COUNT; 366 | 367 | host->channelLimit = channelLimit; 368 | } 369 | 370 | /// 371 | /// Adjusts the bandwidth limits of a host. 372 | /// 373 | /// host to adjust 374 | /// new incoming bandwidth 375 | /// new outgoing bandwidth 376 | /// 377 | /// the incoming and outgoing bandwidth parameters are identical in function to those 378 | /// specified in . 379 | /// 380 | public static void enet_host_bandwidth_limit(ENetHost* host, uint incomingBandwidth, uint outgoingBandwidth) 381 | { 382 | host->incomingBandwidth = incomingBandwidth; 383 | host->outgoingBandwidth = outgoingBandwidth; 384 | host->recalculateBandwidthLimits = 1; 385 | } 386 | 387 | public static void enet_host_bandwidth_throttle(ENetHost* host) 388 | { 389 | uint timeCurrent = enet_time_get(), 390 | elapsedTime = timeCurrent - host->bandwidthThrottleEpoch, 391 | peersRemaining = (uint)host->connectedPeers, 392 | dataTotal = unchecked((uint)(~0)), 393 | bandwidth = unchecked((uint)(~0)), 394 | throttle = 0, 395 | bandwidthLimit = 0; 396 | int needsAdjustment = host->bandwidthLimitedPeers > 0 ? 1 : 0; 397 | ENetPeer* peer; 398 | ENetProtocol command; 399 | 400 | if (elapsedTime < ENET_HOST_BANDWIDTH_THROTTLE_INTERVAL) 401 | return; 402 | 403 | host->bandwidthThrottleEpoch = timeCurrent; 404 | 405 | if (peersRemaining == 0) 406 | return; 407 | 408 | if (host->outgoingBandwidth != 0) 409 | { 410 | dataTotal = 0; 411 | bandwidth = (host->outgoingBandwidth * elapsedTime) / 1000; 412 | 413 | for (peer = host->peers; 414 | peer < &host->peers[host->peerCount]; 415 | ++peer) 416 | { 417 | if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) 418 | continue; 419 | 420 | dataTotal += peer->outgoingDataTotal; 421 | } 422 | } 423 | 424 | while (peersRemaining > 0 && needsAdjustment != 0) 425 | { 426 | needsAdjustment = 0; 427 | 428 | if (dataTotal <= bandwidth) 429 | throttle = ENET_PEER_PACKET_THROTTLE_SCALE; 430 | else 431 | throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; 432 | 433 | for (peer = host->peers; 434 | peer < &host->peers[host->peerCount]; 435 | ++peer) 436 | { 437 | uint peerBandwidth; 438 | 439 | if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || 440 | peer->incomingBandwidth == 0 || 441 | peer->outgoingBandwidthThrottleEpoch == timeCurrent) 442 | continue; 443 | 444 | peerBandwidth = (peer->incomingBandwidth * elapsedTime) / 1000; 445 | if ((throttle * peer->outgoingDataTotal) / ENET_PEER_PACKET_THROTTLE_SCALE <= peerBandwidth) 446 | continue; 447 | 448 | peer->packetThrottleLimit = (peerBandwidth * 449 | ENET_PEER_PACKET_THROTTLE_SCALE) / peer->outgoingDataTotal; 450 | 451 | if (peer->packetThrottleLimit == 0) 452 | peer->packetThrottleLimit = 1; 453 | 454 | if (peer->packetThrottle > peer->packetThrottleLimit) 455 | peer->packetThrottle = peer->packetThrottleLimit; 456 | 457 | peer->outgoingBandwidthThrottleEpoch = timeCurrent; 458 | 459 | peer->incomingDataTotal = 0; 460 | peer->outgoingDataTotal = 0; 461 | 462 | needsAdjustment = 1; 463 | --peersRemaining; 464 | bandwidth -= peerBandwidth; 465 | dataTotal -= peerBandwidth; 466 | } 467 | } 468 | 469 | if (peersRemaining > 0) 470 | { 471 | if (dataTotal <= bandwidth) 472 | throttle = ENET_PEER_PACKET_THROTTLE_SCALE; 473 | else 474 | throttle = (bandwidth * ENET_PEER_PACKET_THROTTLE_SCALE) / dataTotal; 475 | 476 | for (peer = host->peers; 477 | peer < &host->peers[host->peerCount]; 478 | ++peer) 479 | { 480 | if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || 481 | peer->outgoingBandwidthThrottleEpoch == timeCurrent) 482 | continue; 483 | 484 | peer->packetThrottleLimit = throttle; 485 | 486 | if (peer->packetThrottle > peer->packetThrottleLimit) 487 | peer->packetThrottle = peer->packetThrottleLimit; 488 | 489 | peer->incomingDataTotal = 0; 490 | peer->outgoingDataTotal = 0; 491 | } 492 | } 493 | 494 | if ((host->recalculateBandwidthLimits) != 0) 495 | { 496 | host->recalculateBandwidthLimits = 0; 497 | 498 | peersRemaining = (uint)host->connectedPeers; 499 | bandwidth = host->incomingBandwidth; 500 | needsAdjustment = 1; 501 | 502 | if (bandwidth == 0) 503 | bandwidthLimit = 0; 504 | else 505 | { 506 | while (peersRemaining > 0 && needsAdjustment != 0) 507 | { 508 | needsAdjustment = 0; 509 | bandwidthLimit = bandwidth / peersRemaining; 510 | 511 | for (peer = host->peers; 512 | peer < &host->peers[host->peerCount]; 513 | ++peer) 514 | { 515 | if ((peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) || 516 | peer->incomingBandwidthThrottleEpoch == timeCurrent) 517 | continue; 518 | 519 | if (peer->outgoingBandwidth > 0 && 520 | peer->outgoingBandwidth >= bandwidthLimit) 521 | continue; 522 | 523 | peer->incomingBandwidthThrottleEpoch = timeCurrent; 524 | 525 | needsAdjustment = 1; 526 | --peersRemaining; 527 | bandwidth -= peer->outgoingBandwidth; 528 | } 529 | } 530 | } 531 | 532 | for (peer = host->peers; 533 | peer < &host->peers[host->peerCount]; 534 | ++peer) 535 | { 536 | if (peer->state != ENET_PEER_STATE_CONNECTED && peer->state != ENET_PEER_STATE_DISCONNECT_LATER) 537 | continue; 538 | 539 | command.header.command = (byte)((uint)ENET_PROTOCOL_COMMAND_BANDWIDTH_LIMIT | (uint)ENET_PROTOCOL_COMMAND_FLAG_ACKNOWLEDGE); 540 | command.header.channelID = 0xFF; 541 | command.bandwidthLimit.outgoingBandwidth = ENET_HOST_TO_NET_32(host->outgoingBandwidth); 542 | 543 | if (peer->incomingBandwidthThrottleEpoch == timeCurrent) 544 | command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32(peer->outgoingBandwidth); 545 | else 546 | command.bandwidthLimit.incomingBandwidth = ENET_HOST_TO_NET_32(bandwidthLimit); 547 | 548 | enet_peer_queue_outgoing_command(peer, &command, null, 0, 0); 549 | } 550 | } 551 | } 552 | } 553 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/c/enet.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Runtime.CompilerServices; 3 | 4 | #pragma warning disable CS1591 5 | 6 | // ReSharper disable ALL 7 | 8 | namespace enet 9 | { 10 | public static unsafe class ENET_API 11 | { 12 | /// 13 | /// Initializes ENet globally. Must be called prior to using any functions in 14 | /// ENet. 15 | /// 16 | /// 0 on success, < 0 on failure 17 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 18 | public static int enet_initialize() => ENet.enet_initialize(); 19 | 20 | /// 21 | /// Initializes ENet globally and supplies user-overridden callbacks. Must be called prior to using any functions in 22 | /// ENet. 23 | /// Do not use if you use this variant. Make sure the 24 | /// structure 25 | /// is zeroed out so that any additional callbacks added in future versions will be properly ignored. 26 | /// 27 | /// 28 | /// the constant should be supplied so ENet knows which version of 29 | /// struct to use 30 | /// 31 | /// user-overridden callbacks where any NULL callbacks will use ENet's defaults 32 | /// 0 on success, < 0 on failure 33 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 34 | public static int enet_initialize_with_callbacks(uint version, ENetCallbacks* inits) => ENet.enet_initialize_with_callbacks(version, inits); 35 | 36 | /// 37 | /// Shuts down ENet globally. Should be called when a program that has 38 | /// initialized ENet exits. 39 | /// 40 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 41 | public static void enet_deinitialize() => ENet.enet_deinitialize(); 42 | 43 | /// 44 | /// Gives the linked version of the ENet library. 45 | /// 46 | /// the version number 47 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 48 | public static uint enet_linked_version() => ENet.enet_linked_version(); 49 | 50 | /// 51 | /// the wall-time in milliseconds. Its initial value is unspecified 52 | /// unless otherwise set. 53 | /// 54 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 55 | public static uint enet_time_get() => ENet.enet_time_get(); 56 | 57 | /// 58 | /// Sets the current wall-time in milliseconds. 59 | /// 60 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 61 | public static void enet_time_set(uint newTimeBase) => ENet.enet_time_set(newTimeBase); 62 | 63 | 64 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 65 | public static ENetSocket enet_socket_create(ENetSocketType type, ENetHostOption option = 0) => ENet.enet_socket_create(type, option); 66 | 67 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 68 | public static int enet_socket_bind(ENetSocket socket, ENetAddress* address) => ENet.enet_socket_bind(socket, address); 69 | 70 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 71 | public static int enet_socket_get_address(nint socket, ENetAddress* address) => ENet.enet_socket_get_address(socket, address); 72 | 73 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 74 | public static int enet_socket_send(ENetSocket socket, ENetAddress* address, ENetBuffer* buffers, nuint bufferCount) => ENet.enet_socket_send(socket, address, buffers, bufferCount); 75 | 76 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 77 | public static int enet_socket_receive(ENetSocket socket, ENetAddress* address, ENetBuffer* buffers, nuint bufferCount) => ENet.enet_socket_receive(socket, address, buffers, bufferCount); 78 | 79 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 80 | public static int enet_socket_wait(nint socket, uint* condition, uint timeout) => ENet.enet_socket_wait(socket, condition, timeout); 81 | 82 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 83 | public static int enet_socket_set_option(nint socket, ENetSocketOption option, int value) => ENet.enet_socket_set_option(socket, option, value); 84 | 85 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 86 | public static void enet_socket_destroy(ENetSocket* socket) => ENet.enet_socket_destroy(socket); 87 | 88 | /// 89 | /// Attempts to parse the printable form of the IP address in the parameter hostName 90 | /// and sets the host field in the address parameter if successful. 91 | /// 92 | /// destination to store the parsed IP address 93 | /// IP address to parse 94 | /// 95 | /// 96 | /// 97 | /// 0 on success 98 | /// 99 | /// 100 | /// < 0 on failure 101 | /// 102 | /// 103 | /// the address of the given hostName in address on success 104 | /// 105 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 106 | public static int enet_address_set_host_ip(ENetAddress* address, ReadOnlySpan ip) => ENet.enet_address_set_host_ip(address, ip); 107 | 108 | /// 109 | /// Attempts to resolve the host named by the parameter hostName and sets 110 | /// the host field in the address parameter if successful. 111 | /// 112 | /// destination to store resolved address 113 | /// host name to lookup 114 | /// 115 | /// 116 | /// 117 | /// 0 on success 118 | /// 119 | /// 120 | /// < 0 on failure 121 | /// 122 | /// 123 | /// the address of the given hostName in address on success 124 | /// 125 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 126 | public static int enet_address_set_host(ENetAddress* address, ReadOnlySpan hostName) => ENet.enet_address_set_host(address, hostName); 127 | 128 | /// 129 | /// Gives the printable form of the IP address specified in the address parameter. 130 | /// 131 | /// address printed 132 | /// destination for name, must not be NULL 133 | /// maximum length of hostName. 134 | /// 135 | /// 136 | /// 137 | /// 0 on success 138 | /// 139 | /// 140 | /// < 0 on failure 141 | /// 142 | /// 143 | /// the null-terminated name of the host in hostName on success 144 | /// 145 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 146 | public static int enet_address_get_host_ip(ENetAddress* address, byte* ip, nuint nameLength) => ENet.enet_address_get_host_ip(address, ip, nameLength); 147 | 148 | /// 149 | /// Attempts to do a reverse lookup of the host field in the address parameter. 150 | /// 151 | /// address used for reverse lookup 152 | /// destination for name, must not be NULL 153 | /// maximum length of hostName. 154 | /// 155 | /// 156 | /// 157 | /// 0 on success 158 | /// 159 | /// 160 | /// < 0 on failure 161 | /// 162 | /// 163 | /// the null-terminated name of the host in hostName on success 164 | /// 165 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 166 | public static int enet_address_get_host(ENetAddress* address, byte* hostName, nuint nameLength) => ENet.enet_address_get_host(address, hostName, nameLength); 167 | 168 | /// 169 | /// Creates a packet that may be sent to a peer. 170 | /// 171 | /// initial contents of the packet's data; the packet's data will remain uninitialized if data is NULL. 172 | /// size of the data allocated for this packet 173 | /// flags for this packet as described for the ENetPacket structure. 174 | /// the packet on success, NULL on failure 175 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 176 | public static ENetPacket* enet_packet_create(void* data, nuint dataLength, uint flags) => ENet.enet_packet_create(data, dataLength, flags); 177 | 178 | /// 179 | /// Destroys the packet and deallocates its data. 180 | /// 181 | /// packet to be destroyed 182 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 183 | public static void enet_packet_destroy(ENetPacket* packet) => ENet.enet_packet_destroy(packet); 184 | 185 | /// 186 | /// Attempts to resize the data in the packet to length specified in the 187 | /// dataLength parameter. 188 | /// 189 | /// packet to resize 190 | /// new size for the packet data 191 | /// 0 on success, < 0 on failure 192 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 193 | public static int enet_packet_resize(ENetPacket* packet, nuint dataLength) => ENet.enet_packet_resize(packet, dataLength); 194 | 195 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 196 | public static uint enet_crc32(ENetBuffer* buffers, nuint bufferCount) => ENet.enet_crc32(buffers, bufferCount); 197 | 198 | /// 199 | /// Sends a ping request to an address. 200 | /// 201 | /// host ping the address 202 | /// destination for the ping request 203 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 204 | public static int enet_host_ping(ENetHost* host, ENetAddress* address) => ENet.enet_host_ping(host, address); 205 | 206 | /// 207 | /// Creates a host for communicating to peers. 208 | /// 209 | /// 210 | /// The address at which other peers may connect to this host. If NULL, then no peers may connect to 211 | /// the host. 212 | /// 213 | /// The maximum number of peers that should be allocated for the host. 214 | /// 215 | /// The maximum number of channels allowed; if 0, then this is equivalent to 216 | /// ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT 217 | /// 218 | /// 219 | /// Downstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited 220 | /// bandwidth. 221 | /// 222 | /// 223 | /// Upstream bandwidth of the host in bytes/second; if 0, ENet will assume unlimited 224 | /// bandwidth. 225 | /// 226 | /// 227 | /// 228 | /// 229 | /// ENET_HOSTOPT_IPV4 (default): IPv4 230 | /// 231 | /// 232 | /// ENET_HOSTOPT_IPV6_ONLY: IPv6-only 233 | /// 234 | /// 235 | /// ENET_HOSTOPT_IPV6_DUALMODE: both IPv4 and IPv6 236 | /// 237 | /// 238 | /// 239 | /// The host on success and NULL on failure 240 | /// 241 | /// ENet will strategically drop packets on specific sides of a connection between hosts 242 | /// to ensure the host's bandwidth is not overwhelmed. The bandwidth parameters also determine 243 | /// the window size of a connection which limits the amount of reliable packets that may be in transit 244 | /// at any given time. 245 | /// 246 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 247 | public static ENetHost* enet_host_create(ENetAddress* address, nuint peerCount, nuint channelLimit, uint incomingBandwidth, uint outgoingBandwidth, ENetHostOption option = 0) => ENet.enet_host_create(address, peerCount, channelLimit, incomingBandwidth, outgoingBandwidth, option); 248 | 249 | /// 250 | /// Destroys the host and all resources associated with it. 251 | /// 252 | /// pointer to the host to destroy 253 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 254 | public static void enet_host_destroy(ENetHost* host) => ENet.enet_host_destroy(host); 255 | 256 | /// 257 | /// Initiates a connection to a foreign host. 258 | /// 259 | /// host seeking the connection 260 | /// destination for the connection 261 | /// number of channels to allocate 262 | /// user data supplied to the receiving host 263 | /// a peer representing the foreign host on success, NULL on failure 264 | /// 265 | /// The peer returned will have not completed the connection until enet_host_service() 266 | /// notifies of an ENET_EVENT_TYPE_CONNECT event for the peer. 267 | /// 268 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 269 | public static ENetPeer* enet_host_connect(ENetHost* host, ENetAddress* address, nuint channelCount, uint data) => ENet.enet_host_connect(host, address, channelCount, data); 270 | 271 | /// 272 | /// Checks for any queued events on the host and dispatches one if available. 273 | /// 274 | /// host to check for events 275 | /// an event structure where event details will be placed if available 276 | /// 277 | /// 278 | /// 279 | /// > 0 if an event was dispatched 280 | /// 281 | /// 282 | /// 0 if no events are available 283 | /// 284 | /// 285 | /// < 0 on failure 286 | /// 287 | /// 288 | /// 289 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 290 | public static int enet_host_check_events(ENetHost* host, ENetEvent* @event) => ENet.enet_host_check_events(host, @event); 291 | 292 | /// 293 | /// Waits for events on the host specified and shuttles packets between 294 | /// the host and its peers. 295 | /// 296 | /// host to service 297 | /// 298 | /// an event structure where event details will be placed if one occurs 299 | /// if event == NULL then no events will be delivered 300 | /// 301 | /// number of milliseconds that ENet should wait for events 302 | /// 303 | /// 304 | /// 305 | /// > 0 if an event occurred within the specified time limit 306 | /// 307 | /// 308 | /// 0 if no event occurred 309 | /// 310 | /// 311 | /// < 0 on failure 312 | /// 313 | /// 314 | /// 315 | /// 316 | /// enet_host_service should be called fairly regularly for adequate performance 317 | /// 318 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 319 | public static int enet_host_service(ENetHost* host, ENetEvent* @event, uint timeout) => ENet.enet_host_service(host, @event, timeout); 320 | 321 | /// 322 | /// Sends any queued packets on the host specified to its designated peers. 323 | /// 324 | /// host to flush 325 | /// 326 | /// This function need only be used in circumstances where one wishes to send queued packets earlier than in a call to 327 | /// enet_host_service(). 328 | /// 329 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 330 | public static void enet_host_flush(ENetHost* host) => ENet.enet_host_flush(host); 331 | 332 | /// 333 | /// Queues a packet to be sent to all peers associated with the host. 334 | /// 335 | /// host on which to broadcast the packet 336 | /// channel on which to broadcast 337 | /// packet to broadcast 338 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 339 | public static void enet_host_broadcast(ENetHost* host, byte channelID, ENetPacket* packet) => ENet.enet_host_broadcast(host, channelID, packet); 340 | 341 | /// 342 | /// Sets the packet compressor the host should use to compress and decompress packets. 343 | /// 344 | /// host to enable or disable compression for 345 | /// callbacks for for the packet compressor; if NULL, then compression is disabled 346 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 347 | public static void enet_host_compress(ENetHost* host, ENetCompressor* compressor) => ENet.enet_host_compress(host, compressor); 348 | 349 | /// 350 | /// Limits the maximum allowed channels of future incoming connections. 351 | /// 352 | /// host to limit 353 | /// 354 | /// the maximum number of channels allowed; if 0, then this is equivalent to 355 | /// ENET_PROTOCOL_MAXIMUM_CHANNEL_COUNT 356 | /// 357 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 358 | public static void enet_host_channel_limit(ENetHost* host, nuint channelLimit) => ENet.enet_host_channel_limit(host, channelLimit); 359 | 360 | /// 361 | /// Adjusts the bandwidth limits of a host. 362 | /// 363 | /// host to adjust 364 | /// new incoming bandwidth 365 | /// new outgoing bandwidth 366 | /// 367 | /// the incoming and outgoing bandwidth parameters are identical in function to those 368 | /// specified in . 369 | /// 370 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 371 | public static void enet_host_bandwidth_limit(ENetHost* host, uint incomingBandwidth, uint outgoingBandwidth) => ENet.enet_host_bandwidth_limit(host, incomingBandwidth, outgoingBandwidth); 372 | 373 | /// 374 | /// Queues a packet to be sent. 375 | /// 376 | /// 377 | /// On success, ENet will assume ownership of the packet, and so enet_packet_destroy 378 | /// should not be called on it thereafter. On failure, the caller still must destroy 379 | /// the packet on its own as ENet has not queued the packet. The caller can also 380 | /// check the packet's referenceCount field after sending to check if ENet queued 381 | /// the packet and thus incremented the referenceCount. 382 | /// 383 | /// destination for the packet 384 | /// channel on which to send 385 | /// packet to send 386 | /// 387 | /// 388 | /// 389 | /// 0 on success 390 | /// 391 | /// 392 | /// < 0 on failure 393 | /// 394 | /// 395 | /// 396 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 397 | public static int enet_peer_send(ENetPeer* peer, byte channelID, ENetPacket* packet) => ENet.enet_peer_send(peer, channelID, packet); 398 | 399 | /// 400 | /// Attempts to dequeue any incoming queued packet. 401 | /// 402 | /// peer to dequeue packets from 403 | /// holds the channel ID of the channel the packet was received on success 404 | /// a pointer to the packet, or NULL if there are no available incoming queued packets 405 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 406 | public static ENetPacket* enet_peer_receive(ENetPeer* peer, byte* channelID) => ENet.enet_peer_receive(peer, channelID); 407 | 408 | /// 409 | /// Sends a ping request to a peer. 410 | /// 411 | /// destination for the ping request 412 | /// 413 | /// ping requests factor into the mean round trip time as designated by the 414 | /// roundTripTime field in the ENetPeer structure. ENet automatically pings all connected 415 | /// peers at regular intervals, however, this function may be called to ensure more 416 | /// frequent ping requests. 417 | /// 418 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 419 | public static void enet_peer_ping(ENetPeer* peer) => ENet.enet_peer_ping(peer); 420 | 421 | /// 422 | /// Sets the interval at which pings will be sent to a peer. 423 | /// 424 | /// 425 | /// Pings are used both to monitor the liveness of the connection and also to dynamically 426 | /// adjust the throttle during periods of low traffic so that the throttle has reasonable 427 | /// responsiveness during traffic spikes. 428 | /// 429 | /// the peer to adjust 430 | /// the interval at which to send pings; defaults to ENET_PEER_PING_INTERVAL if 0 431 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 432 | public static void enet_peer_ping_interval(ENetPeer* peer, uint pingInterval) => ENet.enet_peer_ping_interval(peer, pingInterval); 433 | 434 | /// 435 | /// Sets the timeout parameters for a peer. 436 | /// 437 | /// 438 | /// The timeout parameter control how and when a peer will timeout from a failure to acknowledge 439 | /// reliable traffic. Timeout values use an exponential backoff mechanism, where if a reliable 440 | /// packet is not acknowledge within some multiple of the average RTT plus a variance tolerance, 441 | /// the timeout will be doubled until it reaches a set limit. If the timeout is thus at this 442 | /// limit and reliable packets have been sent but not acknowledged within a certain minimum time 443 | /// period, the peer will be disconnected. Alternatively, if reliable packets have been sent 444 | /// but not acknowledged for a certain maximum time period, the peer will be disconnected regardless 445 | /// of the current timeout limit value. 446 | /// 447 | /// the peer to adjust 448 | /// the timeout limit; defaults to ENET_PEER_TIMEOUT_LIMIT if 0 449 | /// the timeout minimum; defaults to ENET_PEER_TIMEOUT_MINIMUM if 0 450 | /// the timeout maximum; defaults to ENET_PEER_TIMEOUT_MAXIMUM if 0 451 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 452 | public static void enet_peer_timeout(ENetPeer* peer, uint timeoutLimit, uint timeoutMinimum, uint timeoutMaximum) => ENet.enet_peer_timeout(peer, timeoutLimit, timeoutMinimum, timeoutMaximum); 453 | 454 | /// 455 | /// Forcefully disconnects a peer. 456 | /// 457 | /// peer to forcefully disconnect 458 | /// 459 | /// The foreign host represented by the peer is not notified of the disconnection and will timeout 460 | /// on its connection to the local host. 461 | /// 462 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 463 | public static void enet_peer_reset(ENetPeer* peer) => ENet.enet_peer_reset(peer); 464 | 465 | /// 466 | /// Request a disconnection from a peer. 467 | /// 468 | /// peer to request a disconnection 469 | /// data describing the disconnection 470 | /// 471 | /// An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() 472 | /// once the disconnection is complete. 473 | /// 474 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 475 | public static void enet_peer_disconnect(ENetPeer* peer, uint data) => ENet.enet_peer_disconnect(peer, data); 476 | 477 | /// 478 | /// Force an immediate disconnection from a peer. 479 | /// 480 | /// peer to disconnect 481 | /// data describing the disconnection 482 | /// 483 | /// No ENET_EVENT_DISCONNECT event will be generated. The foreign peer is not 484 | /// guaranteed to receive the disconnect notification, and is reset immediately upon 485 | /// return from this function. 486 | /// 487 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 488 | public static void enet_peer_disconnect_now(ENetPeer* peer, uint data) => ENet.enet_peer_disconnect_now(peer, data); 489 | 490 | /// 491 | /// Request a disconnection from a peer, but only after all queued outgoing packets are sent. 492 | /// 493 | /// peer to request a disconnection 494 | /// data describing the disconnection 495 | /// 496 | /// An ENET_EVENT_DISCONNECT event will be generated by enet_host_service() 497 | /// once the disconnection is complete. 498 | /// 499 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 500 | public static void enet_peer_disconnect_later(ENetPeer* peer, uint data) => ENet.enet_peer_disconnect_later(peer, data); 501 | 502 | /// 503 | /// Configures throttle parameter for a peer. 504 | /// 505 | /// 506 | /// Unreliable packets are dropped by ENet in response to the varying conditions 507 | /// of the Internet connection to the peer. The throttle represents a probability 508 | /// that an unreliable packet should not be dropped and thus sent by ENet to the peer. 509 | /// The lowest mean round trip time from the sending of a reliable packet to the 510 | /// receipt of its acknowledgement is measured over an amount of time specified by 511 | /// the interval parameter in milliseconds. If a measured round trip time happens to 512 | /// be significantly less than the mean round trip time measured over the interval, 513 | /// then the throttle probability is increased to allow more traffic by an amount 514 | /// specified in the acceleration parameter, which is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE 515 | /// constant. If a measured round trip time happens to be significantly greater than 516 | /// the mean round trip time measured over the interval, then the throttle probability 517 | /// is decreased to limit traffic by an amount specified in the deceleration parameter, which 518 | /// is a ratio to the ENET_PEER_PACKET_THROTTLE_SCALE constant. When the throttle has 519 | /// a value of ENET_PEER_PACKET_THROTTLE_SCALE, no unreliable packets are dropped by 520 | /// ENet, and so 100% of all unreliable packets will be sent. When the throttle has a 521 | /// value of 0, all unreliable packets are dropped by ENet, and so 0% of all unreliable 522 | /// packets will be sent. Intermediate values for the throttle represent intermediate 523 | /// probabilities between 0% and 100% of unreliable packets being sent. The bandwidth 524 | /// limits of the local and foreign hosts are taken into account to determine a 525 | /// sensible limit for the throttle probability above which it should not raise even in 526 | /// the best of conditions. 527 | /// 528 | /// peer to configure 529 | /// 530 | /// interval, in milliseconds, over which to measure lowest mean RTT; the default value is 531 | /// ENET_PEER_PACKET_THROTTLE_INTERVAL. 532 | /// 533 | /// rate at which to increase the throttle probability as mean RTT declines 534 | /// rate at which to decrease the throttle probability as mean RTT increases 535 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 536 | public static void enet_peer_throttle_configure(ENetPeer* peer, uint interval, uint acceleration, uint deceleration) => ENet.enet_peer_throttle_configure(peer, interval, acceleration, deceleration); 537 | } 538 | } -------------------------------------------------------------------------------- /enet-csharp/ENet/plugins/NativeSockets/Unix/Linux/c/LinuxSocketPal.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net.Sockets; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Security; 6 | using System.Text; 7 | using static NativeSockets.UnixSocketPal; 8 | 9 | #pragma warning disable CA1401 10 | #pragma warning disable CS1591 11 | #pragma warning disable CS8981 12 | #pragma warning disable SYSLIB1054 13 | 14 | // ReSharper disable ALL 15 | 16 | namespace NativeSockets 17 | { 18 | [SuppressUnmanagedCodeSecurity] 19 | public static unsafe class LinuxSocketPal 20 | { 21 | public const ushort ADDRESS_FAMILY_INTER_NETWORK_V6 = 10; 22 | 23 | public static bool IsSupported { get; } = RuntimeInformation.IsOSPlatform(OSPlatform.Linux); 24 | 25 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 26 | public static SocketError GetLastSocketError() => UnixSocketPal.GetLastSocketError(); 27 | 28 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 29 | public static SocketError Initialize() => SocketError.Success; 30 | 31 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 32 | public static SocketError Cleanup() => SocketError.Success; 33 | 34 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 35 | public static nint Create(bool ipv6) 36 | { 37 | int family = ipv6 ? ADDRESS_FAMILY_INTER_NETWORK_V6 : (int)AddressFamily.InterNetwork; 38 | nint _socket = socket(family, (int)SocketType.Dgram, 0); 39 | return _socket; 40 | } 41 | 42 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 43 | public static SocketError Close(nint socket) 44 | { 45 | SocketError errorCode = close((int)socket); 46 | return errorCode; 47 | } 48 | 49 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 50 | public static SocketError SetDualMode6(nint socket, bool dualMode) 51 | { 52 | int optionValue = dualMode ? 0 : 1; 53 | SocketError errorCode = SetOption(socket, SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, &optionValue); 54 | return errorCode; 55 | } 56 | 57 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 58 | public static SocketError Bind4(nint socket, sockaddr_in* socketAddress) 59 | { 60 | sockaddr_in __socketAddress_native; 61 | if (socketAddress == null) 62 | { 63 | __socketAddress_native = new sockaddr_in(); 64 | __socketAddress_native.sin_family = (ushort)AddressFamily.InterNetwork; 65 | SetIP4(&__socketAddress_native, "0.0.0.0"); 66 | } 67 | else 68 | { 69 | __socketAddress_native = *socketAddress; 70 | __socketAddress_native.sin_port = WinSock2.HOST_TO_NET_16(socketAddress->sin_port); 71 | } 72 | 73 | SocketError errorCode = bind((int)socket, (sockaddr*)&__socketAddress_native, sizeof(sockaddr_in)); 74 | return errorCode; 75 | } 76 | 77 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 78 | public static SocketError Bind6(nint socket, sockaddr_in6* socketAddress) 79 | { 80 | sockaddr_in6 __socketAddress_native; 81 | if (socketAddress == null) 82 | { 83 | __socketAddress_native = new sockaddr_in6(); 84 | __socketAddress_native.sin6_family = ADDRESS_FAMILY_INTER_NETWORK_V6; 85 | SetIP6(&__socketAddress_native, "::"); 86 | } 87 | else 88 | { 89 | __socketAddress_native = *socketAddress; 90 | __socketAddress_native.sin6_port = WinSock2.HOST_TO_NET_16(socketAddress->sin6_port); 91 | } 92 | 93 | SocketError errorCode = bind((int)socket, (sockaddr*)&__socketAddress_native, sizeof(sockaddr_in6)); 94 | return errorCode; 95 | } 96 | 97 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 98 | public static SocketError Connect4(nint socket, sockaddr_in* socketAddress) 99 | { 100 | sockaddr_in __socketAddress_native = *socketAddress; 101 | __socketAddress_native.sin_port = WinSock2.HOST_TO_NET_16(socketAddress->sin_port); 102 | 103 | SocketError errorCode = connect((int)socket, (sockaddr*)&__socketAddress_native, sizeof(sockaddr_in)); 104 | return errorCode; 105 | } 106 | 107 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 108 | public static SocketError Connect6(nint socket, sockaddr_in6* socketAddress) 109 | { 110 | sockaddr_in6 __socketAddress_native = *socketAddress; 111 | __socketAddress_native.sin6_port = WinSock2.HOST_TO_NET_16(socketAddress->sin6_port); 112 | 113 | SocketError errorCode = connect((int)socket, (sockaddr*)&__socketAddress_native, sizeof(sockaddr_in6)); 114 | return errorCode; 115 | } 116 | 117 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 118 | public static SocketError SetOption(nint socket, SocketOptionLevel optionLevel, SocketOptionName optionName, int* optionValue, int optionLength = sizeof(int)) 119 | { 120 | SocketError errorCode = setsockopt((int)socket, optionLevel, optionName, optionValue, optionLength); 121 | return errorCode == SocketError.SocketError ? GetLastSocketError() : SocketError.Success; 122 | } 123 | 124 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 125 | public static SocketError GetOption(nint socket, SocketOptionLevel level, SocketOptionName optionName, int* optionValue, int* optionLength = null) 126 | { 127 | int num = sizeof(int); 128 | if (optionLength == null) 129 | optionLength = # 130 | 131 | SocketError errorCode = getsockopt((int)socket, (int)level, (int)optionName, (byte*)optionValue, optionLength); 132 | return errorCode == SocketError.SocketError ? GetLastSocketError() : SocketError.Success; 133 | } 134 | 135 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 136 | public static SocketError SetBlocking(nint socket, bool shouldBlock) 137 | { 138 | int flags = fcntl((int)socket, 3, 0); 139 | if (flags == -1) 140 | return GetLastSocketError(); 141 | 142 | flags = shouldBlock ? flags & ~2048 : flags | 2048; 143 | if (fcntl((int)socket, 4, flags) == -1) 144 | return GetLastSocketError(); 145 | 146 | return SocketError.Success; 147 | } 148 | 149 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 150 | public static SocketError Poll(nint socket, int microseconds, SelectMode mode, out bool status) 151 | { 152 | PollEvents inEvent = 0; 153 | switch (mode) 154 | { 155 | case SelectMode.SelectRead: 156 | inEvent = PollEvents.POLLIN; 157 | break; 158 | case SelectMode.SelectWrite: 159 | inEvent = PollEvents.POLLOUT; 160 | break; 161 | case SelectMode.SelectError: 162 | inEvent = PollEvents.POLLPRI; 163 | break; 164 | } 165 | 166 | int milliseconds = microseconds == -1 ? -1 : microseconds / 1000; 167 | 168 | pollfd fd; 169 | fd.fd = (int)socket; 170 | fd.events = (short)inEvent; 171 | fd.revents = 0; 172 | 173 | int errno = poll(&fd, 1, milliseconds); 174 | if (errno == -1) 175 | { 176 | status = false; 177 | return GetLastSocketError(); 178 | } 179 | 180 | PollEvents outEvents = (PollEvents)fd.revents; 181 | switch (mode) 182 | { 183 | case SelectMode.SelectRead: 184 | status = (outEvents & (PollEvents.POLLIN | PollEvents.POLLHUP)) != 0; 185 | break; 186 | case SelectMode.SelectWrite: 187 | status = (outEvents & PollEvents.POLLOUT) != 0; 188 | break; 189 | case SelectMode.SelectError: 190 | status = (outEvents & (PollEvents.POLLERR | PollEvents.POLLPRI)) != 0; 191 | break; 192 | default: 193 | status = false; 194 | break; 195 | } 196 | 197 | return SocketError.Success; 198 | } 199 | 200 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 201 | public static int Send(nint socket, void* buffer, int length) 202 | { 203 | int num = send((int)socket, (byte*)buffer, length, SocketFlags.None); 204 | return num; 205 | } 206 | 207 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 208 | public static int SendTo4(nint socket, void* buffer, int length, sockaddr_in* socketAddress) 209 | { 210 | if (socketAddress != null) 211 | { 212 | sockaddr_in __socketAddress_native = *socketAddress; 213 | __socketAddress_native.sin_port = WinSock2.HOST_TO_NET_16(socketAddress->sin_port); 214 | return sendto((int)socket, (byte*)buffer, length, SocketFlags.None, (byte*)&__socketAddress_native, sizeof(sockaddr_in)); 215 | } 216 | 217 | int num = send((int)socket, (byte*)buffer, length, SocketFlags.None); 218 | return num; 219 | } 220 | 221 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 222 | public static int SendTo6(nint socket, void* buffer, int length, sockaddr_in6* socketAddress) 223 | { 224 | if (socketAddress != null) 225 | { 226 | sockaddr_in6 __socketAddress_native = *socketAddress; 227 | __socketAddress_native.sin6_port = WinSock2.HOST_TO_NET_16(socketAddress->sin6_port); 228 | return sendto((int)socket, (byte*)buffer, length, SocketFlags.None, (byte*)&__socketAddress_native, sizeof(sockaddr_in6)); 229 | } 230 | 231 | int num = send((int)socket, (byte*)buffer, length, SocketFlags.None); 232 | return num; 233 | } 234 | 235 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 236 | public static int Receive(nint socket, void* buffer, int length) 237 | { 238 | int num = recv((int)socket, (byte*)buffer, length, SocketFlags.None); 239 | return num; 240 | } 241 | 242 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 243 | public static int ReceiveFrom4(nint socket, void* buffer, int length, sockaddr_in* socketAddress) 244 | { 245 | sockaddr_storage addressStorage = new sockaddr_storage(); 246 | int socketAddressSize = sizeof(sockaddr_storage); 247 | 248 | int num = recvfrom((int)socket, (byte*)buffer, length, SocketFlags.None, (byte*)&addressStorage, &socketAddressSize); 249 | 250 | if (num > 0 && socketAddress != null) 251 | { 252 | sockaddr_in* __socketAddress_native = (sockaddr_in*)&addressStorage; 253 | *socketAddress = *__socketAddress_native; 254 | socketAddress->sin_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin_port); 255 | } 256 | 257 | return num; 258 | } 259 | 260 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 261 | public static int ReceiveFrom6(nint socket, void* buffer, int length, sockaddr_in6* socketAddress) 262 | { 263 | sockaddr_storage addressStorage = new sockaddr_storage(); 264 | int socketAddressSize = sizeof(sockaddr_storage); 265 | 266 | int num = recvfrom((int)socket, (byte*)buffer, length, SocketFlags.None, (byte*)&addressStorage, &socketAddressSize); 267 | 268 | if (num > 0 && socketAddress != null) 269 | { 270 | socketAddress->sin6_family.family = ADDRESS_FAMILY_INTER_NETWORK_V6; 271 | if (addressStorage.ss_family.family == (int)AddressFamily.InterNetwork) 272 | { 273 | sockaddr_in* __socketAddress_native = (sockaddr_in*)&addressStorage; 274 | Unsafe.InitBlockUnaligned(socketAddress->sin6_addr, 0, 8); 275 | Unsafe.WriteUnaligned(socketAddress->sin6_addr + 8, WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6); 276 | Unsafe.WriteUnaligned(socketAddress->sin6_addr + 12, __socketAddress_native->sin_addr); 277 | socketAddress->sin6_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin_port); 278 | socketAddress->sin6_scope_id = 0; 279 | } 280 | else if (addressStorage.ss_family.family == (int)ADDRESS_FAMILY_INTER_NETWORK_V6) 281 | { 282 | sockaddr_in6* __socketAddress_native = (sockaddr_in6*)&addressStorage; 283 | Unsafe.CopyBlockUnaligned(socketAddress->sin6_addr, __socketAddress_native->sin6_addr, 20); 284 | socketAddress->sin6_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin6_port); 285 | } 286 | } 287 | 288 | return num; 289 | } 290 | 291 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 292 | public static int WSASend(nint socket, WSABuffer* buffers, int bufferCount) 293 | { 294 | iovec* msg_iov = stackalloc iovec[bufferCount]; 295 | for (int i = 0; i < bufferCount; ++i) 296 | { 297 | msg_iov[i].iov_base = buffers[i].Pointer; 298 | msg_iov[i].iov_len = buffers[i].Length; 299 | } 300 | 301 | msghdr msg; 302 | msg.msg_name = null; 303 | msg.msg_namelen = 0; 304 | msg.msg_iov = msg_iov; 305 | msg.msg_iovlen = bufferCount; 306 | msg.msg_control = null; 307 | msg.msg_controllen = 0; 308 | msg.msg_flags = 0; 309 | 310 | int num = (int)sendmsg((int)socket, &msg, 0); 311 | return num; 312 | } 313 | 314 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 315 | public static int WSASendTo4(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in* socketAddress) 316 | { 317 | iovec* msg_iov = stackalloc iovec[bufferCount]; 318 | for (int i = 0; i < bufferCount; ++i) 319 | { 320 | msg_iov[i].iov_base = buffers[i].Pointer; 321 | msg_iov[i].iov_len = buffers[i].Length; 322 | } 323 | 324 | sockaddr_in __socketAddress_native; 325 | 326 | msghdr msg; 327 | msg.msg_iov = msg_iov; 328 | msg.msg_iovlen = bufferCount; 329 | msg.msg_control = null; 330 | msg.msg_controllen = 0; 331 | msg.msg_flags = 0; 332 | 333 | if (socketAddress != null) 334 | { 335 | __socketAddress_native = *socketAddress; 336 | __socketAddress_native.sin_port = WinSock2.HOST_TO_NET_16(socketAddress->sin_port); 337 | 338 | msg.msg_name = &__socketAddress_native; 339 | msg.msg_namelen = 16; 340 | } 341 | else 342 | { 343 | msg.msg_name = null; 344 | msg.msg_namelen = 0; 345 | } 346 | 347 | int num = (int)sendmsg((int)socket, &msg, 0); 348 | return num; 349 | } 350 | 351 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 352 | public static int WSASendTo6(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in6* socketAddress) 353 | { 354 | iovec* msg_iov = stackalloc iovec[bufferCount]; 355 | for (int i = 0; i < bufferCount; ++i) 356 | { 357 | msg_iov[i].iov_base = buffers[i].Pointer; 358 | msg_iov[i].iov_len = buffers[i].Length; 359 | } 360 | 361 | sockaddr_in6 __socketAddress_native; 362 | 363 | msghdr msg; 364 | msg.msg_iov = msg_iov; 365 | msg.msg_iovlen = bufferCount; 366 | msg.msg_control = null; 367 | msg.msg_controllen = 0; 368 | msg.msg_flags = 0; 369 | 370 | if (socketAddress != null) 371 | { 372 | __socketAddress_native = *socketAddress; 373 | __socketAddress_native.sin6_port = WinSock2.HOST_TO_NET_16(socketAddress->sin6_port); 374 | 375 | msg.msg_name = &__socketAddress_native; 376 | msg.msg_namelen = 28; 377 | } 378 | else 379 | { 380 | msg.msg_name = null; 381 | msg.msg_namelen = 0; 382 | } 383 | 384 | int num = (int)sendmsg((int)socket, &msg, 0); 385 | return num; 386 | } 387 | 388 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 389 | public static int WSAReceive(nint socket, WSABuffer* buffers, int bufferCount) 390 | { 391 | iovec* msg_iov = stackalloc iovec[bufferCount]; 392 | for (int i = 0; i < bufferCount; ++i) 393 | { 394 | msg_iov[i].iov_base = buffers[i].Pointer; 395 | msg_iov[i].iov_len = buffers[i].Length; 396 | } 397 | 398 | msghdr msg; 399 | msg.msg_name = null; 400 | msg.msg_namelen = 0; 401 | msg.msg_iov = msg_iov; 402 | msg.msg_iovlen = bufferCount; 403 | msg.msg_control = null; 404 | msg.msg_controllen = 0; 405 | msg.msg_flags = 0; 406 | 407 | int num = (int)recvmsg((int)socket, &msg, 0); 408 | 409 | if (msg.msg_flags != 0) 410 | return -1; 411 | 412 | return num; 413 | } 414 | 415 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 416 | public static int WSAReceiveFrom4(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in* socketAddress) 417 | { 418 | iovec* msg_iov = stackalloc iovec[bufferCount]; 419 | for (int i = 0; i < bufferCount; ++i) 420 | { 421 | msg_iov[i].iov_base = buffers[i].Pointer; 422 | msg_iov[i].iov_len = buffers[i].Length; 423 | } 424 | 425 | sockaddr_storage addressStorage = new sockaddr_storage(); 426 | 427 | msghdr msg; 428 | msg.msg_name = &addressStorage; 429 | msg.msg_namelen = (nuint)sizeof(sockaddr_storage); 430 | msg.msg_iov = msg_iov; 431 | msg.msg_iovlen = bufferCount; 432 | msg.msg_control = null; 433 | msg.msg_controllen = 0; 434 | msg.msg_flags = 0; 435 | 436 | int num = (int)recvmsg((int)socket, &msg, 0); 437 | 438 | if (msg.msg_flags != 0) 439 | return -1; 440 | 441 | if (num > 0 && socketAddress != null) 442 | { 443 | sockaddr_in* __socketAddress_native = (sockaddr_in*)&addressStorage; 444 | *socketAddress = *__socketAddress_native; 445 | socketAddress->sin_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin_port); 446 | } 447 | 448 | return num; 449 | } 450 | 451 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 452 | public static int WSAReceiveFrom6(nint socket, WSABuffer* buffers, int bufferCount, sockaddr_in6* socketAddress) 453 | { 454 | iovec* msg_iov = stackalloc iovec[bufferCount]; 455 | for (int i = 0; i < bufferCount; ++i) 456 | { 457 | msg_iov[i].iov_base = buffers[i].Pointer; 458 | msg_iov[i].iov_len = buffers[i].Length; 459 | } 460 | 461 | sockaddr_storage addressStorage = new sockaddr_storage(); 462 | 463 | msghdr msg; 464 | msg.msg_name = &addressStorage; 465 | msg.msg_namelen = (nuint)sizeof(sockaddr_storage); 466 | msg.msg_iov = msg_iov; 467 | msg.msg_iovlen = bufferCount; 468 | msg.msg_control = null; 469 | msg.msg_controllen = 0; 470 | msg.msg_flags = 0; 471 | 472 | int num = (int)recvmsg((int)socket, &msg, 0); 473 | 474 | if (msg.msg_flags != 0) 475 | return -1; 476 | 477 | if (num > 0 && socketAddress != null) 478 | { 479 | socketAddress->sin6_family.family = ADDRESS_FAMILY_INTER_NETWORK_V6; 480 | if (addressStorage.ss_family.family == (int)AddressFamily.InterNetwork) 481 | { 482 | sockaddr_in* __socketAddress_native = (sockaddr_in*)&addressStorage; 483 | Unsafe.InitBlockUnaligned(socketAddress->sin6_addr, 0, 8); 484 | Unsafe.WriteUnaligned(socketAddress->sin6_addr + 8, WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6); 485 | Unsafe.WriteUnaligned(socketAddress->sin6_addr + 12, __socketAddress_native->sin_addr); 486 | socketAddress->sin6_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin_port); 487 | socketAddress->sin6_scope_id = 0; 488 | } 489 | else if (addressStorage.ss_family.family == (int)ADDRESS_FAMILY_INTER_NETWORK_V6) 490 | { 491 | sockaddr_in6* __socketAddress_native = (sockaddr_in6*)&addressStorage; 492 | Unsafe.CopyBlockUnaligned(socketAddress->sin6_addr, __socketAddress_native->sin6_addr, 20); 493 | socketAddress->sin6_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin6_port); 494 | } 495 | } 496 | 497 | return num; 498 | } 499 | 500 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 501 | public static SocketError GetName4(nint socket, sockaddr_in* socketAddress) 502 | { 503 | sockaddr_storage addressStorage = new sockaddr_storage(); 504 | int socketAddressSize = sizeof(sockaddr_storage); 505 | SocketError errorCode = getsockname((int)socket, (sockaddr*)&addressStorage, &socketAddressSize); 506 | if (errorCode == SocketError.Success) 507 | { 508 | socketAddress->sin_family = addressStorage.ss_family; 509 | sockaddr_in* __socketAddress_native = (sockaddr_in*)&addressStorage; 510 | *socketAddress = *__socketAddress_native; 511 | socketAddress->sin_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin_port); 512 | } 513 | 514 | return errorCode; 515 | } 516 | 517 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 518 | public static SocketError GetName6(nint socket, sockaddr_in6* socketAddress) 519 | { 520 | sockaddr_storage addressStorage = new sockaddr_storage(); 521 | int socketAddressSize = sizeof(sockaddr_storage); 522 | SocketError errorCode = getsockname((int)socket, (sockaddr*)&addressStorage, &socketAddressSize); 523 | if (errorCode == SocketError.Success) 524 | { 525 | socketAddress->sin6_family = addressStorage.ss_family; 526 | if (addressStorage.ss_family.family == (int)AddressFamily.InterNetwork) 527 | { 528 | sockaddr_in* __socketAddress_native = (sockaddr_in*)&addressStorage; 529 | Unsafe.InitBlockUnaligned(socketAddress->sin6_addr, 0, 8); 530 | Unsafe.WriteUnaligned(socketAddress->sin6_addr + 8, WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6); 531 | Unsafe.WriteUnaligned(socketAddress->sin6_addr + 12, __socketAddress_native->sin_addr); 532 | socketAddress->sin6_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin_port); 533 | } 534 | else if (addressStorage.ss_family.family == (int)ADDRESS_FAMILY_INTER_NETWORK_V6) 535 | { 536 | sockaddr_in6* __socketAddress_native = (sockaddr_in6*)&addressStorage; 537 | Unsafe.CopyBlockUnaligned(socketAddress->sin6_addr, __socketAddress_native->sin6_addr, 16); 538 | socketAddress->sin6_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin6_port); 539 | } 540 | } 541 | 542 | return errorCode; 543 | } 544 | 545 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 546 | public static SocketError SetIP4(sockaddr_in* socketAddress, ReadOnlySpan ip) 547 | { 548 | void* pAddrBuf = &socketAddress->sin_addr; 549 | 550 | int byteCount = Encoding.ASCII.GetByteCount(ip); 551 | Span buffer = stackalloc byte[byteCount + 1]; 552 | Encoding.ASCII.GetBytes(ip, buffer); 553 | buffer[byteCount] = 0; 554 | 555 | int addressFamily = (int)AddressFamily.InterNetwork; 556 | 557 | int error = inet_pton(addressFamily, Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)), pAddrBuf); 558 | 559 | switch (error) 560 | { 561 | case 1: 562 | return SocketError.Success; 563 | case 0: 564 | return SocketError.InvalidArgument; 565 | default: 566 | return SocketError.Fault; 567 | } 568 | } 569 | 570 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 571 | public static SocketError SetIP6(sockaddr_in6* socketAddress, ReadOnlySpan ip) 572 | { 573 | void* pAddrBuf = socketAddress->sin6_addr; 574 | 575 | int byteCount = Encoding.ASCII.GetByteCount(ip); 576 | Span buffer = stackalloc byte[byteCount + 1]; 577 | Encoding.ASCII.GetBytes(ip, buffer); 578 | buffer[byteCount] = 0; 579 | 580 | int addressFamily = (int)ADDRESS_FAMILY_INTER_NETWORK_V6; 581 | if (ip.IndexOf(':') < 0) 582 | { 583 | addressFamily = (int)AddressFamily.InterNetwork; 584 | Unsafe.InitBlockUnaligned(pAddrBuf, 0, 8); 585 | Unsafe.WriteUnaligned((byte*)pAddrBuf + 8, WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6); 586 | pAddrBuf = (byte*)pAddrBuf + 12; 587 | } 588 | 589 | int error = inet_pton(addressFamily, Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)), pAddrBuf); 590 | 591 | switch (error) 592 | { 593 | case 1: 594 | return SocketError.Success; 595 | case 0: 596 | return SocketError.InvalidArgument; 597 | default: 598 | return SocketError.Fault; 599 | } 600 | } 601 | 602 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 603 | public static SocketError GetIP4(sockaddr_in* socketAddress, Span buffer) 604 | { 605 | void* pAddrBuf = &socketAddress->sin_addr; 606 | 607 | if (inet_ntop((int)AddressFamily.InterNetwork, pAddrBuf, ref MemoryMarshal.GetReference(buffer), (nuint)buffer.Length) == null) 608 | return SocketError.Fault; 609 | 610 | return SocketError.Success; 611 | } 612 | 613 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 614 | public static SocketError GetIP6(sockaddr_in6* socketAddress, Span buffer) 615 | { 616 | void* pAddrBuf = socketAddress->sin6_addr; 617 | 618 | ref int reference = ref Unsafe.AsRef(pAddrBuf); 619 | if (Unsafe.Add(ref reference, 2) == WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6 && reference == 0 && Unsafe.Add(ref reference, 1) == 0) 620 | { 621 | if (inet_ntop((int)AddressFamily.InterNetwork, (byte*)pAddrBuf + 12, ref MemoryMarshal.GetReference(buffer), (nuint)buffer.Length) == null) 622 | return SocketError.Fault; 623 | } 624 | else if (inet_ntop((int)ADDRESS_FAMILY_INTER_NETWORK_V6, pAddrBuf, ref MemoryMarshal.GetReference(buffer), (nuint)buffer.Length) == null) 625 | { 626 | return SocketError.Fault; 627 | } 628 | 629 | return SocketError.Success; 630 | } 631 | 632 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 633 | public static SocketError SetHostName4(sockaddr_in* socketAddress, ReadOnlySpan hostName) 634 | { 635 | void* pAddrBuf = &socketAddress->sin_addr; 636 | 637 | int byteCount = Encoding.ASCII.GetByteCount(hostName); 638 | Span buffer = stackalloc byte[byteCount + 1]; 639 | Encoding.ASCII.GetBytes(hostName, buffer); 640 | buffer[byteCount] = 0; 641 | 642 | addrinfo addressInfo = new addrinfo(); 643 | addrinfo* hint, results = null; 644 | 645 | if (getaddrinfo((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)), null, &addressInfo, &results) != 0) 646 | return SocketError.Fault; 647 | 648 | for (hint = results; hint != null; hint = hint->ai_next) 649 | { 650 | if (hint->ai_addr != null && hint->ai_addrlen >= (nuint)sizeof(sockaddr_in)) 651 | { 652 | if (hint->ai_family == (int)AddressFamily.InterNetwork) 653 | { 654 | sockaddr_in* __socketAddress_native = (sockaddr_in*)hint->ai_addr; 655 | 656 | *socketAddress = *__socketAddress_native; 657 | socketAddress->sin_port = WinSock2.NET_TO_HOST_16(__socketAddress_native->sin_port); 658 | 659 | freeaddrinfo(results); 660 | 661 | return 0; 662 | } 663 | } 664 | } 665 | 666 | if (results != null) 667 | freeaddrinfo(results); 668 | 669 | const int addressFamily = (int)AddressFamily.InterNetwork; 670 | 671 | int error = inet_pton(addressFamily, Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)), pAddrBuf); 672 | 673 | switch (error) 674 | { 675 | case 1: 676 | return SocketError.Success; 677 | case 0: 678 | return SocketError.InvalidArgument; 679 | default: 680 | return SocketError.Fault; 681 | } 682 | } 683 | 684 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 685 | public static SocketError SetHostName6(sockaddr_in6* socketAddress, ReadOnlySpan hostName) 686 | { 687 | void* pAddrBuf = socketAddress->sin6_addr; 688 | 689 | int byteCount = Encoding.ASCII.GetByteCount(hostName); 690 | Span buffer = stackalloc byte[byteCount + 1]; 691 | Encoding.ASCII.GetBytes(hostName, buffer); 692 | buffer[byteCount] = 0; 693 | 694 | addrinfo addressInfo = new addrinfo(); 695 | addrinfo* hint, results = null; 696 | 697 | if (getaddrinfo((byte*)Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)), null, &addressInfo, &results) != 0) 698 | return SocketError.Fault; 699 | 700 | for (hint = results; hint != null; hint = hint->ai_next) 701 | { 702 | if (hint->ai_addr != null && hint->ai_addrlen >= (nuint)sizeof(sockaddr_in)) 703 | { 704 | if (hint->ai_family == (int)AddressFamily.InterNetwork) 705 | { 706 | sockaddr_in* __socketAddress_native = (sockaddr_in*)hint->ai_addr; 707 | 708 | Unsafe.InitBlockUnaligned(pAddrBuf, 0, 8); 709 | Unsafe.WriteUnaligned((byte*)pAddrBuf + 8, WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6); 710 | Unsafe.WriteUnaligned((byte*)pAddrBuf + 12, __socketAddress_native->sin_addr.S_addr); 711 | 712 | freeaddrinfo(results); 713 | 714 | return 0; 715 | } 716 | 717 | if (hint->ai_family == (int)ADDRESS_FAMILY_INTER_NETWORK_V6) 718 | { 719 | sockaddr_in6* __socketAddress_native = (sockaddr_in6*)hint->ai_addr; 720 | 721 | Unsafe.CopyBlockUnaligned(pAddrBuf, __socketAddress_native->sin6_addr, 16); 722 | 723 | freeaddrinfo(results); 724 | 725 | return 0; 726 | } 727 | } 728 | } 729 | 730 | if (results != null) 731 | freeaddrinfo(results); 732 | 733 | int addressFamily = (int)ADDRESS_FAMILY_INTER_NETWORK_V6; 734 | if (buffer.IndexOf((byte)':') == -1) 735 | { 736 | addressFamily = (int)AddressFamily.InterNetwork; 737 | Unsafe.InitBlockUnaligned(pAddrBuf, 0, 8); 738 | Unsafe.WriteUnaligned((byte*)pAddrBuf + 8, WinSock2.ADDRESS_FAMILY_INTER_NETWORK_V4_MAPPED_V6); 739 | pAddrBuf = (byte*)pAddrBuf + 12; 740 | } 741 | 742 | int error = inet_pton(addressFamily, Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)), pAddrBuf); 743 | 744 | switch (error) 745 | { 746 | case 1: 747 | return SocketError.Success; 748 | case 0: 749 | return SocketError.InvalidArgument; 750 | default: 751 | return SocketError.Fault; 752 | } 753 | } 754 | 755 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 756 | public static SocketError GetHostName4(sockaddr_in* socketAddress, Span buffer) 757 | { 758 | sockaddr_in __socketAddress_native = *socketAddress; 759 | 760 | __socketAddress_native.sin_port = WinSock2.HOST_TO_NET_16(socketAddress->sin_port); 761 | 762 | int error = getnameinfo((sockaddr*)&__socketAddress_native, sizeof(sockaddr_in), ref MemoryMarshal.GetReference(buffer), (ulong)buffer.Length, null, 0, 0x4); 763 | 764 | if (error == 0) 765 | { 766 | if (Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)) != null && buffer.Length > 0 && buffer.IndexOf((byte)'\0') < 0) 767 | return SocketError.Fault; 768 | 769 | return SocketError.Success; 770 | } 771 | 772 | if (error != 0x2AF9L) 773 | return SocketError.Fault; 774 | 775 | return GetIP4(socketAddress, buffer); 776 | } 777 | 778 | [MethodImpl(MethodImplOptions.AggressiveInlining)] 779 | public static SocketError GetHostName6(sockaddr_in6* socketAddress, Span buffer) 780 | { 781 | sockaddr_in6 __socketAddress_native = *socketAddress; 782 | 783 | __socketAddress_native.sin6_port = WinSock2.HOST_TO_NET_16(socketAddress->sin6_port); 784 | 785 | int error = getnameinfo((sockaddr*)&__socketAddress_native, sizeof(sockaddr_in6), ref MemoryMarshal.GetReference(buffer), (ulong)buffer.Length, null, 0, 0x4); 786 | 787 | if (error == 0) 788 | { 789 | if (Unsafe.AsPointer(ref MemoryMarshal.GetReference(buffer)) != null && buffer.Length > 0 && buffer.IndexOf((byte)'\0') < 0) 790 | return SocketError.Fault; 791 | 792 | return SocketError.Success; 793 | } 794 | 795 | if (error != 0x2AF9L) 796 | return SocketError.Fault; 797 | 798 | return GetIP6(socketAddress, buffer); 799 | } 800 | } 801 | } --------------------------------------------------------------------------------